mirror of
https://github.com/yuzu-emu/breakpad.git
synced 2025-07-03 14:38:15 +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,25 +60,86 @@ static GTMLogger *gSharedLogger = nil;
|
||||||
}
|
}
|
||||||
|
|
||||||
+ (id)standardLogger {
|
+ (id)standardLogger {
|
||||||
|
// Don't trust NSFileHandle not to throw
|
||||||
|
@try {
|
||||||
id<GTMLogWriter> writer = [NSFileHandle fileHandleWithStandardOutput];
|
id<GTMLogWriter> writer = [NSFileHandle fileHandleWithStandardOutput];
|
||||||
id<GTMLogFormatter> fr = [[[GTMLogStandardFormatter alloc] init] autorelease];
|
id<GTMLogFormatter> fr = [[[GTMLogStandardFormatter alloc] init]
|
||||||
|
autorelease];
|
||||||
id<GTMLogFilter> filter = [[[GTMLogLevelFilter alloc] init] autorelease];
|
id<GTMLogFilter> filter = [[[GTMLogLevelFilter alloc] init] autorelease];
|
||||||
return [self loggerWithWriter:writer formatter:fr filter:filter];
|
return [[[self alloc] initWithWriter:writer
|
||||||
|
formatter:fr
|
||||||
|
filter:filter] autorelease];
|
||||||
|
}
|
||||||
|
@catch (id e) {
|
||||||
|
// Ignored
|
||||||
|
}
|
||||||
|
return nil;
|
||||||
}
|
}
|
||||||
|
|
||||||
+ (id)standardLoggerWithStderr {
|
+ (id)standardLoggerWithStderr {
|
||||||
|
// Don't trust NSFileHandle not to throw
|
||||||
|
@try {
|
||||||
id me = [self standardLogger];
|
id me = [self standardLogger];
|
||||||
[me setWriter:[NSFileHandle fileHandleWithStandardError]];
|
[me setWriter:[NSFileHandle fileHandleWithStandardError]];
|
||||||
return me;
|
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 {
|
||||||
|
@try {
|
||||||
NSFileHandle *fh = [NSFileHandle fileHandleForLoggingAtPath:path mode:0644];
|
NSFileHandle *fh = [NSFileHandle fileHandleForLoggingAtPath:path mode:0644];
|
||||||
if (fh == nil) return nil;
|
if (fh == nil) return nil;
|
||||||
id me = [self standardLogger];
|
id me = [self standardLogger];
|
||||||
[me setWriter:fh];
|
[me setWriter:fh];
|
||||||
return me;
|
return me;
|
||||||
}
|
}
|
||||||
|
@catch (id e) {
|
||||||
|
// Ignored
|
||||||
|
}
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
|
||||||
+ (id)loggerWithWriter:(id<GTMLogWriter>)writer
|
+ (id)loggerWithWriter:(id<GTMLogWriter>)writer
|
||||||
formatter:(id<GTMLogFormatter>)formatter
|
formatter:(id<GTMLogFormatter>)formatter
|
||||||
|
@ -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);
|
|
||||||
[writer_ release];
|
|
||||||
[formatter_ release];
|
[formatter_ release];
|
||||||
[filter_ release];
|
[filter_ release];
|
||||||
|
[writer_ 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;
|
||||||
|
if (writer == nil) {
|
||||||
|
// Try to use stdout, but don't trust NSFileHandle
|
||||||
|
@try {
|
||||||
writer_ = [[NSFileHandle fileHandleWithStandardOutput] retain];
|
writer_ = [[NSFileHandle fileHandleWithStandardOutput] retain];
|
||||||
else
|
}
|
||||||
|
@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;
|
||||||
|
if (formatter == nil) {
|
||||||
|
@try {
|
||||||
formatter_ = [[GTMLogBasicFormatter alloc] init];
|
formatter_ = [[GTMLogBasicFormatter alloc] init];
|
||||||
else
|
}
|
||||||
|
@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;
|
||||||
|
if (filter == nil) {
|
||||||
|
@try {
|
||||||
filter_ = [[GTMLogNoFilter alloc] init];
|
filter_ = [[GTMLogNoFilter alloc] init];
|
||||||
else
|
}
|
||||||
|
@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,17 +307,15 @@ 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
|
||||||
|
@ -259,6 +324,10 @@ static GTMLogger *gSharedLogger = nil;
|
||||||
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,9 +347,17 @@ static GTMLogger *gSharedLogger = nil;
|
||||||
|
|
||||||
- (void)logMessage:(NSString *)msg level:(GTMLoggerLevel)level {
|
- (void)logMessage:(NSString *)msg level:(GTMLoggerLevel)level {
|
||||||
@synchronized(self) {
|
@synchronized(self) {
|
||||||
|
// Closed pipes should not generate exceptions in our caller. Catch here
|
||||||
|
// 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];
|
NSString *line = [NSString stringWithFormat:@"%@\n", msg];
|
||||||
[self writeData:[line dataUsingEncoding:NSUTF8StringEncoding]];
|
[self writeData:[line dataUsingEncoding:NSUTF8StringEncoding]];
|
||||||
}
|
}
|
||||||
|
@catch (id e) {
|
||||||
|
// Ignored
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@end // GTMFileHandleLogWriter
|
@end // GTMFileHandleLogWriter
|
||||||
|
@ -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,14 +463,14 @@ 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| has guard for nil |fmt| and |args|
|
||||||
[super stringForFunc:func withFormat:fmt valist:args level:level]];
|
[super stringForFunc:func withFormat:fmt valist:args level:level]];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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__
|
||||||
|
|
||||||
|
|
|
@ -53,13 +53,29 @@
|
||||||
|
|
||||||
#import "GTMDefines.h"
|
#import "GTMDefines.h"
|
||||||
|
|
||||||
#if (!GTM_IPHONE_SDK)
|
#if (!GTM_IPHONE_SDK) || (GTM_IPHONE_USE_SENTEST)
|
||||||
#import <SenTestingKit/SenTestingKit.h>
|
#import <SenTestingKit/SenTestingKit.h>
|
||||||
#else
|
#else
|
||||||
#import <Foundation/Foundation.h>
|
#import <Foundation/Foundation.h>
|
||||||
NSString *STComposeString(NSString *, ...);
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if defined __clang__
|
||||||
|
// gcc and gcc-llvm do not allow you to use STAssert(blah, nil) with nil
|
||||||
|
// as a description if you have the NS_FORMAT_FUNCTION on.
|
||||||
|
// clang however will not compile without warnings if you don't have it.
|
||||||
|
NSString *STComposeString(NSString *, ...) NS_FORMAT_FUNCTION(1, 2);
|
||||||
|
#else
|
||||||
|
NSString *STComposeString(NSString *, ...);
|
||||||
|
#endif // __clang__
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif // !GTM_IPHONE_SDK || GTM_IPHONE_USE_SENTEST
|
||||||
|
|
||||||
// Generates a failure when a1 != noErr
|
// Generates a failure when a1 != noErr
|
||||||
// Args:
|
// Args:
|
||||||
// a1: should be either an OSErr or an OSStatus
|
// a1: should be either an OSErr or an OSStatus
|
||||||
|
@ -71,13 +87,12 @@ do { \
|
||||||
@try { \
|
@try { \
|
||||||
OSStatus a1value = (a1); \
|
OSStatus a1value = (a1); \
|
||||||
if (a1value != noErr) { \
|
if (a1value != noErr) { \
|
||||||
NSString *_expression = [NSString stringWithFormat:@"Expected noErr, got %ld for (%s)", a1value, #a1]; \
|
NSString *_expression = [NSString stringWithFormat:@"Expected noErr, got %ld for (%s)", (long)a1value, #a1]; \
|
||||||
if (description) { \
|
[self failWithException:([NSException failureInCondition:_expression \
|
||||||
_expression = [NSString stringWithFormat:@"%@: %@", _expression, STComposeString(description, ##__VA_ARGS__)]; \
|
isTrue:NO \
|
||||||
} \
|
inFile:[NSString stringWithUTF8String:__FILE__] \
|
||||||
[self failWithException:[NSException failureInFile:[NSString stringWithUTF8String:__FILE__] \
|
|
||||||
atLine:__LINE__ \
|
atLine:__LINE__ \
|
||||||
withDescription:_expression]]; \
|
withDescription:@"%@", STComposeString(description, ##__VA_ARGS__)])]; \
|
||||||
} \
|
} \
|
||||||
} \
|
} \
|
||||||
@catch (id anException) { \
|
@catch (id anException) { \
|
||||||
|
@ -85,7 +100,7 @@ do { \
|
||||||
exception:anException \
|
exception:anException \
|
||||||
inFile:[NSString stringWithUTF8String:__FILE__] \
|
inFile:[NSString stringWithUTF8String:__FILE__] \
|
||||||
atLine:__LINE__ \
|
atLine:__LINE__ \
|
||||||
withDescription:STComposeString(description, ##__VA_ARGS__)]]; \
|
withDescription:@"%@", STComposeString(description, ##__VA_ARGS__)]]; \
|
||||||
} \
|
} \
|
||||||
} while(0)
|
} while(0)
|
||||||
|
|
||||||
|
@ -102,13 +117,12 @@ do { \
|
||||||
OSStatus a1value = (a1); \
|
OSStatus a1value = (a1); \
|
||||||
OSStatus a2value = (a2); \
|
OSStatus a2value = (a2); \
|
||||||
if (a1value != a2value) { \
|
if (a1value != a2value) { \
|
||||||
NSString *_expression = [NSString stringWithFormat:@"Expected %s(%ld) but got %ld for (%s)", #a2, a2value, a1value, #a1]; \
|
NSString *_expression = [NSString stringWithFormat:@"Expected %s(%ld) but got %ld for (%s)", #a2, (long)a2value, (long)a1value, #a1]; \
|
||||||
if (description) { \
|
[self failWithException:([NSException failureInCondition:_expression \
|
||||||
_expression = [NSString stringWithFormat:@"%@: %@", _expression, STComposeString(description, ##__VA_ARGS__)]; \
|
isTrue:NO \
|
||||||
} \
|
inFile:[NSString stringWithUTF8String:__FILE__] \
|
||||||
[self failWithException:[NSException failureInFile:[NSString stringWithUTF8String:__FILE__] \
|
|
||||||
atLine:__LINE__ \
|
atLine:__LINE__ \
|
||||||
withDescription:_expression]]; \
|
withDescription:@"%@", STComposeString(description, ##__VA_ARGS__)])]; \
|
||||||
} \
|
} \
|
||||||
} \
|
} \
|
||||||
@catch (id anException) { \
|
@catch (id anException) { \
|
||||||
|
@ -116,7 +130,7 @@ do { \
|
||||||
exception:anException \
|
exception:anException \
|
||||||
inFile:[NSString stringWithUTF8String:__FILE__] \
|
inFile:[NSString stringWithUTF8String:__FILE__] \
|
||||||
atLine:__LINE__ \
|
atLine:__LINE__ \
|
||||||
withDescription:STComposeString(description, ##__VA_ARGS__)]]; \
|
withDescription:@"%@", STComposeString(description, ##__VA_ARGS__)]]; \
|
||||||
} \
|
} \
|
||||||
} while(0)
|
} while(0)
|
||||||
|
|
||||||
|
@ -130,15 +144,14 @@ do { \
|
||||||
#define STAssertNotNULL(a1, description, ...) \
|
#define STAssertNotNULL(a1, description, ...) \
|
||||||
do { \
|
do { \
|
||||||
@try { \
|
@try { \
|
||||||
const void* a1value = (a1); \
|
__typeof__(a1) a1value = (a1); \
|
||||||
if (a1value == NULL) { \
|
if (a1value == (__typeof__(a1))NULL) { \
|
||||||
NSString *_expression = [NSString stringWithFormat:@"(%s) != NULL", #a1]; \
|
NSString *_expression = [NSString stringWithFormat:@"((%s) != NULL)", #a1]; \
|
||||||
if (description) { \
|
[self failWithException:([NSException failureInCondition:_expression \
|
||||||
_expression = [NSString stringWithFormat:@"%@: %@", _expression, STComposeString(description, ##__VA_ARGS__)]; \
|
isTrue:NO \
|
||||||
} \
|
inFile:[NSString stringWithUTF8String:__FILE__] \
|
||||||
[self failWithException:[NSException failureInFile:[NSString stringWithUTF8String:__FILE__] \
|
|
||||||
atLine:__LINE__ \
|
atLine:__LINE__ \
|
||||||
withDescription:_expression]]; \
|
withDescription:@"%@", STComposeString(description, ##__VA_ARGS__)])]; \
|
||||||
} \
|
} \
|
||||||
} \
|
} \
|
||||||
@catch (id anException) { \
|
@catch (id anException) { \
|
||||||
|
@ -146,7 +159,7 @@ do { \
|
||||||
exception:anException \
|
exception:anException \
|
||||||
inFile:[NSString stringWithUTF8String:__FILE__] \
|
inFile:[NSString stringWithUTF8String:__FILE__] \
|
||||||
atLine:__LINE__ \
|
atLine:__LINE__ \
|
||||||
withDescription:STComposeString(description, ##__VA_ARGS__)]]; \
|
withDescription:@"%@", STComposeString(description, ##__VA_ARGS__)]]; \
|
||||||
} \
|
} \
|
||||||
} while(0)
|
} while(0)
|
||||||
|
|
||||||
|
@ -159,15 +172,14 @@ do { \
|
||||||
#define STAssertNULL(a1, description, ...) \
|
#define STAssertNULL(a1, description, ...) \
|
||||||
do { \
|
do { \
|
||||||
@try { \
|
@try { \
|
||||||
const void* a1value = (a1); \
|
__typeof__(a1) a1value = (a1); \
|
||||||
if (a1value != NULL) { \
|
if (a1value != (__typeof__(a1))NULL) { \
|
||||||
NSString *_expression = [NSString stringWithFormat:@"(%s) == NULL", #a1]; \
|
NSString *_expression = [NSString stringWithFormat:@"((%s) == NULL)", #a1]; \
|
||||||
if (description) { \
|
[self failWithException:([NSException failureInCondition:_expression \
|
||||||
_expression = [NSString stringWithFormat:@"%@: %@", _expression, STComposeString(description, ##__VA_ARGS__)]; \
|
isTrue:NO \
|
||||||
} \
|
inFile:[NSString stringWithUTF8String:__FILE__] \
|
||||||
[self failWithException:[NSException failureInFile:[NSString stringWithUTF8String:__FILE__] \
|
|
||||||
atLine:__LINE__ \
|
atLine:__LINE__ \
|
||||||
withDescription:_expression]]; \
|
withDescription:@"%@", STComposeString(description, ##__VA_ARGS__)])]; \
|
||||||
} \
|
} \
|
||||||
} \
|
} \
|
||||||
@catch (id anException) { \
|
@catch (id anException) { \
|
||||||
|
@ -175,7 +187,7 @@ do { \
|
||||||
exception:anException \
|
exception:anException \
|
||||||
inFile:[NSString stringWithUTF8String:__FILE__] \
|
inFile:[NSString stringWithUTF8String:__FILE__] \
|
||||||
atLine:__LINE__ \
|
atLine:__LINE__ \
|
||||||
withDescription:STComposeString(description, ##__VA_ARGS__)]]; \
|
withDescription:@"%@", STComposeString(description, ##__VA_ARGS__)]]; \
|
||||||
} \
|
} \
|
||||||
} while(0)
|
} while(0)
|
||||||
|
|
||||||
|
@ -190,23 +202,22 @@ do { \
|
||||||
#define STAssertNotEquals(a1, a2, description, ...) \
|
#define STAssertNotEquals(a1, a2, description, ...) \
|
||||||
do { \
|
do { \
|
||||||
@try { \
|
@try { \
|
||||||
if (@encode(__typeof__(a1)) != @encode(__typeof__(a2))) { \
|
if (strcmp(@encode(__typeof__(a1)), @encode(__typeof__(a2)))) { \
|
||||||
[self failWithException:[NSException failureInFile:[NSString stringWithUTF8String:__FILE__] \
|
[self failWithException:[NSException failureInFile:[NSString stringWithUTF8String:__FILE__] \
|
||||||
atLine:__LINE__ \
|
atLine:__LINE__ \
|
||||||
withDescription:[[[NSString stringWithFormat:@"Type mismatch (%@/%@) -- ",@encode(__typeof__(a1)),@encode(__typeof__(a2))] stringByAppendingString:STComposeString(description, ##__VA_ARGS__)]]]; \
|
withDescription:@"Type mismatch -- %@", STComposeString(description, ##__VA_ARGS__)]]; \
|
||||||
} else { \
|
} else { \
|
||||||
__typeof__(a1) a1value = (a1); \
|
__typeof__(a1) a1value = (a1); \
|
||||||
__typeof__(a2) a2value = (a2); \
|
__typeof__(a2) a2value = (a2); \
|
||||||
NSValue *a1encoded = [NSValue value:&a1value withObjCType:@encode(__typeof__(a1))]; \
|
NSValue *a1encoded = [NSValue value:&a1value withObjCType:@encode(__typeof__(a1))]; \
|
||||||
NSValue *a2encoded = [NSValue value:&a2value withObjCType:@encode(__typeof__(a2))]; \
|
NSValue *a2encoded = [NSValue value:&a2value withObjCType:@encode(__typeof__(a2))]; \
|
||||||
if ([a1encoded isEqualToValue:a2encoded]) { \
|
if ([a1encoded isEqualToValue:a2encoded]) { \
|
||||||
NSString *_expression = [NSString stringWithFormat:@"(%s) != (%s)", #a1, #a2]; \
|
NSString *_expression = [NSString stringWithFormat:@"((%s) != (%s))", #a1, #a2]; \
|
||||||
if (description) { \
|
[self failWithException:([NSException failureInCondition:_expression \
|
||||||
_expression = [NSString stringWithFormat:@"%@: %@", _expression, STComposeString(description, ##__VA_ARGS__)]; \
|
isTrue:NO \
|
||||||
} \
|
inFile:[NSString stringWithUTF8String:__FILE__] \
|
||||||
[self failWithException:[NSException failureInFile:[NSString stringWithUTF8String:__FILE__] \
|
|
||||||
atLine:__LINE__ \
|
atLine:__LINE__ \
|
||||||
withDescription:_expression]]; \
|
withDescription:@"%@", STComposeString(description, ##__VA_ARGS__)])]; \
|
||||||
}\
|
}\
|
||||||
} \
|
} \
|
||||||
} \
|
} \
|
||||||
|
@ -215,7 +226,7 @@ do { \
|
||||||
exception:anException \
|
exception:anException \
|
||||||
inFile:[NSString stringWithUTF8String:__FILE__] \
|
inFile:[NSString stringWithUTF8String:__FILE__] \
|
||||||
atLine:__LINE__ \
|
atLine:__LINE__ \
|
||||||
withDescription:STComposeString(description, ##__VA_ARGS__)]]; \
|
withDescription:@"%@", STComposeString(description, ##__VA_ARGS__)]]; \
|
||||||
} \
|
} \
|
||||||
} while(0)
|
} while(0)
|
||||||
|
|
||||||
|
@ -226,28 +237,26 @@ do { \
|
||||||
// description: A format string as in the printf() function. Can be nil or
|
// description: A format string as in the printf() function. Can be nil or
|
||||||
// an empty string but must be present.
|
// an empty string but must be present.
|
||||||
// ...: A variable number of arguments to the format string. Can be absent.
|
// ...: A variable number of arguments to the format string. Can be absent.
|
||||||
#define STAssertNotEqualObjects(a1, a2, desc, ...) \
|
#define STAssertNotEqualObjects(a1, a2, description, ...) \
|
||||||
do { \
|
do { \
|
||||||
@try {\
|
@try {\
|
||||||
id a1value = (a1); \
|
id a1value = (a1); \
|
||||||
id a2value = (a2); \
|
id a2value = (a2); \
|
||||||
if ( (@encode(__typeof__(a1value)) == @encode(id)) && \
|
if ( (strcmp(@encode(__typeof__(a1value)), @encode(id)) == 0) && \
|
||||||
(@encode(__typeof__(a2value)) == @encode(id)) && \
|
(strcmp(@encode(__typeof__(a2value)), @encode(id)) == 0) && \
|
||||||
![(id)a1value isEqual:(id)a2value] ) continue; \
|
(![(id)a1value isEqual:(id)a2value]) ) continue; \
|
||||||
NSString *_expression = [NSString stringWithFormat:@"%s('%@') != %s('%@')", #a1, [a1 description], #a2, [a2 description]]; \
|
[self failWithException:([NSException failureInEqualityBetweenObject:a1value \
|
||||||
if (desc) { \
|
andObject:a2value \
|
||||||
_expression = [NSString stringWithFormat:@"%@: %@", _expression, STComposeString(desc, ##__VA_ARGS__)]; \
|
inFile:[NSString stringWithUTF8String:__FILE__] \
|
||||||
} \
|
|
||||||
[self failWithException:[NSException failureInFile:[NSString stringWithUTF8String:__FILE__] \
|
|
||||||
atLine:__LINE__ \
|
atLine:__LINE__ \
|
||||||
withDescription:_expression]]; \
|
withDescription:@"%@", STComposeString(description, ##__VA_ARGS__)])]; \
|
||||||
}\
|
}\
|
||||||
@catch (id anException) {\
|
@catch (id anException) {\
|
||||||
[self failWithException:[NSException failureInRaise:[NSString stringWithFormat: @"(%s) != (%s)", #a1, #a2] \
|
[self failWithException:([NSException failureInRaise:[NSString stringWithFormat:@"(%s) != (%s)", #a1, #a2] \
|
||||||
exception:anException \
|
exception:anException \
|
||||||
inFile:[NSString stringWithUTF8String:__FILE__] \
|
inFile:[NSString stringWithUTF8String:__FILE__] \
|
||||||
atLine:__LINE__ \
|
atLine:__LINE__ \
|
||||||
withDescription:STComposeString(desc, ##__VA_ARGS__)]]; \
|
withDescription:@"%@", STComposeString(description, ##__VA_ARGS__)])]; \
|
||||||
}\
|
}\
|
||||||
} while(0)
|
} while(0)
|
||||||
|
|
||||||
|
@ -262,23 +271,22 @@ do { \
|
||||||
#define STAssertOperation(a1, a2, op, description, ...) \
|
#define STAssertOperation(a1, a2, op, description, ...) \
|
||||||
do { \
|
do { \
|
||||||
@try { \
|
@try { \
|
||||||
if (@encode(__typeof__(a1)) != @encode(__typeof__(a2))) { \
|
if (strcmp(@encode(__typeof__(a1)), @encode(__typeof__(a2)))) { \
|
||||||
[self failWithException:[NSException failureInFile:[NSString stringWithUTF8String:__FILE__] \
|
[self failWithException:[NSException failureInFile:[NSString stringWithUTF8String:__FILE__] \
|
||||||
atLine:__LINE__ \
|
atLine:__LINE__ \
|
||||||
withDescription:[[[NSString stringWithFormat:@"Type mismatch (%@/%@) -- ",@encode(__typeof__(a1)),@encode(__typeof__(a2))] stringByAppendingString:STComposeString(description, ##__VA_ARGS__)]]]; \
|
withDescription:@"Type mismatch -- %@", STComposeString(description, ##__VA_ARGS__)]]; \
|
||||||
} else { \
|
} else { \
|
||||||
__typeof__(a1) a1value = (a1); \
|
__typeof__(a1) a1value = (a1); \
|
||||||
__typeof__(a2) a2value = (a2); \
|
__typeof__(a2) a2value = (a2); \
|
||||||
if (!(a1value op a2value)) { \
|
if (!(a1value op a2value)) { \
|
||||||
double a1DoubleValue = a1value; \
|
double a1DoubleValue = a1value; \
|
||||||
double a2DoubleValue = a2value; \
|
double a2DoubleValue = a2value; \
|
||||||
NSString *_expression = [NSString stringWithFormat:@"%s (%lg) %s %s (%lg)", #a1, a1DoubleValue, #op, #a2, a2DoubleValue]; \
|
NSString *_expression = [NSString stringWithFormat:@"(%s (%lg) %s %s (%lg))", #a1, a1DoubleValue, #op, #a2, a2DoubleValue]; \
|
||||||
if (description) { \
|
[self failWithException:([NSException failureInCondition:_expression \
|
||||||
_expression = [NSString stringWithFormat:@"%@: %@", _expression, STComposeString(description, ##__VA_ARGS__)]; \
|
isTrue:NO \
|
||||||
} \
|
inFile:[NSString stringWithUTF8String:__FILE__] \
|
||||||
[self failWithException:[NSException failureInFile:[NSString stringWithUTF8String:__FILE__] \
|
|
||||||
atLine:__LINE__ \
|
atLine:__LINE__ \
|
||||||
withDescription:_expression]]; \
|
withDescription:@"%@", STComposeString(description, ##__VA_ARGS__)])]; \
|
||||||
} \
|
} \
|
||||||
} \
|
} \
|
||||||
} \
|
} \
|
||||||
|
@ -288,7 +296,7 @@ do { \
|
||||||
exception:anException \
|
exception:anException \
|
||||||
inFile:[NSString stringWithUTF8String:__FILE__] \
|
inFile:[NSString stringWithUTF8String:__FILE__] \
|
||||||
atLine:__LINE__ \
|
atLine:__LINE__ \
|
||||||
withDescription:STComposeString(description, ##__VA_ARGS__)]]; \
|
withDescription:@"%@", STComposeString(description, ##__VA_ARGS__)]]; \
|
||||||
} \
|
} \
|
||||||
} while(0)
|
} while(0)
|
||||||
|
|
||||||
|
@ -360,14 +368,14 @@ do { \
|
||||||
andObject:a2value \
|
andObject:a2value \
|
||||||
inFile:[NSString stringWithUTF8String:__FILE__] \
|
inFile:[NSString stringWithUTF8String:__FILE__] \
|
||||||
atLine:__LINE__ \
|
atLine:__LINE__ \
|
||||||
withDescription: STComposeString(description, ##__VA_ARGS__)]]; \
|
withDescription:@"%@", STComposeString(description, ##__VA_ARGS__)]]; \
|
||||||
} \
|
} \
|
||||||
@catch (id anException) { \
|
@catch (id anException) { \
|
||||||
[self failWithException:[NSException failureInRaise:[NSString stringWithFormat:@"(%s) == (%s)", #a1, #a2] \
|
[self failWithException:[NSException failureInRaise:[NSString stringWithFormat:@"(%s) == (%s)", #a1, #a2] \
|
||||||
exception:anException \
|
exception:anException \
|
||||||
inFile:[NSString stringWithUTF8String:__FILE__] \
|
inFile:[NSString stringWithUTF8String:__FILE__] \
|
||||||
atLine:__LINE__ \
|
atLine:__LINE__ \
|
||||||
withDescription:STComposeString(description, ##__VA_ARGS__)]]; \
|
withDescription:@"%@", STComposeString(description, ##__VA_ARGS__)]]; \
|
||||||
} \
|
} \
|
||||||
} while(0)
|
} while(0)
|
||||||
|
|
||||||
|
@ -394,14 +402,14 @@ do { \
|
||||||
andObject:a2value \
|
andObject:a2value \
|
||||||
inFile:[NSString stringWithUTF8String:__FILE__] \
|
inFile:[NSString stringWithUTF8String:__FILE__] \
|
||||||
atLine:__LINE__ \
|
atLine:__LINE__ \
|
||||||
withDescription: STComposeString(description, ##__VA_ARGS__)]]; \
|
withDescription:@"%@", STComposeString(description, ##__VA_ARGS__)]]; \
|
||||||
} \
|
} \
|
||||||
@catch (id anException) { \
|
@catch (id anException) { \
|
||||||
[self failWithException:[NSException failureInRaise:[NSString stringWithFormat:@"(%s) != (%s)", #a1, #a2] \
|
[self failWithException:[NSException failureInRaise:[NSString stringWithFormat:@"(%s) != (%s)", #a1, #a2] \
|
||||||
exception:anException \
|
exception:anException \
|
||||||
inFile:[NSString stringWithUTF8String:__FILE__] \
|
inFile:[NSString stringWithUTF8String:__FILE__] \
|
||||||
atLine:__LINE__ \
|
atLine:__LINE__ \
|
||||||
withDescription:STComposeString(description, ##__VA_ARGS__)]]; \
|
withDescription:@"%@", STComposeString(description, ##__VA_ARGS__)]]; \
|
||||||
} \
|
} \
|
||||||
} while(0)
|
} while(0)
|
||||||
|
|
||||||
|
@ -423,14 +431,14 @@ do { \
|
||||||
andObject:[NSString stringWithUTF8String:a2value] \
|
andObject:[NSString stringWithUTF8String:a2value] \
|
||||||
inFile:[NSString stringWithUTF8String:__FILE__] \
|
inFile:[NSString stringWithUTF8String:__FILE__] \
|
||||||
atLine:__LINE__ \
|
atLine:__LINE__ \
|
||||||
withDescription: STComposeString(description, ##__VA_ARGS__)]]; \
|
withDescription:@"%@", STComposeString(description, ##__VA_ARGS__)]]; \
|
||||||
} \
|
} \
|
||||||
@catch (id anException) { \
|
@catch (id anException) { \
|
||||||
[self failWithException:[NSException failureInRaise:[NSString stringWithFormat:@"(%s) == (%s)", #a1, #a2] \
|
[self failWithException:[NSException failureInRaise:[NSString stringWithFormat:@"(%s) == (%s)", #a1, #a2] \
|
||||||
exception:anException \
|
exception:anException \
|
||||||
inFile:[NSString stringWithUTF8String:__FILE__] \
|
inFile:[NSString stringWithUTF8String:__FILE__] \
|
||||||
atLine:__LINE__ \
|
atLine:__LINE__ \
|
||||||
withDescription:STComposeString(description, ##__VA_ARGS__)]]; \
|
withDescription:@"%@", STComposeString(description, ##__VA_ARGS__)]]; \
|
||||||
} \
|
} \
|
||||||
} while(0)
|
} while(0)
|
||||||
|
|
||||||
|
@ -451,18 +459,85 @@ do { \
|
||||||
andObject:[NSString stringWithUTF8String:a2value] \
|
andObject:[NSString stringWithUTF8String:a2value] \
|
||||||
inFile:[NSString stringWithUTF8String:__FILE__] \
|
inFile:[NSString stringWithUTF8String:__FILE__] \
|
||||||
atLine:__LINE__ \
|
atLine:__LINE__ \
|
||||||
withDescription: STComposeString(description, ##__VA_ARGS__)]]; \
|
withDescription:@"%@", STComposeString(description, ##__VA_ARGS__)]]; \
|
||||||
} \
|
} \
|
||||||
@catch (id anException) { \
|
@catch (id anException) { \
|
||||||
[self failWithException:[NSException failureInRaise:[NSString stringWithFormat:@"(%s) != (%s)", #a1, #a2] \
|
[self failWithException:[NSException failureInRaise:[NSString stringWithFormat:@"(%s) != (%s)", #a1, #a2] \
|
||||||
exception:anException \
|
exception:anException \
|
||||||
inFile:[NSString stringWithUTF8String:__FILE__] \
|
inFile:[NSString stringWithUTF8String:__FILE__] \
|
||||||
atLine:__LINE__ \
|
atLine:__LINE__ \
|
||||||
withDescription:STComposeString(description, ##__VA_ARGS__)]]; \
|
withDescription:@"%@", STComposeString(description, ##__VA_ARGS__)]]; \
|
||||||
} \
|
} \
|
||||||
} while(0)
|
} while(0)
|
||||||
|
|
||||||
#if GTM_IPHONE_SDK
|
/*" Generates a failure when a1 is not equal to a2 within + or - accuracy is false.
|
||||||
|
This test is for GLKit types (GLKVector, GLKMatrix) where small differences
|
||||||
|
could make these items not exactly equal. Do not use this version directly.
|
||||||
|
Use the explicit STAssertEqualGLKVectors and STAssertEqualGLKMatrices defined
|
||||||
|
below.
|
||||||
|
_{a1 The GLKType on the left.}
|
||||||
|
_{a2 The GLKType on the right.}
|
||||||
|
_{accuracy The maximum difference between a1 and a2 for these values to be
|
||||||
|
considered equal.}
|
||||||
|
_{description A format string as in the printf() function. Can be nil or
|
||||||
|
an empty string but must be present.}
|
||||||
|
_{... A variable number of arguments to the format string. Can be absent.}
|
||||||
|
"*/
|
||||||
|
|
||||||
|
#define STInternalAssertEqualGLKVectorsOrMatrices(a1, a2, accuracy, description, ...) \
|
||||||
|
do { \
|
||||||
|
@try { \
|
||||||
|
if (strcmp(@encode(__typeof__(a1)), @encode(__typeof__(a2)))) { \
|
||||||
|
[self failWithException:[NSException failureInFile:[NSString stringWithUTF8String:__FILE__] \
|
||||||
|
atLine:__LINE__ \
|
||||||
|
withDescription:@"Type mismatch -- %@", STComposeString(description, ##__VA_ARGS__)]]; \
|
||||||
|
} else { \
|
||||||
|
__typeof__(a1) a1GLKValue = (a1); \
|
||||||
|
__typeof__(a2) a2GLKValue = (a2); \
|
||||||
|
__typeof__(accuracy) accuracyvalue = (accuracy); \
|
||||||
|
float *a1FloatValue = ((float*)&a1GLKValue); \
|
||||||
|
float *a2FloatValue = ((float*)&a2GLKValue); \
|
||||||
|
for (size_t i = 0; i < sizeof(__typeof__(a1)) / sizeof(float); ++i) { \
|
||||||
|
float a1value = a1FloatValue[i]; \
|
||||||
|
float a2value = a2FloatValue[i]; \
|
||||||
|
if (STAbsoluteDifference(a1value, a2value) > accuracyvalue) { \
|
||||||
|
NSMutableArray *strings = [NSMutableArray arrayWithCapacity:sizeof(a1) / sizeof(float)]; \
|
||||||
|
NSString *string; \
|
||||||
|
for (size_t j = 0; j < sizeof(__typeof__(a1)) / sizeof(float); ++j) { \
|
||||||
|
string = [NSString stringWithFormat:@"(%0.3f == %0.3f)", a1FloatValue[j], a2FloatValue[j]]; \
|
||||||
|
[strings addObject:string]; \
|
||||||
|
} \
|
||||||
|
string = [strings componentsJoinedByString:@", "]; \
|
||||||
|
NSString *desc = STComposeString(description, ##__VA_ARGS__); \
|
||||||
|
desc = [NSString stringWithFormat:@"%@ With Accuracy %0.3f: %@", string, (float)accuracyvalue, desc]; \
|
||||||
|
[self failWithException:[NSException failureInFile:[NSString stringWithUTF8String:__FILE__] \
|
||||||
|
atLine:__LINE__ \
|
||||||
|
withDescription:@"%@", desc]]; \
|
||||||
|
break; \
|
||||||
|
} \
|
||||||
|
} \
|
||||||
|
} \
|
||||||
|
} \
|
||||||
|
@catch (id anException) { \
|
||||||
|
[self failWithException:[NSException failureInRaise:[NSString stringWithFormat:@"(%s) == (%s)", #a1, #a2] \
|
||||||
|
exception:anException \
|
||||||
|
inFile:[NSString stringWithUTF8String:__FILE__] \
|
||||||
|
atLine:__LINE__ \
|
||||||
|
withDescription:@"%@", STComposeString(description, ##__VA_ARGS__)]]; \
|
||||||
|
} \
|
||||||
|
} while(0)
|
||||||
|
|
||||||
|
#define STAssertEqualGLKVectors(a1, a2, accuracy, description, ...) \
|
||||||
|
STInternalAssertEqualGLKVectorsOrMatrices(a1, a2, accuracy, description, ##__VA_ARGS__)
|
||||||
|
|
||||||
|
#define STAssertEqualGLKMatrices(a1, a2, accuracy, description, ...) \
|
||||||
|
STInternalAssertEqualGLKVectorsOrMatrices(a1, a2, accuracy, description, ##__VA_ARGS__)
|
||||||
|
|
||||||
|
#define STAssertEqualGLKQuaternions(a1, a2, accuracy, description, ...) \
|
||||||
|
STInternalAssertEqualGLKVectorsOrMatrices(a1, a2, accuracy, description, ##__VA_ARGS__)
|
||||||
|
|
||||||
|
#if GTM_IPHONE_SDK && !GTM_IPHONE_USE_SENTEST
|
||||||
|
// When not using the Xcode provided version, define everything ourselves.
|
||||||
|
|
||||||
// SENTE_BEGIN
|
// SENTE_BEGIN
|
||||||
/*" Generates a failure when !{ [a1 isEqualTo:a2] } is false
|
/*" Generates a failure when !{ [a1 isEqualTo:a2] } is false
|
||||||
|
@ -479,21 +554,21 @@ do { \
|
||||||
id a1value = (a1); \
|
id a1value = (a1); \
|
||||||
id a2value = (a2); \
|
id a2value = (a2); \
|
||||||
if (a1value == a2value) continue; \
|
if (a1value == a2value) continue; \
|
||||||
if ( (@encode(__typeof__(a1value)) == @encode(id)) && \
|
if ((strcmp(@encode(__typeof__(a1value)), @encode(id)) == 0) && \
|
||||||
(@encode(__typeof__(a2value)) == @encode(id)) && \
|
(strcmp(@encode(__typeof__(a2value)), @encode(id)) == 0) && \
|
||||||
[(id)a1value isEqual:(id)a2value]) continue; \
|
[(id)a1value isEqual:(id)a2value]) continue; \
|
||||||
[self failWithException:[NSException failureInEqualityBetweenObject:a1value \
|
[self failWithException:[NSException failureInEqualityBetweenObject:a1value \
|
||||||
andObject:a2value \
|
andObject:a2value \
|
||||||
inFile:[NSString stringWithUTF8String:__FILE__] \
|
inFile:[NSString stringWithUTF8String:__FILE__] \
|
||||||
atLine:__LINE__ \
|
atLine:__LINE__ \
|
||||||
withDescription: STComposeString(description, ##__VA_ARGS__)]]; \
|
withDescription:@"%@", STComposeString(description, ##__VA_ARGS__)]]; \
|
||||||
} \
|
} \
|
||||||
@catch (id anException) { \
|
@catch (id anException) { \
|
||||||
[self failWithException:[NSException failureInRaise:[NSString stringWithFormat:@"(%s) == (%s)", #a1, #a2] \
|
[self failWithException:[NSException failureInRaise:[NSString stringWithFormat:@"(%s) == (%s)", #a1, #a2] \
|
||||||
exception:anException \
|
exception:anException \
|
||||||
inFile:[NSString stringWithUTF8String:__FILE__] \
|
inFile:[NSString stringWithUTF8String:__FILE__] \
|
||||||
atLine:__LINE__ \
|
atLine:__LINE__ \
|
||||||
withDescription:STComposeString(description, ##__VA_ARGS__)]]; \
|
withDescription:@"%@", STComposeString(description, ##__VA_ARGS__)]]; \
|
||||||
} \
|
} \
|
||||||
} while(0)
|
} while(0)
|
||||||
|
|
||||||
|
@ -509,10 +584,10 @@ do { \
|
||||||
#define STAssertEquals(a1, a2, description, ...) \
|
#define STAssertEquals(a1, a2, description, ...) \
|
||||||
do { \
|
do { \
|
||||||
@try { \
|
@try { \
|
||||||
if (@encode(__typeof__(a1)) != @encode(__typeof__(a2))) { \
|
if (strcmp(@encode(__typeof__(a1)), @encode(__typeof__(a2)))) { \
|
||||||
[self failWithException:[NSException failureInFile:[NSString stringWithUTF8String:__FILE__] \
|
[self failWithException:[NSException failureInFile:[NSString stringWithUTF8String:__FILE__] \
|
||||||
atLine:__LINE__ \
|
atLine:__LINE__ \
|
||||||
withDescription:[[NSString stringWithFormat:@"Type mismatch (%@/%@) -- ",@encode(__typeof__(a1)),@encode(__typeof__(a2))] stringByAppendingString:STComposeString(description, ##__VA_ARGS__)]]]; \
|
withDescription:@"Type mismatch -- %@", STComposeString(description, ##__VA_ARGS__)]]; \
|
||||||
} else { \
|
} else { \
|
||||||
__typeof__(a1) a1value = (a1); \
|
__typeof__(a1) a1value = (a1); \
|
||||||
__typeof__(a2) a2value = (a2); \
|
__typeof__(a2) a2value = (a2); \
|
||||||
|
@ -524,7 +599,7 @@ do { \
|
||||||
withAccuracy:nil \
|
withAccuracy:nil \
|
||||||
inFile:[NSString stringWithUTF8String:__FILE__] \
|
inFile:[NSString stringWithUTF8String:__FILE__] \
|
||||||
atLine:__LINE__ \
|
atLine:__LINE__ \
|
||||||
withDescription: STComposeString(description, ##__VA_ARGS__)]]; \
|
withDescription:@"%@", STComposeString(description, ##__VA_ARGS__)]]; \
|
||||||
} \
|
} \
|
||||||
} \
|
} \
|
||||||
} \
|
} \
|
||||||
|
@ -533,7 +608,7 @@ do { \
|
||||||
exception:anException \
|
exception:anException \
|
||||||
inFile:[NSString stringWithUTF8String:__FILE__] \
|
inFile:[NSString stringWithUTF8String:__FILE__] \
|
||||||
atLine:__LINE__ \
|
atLine:__LINE__ \
|
||||||
withDescription:STComposeString(description, ##__VA_ARGS__)]]; \
|
withDescription:@"%@", STComposeString(description, ##__VA_ARGS__)]]; \
|
||||||
} \
|
} \
|
||||||
} while(0)
|
} while(0)
|
||||||
|
|
||||||
|
@ -555,10 +630,10 @@ do { \
|
||||||
#define STAssertEqualsWithAccuracy(a1, a2, accuracy, description, ...) \
|
#define STAssertEqualsWithAccuracy(a1, a2, accuracy, description, ...) \
|
||||||
do { \
|
do { \
|
||||||
@try { \
|
@try { \
|
||||||
if (@encode(__typeof__(a1)) != @encode(__typeof__(a2))) { \
|
if (strcmp(@encode(__typeof__(a1)), @encode(__typeof__(a2)))) { \
|
||||||
[self failWithException:[NSException failureInFile:[NSString stringWithUTF8String:__FILE__] \
|
[self failWithException:[NSException failureInFile:[NSString stringWithUTF8String:__FILE__] \
|
||||||
atLine:__LINE__ \
|
atLine:__LINE__ \
|
||||||
withDescription:[[[NSString stringWithFormat:@"Type mismatch (%@/%@) -- ",@encode(__typeof__(a1)),@encode(__typeof__(a2))] stringByAppendingString:STComposeString(description, ##__VA_ARGS__)]]]; \
|
withDescription:@"Type mismatch -- %@", STComposeString(description, ##__VA_ARGS__)]]; \
|
||||||
} else { \
|
} else { \
|
||||||
__typeof__(a1) a1value = (a1); \
|
__typeof__(a1) a1value = (a1); \
|
||||||
__typeof__(a2) a2value = (a2); \
|
__typeof__(a2) a2value = (a2); \
|
||||||
|
@ -572,7 +647,7 @@ do { \
|
||||||
withAccuracy:accuracyencoded \
|
withAccuracy:accuracyencoded \
|
||||||
inFile:[NSString stringWithUTF8String:__FILE__] \
|
inFile:[NSString stringWithUTF8String:__FILE__] \
|
||||||
atLine:__LINE__ \
|
atLine:__LINE__ \
|
||||||
withDescription: STComposeString(description, ##__VA_ARGS__)]]; \
|
withDescription:@"%@", STComposeString(description, ##__VA_ARGS__)]]; \
|
||||||
} \
|
} \
|
||||||
} \
|
} \
|
||||||
} \
|
} \
|
||||||
|
@ -581,7 +656,7 @@ do { \
|
||||||
exception:anException \
|
exception:anException \
|
||||||
inFile:[NSString stringWithUTF8String:__FILE__] \
|
inFile:[NSString stringWithUTF8String:__FILE__] \
|
||||||
atLine:__LINE__ \
|
atLine:__LINE__ \
|
||||||
withDescription:STComposeString(description, ##__VA_ARGS__)]]; \
|
withDescription:@"%@", STComposeString(description, ##__VA_ARGS__)]]; \
|
||||||
} \
|
} \
|
||||||
} while(0)
|
} while(0)
|
||||||
|
|
||||||
|
@ -595,7 +670,7 @@ do { \
|
||||||
#define STFail(description, ...) \
|
#define STFail(description, ...) \
|
||||||
[self failWithException:[NSException failureInFile:[NSString stringWithUTF8String:__FILE__] \
|
[self failWithException:[NSException failureInFile:[NSString stringWithUTF8String:__FILE__] \
|
||||||
atLine:__LINE__ \
|
atLine:__LINE__ \
|
||||||
withDescription: STComposeString(description, ##__VA_ARGS__)]]
|
withDescription:@"%@", STComposeString(description, ##__VA_ARGS__)]]
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -616,7 +691,7 @@ do { \
|
||||||
isTrue:NO \
|
isTrue:NO \
|
||||||
inFile:[NSString stringWithUTF8String:__FILE__] \
|
inFile:[NSString stringWithUTF8String:__FILE__] \
|
||||||
atLine:__LINE__ \
|
atLine:__LINE__ \
|
||||||
withDescription: STComposeString(description, ##__VA_ARGS__)]]; \
|
withDescription:@"%@", STComposeString(description, ##__VA_ARGS__)]]; \
|
||||||
} \
|
} \
|
||||||
} \
|
} \
|
||||||
@catch (id anException) { \
|
@catch (id anException) { \
|
||||||
|
@ -624,7 +699,7 @@ do { \
|
||||||
exception:anException \
|
exception:anException \
|
||||||
inFile:[NSString stringWithUTF8String:__FILE__] \
|
inFile:[NSString stringWithUTF8String:__FILE__] \
|
||||||
atLine:__LINE__ \
|
atLine:__LINE__ \
|
||||||
withDescription:STComposeString(description, ##__VA_ARGS__)]]; \
|
withDescription:@"%@", STComposeString(description, ##__VA_ARGS__)]]; \
|
||||||
} \
|
} \
|
||||||
} while(0)
|
} while(0)
|
||||||
|
|
||||||
|
@ -646,7 +721,7 @@ do { \
|
||||||
isTrue:NO \
|
isTrue:NO \
|
||||||
inFile:[NSString stringWithUTF8String:__FILE__] \
|
inFile:[NSString stringWithUTF8String:__FILE__] \
|
||||||
atLine:__LINE__ \
|
atLine:__LINE__ \
|
||||||
withDescription: STComposeString(description, ##__VA_ARGS__)]]; \
|
withDescription:@"%@", STComposeString(description, ##__VA_ARGS__)]]; \
|
||||||
} \
|
} \
|
||||||
} \
|
} \
|
||||||
@catch (id anException) { \
|
@catch (id anException) { \
|
||||||
|
@ -654,7 +729,7 @@ do { \
|
||||||
exception:anException \
|
exception:anException \
|
||||||
inFile:[NSString stringWithUTF8String:__FILE__] \
|
inFile:[NSString stringWithUTF8String:__FILE__] \
|
||||||
atLine:__LINE__ \
|
atLine:__LINE__ \
|
||||||
withDescription:STComposeString(description, ##__VA_ARGS__)]]; \
|
withDescription:@"%@", STComposeString(description, ##__VA_ARGS__)]]; \
|
||||||
} \
|
} \
|
||||||
} while(0)
|
} while(0)
|
||||||
|
|
||||||
|
@ -674,7 +749,7 @@ do { \
|
||||||
isTrue:NO \
|
isTrue:NO \
|
||||||
inFile:[NSString stringWithUTF8String:__FILE__] \
|
inFile:[NSString stringWithUTF8String:__FILE__] \
|
||||||
atLine:__LINE__ \
|
atLine:__LINE__ \
|
||||||
withDescription: STComposeString(description, ##__VA_ARGS__)]]; \
|
withDescription:@"%@", STComposeString(description, ##__VA_ARGS__)]]; \
|
||||||
} \
|
} \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
|
@ -696,7 +771,7 @@ do { \
|
||||||
isTrue:NO \
|
isTrue:NO \
|
||||||
inFile:[NSString stringWithUTF8String:__FILE__] \
|
inFile:[NSString stringWithUTF8String:__FILE__] \
|
||||||
atLine:__LINE__ \
|
atLine:__LINE__ \
|
||||||
withDescription: STComposeString(description, ##__VA_ARGS__)]]; \
|
withDescription:@"%@", STComposeString(description, ##__VA_ARGS__)]]; \
|
||||||
} \
|
} \
|
||||||
} \
|
} \
|
||||||
@catch (id anException) { \
|
@catch (id anException) { \
|
||||||
|
@ -704,7 +779,7 @@ do { \
|
||||||
exception:anException \
|
exception:anException \
|
||||||
inFile:[NSString stringWithUTF8String:__FILE__] \
|
inFile:[NSString stringWithUTF8String:__FILE__] \
|
||||||
atLine:__LINE__ \
|
atLine:__LINE__ \
|
||||||
withDescription:STComposeString(description, ##__VA_ARGS__)]]; \
|
withDescription:@"%@", STComposeString(description, ##__VA_ARGS__)]]; \
|
||||||
} \
|
} \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
|
@ -724,7 +799,7 @@ do { \
|
||||||
isTrue:YES \
|
isTrue:YES \
|
||||||
inFile:[NSString stringWithUTF8String:__FILE__] \
|
inFile:[NSString stringWithUTF8String:__FILE__] \
|
||||||
atLine:__LINE__ \
|
atLine:__LINE__ \
|
||||||
withDescription: STComposeString(description, ##__VA_ARGS__)]]; \
|
withDescription:@"%@", STComposeString(description, ##__VA_ARGS__)]]; \
|
||||||
} \
|
} \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
|
@ -746,7 +821,7 @@ do { \
|
||||||
isTrue:YES \
|
isTrue:YES \
|
||||||
inFile:[NSString stringWithUTF8String:__FILE__] \
|
inFile:[NSString stringWithUTF8String:__FILE__] \
|
||||||
atLine:__LINE__ \
|
atLine:__LINE__ \
|
||||||
withDescription: STComposeString(description, ##__VA_ARGS__)]]; \
|
withDescription:@"%@", STComposeString(description, ##__VA_ARGS__)]]; \
|
||||||
} \
|
} \
|
||||||
} \
|
} \
|
||||||
@catch (id anException) { \
|
@catch (id anException) { \
|
||||||
|
@ -754,7 +829,7 @@ do { \
|
||||||
exception:anException \
|
exception:anException \
|
||||||
inFile:[NSString stringWithUTF8String:__FILE__] \
|
inFile:[NSString stringWithUTF8String:__FILE__] \
|
||||||
atLine:__LINE__ \
|
atLine:__LINE__ \
|
||||||
withDescription:STComposeString(description, ##__VA_ARGS__)]]; \
|
withDescription:@"%@", STComposeString(description, ##__VA_ARGS__)]]; \
|
||||||
} \
|
} \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
|
@ -777,7 +852,7 @@ do { \
|
||||||
exception:nil \
|
exception:nil \
|
||||||
inFile:[NSString stringWithUTF8String:__FILE__] \
|
inFile:[NSString stringWithUTF8String:__FILE__] \
|
||||||
atLine:__LINE__ \
|
atLine:__LINE__ \
|
||||||
withDescription: STComposeString(description, ##__VA_ARGS__)]]; \
|
withDescription:@"%@", STComposeString(description, ##__VA_ARGS__)]]; \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
|
|
||||||
|
@ -803,7 +878,7 @@ do { \
|
||||||
exception:anException \
|
exception:anException \
|
||||||
inFile:[NSString stringWithUTF8String:__FILE__] \
|
inFile:[NSString stringWithUTF8String:__FILE__] \
|
||||||
atLine:__LINE__ \
|
atLine:__LINE__ \
|
||||||
withDescription: STComposeString(_descrip, ##__VA_ARGS__)]]; \
|
withDescription:@"%@", STComposeString(_descrip, ##__VA_ARGS__)]]; \
|
||||||
continue; \
|
continue; \
|
||||||
} \
|
} \
|
||||||
NSString *_descrip = STComposeString(@"(Expected exception: %@) %@", NSStringFromClass([specificException class]), description); \
|
NSString *_descrip = STComposeString(@"(Expected exception: %@) %@", NSStringFromClass([specificException class]), description); \
|
||||||
|
@ -811,7 +886,7 @@ do { \
|
||||||
exception:nil \
|
exception:nil \
|
||||||
inFile:[NSString stringWithUTF8String:__FILE__] \
|
inFile:[NSString stringWithUTF8String:__FILE__] \
|
||||||
atLine:__LINE__ \
|
atLine:__LINE__ \
|
||||||
withDescription: STComposeString(_descrip, ##__VA_ARGS__)]]; \
|
withDescription:@"%@", STComposeString(_descrip, ##__VA_ARGS__)]]; \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
|
|
||||||
|
@ -840,7 +915,7 @@ do { \
|
||||||
exception:anException \
|
exception:anException \
|
||||||
inFile:[NSString stringWithUTF8String:__FILE__] \
|
inFile:[NSString stringWithUTF8String:__FILE__] \
|
||||||
atLine:__LINE__ \
|
atLine:__LINE__ \
|
||||||
withDescription: STComposeString(_descrip, ##__VA_ARGS__)]]; \
|
withDescription:@"%@", STComposeString(_descrip, ##__VA_ARGS__)]]; \
|
||||||
continue; \
|
continue; \
|
||||||
} \
|
} \
|
||||||
@catch (id anException) { \
|
@catch (id anException) { \
|
||||||
|
@ -850,7 +925,7 @@ do { \
|
||||||
exception:anException \
|
exception:anException \
|
||||||
inFile:[NSString stringWithUTF8String:__FILE__] \
|
inFile:[NSString stringWithUTF8String:__FILE__] \
|
||||||
atLine:__LINE__ \
|
atLine:__LINE__ \
|
||||||
withDescription: STComposeString(_descrip, ##__VA_ARGS__)]]; \
|
withDescription:@"%@", STComposeString(_descrip, ##__VA_ARGS__)]]; \
|
||||||
continue; \
|
continue; \
|
||||||
} \
|
} \
|
||||||
NSString *_descrip = STComposeString(@"(Expected exception: %@) %@", NSStringFromClass([specificException class]), description); \
|
NSString *_descrip = STComposeString(@"(Expected exception: %@) %@", NSStringFromClass([specificException class]), description); \
|
||||||
|
@ -859,7 +934,7 @@ do { \
|
||||||
exception:nil \
|
exception:nil \
|
||||||
inFile:[NSString stringWithUTF8String:__FILE__] \
|
inFile:[NSString stringWithUTF8String:__FILE__] \
|
||||||
atLine:__LINE__ \
|
atLine:__LINE__ \
|
||||||
withDescription: STComposeString(_descrip, ##__VA_ARGS__)]]; \
|
withDescription:@"%@", STComposeString(_descrip, ##__VA_ARGS__)]]; \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
|
|
||||||
|
@ -879,7 +954,7 @@ do { \
|
||||||
exception:anException \
|
exception:anException \
|
||||||
inFile:[NSString stringWithUTF8String:__FILE__] \
|
inFile:[NSString stringWithUTF8String:__FILE__] \
|
||||||
atLine:__LINE__ \
|
atLine:__LINE__ \
|
||||||
withDescription: STComposeString(description, ##__VA_ARGS__)]]; \
|
withDescription:@"%@", STComposeString(description, ##__VA_ARGS__)]]; \
|
||||||
} \
|
} \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
|
@ -902,7 +977,7 @@ do { \
|
||||||
exception:anException \
|
exception:anException \
|
||||||
inFile:[NSString stringWithUTF8String:__FILE__] \
|
inFile:[NSString stringWithUTF8String:__FILE__] \
|
||||||
atLine:__LINE__ \
|
atLine:__LINE__ \
|
||||||
withDescription: STComposeString(description, ##__VA_ARGS__)]]; \
|
withDescription:@"%@", STComposeString(description, ##__VA_ARGS__)]]; \
|
||||||
} \
|
} \
|
||||||
@catch (id anythingElse) { \
|
@catch (id anythingElse) { \
|
||||||
; \
|
; \
|
||||||
|
@ -935,7 +1010,7 @@ do { \
|
||||||
exception:anException \
|
exception:anException \
|
||||||
inFile:[NSString stringWithUTF8String:__FILE__] \
|
inFile:[NSString stringWithUTF8String:__FILE__] \
|
||||||
atLine:__LINE__ \
|
atLine:__LINE__ \
|
||||||
withDescription: STComposeString(_descrip, ##__VA_ARGS__)]]; \
|
withDescription:@"%@", STComposeString(_descrip, ##__VA_ARGS__)]]; \
|
||||||
} \
|
} \
|
||||||
continue; \
|
continue; \
|
||||||
} \
|
} \
|
||||||
|
@ -949,45 +1024,53 @@ do { \
|
||||||
@interface NSException (GTMSenTestAdditions)
|
@interface NSException (GTMSenTestAdditions)
|
||||||
+ (NSException *)failureInFile:(NSString *)filename
|
+ (NSException *)failureInFile:(NSString *)filename
|
||||||
atLine:(int)lineNumber
|
atLine:(int)lineNumber
|
||||||
withDescription:(NSString *)formatString, ...;
|
withDescription:(NSString *)formatString, ... NS_FORMAT_FUNCTION(3, 4);
|
||||||
+ (NSException *)failureInCondition:(NSString *)condition
|
+ (NSException *)failureInCondition:(NSString *)condition
|
||||||
isTrue:(BOOL)isTrue
|
isTrue:(BOOL)isTrue
|
||||||
inFile:(NSString *)filename
|
inFile:(NSString *)filename
|
||||||
atLine:(int)lineNumber
|
atLine:(int)lineNumber
|
||||||
withDescription:(NSString *)formatString, ...;
|
withDescription:(NSString *)formatString, ... NS_FORMAT_FUNCTION(5, 6);
|
||||||
+ (NSException *)failureInEqualityBetweenObject:(id)left
|
+ (NSException *)failureInEqualityBetweenObject:(id)left
|
||||||
andObject:(id)right
|
andObject:(id)right
|
||||||
inFile:(NSString *)filename
|
inFile:(NSString *)filename
|
||||||
atLine:(int)lineNumber
|
atLine:(int)lineNumber
|
||||||
withDescription:(NSString *)formatString, ...;
|
withDescription:(NSString *)formatString, ... NS_FORMAT_FUNCTION(5, 6);
|
||||||
+ (NSException *)failureInEqualityBetweenValue:(NSValue *)left
|
+ (NSException *)failureInEqualityBetweenValue:(NSValue *)left
|
||||||
andValue:(NSValue *)right
|
andValue:(NSValue *)right
|
||||||
withAccuracy:(NSValue *)accuracy
|
withAccuracy:(NSValue *)accuracy
|
||||||
inFile:(NSString *)filename
|
inFile:(NSString *)filename
|
||||||
atLine:(int) ineNumber
|
atLine:(int) ineNumber
|
||||||
withDescription:(NSString *)formatString, ...;
|
withDescription:(NSString *)formatString, ... NS_FORMAT_FUNCTION(6, 7);
|
||||||
+ (NSException *)failureInRaise:(NSString *)expression
|
+ (NSException *)failureInRaise:(NSString *)expression
|
||||||
inFile:(NSString *)filename
|
inFile:(NSString *)filename
|
||||||
atLine:(int)lineNumber
|
atLine:(int)lineNumber
|
||||||
withDescription:(NSString *)formatString, ...;
|
withDescription:(NSString *)formatString, ... NS_FORMAT_FUNCTION(4, 5);
|
||||||
+ (NSException *)failureInRaise:(NSString *)expression
|
+ (NSException *)failureInRaise:(NSString *)expression
|
||||||
exception:(NSException *)exception
|
exception:(NSException *)exception
|
||||||
inFile:(NSString *)filename
|
inFile:(NSString *)filename
|
||||||
atLine:(int)lineNumber
|
atLine:(int)lineNumber
|
||||||
withDescription:(NSString *)formatString, ...;
|
withDescription:(NSString *)formatString, ... NS_FORMAT_FUNCTION(5, 6);
|
||||||
@end
|
@end
|
||||||
|
|
||||||
// SENTE_END
|
// SENTE_END
|
||||||
|
|
||||||
@interface SenTestCase : NSObject {
|
@protocol SenTestCase
|
||||||
SEL currentSelector_;
|
+ (id)testCaseWithInvocation:(NSInvocation *)anInvocation;
|
||||||
}
|
- (id)initWithInvocation:(NSInvocation *)anInvocation;
|
||||||
|
|
||||||
- (void)setUp;
|
- (void)setUp;
|
||||||
- (void)invokeTest;
|
- (void)invokeTest;
|
||||||
- (void)tearDown;
|
- (void)tearDown;
|
||||||
- (void)performTest:(SEL)sel;
|
- (void)performTest;
|
||||||
- (void)failWithException:(NSException*)exception;
|
- (void)failWithException:(NSException*)exception;
|
||||||
|
- (NSInvocation *)invocation;
|
||||||
|
- (SEL)selector;
|
||||||
|
+ (NSArray *)testInvocations;
|
||||||
|
@end
|
||||||
|
|
||||||
|
@interface SenTestCase : NSObject<SenTestCase> {
|
||||||
|
@private
|
||||||
|
NSInvocation *invocation_;
|
||||||
|
}
|
||||||
@end
|
@end
|
||||||
|
|
||||||
GTM_EXTERN NSString *const SenTestFailureException;
|
GTM_EXTERN NSString *const SenTestFailureException;
|
||||||
|
@ -995,10 +1078,33 @@ GTM_EXTERN NSString *const SenTestFailureException;
|
||||||
GTM_EXTERN NSString *const SenTestFilenameKey;
|
GTM_EXTERN NSString *const SenTestFilenameKey;
|
||||||
GTM_EXTERN NSString *const SenTestLineNumberKey;
|
GTM_EXTERN NSString *const SenTestLineNumberKey;
|
||||||
|
|
||||||
#endif // GTM_IPHONE_SDK
|
#endif // GTM_IPHONE_SDK && !GTM_IPHONE_USE_SENTEST
|
||||||
|
|
||||||
// All unittest cases in GTM should inherit from GTMTestCase. It makes sure
|
// All unittest cases in GTM should inherit from GTMTestCase. It makes sure
|
||||||
// to set up our logging system correctly to verify logging calls.
|
// to set up our logging system correctly to verify logging calls.
|
||||||
// See GTMUnitTestDevLog.h for details
|
// See GTMUnitTestDevLog.h for details
|
||||||
@interface GTMTestCase : SenTestCase
|
@interface GTMTestCase : SenTestCase
|
||||||
|
|
||||||
|
// Returns YES if this is an abstract testCase class as opposed to a concrete
|
||||||
|
// testCase class that you want tests run against. SenTestCase is not designed
|
||||||
|
// out of the box to handle an abstract class hierarchy descending from it with
|
||||||
|
// some concrete subclasses. In some cases we want all the "concrete"
|
||||||
|
// subclasses of an abstract subclass of SenTestCase to run a test, but we don't
|
||||||
|
// want that test to be run against an instance of an abstract subclass itself.
|
||||||
|
// By returning "YES" here, the tests defined by this class won't be run against
|
||||||
|
// an instance of this class. As an example class hierarchy:
|
||||||
|
//
|
||||||
|
// FooExtensionTestCase
|
||||||
|
// GTMTestCase <- ExtensionAbstractTestCase <
|
||||||
|
// BarExtensionTestCase
|
||||||
|
//
|
||||||
|
// So FooExtensionTestCase and BarExtensionTestCase inherit from
|
||||||
|
// ExtensionAbstractTestCase (and probably FooExtension and BarExtension inherit
|
||||||
|
// from a class named Extension). We want the tests in ExtensionAbstractTestCase
|
||||||
|
// to be run as part of FooExtensionTestCase and BarExtensionTestCase, but we
|
||||||
|
// don't want them run against ExtensionAbstractTestCase. The default
|
||||||
|
// implementation checks to see if the name of the class contains the word
|
||||||
|
// "AbstractTest" (case sensitive).
|
||||||
|
+ (BOOL)isAbstractTestCase;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
|
@ -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