mirror of
https://github.com/yuzu-emu/breakpad.git
synced 2025-07-03 14:48:19 +00:00
Update GTM files to latest from
http://google-toolbox-for-mac.googlecode.com/svn/trunk/ Patch by: jakerr@google.com Review: https://breakpad.appspot.com/452002/ git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@1045 4c0a9323-5329-0410-9bdc-e9ce6186880e
This commit is contained in:
parent
0e91d185ca
commit
c83cd11615
|
@ -21,6 +21,14 @@
|
||||||
#include <AvailabilityMacros.h>
|
#include <AvailabilityMacros.h>
|
||||||
#include <TargetConditionals.h>
|
#include <TargetConditionals.h>
|
||||||
|
|
||||||
|
#ifdef __OBJC__
|
||||||
|
#include <Foundation/NSObjCRuntime.h>
|
||||||
|
#endif // __OBJC__
|
||||||
|
|
||||||
|
#if TARGET_OS_IPHONE
|
||||||
|
#include <Availability.h>
|
||||||
|
#endif // TARGET_OS_IPHONE
|
||||||
|
|
||||||
// Not all MAC_OS_X_VERSION_10_X macros defined in past SDKs
|
// Not all MAC_OS_X_VERSION_10_X macros defined in past SDKs
|
||||||
#ifndef MAC_OS_X_VERSION_10_5
|
#ifndef MAC_OS_X_VERSION_10_5
|
||||||
#define MAC_OS_X_VERSION_10_5 1050
|
#define MAC_OS_X_VERSION_10_5 1050
|
||||||
|
@ -28,6 +36,29 @@
|
||||||
#ifndef MAC_OS_X_VERSION_10_6
|
#ifndef MAC_OS_X_VERSION_10_6
|
||||||
#define MAC_OS_X_VERSION_10_6 1060
|
#define MAC_OS_X_VERSION_10_6 1060
|
||||||
#endif
|
#endif
|
||||||
|
#ifndef MAC_OS_X_VERSION_10_7
|
||||||
|
#define MAC_OS_X_VERSION_10_7 1070
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Not all __IPHONE_X macros defined in past SDKs
|
||||||
|
#ifndef __IPHONE_3_0
|
||||||
|
#define __IPHONE_3_0 30000
|
||||||
|
#endif
|
||||||
|
#ifndef __IPHONE_3_1
|
||||||
|
#define __IPHONE_3_1 30100
|
||||||
|
#endif
|
||||||
|
#ifndef __IPHONE_3_2
|
||||||
|
#define __IPHONE_3_2 30200
|
||||||
|
#endif
|
||||||
|
#ifndef __IPHONE_4_0
|
||||||
|
#define __IPHONE_4_0 40000
|
||||||
|
#endif
|
||||||
|
#ifndef __IPHONE_4_3
|
||||||
|
#define __IPHONE_4_3 40300
|
||||||
|
#endif
|
||||||
|
#ifndef __IPHONE_5_0
|
||||||
|
#define __IPHONE_5_0 50000
|
||||||
|
#endif
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
// CPP symbols that can be overridden in a prefix to control how the toolbox
|
// CPP symbols that can be overridden in a prefix to control how the toolbox
|
||||||
|
@ -47,7 +78,7 @@
|
||||||
// a few different actual definitions, so we're based off of the foundation
|
// a few different actual definitions, so we're based off of the foundation
|
||||||
// one.
|
// one.
|
||||||
#if !defined(GTM_INLINE)
|
#if !defined(GTM_INLINE)
|
||||||
#if defined (__GNUC__) && (__GNUC__ == 4)
|
#if (defined (__GNUC__) && (__GNUC__ == 4)) || defined (__clang__)
|
||||||
#define GTM_INLINE static __inline__ __attribute__((always_inline))
|
#define GTM_INLINE static __inline__ __attribute__((always_inline))
|
||||||
#else
|
#else
|
||||||
#define GTM_INLINE static __inline__
|
#define GTM_INLINE static __inline__
|
||||||
|
@ -59,8 +90,12 @@
|
||||||
#if !defined (GTM_EXTERN)
|
#if !defined (GTM_EXTERN)
|
||||||
#if defined __cplusplus
|
#if defined __cplusplus
|
||||||
#define GTM_EXTERN extern "C"
|
#define GTM_EXTERN extern "C"
|
||||||
|
#define GTM_EXTERN_C_BEGIN extern "C" {
|
||||||
|
#define GTM_EXTERN_C_END }
|
||||||
#else
|
#else
|
||||||
#define GTM_EXTERN extern
|
#define GTM_EXTERN extern
|
||||||
|
#define GTM_EXTERN_C_BEGIN
|
||||||
|
#define GTM_EXTERN_C_END
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -70,6 +105,12 @@
|
||||||
#define GTM_EXPORT __attribute__((visibility("default")))
|
#define GTM_EXPORT __attribute__((visibility("default")))
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// Give ourselves a consistent way of declaring something as unused. This
|
||||||
|
// doesn't use __unused because that is only supported in gcc 4.2 and greater.
|
||||||
|
#if !defined (GTM_UNUSED)
|
||||||
|
#define GTM_UNUSED(x) ((void)(x))
|
||||||
|
#endif
|
||||||
|
|
||||||
// _GTMDevLog & _GTMDevAssert
|
// _GTMDevLog & _GTMDevAssert
|
||||||
//
|
//
|
||||||
// _GTMDevLog & _GTMDevAssert are meant to be a very lightweight shell for
|
// _GTMDevLog & _GTMDevAssert are meant to be a very lightweight shell for
|
||||||
|
@ -100,11 +141,6 @@
|
||||||
|
|
||||||
#endif // _GTMDevLog
|
#endif // _GTMDevLog
|
||||||
|
|
||||||
// Declared here so that it can easily be used for logging tracking if
|
|
||||||
// necessary. See GTMUnitTestDevLog.h for details.
|
|
||||||
@class NSString;
|
|
||||||
GTM_EXTERN void _GTMUnitTestDevLog(NSString *format, ...);
|
|
||||||
|
|
||||||
#ifndef _GTMDevAssert
|
#ifndef _GTMDevAssert
|
||||||
// we directly invoke the NSAssert handler so we can pass on the varargs
|
// we directly invoke the NSAssert handler so we can pass on the varargs
|
||||||
// (NSAssert doesn't have a macro we can use that takes varargs)
|
// (NSAssert doesn't have a macro we can use that takes varargs)
|
||||||
|
@ -145,28 +181,6 @@ GTM_EXTERN void _GTMUnitTestDevLog(NSString *format, ...);
|
||||||
typedef char _GTMCompileAssertSymbol(__LINE__, msg) [ ((test) ? 1 : -1) ]
|
typedef char _GTMCompileAssertSymbol(__LINE__, msg) [ ((test) ? 1 : -1) ]
|
||||||
#endif // _GTMCompileAssert
|
#endif // _GTMCompileAssert
|
||||||
|
|
||||||
// Macro to allow fast enumeration when building for 10.5 or later, and
|
|
||||||
// reliance on NSEnumerator for 10.4. Remember, NSDictionary w/ FastEnumeration
|
|
||||||
// does keys, so pick the right thing, nothing is done on the FastEnumeration
|
|
||||||
// side to be sure you're getting what you wanted.
|
|
||||||
#ifndef GTM_FOREACH_OBJECT
|
|
||||||
#if TARGET_OS_IPHONE || (MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_5)
|
|
||||||
#define GTM_FOREACH_OBJECT(element, collection) \
|
|
||||||
for (element in collection)
|
|
||||||
#define GTM_FOREACH_KEY(element, collection) \
|
|
||||||
for (element in collection)
|
|
||||||
#else
|
|
||||||
#define GTM_FOREACH_OBJECT(element, collection) \
|
|
||||||
for (NSEnumerator * _ ## element ## _enum = [collection objectEnumerator]; \
|
|
||||||
(element = [_ ## element ## _enum nextObject]) != nil; )
|
|
||||||
#define GTM_FOREACH_KEY(element, collection) \
|
|
||||||
for (NSEnumerator * _ ## element ## _enum = [collection keyEnumerator]; \
|
|
||||||
(element = [_ ## element ## _enum nextObject]) != nil; )
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
// CPP symbols defined based on the project settings so the GTM code has
|
// CPP symbols defined based on the project settings so the GTM code has
|
||||||
// simple things to test against w/o scattering the knowledge of project
|
// simple things to test against w/o scattering the knowledge of project
|
||||||
|
@ -183,11 +197,26 @@ GTM_EXTERN void _GTMUnitTestDevLog(NSString *format, ...);
|
||||||
#else
|
#else
|
||||||
#define GTM_IPHONE_DEVICE 1
|
#define GTM_IPHONE_DEVICE 1
|
||||||
#endif // TARGET_IPHONE_SIMULATOR
|
#endif // TARGET_IPHONE_SIMULATOR
|
||||||
|
// By default, GTM has provided it's own unittesting support, define this
|
||||||
|
// to use the support provided by Xcode, especially for the Xcode4 support
|
||||||
|
// for unittesting.
|
||||||
|
#ifndef GTM_IPHONE_USE_SENTEST
|
||||||
|
#define GTM_IPHONE_USE_SENTEST 0
|
||||||
|
#endif
|
||||||
#else
|
#else
|
||||||
// For MacOS specific stuff
|
// For MacOS specific stuff
|
||||||
#define GTM_MACOS_SDK 1
|
#define GTM_MACOS_SDK 1
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// Some of our own availability macros
|
||||||
|
#if GTM_MACOS_SDK
|
||||||
|
#define GTM_AVAILABLE_ONLY_ON_IPHONE UNAVAILABLE_ATTRIBUTE
|
||||||
|
#define GTM_AVAILABLE_ONLY_ON_MACOS
|
||||||
|
#else
|
||||||
|
#define GTM_AVAILABLE_ONLY_ON_IPHONE
|
||||||
|
#define GTM_AVAILABLE_ONLY_ON_MACOS UNAVAILABLE_ATTRIBUTE
|
||||||
|
#endif
|
||||||
|
|
||||||
// Provide a symbol to include/exclude extra code for GC support. (This mainly
|
// Provide a symbol to include/exclude extra code for GC support. (This mainly
|
||||||
// just controls the inclusion of finalize methods).
|
// just controls the inclusion of finalize methods).
|
||||||
#ifndef GTM_SUPPORT_GC
|
#ifndef GTM_SUPPORT_GC
|
||||||
|
@ -197,7 +226,7 @@ GTM_EXTERN void _GTMUnitTestDevLog(NSString *format, ...);
|
||||||
#else
|
#else
|
||||||
// We can't find a symbol to tell if GC is supported/required, so best we
|
// We can't find a symbol to tell if GC is supported/required, so best we
|
||||||
// do on Mac targets is include it if we're on 10.5 or later.
|
// do on Mac targets is include it if we're on 10.5 or later.
|
||||||
#if MAC_OS_X_VERSION_MAX_ALLOWED <= MAC_OS_X_VERSION_10_4
|
#if MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_5
|
||||||
#define GTM_SUPPORT_GC 0
|
#define GTM_SUPPORT_GC 0
|
||||||
#else
|
#else
|
||||||
#define GTM_SUPPORT_GC 1
|
#define GTM_SUPPORT_GC 1
|
||||||
|
@ -207,7 +236,7 @@ GTM_EXTERN void _GTMUnitTestDevLog(NSString *format, ...);
|
||||||
|
|
||||||
// To simplify support for 64bit (and Leopard in general), we provide the type
|
// To simplify support for 64bit (and Leopard in general), we provide the type
|
||||||
// defines for non Leopard SDKs
|
// defines for non Leopard SDKs
|
||||||
#if MAC_OS_X_VERSION_MAX_ALLOWED <= MAC_OS_X_VERSION_10_4
|
#if !(MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5)
|
||||||
// NSInteger/NSUInteger and Max/Mins
|
// NSInteger/NSUInteger and Max/Mins
|
||||||
#ifndef NSINTEGER_DEFINED
|
#ifndef NSINTEGER_DEFINED
|
||||||
#if __LP64__ || NS_BUILD_32_LIKE_64
|
#if __LP64__ || NS_BUILD_32_LIKE_64
|
||||||
|
@ -238,4 +267,178 @@ GTM_EXTERN void _GTMUnitTestDevLog(NSString *format, ...);
|
||||||
#endif /* !defined(__LP64__) || !__LP64__ */
|
#endif /* !defined(__LP64__) || !__LP64__ */
|
||||||
#define CGFLOAT_DEFINED 1
|
#define CGFLOAT_DEFINED 1
|
||||||
#endif // CGFLOAT_DEFINED
|
#endif // CGFLOAT_DEFINED
|
||||||
#endif // MAC_OS_X_VERSION_MAX_ALLOWED <= MAC_OS_X_VERSION_10_4
|
#endif // MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_5
|
||||||
|
|
||||||
|
// Some support for advanced clang static analysis functionality
|
||||||
|
// See http://clang-analyzer.llvm.org/annotations.html
|
||||||
|
#ifndef __has_feature // Optional.
|
||||||
|
#define __has_feature(x) 0 // Compatibility with non-clang compilers.
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef NS_RETURNS_RETAINED
|
||||||
|
#if __has_feature(attribute_ns_returns_retained)
|
||||||
|
#define NS_RETURNS_RETAINED __attribute__((ns_returns_retained))
|
||||||
|
#else
|
||||||
|
#define NS_RETURNS_RETAINED
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef NS_RETURNS_NOT_RETAINED
|
||||||
|
#if __has_feature(attribute_ns_returns_not_retained)
|
||||||
|
#define NS_RETURNS_NOT_RETAINED __attribute__((ns_returns_not_retained))
|
||||||
|
#else
|
||||||
|
#define NS_RETURNS_NOT_RETAINED
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef CF_RETURNS_RETAINED
|
||||||
|
#if __has_feature(attribute_cf_returns_retained)
|
||||||
|
#define CF_RETURNS_RETAINED __attribute__((cf_returns_retained))
|
||||||
|
#else
|
||||||
|
#define CF_RETURNS_RETAINED
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef CF_RETURNS_NOT_RETAINED
|
||||||
|
#if __has_feature(attribute_cf_returns_not_retained)
|
||||||
|
#define CF_RETURNS_NOT_RETAINED __attribute__((cf_returns_not_retained))
|
||||||
|
#else
|
||||||
|
#define CF_RETURNS_NOT_RETAINED
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef NS_CONSUMED
|
||||||
|
#if __has_feature(attribute_ns_consumed)
|
||||||
|
#define NS_CONSUMED __attribute__((ns_consumed))
|
||||||
|
#else
|
||||||
|
#define NS_CONSUMED
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef CF_CONSUMED
|
||||||
|
#if __has_feature(attribute_cf_consumed)
|
||||||
|
#define CF_CONSUMED __attribute__((cf_consumed))
|
||||||
|
#else
|
||||||
|
#define CF_CONSUMED
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef NS_CONSUMES_SELF
|
||||||
|
#if __has_feature(attribute_ns_consumes_self)
|
||||||
|
#define NS_CONSUMES_SELF __attribute__((ns_consumes_self))
|
||||||
|
#else
|
||||||
|
#define NS_CONSUMES_SELF
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Defined on 10.6 and above.
|
||||||
|
#ifndef NS_FORMAT_ARGUMENT
|
||||||
|
#define NS_FORMAT_ARGUMENT(A)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Defined on 10.6 and above.
|
||||||
|
#ifndef NS_FORMAT_FUNCTION
|
||||||
|
#define NS_FORMAT_FUNCTION(F,A)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Defined on 10.6 and above.
|
||||||
|
#ifndef CF_FORMAT_ARGUMENT
|
||||||
|
#define CF_FORMAT_ARGUMENT(A)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Defined on 10.6 and above.
|
||||||
|
#ifndef CF_FORMAT_FUNCTION
|
||||||
|
#define CF_FORMAT_FUNCTION(F,A)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef GTM_NONNULL
|
||||||
|
#define GTM_NONNULL(x) __attribute__((nonnull(x)))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Invalidates the initializer from which it's called.
|
||||||
|
#ifndef GTMInvalidateInitializer
|
||||||
|
#if __has_feature(objc_arc)
|
||||||
|
#define GTMInvalidateInitializer() \
|
||||||
|
do { \
|
||||||
|
[self class]; /* Avoid warning of dead store to |self|. */ \
|
||||||
|
_GTMDevAssert(NO, @"Invalid initializer."); \
|
||||||
|
return nil; \
|
||||||
|
} while (0)
|
||||||
|
#else
|
||||||
|
#define GTMInvalidateInitializer() \
|
||||||
|
do { \
|
||||||
|
[self release]; \
|
||||||
|
_GTMDevAssert(NO, @"Invalid initializer."); \
|
||||||
|
return nil; \
|
||||||
|
} while (0)
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __OBJC__
|
||||||
|
|
||||||
|
// Declared here so that it can easily be used for logging tracking if
|
||||||
|
// necessary. See GTMUnitTestDevLog.h for details.
|
||||||
|
@class NSString;
|
||||||
|
GTM_EXTERN void _GTMUnitTestDevLog(NSString *format, ...) NS_FORMAT_FUNCTION(1, 2);
|
||||||
|
|
||||||
|
// Macro to allow you to create NSStrings out of other macros.
|
||||||
|
// #define FOO foo
|
||||||
|
// NSString *fooString = GTM_NSSTRINGIFY(FOO);
|
||||||
|
#if !defined (GTM_NSSTRINGIFY)
|
||||||
|
#define GTM_NSSTRINGIFY_INNER(x) @#x
|
||||||
|
#define GTM_NSSTRINGIFY(x) GTM_NSSTRINGIFY_INNER(x)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Macro to allow fast enumeration when building for 10.5 or later, and
|
||||||
|
// reliance on NSEnumerator for 10.4. Remember, NSDictionary w/ FastEnumeration
|
||||||
|
// does keys, so pick the right thing, nothing is done on the FastEnumeration
|
||||||
|
// side to be sure you're getting what you wanted.
|
||||||
|
#ifndef GTM_FOREACH_OBJECT
|
||||||
|
#if TARGET_OS_IPHONE || !(MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_5)
|
||||||
|
#define GTM_FOREACH_ENUMEREE(element, enumeration) \
|
||||||
|
for (element in enumeration)
|
||||||
|
#define GTM_FOREACH_OBJECT(element, collection) \
|
||||||
|
for (element in collection)
|
||||||
|
#define GTM_FOREACH_KEY(element, collection) \
|
||||||
|
for (element in collection)
|
||||||
|
#else
|
||||||
|
#define GTM_FOREACH_ENUMEREE(element, enumeration) \
|
||||||
|
for (NSEnumerator *_ ## element ## _enum = enumeration; \
|
||||||
|
(element = [_ ## element ## _enum nextObject]) != nil; )
|
||||||
|
#define GTM_FOREACH_OBJECT(element, collection) \
|
||||||
|
GTM_FOREACH_ENUMEREE(element, [collection objectEnumerator])
|
||||||
|
#define GTM_FOREACH_KEY(element, collection) \
|
||||||
|
GTM_FOREACH_ENUMEREE(element, [collection keyEnumerator])
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
|
// To simplify support for both Leopard and Snow Leopard we declare
|
||||||
|
// the Snow Leopard protocols that we need here.
|
||||||
|
#if !defined(GTM_10_6_PROTOCOLS_DEFINED) && !(MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6)
|
||||||
|
#define GTM_10_6_PROTOCOLS_DEFINED 1
|
||||||
|
@protocol NSConnectionDelegate
|
||||||
|
@end
|
||||||
|
@protocol NSAnimationDelegate
|
||||||
|
@end
|
||||||
|
@protocol NSImageDelegate
|
||||||
|
@end
|
||||||
|
@protocol NSTabViewDelegate
|
||||||
|
@end
|
||||||
|
#endif // !defined(GTM_10_6_PROTOCOLS_DEFINED) && !(MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6)
|
||||||
|
|
||||||
|
// GTM_SEL_STRING is for specifying selector (usually property) names to KVC
|
||||||
|
// or KVO methods.
|
||||||
|
// In debug it will generate warnings for undeclared selectors if
|
||||||
|
// -Wunknown-selector is turned on.
|
||||||
|
// In release it will have no runtime overhead.
|
||||||
|
#ifndef GTM_SEL_STRING
|
||||||
|
#ifdef DEBUG
|
||||||
|
#define GTM_SEL_STRING(selName) NSStringFromSelector(@selector(selName))
|
||||||
|
#else
|
||||||
|
#define GTM_SEL_STRING(selName) @#selName
|
||||||
|
#endif // DEBUG
|
||||||
|
#endif // GTM_SEL_STRING
|
||||||
|
|
||||||
|
#endif // __OBJC__
|
||||||
|
|
|
@ -55,12 +55,6 @@
|
||||||
// Predeclaration of used protocols that are declared later in this file.
|
// Predeclaration of used protocols that are declared later in this file.
|
||||||
@protocol GTMLogWriter, GTMLogFormatter, GTMLogFilter;
|
@protocol GTMLogWriter, GTMLogFormatter, GTMLogFilter;
|
||||||
|
|
||||||
#if MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_5
|
|
||||||
#define CHECK_FORMAT_NSSTRING(a, b) __attribute__((format(__NSString__, a, b)))
|
|
||||||
#else
|
|
||||||
#define CHECK_FORMAT_NSSTRING(a, b)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// GTMLogger
|
// GTMLogger
|
||||||
//
|
//
|
||||||
// GTMLogger is the primary user-facing class for an object-oriented logging
|
// GTMLogger is the primary user-facing class for an object-oriented logging
|
||||||
|
@ -244,6 +238,10 @@
|
||||||
// Same as +standardLogger, but logs to stderr.
|
// Same as +standardLogger, but logs to stderr.
|
||||||
+ (id)standardLoggerWithStderr;
|
+ (id)standardLoggerWithStderr;
|
||||||
|
|
||||||
|
// Same as +standardLogger but levels >= kGTMLoggerLevelError are routed to
|
||||||
|
// stderr, everything else goes to stdout.
|
||||||
|
+ (id)standardLoggerWithStdoutAndStderr;
|
||||||
|
|
||||||
// Returns a new standard GTMLogger instance with a log writer that will
|
// Returns a new standard GTMLogger instance with a log writer that will
|
||||||
// write to the file at |path|, and will use the GTMLogStandardFormatter and
|
// write to the file at |path|, and will use the GTMLogStandardFormatter and
|
||||||
// GTMLogLevelFilter classes. If |path| does not exist, it will be created.
|
// GTMLogLevelFilter classes. If |path| does not exist, it will be created.
|
||||||
|
@ -274,13 +272,13 @@
|
||||||
//
|
//
|
||||||
|
|
||||||
// Logs a message at the debug level (kGTMLoggerLevelDebug).
|
// Logs a message at the debug level (kGTMLoggerLevelDebug).
|
||||||
- (void)logDebug:(NSString *)fmt, ... CHECK_FORMAT_NSSTRING(1, 2);
|
- (void)logDebug:(NSString *)fmt, ... NS_FORMAT_FUNCTION(1, 2);
|
||||||
// Logs a message at the info level (kGTMLoggerLevelInfo).
|
// Logs a message at the info level (kGTMLoggerLevelInfo).
|
||||||
- (void)logInfo:(NSString *)fmt, ... CHECK_FORMAT_NSSTRING(1, 2);
|
- (void)logInfo:(NSString *)fmt, ... NS_FORMAT_FUNCTION(1, 2);
|
||||||
// Logs a message at the error level (kGTMLoggerLevelError).
|
// Logs a message at the error level (kGTMLoggerLevelError).
|
||||||
- (void)logError:(NSString *)fmt, ... CHECK_FORMAT_NSSTRING(1, 2);
|
- (void)logError:(NSString *)fmt, ... NS_FORMAT_FUNCTION(1, 2);
|
||||||
// Logs a message at the assert level (kGTMLoggerLevelAssert).
|
// Logs a message at the assert level (kGTMLoggerLevelAssert).
|
||||||
- (void)logAssert:(NSString *)fmt, ... CHECK_FORMAT_NSSTRING(1, 2);
|
- (void)logAssert:(NSString *)fmt, ... NS_FORMAT_FUNCTION(1, 2);
|
||||||
|
|
||||||
|
|
||||||
//
|
//
|
||||||
|
@ -310,16 +308,19 @@
|
||||||
// enable the logging of function names.
|
// enable the logging of function names.
|
||||||
@interface GTMLogger (GTMLoggerMacroHelpers)
|
@interface GTMLogger (GTMLoggerMacroHelpers)
|
||||||
- (void)logFuncDebug:(const char *)func msg:(NSString *)fmt, ...
|
- (void)logFuncDebug:(const char *)func msg:(NSString *)fmt, ...
|
||||||
CHECK_FORMAT_NSSTRING(2, 3);
|
NS_FORMAT_FUNCTION(2, 3);
|
||||||
- (void)logFuncInfo:(const char *)func msg:(NSString *)fmt, ...
|
- (void)logFuncInfo:(const char *)func msg:(NSString *)fmt, ...
|
||||||
CHECK_FORMAT_NSSTRING(2, 3);
|
NS_FORMAT_FUNCTION(2, 3);
|
||||||
- (void)logFuncError:(const char *)func msg:(NSString *)fmt, ...
|
- (void)logFuncError:(const char *)func msg:(NSString *)fmt, ...
|
||||||
CHECK_FORMAT_NSSTRING(2, 3);
|
NS_FORMAT_FUNCTION(2, 3);
|
||||||
- (void)logFuncAssert:(const char *)func msg:(NSString *)fmt, ...
|
- (void)logFuncAssert:(const char *)func msg:(NSString *)fmt, ...
|
||||||
CHECK_FORMAT_NSSTRING(2, 3);
|
NS_FORMAT_FUNCTION(2, 3);
|
||||||
@end // GTMLoggerMacroHelpers
|
@end // GTMLoggerMacroHelpers
|
||||||
|
|
||||||
|
|
||||||
|
// The convenience macros are only defined if they haven't already been defined.
|
||||||
|
#ifndef GTMLoggerInfo
|
||||||
|
|
||||||
// Convenience macros that log to the shared GTMLogger instance. These macros
|
// Convenience macros that log to the shared GTMLogger instance. These macros
|
||||||
// are how users should typically log to GTMLogger. Notice that GTMLoggerDebug()
|
// are how users should typically log to GTMLogger. Notice that GTMLoggerDebug()
|
||||||
// calls will be compiled out of non-Debug builds.
|
// calls will be compiled out of non-Debug builds.
|
||||||
|
@ -339,6 +340,8 @@
|
||||||
#define GTMLoggerDebug(...) do {} while(0)
|
#define GTMLoggerDebug(...) do {} while(0)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#endif // !defined(GTMLoggerInfo)
|
||||||
|
|
||||||
// Log levels.
|
// Log levels.
|
||||||
typedef enum {
|
typedef enum {
|
||||||
kGTMLoggerLevelUnknown,
|
kGTMLoggerLevelUnknown,
|
||||||
|
@ -407,7 +410,7 @@ typedef enum {
|
||||||
- (NSString *)stringForFunc:(NSString *)func
|
- (NSString *)stringForFunc:(NSString *)func
|
||||||
withFormat:(NSString *)fmt
|
withFormat:(NSString *)fmt
|
||||||
valist:(va_list)args
|
valist:(va_list)args
|
||||||
level:(GTMLoggerLevel)level;
|
level:(GTMLoggerLevel)level NS_FORMAT_FUNCTION(2, 0);
|
||||||
@end // GTMLogFormatter
|
@end // GTMLogFormatter
|
||||||
|
|
||||||
|
|
||||||
|
@ -415,6 +418,10 @@ typedef enum {
|
||||||
// printf) would. It does not do anything fancy, nor does it add any data of its
|
// printf) would. It does not do anything fancy, nor does it add any data of its
|
||||||
// own.
|
// own.
|
||||||
@interface GTMLogBasicFormatter : NSObject <GTMLogFormatter>
|
@interface GTMLogBasicFormatter : NSObject <GTMLogFormatter>
|
||||||
|
|
||||||
|
// Helper method for prettying C99 __func__ and GCC __PRETTY_FUNCTION__
|
||||||
|
- (NSString *)prettyNameForFunc:(NSString *)func;
|
||||||
|
|
||||||
@end // GTMLogBasicFormatter
|
@end // GTMLogBasicFormatter
|
||||||
|
|
||||||
|
|
||||||
|
@ -450,9 +457,48 @@ typedef enum {
|
||||||
@interface GTMLogLevelFilter : NSObject <GTMLogFilter>
|
@interface GTMLogLevelFilter : NSObject <GTMLogFilter>
|
||||||
@end // GTMLogLevelFilter
|
@end // GTMLogLevelFilter
|
||||||
|
|
||||||
|
|
||||||
// A simple log filter that does NOT filter anything out;
|
// A simple log filter that does NOT filter anything out;
|
||||||
// -filterAllowsMessage:level will always return YES. This can be a convenient
|
// -filterAllowsMessage:level will always return YES. This can be a convenient
|
||||||
// way to enable debug-level logging in release builds (if you so desire).
|
// way to enable debug-level logging in release builds (if you so desire).
|
||||||
@interface GTMLogNoFilter : NSObject <GTMLogFilter>
|
@interface GTMLogNoFilter : NSObject <GTMLogFilter>
|
||||||
@end // GTMLogNoFilter
|
@end // GTMLogNoFilter
|
||||||
|
|
||||||
|
|
||||||
|
// Base class for custom level filters. Not for direct use, use the minimum
|
||||||
|
// or maximum level subclasses below.
|
||||||
|
@interface GTMLogAllowedLevelFilter : NSObject <GTMLogFilter> {
|
||||||
|
@private
|
||||||
|
NSIndexSet *allowedLevels_;
|
||||||
|
}
|
||||||
|
@end
|
||||||
|
|
||||||
|
// A log filter that allows you to set a minimum log level. Messages below this
|
||||||
|
// level will be filtered.
|
||||||
|
@interface GTMLogMininumLevelFilter : GTMLogAllowedLevelFilter
|
||||||
|
|
||||||
|
// Designated initializer, logs at levels < |level| will be filtered.
|
||||||
|
- (id)initWithMinimumLevel:(GTMLoggerLevel)level;
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
// A log filter that allows you to set a maximum log level. Messages whose level
|
||||||
|
// exceeds this level will be filtered. This is really only useful if you have
|
||||||
|
// a composite GTMLogger that is sending the other messages elsewhere.
|
||||||
|
@interface GTMLogMaximumLevelFilter : GTMLogAllowedLevelFilter
|
||||||
|
|
||||||
|
// Designated initializer, logs at levels > |level| will be filtered.
|
||||||
|
- (id)initWithMaximumLevel:(GTMLoggerLevel)level;
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
|
||||||
|
// For subclasses only
|
||||||
|
@interface GTMLogger (PrivateMethods)
|
||||||
|
|
||||||
|
- (void)logInternalFunc:(const char *)func
|
||||||
|
format:(NSString *)fmt
|
||||||
|
valist:(va_list)args
|
||||||
|
level:(GTMLoggerLevel)level NS_FORMAT_FUNCTION(2, 0);
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
|
|
@ -24,23 +24,15 @@
|
||||||
#import <pthread.h>
|
#import <pthread.h>
|
||||||
|
|
||||||
|
|
||||||
// Define a trivial assertion macro to avoid dependencies
|
#if !defined(__clang__) && (__GNUC__*10+__GNUC_MINOR__ >= 42)
|
||||||
#ifdef DEBUG
|
// Some versions of GCC (4.2 and below AFAIK) aren't great about supporting
|
||||||
#define GTMLOGGER_ASSERT(expr) assert(expr)
|
// -Wmissing-format-attribute
|
||||||
#else
|
// when the function is anything more complex than foo(NSString *fmt, ...).
|
||||||
#define GTMLOGGER_ASSERT(expr)
|
// You see the error inside the function when you turn ... into va_args and
|
||||||
#endif
|
// attempt to call another function (like vsprintf for example).
|
||||||
|
// So we just shut off the warning for this file. We reenable it at the end.
|
||||||
|
#pragma GCC diagnostic ignored "-Wmissing-format-attribute"
|
||||||
@interface GTMLogger (PrivateMethods)
|
#endif // !__clang__
|
||||||
|
|
||||||
- (void)logInternalFunc:(const char *)func
|
|
||||||
format:(NSString *)fmt
|
|
||||||
valist:(va_list)args
|
|
||||||
level:(GTMLoggerLevel)level;
|
|
||||||
|
|
||||||
@end
|
|
||||||
|
|
||||||
|
|
||||||
// Reference to the shared GTMLogger instance. This is not a singleton, it's
|
// Reference to the shared GTMLogger instance. This is not a singleton, it's
|
||||||
// just an easy reference to one shared instance.
|
// just an easy reference to one shared instance.
|
||||||
|
@ -56,7 +48,6 @@ static GTMLogger *gSharedLogger = nil;
|
||||||
if (gSharedLogger == nil) {
|
if (gSharedLogger == nil) {
|
||||||
gSharedLogger = [[self standardLogger] retain];
|
gSharedLogger = [[self standardLogger] retain];
|
||||||
}
|
}
|
||||||
GTMLOGGER_ASSERT(gSharedLogger != nil);
|
|
||||||
}
|
}
|
||||||
return [[gSharedLogger retain] autorelease];
|
return [[gSharedLogger retain] autorelease];
|
||||||
}
|
}
|
||||||
|
@ -69,24 +60,85 @@ static GTMLogger *gSharedLogger = nil;
|
||||||
}
|
}
|
||||||
|
|
||||||
+ (id)standardLogger {
|
+ (id)standardLogger {
|
||||||
id<GTMLogWriter> writer = [NSFileHandle fileHandleWithStandardOutput];
|
// Don't trust NSFileHandle not to throw
|
||||||
id<GTMLogFormatter> fr = [[[GTMLogStandardFormatter alloc] init] autorelease];
|
@try {
|
||||||
id<GTMLogFilter> filter = [[[GTMLogLevelFilter alloc] init] autorelease];
|
id<GTMLogWriter> writer = [NSFileHandle fileHandleWithStandardOutput];
|
||||||
return [self loggerWithWriter:writer formatter:fr filter:filter];
|
id<GTMLogFormatter> fr = [[[GTMLogStandardFormatter alloc] init]
|
||||||
|
autorelease];
|
||||||
|
id<GTMLogFilter> filter = [[[GTMLogLevelFilter alloc] init] autorelease];
|
||||||
|
return [[[self alloc] initWithWriter:writer
|
||||||
|
formatter:fr
|
||||||
|
filter:filter] autorelease];
|
||||||
|
}
|
||||||
|
@catch (id e) {
|
||||||
|
// Ignored
|
||||||
|
}
|
||||||
|
return nil;
|
||||||
}
|
}
|
||||||
|
|
||||||
+ (id)standardLoggerWithStderr {
|
+ (id)standardLoggerWithStderr {
|
||||||
id me = [self standardLogger];
|
// Don't trust NSFileHandle not to throw
|
||||||
[me setWriter:[NSFileHandle fileHandleWithStandardError]];
|
@try {
|
||||||
return me;
|
id me = [self standardLogger];
|
||||||
|
[me setWriter:[NSFileHandle fileHandleWithStandardError]];
|
||||||
|
return me;
|
||||||
|
}
|
||||||
|
@catch (id e) {
|
||||||
|
// Ignored
|
||||||
|
}
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (id)standardLoggerWithStdoutAndStderr {
|
||||||
|
// We're going to take advantage of the GTMLogger to GTMLogWriter adaptor
|
||||||
|
// and create a composite logger that an outer "standard" logger can use
|
||||||
|
// as a writer. Our inner loggers should apply no formatting since the main
|
||||||
|
// logger does that and we want the caller to be able to change formatters
|
||||||
|
// or add writers without knowing the inner structure of our composite.
|
||||||
|
|
||||||
|
// Don't trust NSFileHandle not to throw
|
||||||
|
@try {
|
||||||
|
GTMLogBasicFormatter *formatter = [[[GTMLogBasicFormatter alloc] init]
|
||||||
|
autorelease];
|
||||||
|
GTMLogger *stdoutLogger =
|
||||||
|
[self loggerWithWriter:[NSFileHandle fileHandleWithStandardOutput]
|
||||||
|
formatter:formatter
|
||||||
|
filter:[[[GTMLogMaximumLevelFilter alloc]
|
||||||
|
initWithMaximumLevel:kGTMLoggerLevelInfo]
|
||||||
|
autorelease]];
|
||||||
|
GTMLogger *stderrLogger =
|
||||||
|
[self loggerWithWriter:[NSFileHandle fileHandleWithStandardError]
|
||||||
|
formatter:formatter
|
||||||
|
filter:[[[GTMLogMininumLevelFilter alloc]
|
||||||
|
initWithMinimumLevel:kGTMLoggerLevelError]
|
||||||
|
autorelease]];
|
||||||
|
GTMLogger *compositeWriter =
|
||||||
|
[self loggerWithWriter:[NSArray arrayWithObjects:
|
||||||
|
stdoutLogger, stderrLogger, nil]
|
||||||
|
formatter:formatter
|
||||||
|
filter:[[[GTMLogNoFilter alloc] init] autorelease]];
|
||||||
|
GTMLogger *outerLogger = [self standardLogger];
|
||||||
|
[outerLogger setWriter:compositeWriter];
|
||||||
|
return outerLogger;
|
||||||
|
}
|
||||||
|
@catch (id e) {
|
||||||
|
// Ignored
|
||||||
|
}
|
||||||
|
return nil;
|
||||||
}
|
}
|
||||||
|
|
||||||
+ (id)standardLoggerWithPath:(NSString *)path {
|
+ (id)standardLoggerWithPath:(NSString *)path {
|
||||||
NSFileHandle *fh = [NSFileHandle fileHandleForLoggingAtPath:path mode:0644];
|
@try {
|
||||||
if (fh == nil) return nil;
|
NSFileHandle *fh = [NSFileHandle fileHandleForLoggingAtPath:path mode:0644];
|
||||||
id me = [self standardLogger];
|
if (fh == nil) return nil;
|
||||||
[me setWriter:fh];
|
id me = [self standardLogger];
|
||||||
return me;
|
[me setWriter:fh];
|
||||||
|
return me;
|
||||||
|
}
|
||||||
|
@catch (id e) {
|
||||||
|
// Ignored
|
||||||
|
}
|
||||||
|
return nil;
|
||||||
}
|
}
|
||||||
|
|
||||||
+ (id)loggerWithWriter:(id<GTMLogWriter>)writer
|
+ (id)loggerWithWriter:(id<GTMLogWriter>)writer
|
||||||
|
@ -112,69 +164,85 @@ static GTMLogger *gSharedLogger = nil;
|
||||||
[self setWriter:writer];
|
[self setWriter:writer];
|
||||||
[self setFormatter:formatter];
|
[self setFormatter:formatter];
|
||||||
[self setFilter:filter];
|
[self setFilter:filter];
|
||||||
GTMLOGGER_ASSERT(formatter_ != nil);
|
|
||||||
GTMLOGGER_ASSERT(filter_ != nil);
|
|
||||||
GTMLOGGER_ASSERT(writer_ != nil);
|
|
||||||
}
|
}
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)dealloc {
|
- (void)dealloc {
|
||||||
GTMLOGGER_ASSERT(writer_ != nil);
|
// Unlikely, but |writer_| may be an NSFileHandle, which can throw
|
||||||
GTMLOGGER_ASSERT(formatter_ != nil);
|
@try {
|
||||||
GTMLOGGER_ASSERT(filter_ != nil);
|
[formatter_ release];
|
||||||
[writer_ release];
|
[filter_ release];
|
||||||
[formatter_ release];
|
[writer_ release];
|
||||||
[filter_ release];
|
}
|
||||||
|
@catch (id e) {
|
||||||
|
// Ignored
|
||||||
|
}
|
||||||
[super dealloc];
|
[super dealloc];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (id<GTMLogWriter>)writer {
|
- (id<GTMLogWriter>)writer {
|
||||||
GTMLOGGER_ASSERT(writer_ != nil);
|
|
||||||
return [[writer_ retain] autorelease];
|
return [[writer_ retain] autorelease];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setWriter:(id<GTMLogWriter>)writer {
|
- (void)setWriter:(id<GTMLogWriter>)writer {
|
||||||
@synchronized(self) {
|
@synchronized(self) {
|
||||||
[writer_ autorelease];
|
[writer_ autorelease];
|
||||||
if (writer == nil)
|
writer_ = nil;
|
||||||
writer_ = [[NSFileHandle fileHandleWithStandardOutput] retain];
|
if (writer == nil) {
|
||||||
else
|
// Try to use stdout, but don't trust NSFileHandle
|
||||||
|
@try {
|
||||||
|
writer_ = [[NSFileHandle fileHandleWithStandardOutput] retain];
|
||||||
|
}
|
||||||
|
@catch (id e) {
|
||||||
|
// Leave |writer_| nil
|
||||||
|
}
|
||||||
|
} else {
|
||||||
writer_ = [writer retain];
|
writer_ = [writer retain];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
GTMLOGGER_ASSERT(writer_ != nil);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
- (id<GTMLogFormatter>)formatter {
|
- (id<GTMLogFormatter>)formatter {
|
||||||
GTMLOGGER_ASSERT(formatter_ != nil);
|
|
||||||
return [[formatter_ retain] autorelease];
|
return [[formatter_ retain] autorelease];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setFormatter:(id<GTMLogFormatter>)formatter {
|
- (void)setFormatter:(id<GTMLogFormatter>)formatter {
|
||||||
@synchronized(self) {
|
@synchronized(self) {
|
||||||
[formatter_ autorelease];
|
[formatter_ autorelease];
|
||||||
if (formatter == nil)
|
formatter_ = nil;
|
||||||
formatter_ = [[GTMLogBasicFormatter alloc] init];
|
if (formatter == nil) {
|
||||||
else
|
@try {
|
||||||
|
formatter_ = [[GTMLogBasicFormatter alloc] init];
|
||||||
|
}
|
||||||
|
@catch (id e) {
|
||||||
|
// Leave |formatter_| nil
|
||||||
|
}
|
||||||
|
} else {
|
||||||
formatter_ = [formatter retain];
|
formatter_ = [formatter retain];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
GTMLOGGER_ASSERT(formatter_ != nil);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
- (id<GTMLogFilter>)filter {
|
- (id<GTMLogFilter>)filter {
|
||||||
GTMLOGGER_ASSERT(filter_ != nil);
|
|
||||||
return [[filter_ retain] autorelease];
|
return [[filter_ retain] autorelease];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setFilter:(id<GTMLogFilter>)filter {
|
- (void)setFilter:(id<GTMLogFilter>)filter {
|
||||||
@synchronized(self) {
|
@synchronized(self) {
|
||||||
[filter_ autorelease];
|
[filter_ autorelease];
|
||||||
if (filter == nil)
|
filter_ = nil;
|
||||||
filter_ = [[GTMLogNoFilter alloc] init];
|
if (filter == nil) {
|
||||||
else
|
@try {
|
||||||
|
filter_ = [[GTMLogNoFilter alloc] init];
|
||||||
|
}
|
||||||
|
@catch (id e) {
|
||||||
|
// Leave |filter_| nil
|
||||||
|
}
|
||||||
|
} else {
|
||||||
filter_ = [filter retain];
|
filter_ = [filter retain];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
GTMLOGGER_ASSERT(filter_ != nil);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)logDebug:(NSString *)fmt, ... {
|
- (void)logDebug:(NSString *)fmt, ... {
|
||||||
|
@ -207,7 +275,6 @@ static GTMLogger *gSharedLogger = nil;
|
||||||
|
|
||||||
@end // GTMLogger
|
@end // GTMLogger
|
||||||
|
|
||||||
|
|
||||||
@implementation GTMLogger (GTMLoggerMacroHelpers)
|
@implementation GTMLogger (GTMLoggerMacroHelpers)
|
||||||
|
|
||||||
- (void)logFuncDebug:(const char *)func msg:(NSString *)fmt, ... {
|
- (void)logFuncDebug:(const char *)func msg:(NSString *)fmt, ... {
|
||||||
|
@ -240,24 +307,26 @@ static GTMLogger *gSharedLogger = nil;
|
||||||
|
|
||||||
@end // GTMLoggerMacroHelpers
|
@end // GTMLoggerMacroHelpers
|
||||||
|
|
||||||
|
|
||||||
@implementation GTMLogger (PrivateMethods)
|
@implementation GTMLogger (PrivateMethods)
|
||||||
|
|
||||||
- (void)logInternalFunc:(const char *)func
|
- (void)logInternalFunc:(const char *)func
|
||||||
format:(NSString *)fmt
|
format:(NSString *)fmt
|
||||||
valist:(va_list)args
|
valist:(va_list)args
|
||||||
level:(GTMLoggerLevel)level {
|
level:(GTMLoggerLevel)level {
|
||||||
GTMLOGGER_ASSERT(formatter_ != nil);
|
// Primary point where logging happens, logging should never throw, catch
|
||||||
GTMLOGGER_ASSERT(filter_ != nil);
|
// everything.
|
||||||
GTMLOGGER_ASSERT(writer_ != nil);
|
@try {
|
||||||
|
NSString *fname = func ? [NSString stringWithUTF8String:func] : nil;
|
||||||
NSString *fname = func ? [NSString stringWithUTF8String:func] : nil;
|
NSString *msg = [formatter_ stringForFunc:fname
|
||||||
NSString *msg = [formatter_ stringForFunc:fname
|
withFormat:fmt
|
||||||
withFormat:fmt
|
valist:args
|
||||||
valist:args
|
level:level];
|
||||||
level:level];
|
if (msg && [filter_ filterAllowsMessage:msg level:level])
|
||||||
if (msg && [filter_ filterAllowsMessage:msg level:level])
|
[writer_ logMessage:msg level:level];
|
||||||
[writer_ logMessage:msg level:level];
|
}
|
||||||
|
@catch (id e) {
|
||||||
|
// Ignored
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@end // PrivateMethods
|
@end // PrivateMethods
|
||||||
|
@ -278,8 +347,16 @@ static GTMLogger *gSharedLogger = nil;
|
||||||
|
|
||||||
- (void)logMessage:(NSString *)msg level:(GTMLoggerLevel)level {
|
- (void)logMessage:(NSString *)msg level:(GTMLoggerLevel)level {
|
||||||
@synchronized(self) {
|
@synchronized(self) {
|
||||||
NSString *line = [NSString stringWithFormat:@"%@\n", msg];
|
// Closed pipes should not generate exceptions in our caller. Catch here
|
||||||
[self writeData:[line dataUsingEncoding:NSUTF8StringEncoding]];
|
// as well [GTMLogger logInternalFunc:...] so that an exception in this
|
||||||
|
// writer does not prevent other writers from having a chance.
|
||||||
|
@try {
|
||||||
|
NSString *line = [NSString stringWithFormat:@"%@\n", msg];
|
||||||
|
[self writeData:[line dataUsingEncoding:NSUTF8StringEncoding]];
|
||||||
|
}
|
||||||
|
@catch (id e) {
|
||||||
|
// Ignored
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -328,19 +405,32 @@ static GTMLogger *gSharedLogger = nil;
|
||||||
|
|
||||||
@implementation GTMLogBasicFormatter
|
@implementation GTMLogBasicFormatter
|
||||||
|
|
||||||
|
- (NSString *)prettyNameForFunc:(NSString *)func {
|
||||||
|
NSString *name = [func stringByTrimmingCharactersInSet:
|
||||||
|
[NSCharacterSet whitespaceAndNewlineCharacterSet]];
|
||||||
|
NSString *function = @"(unknown)";
|
||||||
|
if ([name length]) {
|
||||||
|
if (// Objective C __func__ and __PRETTY_FUNCTION__
|
||||||
|
[name hasPrefix:@"-["] || [name hasPrefix:@"+["] ||
|
||||||
|
// C++ __PRETTY_FUNCTION__ and other preadorned formats
|
||||||
|
[name hasSuffix:@")"]) {
|
||||||
|
function = name;
|
||||||
|
} else {
|
||||||
|
// Assume C99 __func__
|
||||||
|
function = [NSString stringWithFormat:@"%@()", name];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return function;
|
||||||
|
}
|
||||||
|
|
||||||
- (NSString *)stringForFunc:(NSString *)func
|
- (NSString *)stringForFunc:(NSString *)func
|
||||||
withFormat:(NSString *)fmt
|
withFormat:(NSString *)fmt
|
||||||
valist:(va_list)args
|
valist:(va_list)args
|
||||||
level:(GTMLoggerLevel)level {
|
level:(GTMLoggerLevel)level {
|
||||||
// Performance note: since we always have to create a new NSString from the
|
// Performance note: We may want to do a quick check here to see if |fmt|
|
||||||
// returned CFStringRef, we may want to do a quick check here to see if |fmt|
|
|
||||||
// contains a '%', and if not, simply return 'fmt'.
|
// contains a '%', and if not, simply return 'fmt'.
|
||||||
CFStringRef cfmsg = NULL;
|
if (!(fmt && args)) return nil;
|
||||||
cfmsg = CFStringCreateWithFormatAndArguments(kCFAllocatorDefault,
|
return [[[NSString alloc] initWithFormat:fmt arguments:args] autorelease];
|
||||||
NULL, // format options
|
|
||||||
(CFStringRef)fmt,
|
|
||||||
args);
|
|
||||||
return GTMCFAutorelease(cfmsg);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@end // GTMLogBasicFormatter
|
@end // GTMLogBasicFormatter
|
||||||
|
@ -355,6 +445,10 @@ static GTMLogger *gSharedLogger = nil;
|
||||||
[dateFormatter_ setDateFormat:@"yyyy-MM-dd HH:mm:ss.SSS"];
|
[dateFormatter_ setDateFormat:@"yyyy-MM-dd HH:mm:ss.SSS"];
|
||||||
pname_ = [[[NSProcessInfo processInfo] processName] copy];
|
pname_ = [[[NSProcessInfo processInfo] processName] copy];
|
||||||
pid_ = [[NSProcessInfo processInfo] processIdentifier];
|
pid_ = [[NSProcessInfo processInfo] processIdentifier];
|
||||||
|
if (!(dateFormatter_ && pname_)) {
|
||||||
|
[self release];
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
@ -369,15 +463,15 @@ static GTMLogger *gSharedLogger = nil;
|
||||||
withFormat:(NSString *)fmt
|
withFormat:(NSString *)fmt
|
||||||
valist:(va_list)args
|
valist:(va_list)args
|
||||||
level:(GTMLoggerLevel)level {
|
level:(GTMLoggerLevel)level {
|
||||||
GTMLOGGER_ASSERT(dateFormatter_ != nil);
|
|
||||||
NSString *tstamp = nil;
|
NSString *tstamp = nil;
|
||||||
@synchronized (dateFormatter_) {
|
@synchronized (dateFormatter_) {
|
||||||
tstamp = [dateFormatter_ stringFromDate:[NSDate date]];
|
tstamp = [dateFormatter_ stringFromDate:[NSDate date]];
|
||||||
}
|
}
|
||||||
return [NSString stringWithFormat:@"%@ %@[%d/%p] [lvl=%d] %@ %@",
|
return [NSString stringWithFormat:@"%@ %@[%d/%p] [lvl=%d] %@ %@",
|
||||||
tstamp, pname_, pid_, pthread_self(),
|
tstamp, pname_, pid_, pthread_self(),
|
||||||
level, (func ? func : @"(no func)"),
|
level, [self prettyNameForFunc:func],
|
||||||
[super stringForFunc:func withFormat:fmt valist:args level:level]];
|
// |super| has guard for nil |fmt| and |args|
|
||||||
|
[super stringForFunc:func withFormat:fmt valist:args level:level]];
|
||||||
}
|
}
|
||||||
|
|
||||||
@end // GTMLogStandardFormatter
|
@end // GTMLogStandardFormatter
|
||||||
|
@ -391,14 +485,20 @@ static GTMLogger *gSharedLogger = nil;
|
||||||
// COV_NF_START
|
// COV_NF_START
|
||||||
static BOOL IsVerboseLoggingEnabled(void) {
|
static BOOL IsVerboseLoggingEnabled(void) {
|
||||||
static NSString *const kVerboseLoggingKey = @"GTMVerboseLogging";
|
static NSString *const kVerboseLoggingKey = @"GTMVerboseLogging";
|
||||||
static char *env = NULL;
|
NSString *value = [[[NSProcessInfo processInfo] environment]
|
||||||
if (env == NULL)
|
objectForKey:kVerboseLoggingKey];
|
||||||
env = getenv([kVerboseLoggingKey UTF8String]);
|
if (value) {
|
||||||
|
// Emulate [NSString boolValue] for pre-10.5
|
||||||
if (env && env[0]) {
|
value = [value stringByTrimmingCharactersInSet:
|
||||||
return (strtol(env, NULL, 10) != 0);
|
[NSCharacterSet whitespaceAndNewlineCharacterSet]];
|
||||||
|
if ([[value uppercaseString] hasPrefix:@"Y"] ||
|
||||||
|
[[value uppercaseString] hasPrefix:@"T"] ||
|
||||||
|
[value intValue]) {
|
||||||
|
return YES;
|
||||||
|
} else {
|
||||||
|
return NO;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return [[NSUserDefaults standardUserDefaults] boolForKey:kVerboseLoggingKey];
|
return [[NSUserDefaults standardUserDefaults] boolForKey:kVerboseLoggingKey];
|
||||||
}
|
}
|
||||||
// COV_NF_END
|
// COV_NF_END
|
||||||
|
@ -417,7 +517,7 @@ static BOOL IsVerboseLoggingEnabled(void) {
|
||||||
allow = NO;
|
allow = NO;
|
||||||
break;
|
break;
|
||||||
case kGTMLoggerLevelInfo:
|
case kGTMLoggerLevelInfo:
|
||||||
allow = (IsVerboseLoggingEnabled() == YES);
|
allow = IsVerboseLoggingEnabled();
|
||||||
break;
|
break;
|
||||||
case kGTMLoggerLevelError:
|
case kGTMLoggerLevelError:
|
||||||
allow = YES;
|
allow = YES;
|
||||||
|
@ -443,3 +543,70 @@ static BOOL IsVerboseLoggingEnabled(void) {
|
||||||
}
|
}
|
||||||
|
|
||||||
@end // GTMLogNoFilter
|
@end // GTMLogNoFilter
|
||||||
|
|
||||||
|
|
||||||
|
@implementation GTMLogAllowedLevelFilter
|
||||||
|
|
||||||
|
// Private designated initializer
|
||||||
|
- (id)initWithAllowedLevels:(NSIndexSet *)levels {
|
||||||
|
self = [super init];
|
||||||
|
if (self != nil) {
|
||||||
|
allowedLevels_ = [levels retain];
|
||||||
|
// Cap min/max level
|
||||||
|
if (!allowedLevels_ ||
|
||||||
|
// NSIndexSet is unsigned so only check the high bound, but need to
|
||||||
|
// check both first and last index because NSIndexSet appears to allow
|
||||||
|
// wraparound.
|
||||||
|
([allowedLevels_ firstIndex] > kGTMLoggerLevelAssert) ||
|
||||||
|
([allowedLevels_ lastIndex] > kGTMLoggerLevelAssert)) {
|
||||||
|
[self release];
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (id)init {
|
||||||
|
// Allow all levels in default init
|
||||||
|
return [self initWithAllowedLevels:[NSIndexSet indexSetWithIndexesInRange:
|
||||||
|
NSMakeRange(kGTMLoggerLevelUnknown,
|
||||||
|
(kGTMLoggerLevelAssert - kGTMLoggerLevelUnknown + 1))]];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)dealloc {
|
||||||
|
[allowedLevels_ release];
|
||||||
|
[super dealloc];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (BOOL)filterAllowsMessage:(NSString *)msg level:(GTMLoggerLevel)level {
|
||||||
|
return [allowedLevels_ containsIndex:level];
|
||||||
|
}
|
||||||
|
|
||||||
|
@end // GTMLogAllowedLevelFilter
|
||||||
|
|
||||||
|
|
||||||
|
@implementation GTMLogMininumLevelFilter
|
||||||
|
|
||||||
|
- (id)initWithMinimumLevel:(GTMLoggerLevel)level {
|
||||||
|
return [super initWithAllowedLevels:[NSIndexSet indexSetWithIndexesInRange:
|
||||||
|
NSMakeRange(level,
|
||||||
|
(kGTMLoggerLevelAssert - level + 1))]];
|
||||||
|
}
|
||||||
|
|
||||||
|
@end // GTMLogMininumLevelFilter
|
||||||
|
|
||||||
|
|
||||||
|
@implementation GTMLogMaximumLevelFilter
|
||||||
|
|
||||||
|
- (id)initWithMaximumLevel:(GTMLoggerLevel)level {
|
||||||
|
return [super initWithAllowedLevels:[NSIndexSet indexSetWithIndexesInRange:
|
||||||
|
NSMakeRange(kGTMLoggerLevelUnknown, level + 1)]];
|
||||||
|
}
|
||||||
|
|
||||||
|
@end // GTMLogMaximumLevelFilter
|
||||||
|
|
||||||
|
#if !defined(__clang__) && (__GNUC__*10+__GNUC_MINOR__ >= 42)
|
||||||
|
// See comment at top of file.
|
||||||
|
#pragma GCC diagnostic error "-Wmissing-format-attribute"
|
||||||
|
#endif // !__clang__
|
||||||
|
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -17,13 +17,20 @@
|
||||||
//
|
//
|
||||||
|
|
||||||
#import "GTMSenTestCase.h"
|
#import "GTMSenTestCase.h"
|
||||||
|
|
||||||
#import <unistd.h>
|
#import <unistd.h>
|
||||||
|
#if GTM_IPHONE_SIMULATOR
|
||||||
|
#import <objc/message.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#import "GTMObjC2Runtime.h"
|
||||||
|
#import "GTMUnitTestDevLog.h"
|
||||||
|
|
||||||
#if !GTM_IPHONE_SDK
|
#if !GTM_IPHONE_SDK
|
||||||
#import "GTMGarbageCollection.h"
|
#import "GTMGarbageCollection.h"
|
||||||
#endif // !GTM_IPHONE_SDK
|
#endif // !GTM_IPHONE_SDK
|
||||||
|
|
||||||
#if GTM_IPHONE_SDK
|
#if GTM_IPHONE_SDK && !GTM_IPHONE_USE_SENTEST
|
||||||
#import <stdarg.h>
|
#import <stdarg.h>
|
||||||
|
|
||||||
@interface NSException (GTMSenTestPrivateAdditions)
|
@interface NSException (GTMSenTestPrivateAdditions)
|
||||||
|
@ -84,7 +91,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
NSString *reason = [NSString stringWithFormat:@"'%@' should be %s. %@",
|
NSString *reason = [NSString stringWithFormat:@"'%@' should be %s. %@",
|
||||||
condition, isTrue ? "TRUE" : "FALSE", testDescription];
|
condition, isTrue ? "false" : "true", testDescription];
|
||||||
|
|
||||||
return [self failureInFile:filename atLine:lineNumber reason:reason];
|
return [self failureInFile:filename atLine:lineNumber reason:reason];
|
||||||
}
|
}
|
||||||
|
@ -213,6 +220,22 @@ NSString *const SenTestLineNumberKey = @"SenTestLineNumberKey";
|
||||||
@end
|
@end
|
||||||
|
|
||||||
@implementation SenTestCase
|
@implementation SenTestCase
|
||||||
|
+ (id)testCaseWithInvocation:(NSInvocation *)anInvocation {
|
||||||
|
return [[[self alloc] initWithInvocation:anInvocation] autorelease];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (id)initWithInvocation:(NSInvocation *)anInvocation {
|
||||||
|
if ((self = [super init])) {
|
||||||
|
invocation_ = [anInvocation retain];
|
||||||
|
}
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)dealloc {
|
||||||
|
[invocation_ release];
|
||||||
|
[super dealloc];
|
||||||
|
}
|
||||||
|
|
||||||
- (void)failWithException:(NSException*)exception {
|
- (void)failWithException:(NSException*)exception {
|
||||||
[exception raise];
|
[exception raise];
|
||||||
}
|
}
|
||||||
|
@ -220,17 +243,24 @@ NSString *const SenTestLineNumberKey = @"SenTestLineNumberKey";
|
||||||
- (void)setUp {
|
- (void)setUp {
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)performTest:(SEL)sel {
|
- (void)performTest {
|
||||||
currentSelector_ = sel;
|
|
||||||
@try {
|
@try {
|
||||||
[self invokeTest];
|
[self invokeTest];
|
||||||
} @catch (NSException *exception) {
|
} @catch (NSException *exception) {
|
||||||
[[self class] printException:exception
|
[[self class] printException:exception
|
||||||
fromTestName:NSStringFromSelector(sel)];
|
fromTestName:NSStringFromSelector([self selector])];
|
||||||
[exception raise];
|
[exception raise];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (NSInvocation *)invocation {
|
||||||
|
return invocation_;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (SEL)selector {
|
||||||
|
return [invocation_ selector];
|
||||||
|
}
|
||||||
|
|
||||||
+ (void)printException:(NSException *)exception fromTestName:(NSString *)name {
|
+ (void)printException:(NSException *)exception fromTestName:(NSString *)name {
|
||||||
NSDictionary *userInfo = [exception userInfo];
|
NSDictionary *userInfo = [exception userInfo];
|
||||||
NSString *filename = [userInfo objectForKey:SenTestFilenameKey];
|
NSString *filename = [userInfo objectForKey:SenTestFilenameKey];
|
||||||
|
@ -261,7 +291,17 @@ NSString *const SenTestLineNumberKey = @"SenTestLineNumberKey";
|
||||||
@try {
|
@try {
|
||||||
[self setUp];
|
[self setUp];
|
||||||
@try {
|
@try {
|
||||||
[self performSelector:currentSelector_];
|
NSInvocation *invocation = [self invocation];
|
||||||
|
#if GTM_IPHONE_SIMULATOR
|
||||||
|
// We don't call [invocation invokeWithTarget:self]; because of
|
||||||
|
// Radar 8081169: NSInvalidArgumentException can't be caught
|
||||||
|
// It turns out that on iOS4 (and 3.2) exceptions thrown inside an
|
||||||
|
// [invocation invoke] on the simulator cannot be caught.
|
||||||
|
// http://openradar.appspot.com/8081169
|
||||||
|
objc_msgSend(self, [invocation selector]);
|
||||||
|
#else
|
||||||
|
[invocation invokeWithTarget:self];
|
||||||
|
#endif
|
||||||
} @catch (NSException *exception) {
|
} @catch (NSException *exception) {
|
||||||
e = [exception retain];
|
e = [exception retain];
|
||||||
}
|
}
|
||||||
|
@ -285,14 +325,83 @@ NSString *const SenTestLineNumberKey = @"SenTestLineNumberKey";
|
||||||
- (NSString *)description {
|
- (NSString *)description {
|
||||||
// This matches the description OCUnit would return to you
|
// This matches the description OCUnit would return to you
|
||||||
return [NSString stringWithFormat:@"-[%@ %@]", [self class],
|
return [NSString stringWithFormat:@"-[%@ %@]", [self class],
|
||||||
NSStringFromSelector(currentSelector_)];
|
NSStringFromSelector([self selector])];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Used for sorting methods below
|
||||||
|
static int MethodSort(id a, id b, void *context) {
|
||||||
|
NSInvocation *invocationA = a;
|
||||||
|
NSInvocation *invocationB = b;
|
||||||
|
const char *nameA = sel_getName([invocationA selector]);
|
||||||
|
const char *nameB = sel_getName([invocationB selector]);
|
||||||
|
return strcmp(nameA, nameB);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
+ (NSArray *)testInvocations {
|
||||||
|
NSMutableArray *invocations = nil;
|
||||||
|
// Need to walk all the way up the parent classes collecting methods (in case
|
||||||
|
// a test is a subclass of another test).
|
||||||
|
Class senTestCaseClass = [SenTestCase class];
|
||||||
|
for (Class currentClass = self;
|
||||||
|
currentClass && (currentClass != senTestCaseClass);
|
||||||
|
currentClass = class_getSuperclass(currentClass)) {
|
||||||
|
unsigned int methodCount;
|
||||||
|
Method *methods = class_copyMethodList(currentClass, &methodCount);
|
||||||
|
if (methods) {
|
||||||
|
// This handles disposing of methods for us even if an exception should fly.
|
||||||
|
[NSData dataWithBytesNoCopy:methods
|
||||||
|
length:sizeof(Method) * methodCount];
|
||||||
|
if (!invocations) {
|
||||||
|
invocations = [NSMutableArray arrayWithCapacity:methodCount];
|
||||||
|
}
|
||||||
|
for (size_t i = 0; i < methodCount; ++i) {
|
||||||
|
Method currMethod = methods[i];
|
||||||
|
SEL sel = method_getName(currMethod);
|
||||||
|
char *returnType = NULL;
|
||||||
|
const char *name = sel_getName(sel);
|
||||||
|
// If it starts with test, takes 2 args (target and sel) and returns
|
||||||
|
// void run it.
|
||||||
|
if (strstr(name, "test") == name) {
|
||||||
|
returnType = method_copyReturnType(currMethod);
|
||||||
|
if (returnType) {
|
||||||
|
// This handles disposing of returnType for us even if an
|
||||||
|
// exception should fly. Length +1 for the terminator, not that
|
||||||
|
// the length really matters here, as we never reference inside
|
||||||
|
// the data block.
|
||||||
|
[NSData dataWithBytesNoCopy:returnType
|
||||||
|
length:strlen(returnType) + 1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// TODO: If a test class is a subclass of another, and they reuse the
|
||||||
|
// same selector name (ie-subclass overrides it), this current loop
|
||||||
|
// and test here will cause cause it to get invoked twice. To fix this
|
||||||
|
// the selector would have to be checked against all the ones already
|
||||||
|
// added, so it only gets done once.
|
||||||
|
if (returnType // True if name starts with "test"
|
||||||
|
&& strcmp(returnType, @encode(void)) == 0
|
||||||
|
&& method_getNumberOfArguments(currMethod) == 2) {
|
||||||
|
NSMethodSignature *sig = [self instanceMethodSignatureForSelector:sel];
|
||||||
|
NSInvocation *invocation
|
||||||
|
= [NSInvocation invocationWithMethodSignature:sig];
|
||||||
|
[invocation setSelector:sel];
|
||||||
|
[invocations addObject:invocation];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Match SenTestKit and run everything in alphbetical order.
|
||||||
|
[invocations sortUsingFunction:MethodSort context:nil];
|
||||||
|
return invocations;
|
||||||
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
#endif // GTM_IPHONE_SDK
|
#endif // GTM_IPHONE_SDK && !GTM_IPHONE_USE_SENTEST
|
||||||
|
|
||||||
@implementation GTMTestCase : SenTestCase
|
@implementation GTMTestCase : SenTestCase
|
||||||
- (void)invokeTest {
|
- (void)invokeTest {
|
||||||
|
NSAutoreleasePool *localPool = [[NSAutoreleasePool alloc] init];
|
||||||
Class devLogClass = NSClassFromString(@"GTMUnitTestDevLog");
|
Class devLogClass = NSClassFromString(@"GTMUnitTestDevLog");
|
||||||
if (devLogClass) {
|
if (devLogClass) {
|
||||||
[devLogClass performSelector:@selector(enableTracking)];
|
[devLogClass performSelector:@selector(enableTracking)];
|
||||||
|
@ -304,11 +413,26 @@ NSString *const SenTestLineNumberKey = @"SenTestLineNumberKey";
|
||||||
[devLogClass performSelector:@selector(verifyNoMoreLogsExpected)];
|
[devLogClass performSelector:@selector(verifyNoMoreLogsExpected)];
|
||||||
[devLogClass performSelector:@selector(disableTracking)];
|
[devLogClass performSelector:@selector(disableTracking)];
|
||||||
}
|
}
|
||||||
|
[localPool drain];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
+ (BOOL)isAbstractTestCase {
|
||||||
|
NSString *name = NSStringFromClass(self);
|
||||||
|
return [name rangeOfString:@"AbstractTest"].location != NSNotFound;
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (NSArray *)testInvocations {
|
||||||
|
NSArray *invocations = nil;
|
||||||
|
if (![self isAbstractTestCase]) {
|
||||||
|
invocations = [super testInvocations];
|
||||||
|
}
|
||||||
|
return invocations;
|
||||||
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
// Leak detection
|
// Leak detection
|
||||||
#if !GTM_IPHONE_DEVICE
|
#if !GTM_IPHONE_DEVICE && !GTM_SUPPRESS_RUN_LEAKS_HOOK
|
||||||
// Don't want to get leaks on the iPhone Device as the device doesn't
|
// Don't want to get leaks on the iPhone Device as the device doesn't
|
||||||
// have 'leaks'. The simulator does though.
|
// have 'leaks'. The simulator does though.
|
||||||
|
|
||||||
|
@ -329,13 +453,21 @@ static void _GTMRunLeaks(void) {
|
||||||
[exclusions appendFormat:@"-exclude \"%@\" ", exclusion];
|
[exclusions appendFormat:@"-exclude \"%@\" ", exclusion];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// Clearing out DYLD_ROOT_PATH because iPhone Simulator framework libraries
|
||||||
|
// are different from regular OS X libraries and leaks will fail to run
|
||||||
|
// because of missing symbols. Also capturing the output of leaks and then
|
||||||
|
// pipe rather than a direct pipe, because otherwise if leaks failed,
|
||||||
|
// the system() call will still be successful. Bug:
|
||||||
|
// http://code.google.com/p/google-toolbox-for-mac/issues/detail?id=56
|
||||||
NSString *string
|
NSString *string
|
||||||
= [NSString stringWithFormat:@"/usr/bin/leaks %@%d"
|
= [NSString stringWithFormat:
|
||||||
@"| /usr/bin/sed -e 's/Leak: /Leaks:0: warning: Leak /'",
|
@"LeakOut=`DYLD_ROOT_PATH='' /usr/bin/leaks %@%d` &&"
|
||||||
|
@"echo \"$LeakOut\"|/usr/bin/sed -e 's/Leak: /Leaks:0: warning: Leak /'",
|
||||||
exclusions, getpid()];
|
exclusions, getpid()];
|
||||||
int ret = system([string UTF8String]);
|
int ret = system([string UTF8String]);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
fprintf(stderr, "%s:%d: Error: Unable to run leaks. 'system' returned: %d",
|
fprintf(stderr,
|
||||||
|
"%s:%d: Error: Unable to run leaks. 'system' returned: %d\n",
|
||||||
__FILE__, __LINE__, ret);
|
__FILE__, __LINE__, ret);
|
||||||
fflush(stderr);
|
fflush(stderr);
|
||||||
}
|
}
|
||||||
|
@ -355,6 +487,8 @@ static __attribute__((constructor)) void _GTMInstallLeaks(void) {
|
||||||
fprintf(stderr, "Leak Checking Enabled\n");
|
fprintf(stderr, "Leak Checking Enabled\n");
|
||||||
fflush(stderr);
|
fflush(stderr);
|
||||||
int ret = atexit(&_GTMRunLeaks);
|
int ret = atexit(&_GTMRunLeaks);
|
||||||
|
// To avoid unused variable warning when _GTMDevAssert is stripped.
|
||||||
|
(void)ret;
|
||||||
_GTMDevAssert(ret == 0,
|
_GTMDevAssert(ret == 0,
|
||||||
@"Unable to install _GTMRunLeaks as an atexit handler (%d)",
|
@"Unable to install _GTMRunLeaks as an atexit handler (%d)",
|
||||||
errno);
|
errno);
|
||||||
|
@ -363,4 +497,4 @@ static __attribute__((constructor)) void _GTMInstallLeaks(void) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // !GTM_IPHONE_DEVICE
|
#endif // !GTM_IPHONE_DEVICE && !GTM_SUPPRESS_RUN_LEAKS_HOOK
|
||||||
|
|
Loading…
Reference in a new issue