ALWAYS_DETAILED_SEC = NO
INLINE_INHERITED_MEMB = NO
FULL_PATH_NAMES = NO
-STRIP_FROM_PATH =
-STRIP_FROM_INC_PATH =
+STRIP_FROM_PATH =
+STRIP_FROM_INC_PATH =
SHORT_NAMES = NO
JAVADOC_AUTOBRIEF = YES
MULTILINE_CPP_IS_BRIEF = NO
GENERATE_TESTLIST = YES
GENERATE_BUGLIST = YES
GENERATE_DEPRECATEDLIST= YES
-ENABLED_SECTIONS =
+ENABLED_SECTIONS =
MAX_INITIALIZER_LINES = 30
SHOW_USED_FILES = YES
SHOW_DIRECTORIES = YES
-FILE_VERSION_FILTER =
+FILE_VERSION_FILTER =
#---------------------------------------------------------------------------
# configuration options related to warning and progress messages
#---------------------------------------------------------------------------
WARN_IF_DOC_ERROR = YES
WARN_NO_PARAMDOC = NO
WARN_FORMAT = "$file:$line: $text"
-WARN_LOGFILE =
+WARN_LOGFILE =
#---------------------------------------------------------------------------
# configuration options related to the input files
#---------------------------------------------------------------------------
FILE_PATTERNS = *.h \
*.H
RECURSIVE = YES
-EXCLUDE =
+EXCLUDE =
EXCLUDE_SYMLINKS = NO
-EXCLUDE_PATTERNS =
-EXAMPLE_PATH =
+EXCLUDE_PATTERNS =
+EXAMPLE_PATH =
EXAMPLE_PATTERNS = *
EXAMPLE_RECURSIVE = NO
-IMAGE_PATH =
-INPUT_FILTER =
-FILTER_PATTERNS =
+IMAGE_PATH =
+INPUT_FILTER =
+FILTER_PATTERNS =
FILTER_SOURCE_FILES = NO
#---------------------------------------------------------------------------
# configuration options related to source browsing
#---------------------------------------------------------------------------
ALPHABETICAL_INDEX = YES
COLS_IN_ALPHA_INDEX = 5
-IGNORE_PREFIX =
+IGNORE_PREFIX =
#---------------------------------------------------------------------------
# configuration options related to the HTML output
#---------------------------------------------------------------------------
GENERATE_HTML = YES
HTML_OUTPUT = html
HTML_FILE_EXTENSION = .html
-HTML_HEADER =
-HTML_FOOTER =
-HTML_STYLESHEET =
+HTML_HEADER =
+HTML_FOOTER =
+HTML_STYLESHEET =
HTML_ALIGN_MEMBERS = YES
GENERATE_HTMLHELP = NO
-CHM_FILE =
-HHC_LOCATION =
+CHM_FILE =
+HHC_LOCATION =
GENERATE_CHI = NO
BINARY_TOC = NO
TOC_EXPAND = NO
MAKEINDEX_CMD_NAME = makeindex
COMPACT_LATEX = NO
PAPER_TYPE = a4wide
-EXTRA_PACKAGES =
-LATEX_HEADER =
+EXTRA_PACKAGES =
+LATEX_HEADER =
PDF_HYPERLINKS = YES
USE_PDFLATEX = YES
LATEX_BATCHMODE = NO
RTF_OUTPUT = rtf
COMPACT_RTF = NO
RTF_HYPERLINKS = NO
-RTF_STYLESHEET_FILE =
-RTF_EXTENSIONS_FILE =
+RTF_STYLESHEET_FILE =
+RTF_EXTENSIONS_FILE =
#---------------------------------------------------------------------------
# configuration options related to the man page output
#---------------------------------------------------------------------------
#---------------------------------------------------------------------------
GENERATE_XML = NO
XML_OUTPUT = xml
-XML_SCHEMA =
-XML_DTD =
+XML_SCHEMA =
+XML_DTD =
XML_PROGRAMLISTING = YES
#---------------------------------------------------------------------------
# configuration options for the AutoGen Definitions output
GENERATE_PERLMOD = NO
PERLMOD_LATEX = NO
PERLMOD_PRETTY = YES
-PERLMOD_MAKEVAR_PREFIX =
+PERLMOD_MAKEVAR_PREFIX =
#---------------------------------------------------------------------------
-# Configuration options related to the preprocessor
+# Configuration options related to the preprocessor
#---------------------------------------------------------------------------
ENABLE_PREPROCESSING = YES
MACRO_EXPANSION = NO
EXPAND_ONLY_PREDEF = NO
SEARCH_INCLUDES = YES
-INCLUDE_PATH =
-INCLUDE_FILE_PATTERNS =
-PREDEFINED =
-EXPAND_AS_DEFINED =
+INCLUDE_PATH =
+INCLUDE_FILE_PATTERNS =
+PREDEFINED =
+EXPAND_AS_DEFINED =
SKIP_FUNCTION_MACROS = YES
#---------------------------------------------------------------------------
-# Configuration::additions related to external references
+# Configuration::additions related to external references
#---------------------------------------------------------------------------
-TAGFILES =
-GENERATE_TAGFILE =
+TAGFILES =
+GENERATE_TAGFILE =
ALLEXTERNALS = NO
EXTERNAL_GROUPS = YES
PERL_PATH = /usr/bin/perl
#---------------------------------------------------------------------------
-# Configuration options related to the dot tool
+# Configuration options related to the dot tool
#---------------------------------------------------------------------------
CLASS_DIAGRAMS = NO
HIDE_UNDOC_RELATIONS = YES
DIRECTORY_GRAPH = YES
DOT_IMAGE_FORMAT = png
DOT_PATH = /usr/local/bin
-DOTFILE_DIRS =
+DOTFILE_DIRS =
MAX_DOT_GRAPH_WIDTH = 1024
MAX_DOT_GRAPH_HEIGHT = 1024
MAX_DOT_GRAPH_DEPTH = 1000
GENERATE_LEGEND = YES
DOT_CLEANUP = YES
#---------------------------------------------------------------------------
-# Configuration::additions related to the search engine
+# Configuration::additions related to the search engine
#---------------------------------------------------------------------------
SEARCHENGINE = NO
-WOTest is an Objective-C unit testing framework written by Wincent Colaiuta
+WOTest is an Objective-C unit testing framework written by Wincent Colaiuta
<win@wincent.com>. More information available at:
http://test.wincent.com/
3. Xcode integration. It should be easy to automatically run the test suite from within Xcode, and not just by performing a "Run" (Command-R) but as a part of the actual build process (Command-B). You should be able to click on failed test results and be taken to the corresponding line in the source code.
-4. Separation of test target and non-test target. It should be possible to have a target in Xcode that doesn't run any tests, and a separate target that does run the tests.
+4. Separation of test target and non-test target. It should be possible to have a target in Xcode that doesn't run any tests, and a separate target that does run the tests.
5. No parallel hierarchies (either class hierarchies or category hierarchies). It shouldn't be necessary to maintain two hierarchies of code (one for the product and one for the tests) which could get out of synchronization (see the following two points).
9. Ability to run unit tests from within the debugger.
-9. The code that ships should be tested, not the code that doesn't ship. I don't want to only test the "Development" build of the product and then ship an (untested!) "Deployment" build. Nor do I want to test a selection of classes from the product in isolation (for example, taking the source files for those selected classes and compiling them into my test suite). I want to test the exact code which will ship to customers.
+9. The code that ships should be tested, not the code that doesn't ship. I don't want to only test the "Development" build of the product and then ship an (untested!) "Deployment" build. Nor do I want to test a selection of classes from the product in isolation (for example, taking the source files for those selected classes and compiling them into my test suite). I want to test the exact code which will ship to customers.
10. Customers and beta-testers should be able to run the tests (if you want them to, that is). It's useful that third parties can run the tests for the purposes of support or squishing bugs. It is possible that the tests may pass "in house", but fail on other hardware or other configurations, and information gathered on those configurations is of obvious value.
There's a lot more to it than that, but this is what essentially lies at the heart of unit testing. So instead of grappling with any of those tools, I came up with a set of macros that enabled me to do unit testing. Here is a basic example:
#ifdef DEBUG
-
+
/*! Test for a positive result (> 0) */
#define WO_TEST_POSITIVE(expr) \
do { \
if ((expr) <= 0) \
ELOG(@"Unit test failed (expected POSITIVE; obtained <= 0)"); \
} while (0)
-
+
#else /* DEBUG not defined*/
-
+
#define WO_TEST_POSITIVE(expr)
-
+
#endif
The ELOG macro was defined elsewhere, and logged the class, method, line number and so forth where the error was produced. Note that when the DEBUG flag is not defined (as is the case with "Deployment" builds), the tests produce no code. This means that the tests don't wind up in production code shipped to customers (which was in keeping with my goal at the time), but the down side is that the code that is tested is the "Development" build and not the "Deployment" build. It's conceivable (although it never happened to me) that tests could pass in the Development build yet the same function could fail in the "real world" deployment build.
Before I could use it to test itself, I had to complete a significant proportion of the code. "Test-Driven Development" was not an option, because until I had written the testing mechanism I didn't even know how I could write the tests. Now that WOTest is basically complete, it can be used to test itself. The key piece that needed to be written before I could start using WOTest to test itself was the WOTestRunner command-line executable.
-The tests appear in the file, "WOTestSelfTests.m". The file is a fairly comprehensive example of the kinds of tests that are possible with WOTest. Because the objective is to test the tests, all of the test methods include two approaches to the testing: one batch of tests that are expected to pass (in other words, if a test passes when it is expected to pass, then this is a pass); and a second batch of tests that are expected to fail (in other words, if a test fails a test when it is expected to fail, then this also is a pass). In this respect, this shows a highly atypical application of the tests; generally you would write code with the intention that all tests should pass, but in order to test that the tests work you must show that the both pass when you expect them to pass and fail when you expect them to fail.
+The tests appear in the file, "WOTestSelfTests.m". The file is a fairly comprehensive example of the kinds of tests that are possible with WOTest. Because the objective is to test the tests, all of the test methods include two approaches to the testing: one batch of tests that are expected to pass (in other words, if a test passes when it is expected to pass, then this is a pass); and a second batch of tests that are expected to fail (in other words, if a test fails a test when it is expected to fail, then this also is a pass). In this respect, this shows a highly atypical application of the tests; generally you would write code with the intention that all tests should pass, but in order to test that the tests work you must show that the both pass when you expect them to pass and fail when you expect them to fail.
However, the presence of all those failure warnings in the build log can make the test results hard to read. For this reason, WOTest implements a special variable (expectFailures) that should be used only during WOTest self-testing. When the flag is set, in addition to the standard "Failed" and "Passed" status messages, there are an additional two messages: "Failed (expected failure)" and "Passed (unexpected pass)". Normally in your own unit tests you wouldn't need to set the expectFailures variable; rather you would write tests such that an expected failure results in pass. This is much safer, because there's no risk of you setting the expectFailures variable to YES and later forgetting to set it back to NO.
By including the AppKit header file you ensure that the compiler doesn't give you any warnings, but if you try to build such code the linker will give you an error that "NSView" is an undefined symbol. Of course, even if you could produce an executable and run it, it wouldn't work because the executable isn't linked to the AppKit.framework. One way to force the framework to load is to set environment variables and then run the product from the command-line. For example, in the bash shell:
export DYLD_FRAMEWORK_PATH=/System/Library/Frameworks
-export DYLD_INSERT_LIBRARIES=/System/Library/Frameworks/AppKit.framework/AppKit
+export DYLD_INSERT_LIBRARIES=/System/Library/Frameworks/AppKit.framework/AppKit
/path/to/executable
On running, the executable has access to all of the AppKit.framework's classes, even though it didn't link to them. But this still doesn't solve the problem that the linker will complain about undefined symbols. One way around this is to pass "-undefined define_a_way" to the linker when building your executable (see the ld (1) man page for more options).
- (void)callAppKitMethod
{
- NSBundle *theBundle =
+ NSBundle *theBundle =
[NSBundle bundleWithPath:@"/System/Library/Frameworks/AppKit.framework"];
Class viewClass = [theBundle classNamed:@"NSView"];
NSView *aView = [[viewClass alloc] initWithFrame:NSZeroRect];
[aView release];
}
-No compiler warnings, no linker errors, everything just works. WOTest uses this technique to allow you to load code "on the fly" without having to link to it. All it has to do is look for bundles, load them, and then run the test methods on them.
+No compiler warnings, no linker errors, everything just works. WOTest uses this technique to allow you to load code "on the fly" without having to link to it. All it has to do is look for bundles, load them, and then run the test methods on them.
================================================================================
How to test frameworks
export WOTestInjectBundle="/Users/wincent/trabajo/build/Release/REnamer.app/Contents/Resources/ApplicationTests.bundle"
export DYLD_INSERT_LIBRARIES="/Users/wincent/trabajo/build/Release/REnamer.app/Contents/Frameworks/WOTest.framework/WOTest"
export DYLD_PRINT_LIBRARIES=1
-/Users/wincent/trabajo/build/Release/REnamer.app/Contents/MacOS/REnamer
+/Users/wincent/trabajo/build/Release/REnamer.app/Contents/MacOS/REnamer
================================================================================
Shipping testable production applications
#define WO_TEST_USERINFO_LINE @"WOTestLine"
#define WO_TEST_USERINFO_PATH @"WOTestPath"
-@interface NSException (WOTest)
+@interface NSException (WOTest)
/*! Cocoa allows any Objective-C object to be thrown in an exception. Although NSException objects are most commonly used for this purpose there is no limitation that prevents other objects from being used. These objects may or may not respond to the name, reason and userInfo methods that are implemented by NSException. This method accepts any object and attempts to produce a textual description, using the name and reason methods if implemented and otherwise resorting to the description method if implented and finally a basic description based on the name of the class if not. */
+ (NSString *)WOTest_descriptionForException:(id)exception;
else if ([NSObject WOTest_object:exception respondsToSelector:@selector(name)])
{
NSString *name = nil; // attempt to get name
-
+
if ([NSObject WOTest_objectReturnsId:exception forSelector:@selector(name)])
{
name = [exception name];
const char *charString = (const char *)[exception name];
name = [NSString stringWithUTF8String:charString];
}
-
+
NSString *reason = nil; // attempt to get reason
if ([NSObject WOTest_object:exception respondsToSelector:@selector(reason)])
{
reason = [NSString stringWithUTF8String:charString];
}
}
-
+
if (name && reason)
return [NSString stringWithFormat:@"%@: %@", name, reason];
else if (name)
else
{
return [NSObject WOTest_descriptionForObject:exception];
- }
+ }
}
@catch (id e)
{
// fall through
}
-
+
// last resort
return [NSString stringWithFormat:@"unknown exception (%x)", exception];
}
returnString = [NSString stringWithUTF8String:charString];
}
}
- else
+ else
returnString = [NSObject WOTest_descriptionForObject:exception];
}
@catch (id e)
{
returnString = @"(exception caught trying to determine exception name)";
- }
+ }
return returnString;
}
{
// first do a basic comparison without arguments
if (![self WOTest_isEqualToInvocationIgnoringArguments:anInvocation]) return NO;
-
+
// compare arguments (skip first two: self and _cmd)
NSMethodSignature *aSignature = [self methodSignature];
NSMethodSignature *otherSignature = [anInvocation methodSignature];
const char *aType = [aSignature getArgumentTypeAtIndex:i];
const char *otherType = [otherSignature getArgumentTypeAtIndex:i];
if (strcmp(aType, otherType) != 0) return NO;
-
+
// compare the two values
return [[self WOTest_valueForArgumentAtIndex:i] isEqual:[anInvocation WOTest_valueForArgumentAtIndex:i]];
}
-
+
return YES; // if get this far, all equality tests passed (no arguments)
}
// basic checks: compare against nil and against self
if (!anInvocation) return NO;
if (anInvocation == self) return YES;
-
+
// compare selectors
if ([self selector] != [anInvocation selector]) return NO;
-
+
// compare signatures
NSMethodSignature *aSignature = [self methodSignature];
NSMethodSignature *otherSignature = [anInvocation methodSignature];
if (![aSignature isEqual:otherSignature]) return NO;
-
+
return YES; // if get this far, all equality tests passed (no arguments)
}
#import <Foundation/Foundation.h>
-@interface NSMethodSignature (WOTest)
+@interface NSMethodSignature (WOTest)
+ (id)WOTest_signatureBasedOnObjCTypes:(const char *)types;
#import <objc/objc-class.h>
/*
-
+
The real 10.4 NSMethodSignature API (obtained using class-dump; TODO: run class-dump to get 10.5 API):
-
+
@interface NSMethodSignature : NSObject
{
char *_types;
@interface NSMethodSignature : NSObject {
@private
- const char *_types;
- int _nargs;
- unsigned _sizeofParams;
- unsigned _returnValueLength;
- void *_parmInfoP;
- int *_fixup;
- void *_reserved;
+ const char *_types;
+ int _nargs;
+ unsigned _sizeofParams;
+ unsigned _returnValueLength;
+ void *_parmInfoP;
+ int *_fixup;
+ void *_reserved;
}
- (unsigned)numberOfArguments;
NSParameterAssert(types != NULL);
#ifdef WO_USE_OWN_METHOD_SIGNATURE_IMPLEMENTATION
-
+
return [[[self alloc] initWithObjCTypes:types] autorelease];
-
+
#else /* use private Apple API */
-
+
NSAssert([self respondsToSelector:@selector(signatureWithObjCTypes:)],
@"signatureWithObjCTypes: selector not recognized");
return [self signatureWithObjCTypes:types];
#endif
-
+
}
- (id)initWithObjCTypes:(const char *)types
// loop through args
/* unsigned method_getNumberOfArguments(Method);
unsigned method_getSizeOfArguments(Method); */
-
+
// I hate using private Apple APIs, even ones that appear stable, but
- // not sure that meddling with these instance variables is a good idea
+ // not sure that meddling with these instance variables is a good idea
}
return self;
}
#import <Foundation/Foundation.h>
-/*! WOTest is designed to work with any Objective-C class or object. You are not limited to working only with classes that derive from the Apple root classes (NSObject and NSProxy) or the other root classes (such as Object and NSZombie) that are implemented in libobjc (libobjc is part of Darwin and open source but the headers do not ship with Mac OS X). In most Objective-C programming you can assume that the objects with which you are working descend from NSObject and implement the NSObject protocol. This means that you can avoid exceptions by testing objects to see whether they implement selectors before sending messages; NSObject methods such as conformsToProtocol:, respondsToSelector: and performSelector: are frequently used for this purpose.
+/*! WOTest is designed to work with any Objective-C class or object. You are not limited to working only with classes that derive from the Apple root classes (NSObject and NSProxy) or the other root classes (such as Object and NSZombie) that are implemented in libobjc (libobjc is part of Darwin and open source but the headers do not ship with Mac OS X). In most Objective-C programming you can assume that the objects with which you are working descend from NSObject and implement the NSObject protocol. This means that you can avoid exceptions by testing objects to see whether they implement selectors before sending messages; NSObject methods such as conformsToProtocol:, respondsToSelector: and performSelector: are frequently used for this purpose.
If you try sending these messages to objects which do not implement them then you could cause a non-catchable exception (generated in _objc_error and _objc_trap) which will terminate the testing process. One of the goals of WOTest is to be extremely robust; exceptions should be caught and reported and they should not crash the program. It is true that custom root classes are extremely uncommon but WOTest nevertheless has been designed to cope with them. WOTest interacts with the Objective-C runtime at a low level and implements a number of convenience wrapper routines that enable the framework to work with any Objective-C object without fear of provoking uncatchable exceptions. The wrapper methods are described in this section. In simple cases (for example when invoking the objc_msgSend function) the framework calls the function directly without a wrapper. */
-@interface NSObject (WOTest)
+@interface NSObject (WOTest)
/*! Substitute for NSObject description method. Returns "(nil)" if \p anObject is nil. */
+ (NSString *)WOTest_descriptionForObject:(id)anObject;
+ (NSString *)WOTest_descriptionForObject:(id)anObject
{
if (!anObject) return @"(nil)";
-
+
@try
{
// special case handling for NSValue objects
if ([self WOTest_object:anObject isKindOfClass:[NSValue class]])
return [(NSValue *)anObject WOTest_description];
-
+
// fallback case: try "description" selector
if ([self WOTest_object:anObject respondsToSelector:@selector(description)])
{
NSString *returnType = [self WOTest_returnTypeForObject:anObject selector:@selector(description)];
-
+
if ([self WOTest_isIdReturnType:returnType])
{
NSString *description = [anObject description];
if ([self WOTest_object:description isKindOfClass:[NSString class]])
return description;
}
- else if ([self WOTest_isCharacterStringReturnType:returnType] ||
+ else if ([self WOTest_isCharacterStringReturnType:returnType] ||
[self WOTest_isConstantCharacterStringReturnType:returnType])
{
const char *charString = (const char *)[anObject description];
}
}
}
- @catch (id e)
+ @catch (id e)
{
// fall through
}
+ (BOOL)WOTest_isRegisteredClass:(Class)aClass
{
if (!aClass) return NO;
-
+
BOOL isRegisteredClass = NO;
int numClasses = 0;
int newNumClasses = objc_getClassList(NULL, 0);
Class *classes = NULL;
-
+
// get list of all classes on the system
while (numClasses < newNumClasses)
{
NSAssert1((classes != NULL), @"realloc() failed (size %d)", bufferSize);
newNumClasses = objc_getClassList(classes, numClasses);
}
-
+
if (classes)
{
for (int i = 0; i < newNumClasses; i++)
- {
+ {
if (aClass == classes[i]) // found in list!
{
isRegisteredClass = YES;
+ (BOOL)WOTest_isMetaClass:(Class)aClass
{
if (!aClass) return NO;
-
+
BOOL isMetaClass = NO;
int numClasses = 0;
int newNumClasses = objc_getClassList(NULL, 0);
Class *classes = NULL;
-
+
// get a list of all classes on the system
// get list of all classes on the system
while (numClasses < newNumClasses)
NSAssert1((classes != NULL), @"realloc() failed (size %d)", bufferSize);
newNumClasses = objc_getClassList(classes, numClasses);
}
-
+
if (classes)
{
for (int i = 0; i < newNumClasses; i++)
{
if (class_isMetaClass(classes[i])) // looking at a meta class
{
- if (aClass == classes[i]) // found in list!
+ if (aClass == classes[i]) // found in list!
{
isMetaClass = YES;
break;
}
free(classes);
}
- return isMetaClass;
+ return isMetaClass;
}
+ (BOOL)WOTest_object:(id)anObject isKindOfClass:(Class)aClass
NSParameterAssert([self WOTest_isRegisteredClass:aClass] || [self WOTest_isMetaClass:aClass]);
if (!anObject) return NO;
Class objectClass = object_getClass(anObject);
-
+
if (objectClass == aClass)
return YES;
else
{
- // check superclass
+ // check superclass
Class superClass = class_getSuperclass(objectClass);
- if (superClass)
- return [self WOTest_instancesOfClass:superClass areKindOfClass:aClass];
+ if (superClass)
+ return [self WOTest_instancesOfClass:superClass areKindOfClass:aClass];
}
-
+
return NO; // give up
}
NSParameterAssert([self WOTest_isRegisteredClass:aClass] || [self WOTest_isMetaClass:aClass]);
if (!otherClass) return NO;
NSParameterAssert([self WOTest_isRegisteredClass:otherClass] || [self WOTest_isMetaClass:otherClass]);
-
+
if (aClass == otherClass)
return YES;
-
- Class superClass = class_getSuperclass(aClass);
+
+ Class superClass = class_getSuperclass(aClass);
if (superClass)
return [self WOTest_instancesOfClass:superClass areKindOfClass:otherClass];
-
+
return NO; // give up
}
if (!aClass) return NO;
NSParameterAssert([self WOTest_isRegisteredClass:aClass] || [self WOTest_isMetaClass:aClass]);
if (!aProtocol) return NO;
- if (class_conformsToProtocol(aClass, aProtocol))
- return YES;
- Class superClass = class_getSuperclass(aClass);
- if (superClass)
+ if (class_conformsToProtocol(aClass, aProtocol))
+ return YES;
+ Class superClass = class_getSuperclass(aClass);
+ if (superClass)
return [self WOTest_instancesOfClass:superClass conformToProtocol:aProtocol];
-
+
return NO; // give up
}
NSParameterAssert([self WOTest_isRegisteredClass:aClass] || [self WOTest_isMetaClass:aClass]);
NSParameterAssert(aSelector != NULL);
Method theMethod = class_getClassMethod(aClass, aSelector);
-
+
if (theMethod == NULL) // class does not respond to this selector
return nil;
// get return type and list of arguments
- char *returnType = method_copyReturnType(theMethod);
- if (returnType)
- {
- NSString *returnString = [[NSString alloc] initWithUTF8String:returnType];
- free(returnType);
- return returnString;
- }
- return nil;
+ char *returnType = method_copyReturnType(theMethod);
+ if (returnType)
+ {
+ NSString *returnString = [[NSString alloc] initWithUTF8String:returnType];
+ free(returnType);
+ return returnString;
+ }
+ return nil;
}
+ (NSString *)WOTest_returnTypeForObject:(id)anObject selector:(SEL)aSelector
NSParameterAssert(anObject != nil);
NSParameterAssert(aSelector != NULL);
Method theMethod = class_getInstanceMethod(object_getClass(anObject), aSelector);
-
- if (theMethod == NULL) // object does not respond to this selector
+
+ if (theMethod == NULL) // object does not respond to this selector
return nil;
-
+
// get return type and list of arguments
- char *returnType = method_copyReturnType(theMethod);
- if (returnType)
- {
- NSString *typeString = [NSString stringWithUTF8String:returnType];
- free(returnType);
- return typeString;
- }
- return nil;
+ char *returnType = method_copyReturnType(theMethod);
+ if (returnType)
+ {
+ NSString *typeString = [NSString stringWithUTF8String:returnType];
+ free(returnType);
+ return typeString;
+ }
+ return nil;
}
+ (BOOL)WOTest_isIdReturnType:(NSString *)returnType
{
NSParameterAssert(anObject != nil);
NSParameterAssert(aSelector != NULL);
- return [self WOTest_isConstantCharacterStringReturnType:[self WOTest_returnTypeForObject:anObject selector:aSelector]];
+ return [self WOTest_isConstantCharacterStringReturnType:[self WOTest_returnTypeForObject:anObject selector:aSelector]];
}
@end
#import <Foundation/Foundation.h>
-/*!
+/*!
Example method signatures and types:
-
+
The documentation notes the following: "The compiler generates the method type encodings in a format that includes information on the size of the stack and the size occupied by the arguments. These numbers appear after each encoding in the method_types string. However, because the compiler historically generates them incorrectly, and because they differ depending on the CPU type, the runtime ignores them if they are present. These numbers are not required by the Objective-C runtime in Mac OS X v10.0 or later."
-
+
The first entry indicates the type of the return value.
This is followed by the first argument which is always \@0 or \@8 (self).
The second argument is always :4 or :12 (_cmd).
Any subsequent arguments follow.
-
+
+ new : \@8\@0:4
-
+
+ (const char *) name : r*8\@0:4
- (const char *) name : r*8\@0:4
- (void *)zone : ^v8\@0:4
- (BOOL) conformsTo: (Protocol *)aProtocolObject : c12\@0:4\@8
-
+
+ (id)allocWithZone:(NSZone *)zone : \@12\@0:4^{_NSZone=}8
-
+
+ (Class)class : #8\@0:4
-
- + (void)cancelPreviousPerformRequestsWithTarget:(id)aTarget
+
+ + (void)cancelPreviousPerformRequestsWithTarget:(id)aTarget
selector:(SEL)aSelector object:(id)anArgument
v20\@0:4\@8:12\@16
-
+
+ (NSRect)contentRectForFrameRect:(NSRect)frameRect styleMask:(unsigned int)aStyle
- {_NSRect={_NSPoint=ff}{_NSSize=ff}}28\@0:4{_NSRect={_NSPoint=ff}{_NSSize=ff}}8I24
-
+ {_NSRect={_NSPoint=ff}{_NSSize=ff}}28\@0:4{_NSRect={_NSPoint=ff}{_NSSize=ff}}8I24
+
+ (id)stringWithString:(NSString *)aString : \@12\@0:4\@8
-
+
+ (NSString *)localizedNameOfStringEncoding:(NSStringEncoding)encoding
\@12\@0:4\@8
-
- See objc/objc-class.h for macros
-
-
+
+ See objc/objc-class.h for macros
+
+
Additional codes used by runtime as described here: file:///Developer/ADC%20Reference%20Library/documentation/Cocoa/Conceptual/ObjectiveC/RuntimeOverview/chapter_4_section_6.html */
#define WO_ENCODING_QUALIFIER_CONST 'r'
#define WO_ENCODING_QUALIFIER_BYREF 'R'
#define WO_ENCODING_QUALIFIER_ONEWAY 'V'
-@interface NSScanner (WOTest)
+@interface NSScanner (WOTest)
/*! Raises an NSInternalInconsistencyException if value is NULL. */
- (BOOL)WOTest_peekCharacter:(unichar *)value;
{
*value = [string characterAtIndex:scanLocation];
return YES;
- }
+ }
return NO;
}
- (BOOL)WOTest_scanCharacter:(unichar *)value;
-{
+{
unichar character;
if ([self WOTest_peekCharacter:&character])
{
- (BOOL)WOTest_scanCharacterFromSet:(NSCharacterSet *)scanSet intoChar:(unichar *)value;
{
if (!scanSet) return NO; // nothing to do
-
+
unsigned scanLocation = [self scanLocation];
unichar character;
if ([self WOTest_scanCharacter:&character] && [scanSet characterIsMember:character])
*value = character;
return YES;
}
-
+
[self setScanLocation:scanLocation]; // revert
return NO;
}
{
if ([self scanLocation] != 0)
return NO; // the return type must be at the start of the string
-
+
// scan a single type (the first one will be the return type)
return [self WOTest_scanTypeIntoString:stringValue];
}
unsigned scanLocation = [self scanLocation];
NSString *qualifiers = nil;
NSString *type = nil;
-
+
// scan any qualifers that are present
if (![self WOTest_scanQualifiersIntoString:&qualifiers]) qualifiers = @"";
-
+
// scan type
if ([self WOTest_scanBitfieldIntoString:&type] ||
[self scanPointerIntoString:&type] ||
{
// success
if (stringValue)
- *stringValue =
+ *stringValue =
[NSString stringWithFormat:@"%@%@", qualifiers, type];
- return YES;
+ return YES;
}
-
+
[self setScanLocation:scanLocation]; // revert
return NO;
}
- (BOOL)WOTest_scanQualifiersIntoString:(NSString **)stringValue
-{
- NSCharacterSet *qualifiersSet =
+{
+ NSCharacterSet *qualifiersSet =
[NSCharacterSet characterSetWithCharactersInString:
[NSString stringWithFormat:@"%C%C%C%C%C%C%C",
WO_ENCODING_QUALIFIER_CONST, WO_ENCODING_QUALIFIER_IN,
WO_ENCODING_QUALIFIER_INOUT, WO_ENCODING_QUALIFIER_OUT,
WO_ENCODING_QUALIFIER_BYCOPY, WO_ENCODING_QUALIFIER_BYREF,
WO_ENCODING_QUALIFIER_ONEWAY]];
-
+
return [self scanCharactersFromSet:qualifiersSet
intoString:stringValue];
}
- (BOOL)WOTest_scanNonCompoundTypeIntoString:(NSString **)stringValue
{
- NSCharacterSet *nonCompoundSet =
+ NSCharacterSet *nonCompoundSet =
[NSCharacterSet characterSetWithCharactersInString:
[NSString stringWithFormat:@"%C%C%C%C%C%C%C%C%C%C%C%C%C%C%C%C%C%C%C",
- _C_ID, _C_CLASS, _C_SEL, _C_CHR, _C_UCHR,
+ _C_ID, _C_CLASS, _C_SEL, _C_CHR, _C_UCHR,
_C_SHT, _C_USHT, _C_INT, _C_UINT, _C_LNG,
- _C_ULNG, _C_LNGLNG, _C_ULNGLNG, _C_FLT, _C_DBL,
+ _C_ULNG, _C_LNGLNG, _C_ULNGLNG, _C_FLT, _C_DBL,
_C_99BOOL, _C_VOID, _C_UNDEF, _C_CHARPTR]];
-
+
unichar character;
if ([self WOTest_scanCharacterFromSet:nonCompoundSet intoChar:&character])
{
if (stringValue)
- *stringValue = [NSString WOTest_stringWithCharacter:character];
+ *stringValue = [NSString WOTest_stringWithCharacter:character];
return YES;
}
-
+
return NO;
}
- (BOOL)WOTest_scanBitfieldIntoString:(NSString **)stringValue
{
unsigned scanLocation = [self scanLocation];
-
+
unichar marker; // look for bitfield marker
int num; // scan number of bits
if ([self WOTest_scanCharacter:&marker] && (marker == _C_BFLD) && [self scanInt:&num])
*stringValue = [NSString stringWithFormat:@"%C%d", marker, num];
return YES;
}
-
+
[self setScanLocation:scanLocation]; // revert
return NO;
}
- (BOOL)WOTest_scanArrayIntoString:(NSString **)stringValue
{
unsigned scanLocation = [self scanLocation];
-
+
unichar startMarker, endMarker; // look for array start marker
int num; // scan number of elements
NSString *type; // scan type of elements
-
+
if ([self WOTest_scanCharacter:&startMarker] && (startMarker == _C_ARY_B) &&
[self scanInt:&num] && [self WOTest_scanTypeIntoString:&type] &&
[self WOTest_scanCharacter:&endMarker] && (endMarker == _C_ARY_E))
*stringValue = [NSString stringWithFormat:@"%C%d%@%C", startMarker, num, type, endMarker];
return YES;
}
-
-
+
+
[self setScanLocation:scanLocation]; // revert
return NO;
}
- (BOOL)WOTest_scanIdentifierIntoString:(NSString **)stringValue
{
unsigned scanLocation = [self scanLocation];
-
+
unichar firstChar, equalsChar;
if ([self WOTest_peekCharacter:&firstChar])
{
// identifiers must begin with a letter or underscore (no numbers!)
- if (((firstChar >= 'a') && (firstChar <= 'z')) ||
+ if (((firstChar >= 'a') && (firstChar <= 'z')) ||
((firstChar >= 'A') && (firstChar <= 'Z')) ||
(firstChar == '_'))
{
}
}
}
-
+
[self setScanLocation:scanLocation]; // revert
return NO;
}
- (BOOL)WOTest_scanStructIntoString:(NSString **)stringValue
{
unsigned scanLocation = [self scanLocation];
-
+
unichar startMarker, endMarker;
NSString *identifier;
if ([self WOTest_scanCharacter:&startMarker] && (startMarker == _C_STRUCT_B))
if ([self WOTest_scanIdentifierIntoString:&identifier])
{
[self WOTest_scanCharacter:NULL]; // scan past "="
-
+
// prepare identifier for later insertion (append equals sign)
identifier = [NSString stringWithFormat:@"%@=", identifier];
}
else // optional identifier not found
identifier = @"";
-
+
// scan types until you hit end marker
NSMutableString *types = [NSMutableString string];
NSString *type;
[types appendString:type];
[self scanInt:nil]; // skip over any superfluous numbers in string
}
-
+
// scan end marker
if ([self WOTest_scanCharacter:&endMarker] && (endMarker == _C_STRUCT_E))
{
- (BOOL)WOTest_scanUnionIntoString:(NSString **)stringValue
{
unsigned scanLocation = [self scanLocation];
-
+
unichar startMarker, equalsMarker, endMarker;
NSString *identifier;
if ([self WOTest_scanCharacter:&startMarker] && (startMarker == _C_UNION_B))
[types appendString:type];
[self scanInt:nil]; // skip over any superfluous numbers in string
}
-
+
// scan end marker
if ([self WOTest_scanCharacter:&endMarker] && (endMarker == _C_UNION_E))
{
return YES;
}
}
-
+
[self setScanLocation:scanLocation]; // revert
- return NO;
+ return NO;
}
- (BOOL)scanPointerIntoString:(NSString **)stringValue
{
unsigned scanLocation = [self scanLocation];
-
+
unichar marker; // look for pointer marker
NSString *type; // scan type to which pointer points
if ([self WOTest_scanCharacter:&marker] && (marker == _C_PTR) && [self WOTest_scanTypeIntoString:&type])
*stringValue = [NSString stringWithFormat:@"%C%@", marker, type];
return YES;
}
-
+
[self setScanLocation:scanLocation]; // revert
return NO;
}
/*! This function is an alternative to NSLogv that accepts the same kinds of format specifiers (including the "%@" format specifier to print object descriptions) but which omits the prelimary information that is prepended by NSLogv (date, time, process name, process number). Named with a preceding underscore for consistency with the _WOLog function. */
void _WOLogv(NSString *format, va_list args);
-@interface NSString (WOTest)
+@interface NSString (WOTest)
+ (NSString *)WOTest_stringWithFormat:(NSString *)format arguments:(va_list)argList;
{
fprintf(stdout, "%s\n", [string UTF8String]);
fflush(NULL); // flush all open streams (not just stdout)
- [string release];
+ [string release];
}
}
+ (NSString *)WOTest_stringWithFormat:(NSString *)format arguments:(va_list)argList
{
- return [[[NSString alloc] initWithFormat:format
+ return [[[NSString alloc] initWithFormat:format
arguments:argList] autorelease];
}
if ([self isAbsolutePath])
return self;
NSString *path = [[NSFileManager defaultManager] currentDirectoryPath];
-
+
// TODO: strictly speaking, should write a method stringByAppendPathComponents (see draft above)
return [path stringByAppendingPathComponent:self];
}
{
// convert newslines, tabs etc to spaces
[temp replaceCharactersInRange:NSMakeRange(i, 1) withString:@" "];
-
+
// was the last character also a space?
if ((i > 0) && ([temp characterAtIndex:i - 1] == ' '))
{
#ifndef _C_LNGLNG
/*! Type macros missing from objc-class.h at the time of writing; definition taken from docs file:///Developer/ADC%20Reference%20Library/documentation/Cocoa/Conceptual/ObjectiveC/index.html */
-#define _C_LNGLNG 'q'
+#define _C_LNGLNG 'q'
#endif
Objects can be compared to one another for ordering provided that they are of the same class (or at least have a super-subclass relationship) and at least one of the objects implement the compare: method. If neither of these conditions are true then an NSInvalidArgument exception will be raised.
Class objects, method selectors (SEL), void types, character strings (char *), arrays, structs, unions and pointers have no special behaviour implemented in this category. If you try to compare them the standard isEqualTo: NSValue method will be used and testing the ordering will raise an NSInvalidArgument exception. */
-@interface NSValue (WOTest)
+@interface NSValue (WOTest)
#pragma mark -
#pragma mark Value creation methods
+ (BOOL)WOTest_typeIsInt:(NSString *)typeString;
-+ (BOOL)WOTest_typeIsShort:(NSString *)typeString;
++ (BOOL)WOTest_typeIsShort:(NSString *)typeString;
-+ (BOOL)WOTest_typeIsLong:(NSString *)typeString;
++ (BOOL)WOTest_typeIsLong:(NSString *)typeString;
+ (BOOL)WOTest_typeIsLongLong:(NSString *)typeString;
+ (BOOL)WOTest_typeIsUnsignedChar:(NSString *)typeString;
-+ (BOOL)WOTest_typeIsUnsignedInt:(NSString *)typeString;
++ (BOOL)WOTest_typeIsUnsignedInt:(NSString *)typeString;
-+ (BOOL)WOTest_typeIsUnsignedShort:(NSString *)typeString;
++ (BOOL)WOTest_typeIsUnsignedShort:(NSString *)typeString;
-+ (BOOL)WOTest_typeIsUnsignedLong:(NSString *)typeString;
++ (BOOL)WOTest_typeIsUnsignedLong:(NSString *)typeString;
+ (BOOL)WOTest_typeIsUnsignedLongLong:(NSString *)typeString;
-+ (BOOL)WOTest_typeIsFloat:(NSString *)typeString;
++ (BOOL)WOTest_typeIsFloat:(NSString *)typeString;
-+ (BOOL)WOTest_typeIsDouble:(NSString *)typeString;
++ (BOOL)WOTest_typeIsDouble:(NSString *)typeString;
+ (BOOL)WOTest_typeIsC99Bool:(NSString *)typeString;
+ (BOOL)WOTest_typeIsPointerToVoid:(NSString *)typeString;
+ (BOOL)WOTest_typeIsPointer:(NSString *)typeString;
-
+
+ (BOOL)WOTest_typeIsArray:(NSString *)typeString;
+ (BOOL)WOTest_typeIsStruct:(NSString *)typeString;
/*! \endgroup */
-#pragma mark -
+#pragma mark -
#pragma mark High-level test methods
/*!
WO_TEST_EQUAL(25, aString); // raises
\endcode
-In all other cases the default NSValue isEqualToValue: method is used as a fallback.
+In all other cases the default NSValue isEqualToValue: method is used as a fallback.
<table>
<tr>
/*! \endgroup */
-#pragma mark -
+#pragma mark -
#pragma mark Utility methods
//! \name Utility methods
/*! \endgroup */
-#pragma mark -
+#pragma mark -
#pragma mark Low-level test methods
/*!
+ (NSValue *)WOTest_valueWithUnsignedLongLong:(unsigned long long)anUnsignedLongLong
{
- return [NSValue value:&anUnsignedLongLong withObjCType:@encode(unsigned long long)];
+ return [NSValue value:&anUnsignedLongLong withObjCType:@encode(unsigned long long)];
}
+ (NSValue *)WOTest_valueWithFloat:(float)aFloat
+ (NSValue *)WOTest_valueWithConstantCharacterString:(const char *)aConstantCharString
{
- return [NSValue value:&aConstantCharString withObjCType:@encode(const char *)];
+ return [NSValue value:&aConstantCharString withObjCType:@encode(const char *)];
}
+ (NSValue *)WOTest_valueWithCharacterString:(char *)aCharacterString
if ([self WOTest_typeIsBitfield:typeString])
return sizeof(int);
-
+
#if defined (__i386__)
if ([self WOTest_typeIsC99Bool:typeString] ||
// long double 16 bytes
// vector (64 bits) 8 bytes
// vector (128 bits) 16 bytes
- [NSException raise:NSInternalInconsistencyException
+ [NSException raise:NSInternalInconsistencyException
format:@"Type %@ not supported by WOTest_maximumEmbeddedSizeForType:", typeString];
-
+
#elif defined (__ppc__)
-
+
if ([self WOTest_typeIsUnsignedChar:typeString] ||
[self WOTest_typeIsChar:typeString])
size = 1; // scalars of size/alignment 1
// long double 8 bytes (Mac OS X < 10.4, GCC < 4.0)
// long double 16 bytes (Mac OS X >= 10.4, GCC >= 4.0)
// vector 16 bytes
- [NSException raise:NSInternalInconsistencyException
+ [NSException raise:NSInternalInconsistencyException
format:@"Type %@ not supported by WOTest_maximumEmbeddedSizeForType:", typeString];
#elif defined (__ppc64__)
// documented in "Mac OS X ABI Function Call Guide" but not supported:
// long double 16 bytes
// vector 16 bytes
- [NSException raise:NSInternalInconsistencyException
+ [NSException raise:NSInternalInconsistencyException
format:@"Type %@ not supported by WOTest_maximumEmbeddedSizeForType:", typeString];
-
+
#else
-
+
#error Unsupported architecture
#endif
-
+
return size;
}
{
NSParameterAssert(typeString != nil);
size_t size = 0;
-
+
if ([self WOTest_typeIsChar:typeString])
size = sizeof(char);
else if ([self WOTest_typeIsInt:typeString])
size = sizeof(int);
- else if ([self WOTest_typeIsShort:typeString])
+ else if ([self WOTest_typeIsShort:typeString])
size = sizeof(short);
- else if ([self WOTest_typeIsLong:typeString])
+ else if ([self WOTest_typeIsLong:typeString])
size = sizeof(long);
else if ([self WOTest_typeIsLongLong:typeString])
size = sizeof(long long);
else if ([self WOTest_typeIsUnsignedChar:typeString])
size = sizeof(unsigned char);
- else if ([self WOTest_typeIsUnsignedInt:typeString])
+ else if ([self WOTest_typeIsUnsignedInt:typeString])
size = sizeof(unsigned int);
- else if ([self WOTest_typeIsUnsignedShort:typeString])
+ else if ([self WOTest_typeIsUnsignedShort:typeString])
size = sizeof(unsigned short);
- else if ([self WOTest_typeIsUnsignedLong:typeString])
+ else if ([self WOTest_typeIsUnsignedLong:typeString])
size = sizeof(unsigned long);
else if ([self WOTest_typeIsUnsignedLongLong:typeString])
size = sizeof(unsigned long long);
- else if ([self WOTest_typeIsFloat:typeString])
+ else if ([self WOTest_typeIsFloat:typeString])
size = sizeof(float);
- else if ([self WOTest_typeIsDouble:typeString])
+ else if ([self WOTest_typeIsDouble:typeString])
size = sizeof(double);
else if ([self WOTest_typeIsC99Bool:typeString])
size = sizeof(_Bool);
unichar startMarker, endMarker;
int count;
NSString *elementType;
- if ([scanner WOTest_scanCharacter:&startMarker] &&
- (startMarker == _C_ARY_B) && [scanner scanInt:&count] &&
+ if ([scanner WOTest_scanCharacter:&startMarker] &&
+ (startMarker == _C_ARY_B) && [scanner scanInt:&count] &&
[scanner WOTest_scanTypeIntoString:&elementType] &&
[scanner WOTest_scanCharacter:&endMarker] && (endMarker == _C_ARY_E) &&
[scanner isAtEnd])
size = [self WOTest_sizeForType:elementType] * count;
}
else
- [NSException raise:NSInternalInconsistencyException
+ [NSException raise:NSInternalInconsistencyException
format:@"scanner error in sizeForType for type %@", typeString];
}
else if ([self WOTest_typeIsStruct:typeString])
{
NSScanner *scanner = [NSScanner scannerWithString:typeString];
unichar startMarker, endMarker;
-
- if ([scanner WOTest_scanCharacter:&startMarker] &&
+
+ if ([scanner WOTest_scanCharacter:&startMarker] &&
(startMarker == _C_STRUCT_B))
{
// scan optional identifier
- if ([scanner WOTest_scanIdentifierIntoString:nil])
+ if ([scanner WOTest_scanIdentifierIntoString:nil])
[scanner WOTest_scanCharacter:NULL]; // scan past "="
-
+
NSString *memberType;
size_t largestMember = 0;
while ([scanner WOTest_scanTypeIntoString:&memberType])
{
size_t memberSize = [self WOTest_maximumEmbeddedSizeForType:memberType];
largestMember = MAX(largestMember, memberSize);
-
+
if (memberSize != 0) // watch out for division by zero
{
// check for alignment gap
if (modulo != 0) // fill alignment gap
size += (memberSize - modulo);
}
-
+
size += memberSize;
}
-
+
#if defined (__i386__) || defined (__ppc64)
-
+
// Special rules for i386:
// 1. Composite data types (structs/arrays/unions) take on the alignment of the member with the highest alignment
- // 2. Size of composite type is a multiple of its alignment
+ // 2. Size of composite type is a multiple of its alignment
// Special rules for ppc64 (equivalent):
// 1. Embedding alignment of composite types (array/struct) is same as largest embedding align of members.
// 2. Total size of the composite is rounded up to multiple of its embedding alignment.
-
+
// Special rules for ppc: None.
-
+
if (largestMember != 0) // watch out for division by zero
{
// check for alignment gap
if (modulo != 0) // fill alignment gap
size += (largestMember - modulo);
}
-
+
#endif
-
+
if ([scanner WOTest_scanCharacter:&endMarker] && (endMarker == _C_STRUCT_E) && [scanner isAtEnd])
return size; // all done
}
-
+
[NSException raise:NSInternalInconsistencyException format:@"scanner error in sizeForType for type %@", typeString];
}
else if ([self WOTest_typeIsUnion:typeString])
{
NSScanner *scanner = [NSScanner scannerWithString:typeString];
unichar startMarker, endMarker;
-
- if ([scanner WOTest_scanCharacter:&startMarker] && (startMarker == _C_UNION_B))
+
+ if ([scanner WOTest_scanCharacter:&startMarker] && (startMarker == _C_UNION_B))
{
// scan optional identifier
- if ([scanner WOTest_scanIdentifierIntoString:nil])
+ if ([scanner WOTest_scanIdentifierIntoString:nil])
[scanner WOTest_scanCharacter:NULL]; // scan past "="
-
+
NSString *memberType;
while ([scanner WOTest_scanTypeIntoString:&memberType])
// size of union is size of largest type in the union
- size = MAX(size, [self WOTest_maximumEmbeddedSizeForType:memberType]);
-
+ size = MAX(size, [self WOTest_maximumEmbeddedSizeForType:memberType]);
+
if ([scanner WOTest_scanCharacter:&endMarker] && (endMarker == _C_UNION_E) && [scanner isAtEnd])
return size; // all done
}
-
+
[NSException raise:NSInternalInconsistencyException format:@"scanner error in sizeForType for type %@", typeString];
}
else if ([self WOTest_typeIsBitfield:typeString])
else if ([self WOTest_typeIsUnknown:typeString])
{
// could be a function pointer, but could be something else
- [NSException raise:NSInternalInconsistencyException format: @"Cannot calculate buffer size for type %@", typeString];
+ [NSException raise:NSInternalInconsistencyException format: @"Cannot calculate buffer size for type %@", typeString];
}
else // we officially have no idea whatsoever
- [NSException raise:NSInternalInconsistencyException
+ [NSException raise:NSInternalInconsistencyException
format:@"Cannot calculate buffer size for unknown type %@", typeString];
}
-
- return size;
+
+ return size;
}
/*! Returns YES if \p typeString contains a numeric scalar value (char, int, short, long, long long, unsigned char, unsigned int, unsigned short, unsigned long, unsigned long long, float, double, C99 _Bool). Returns NO if the receiver contains any other type, object or pointer (id, Class, SEL, void, char *, as well as arrays, structures and pointers). */
+ (BOOL)WOTest_typeIsNumericScalar:(NSString *)typeString
{
if (!typeString) return NO;
- return ([self WOTest_typeIsChar:typeString] ||
+ return ([self WOTest_typeIsChar:typeString] ||
[self WOTest_typeIsInt:typeString] ||
- [self WOTest_typeIsShort:typeString] ||
+ [self WOTest_typeIsShort:typeString] ||
[self WOTest_typeIsLong:typeString] ||
- [self WOTest_typeIsLongLong:typeString] ||
+ [self WOTest_typeIsLongLong:typeString] ||
[self WOTest_typeIsUnsignedChar:typeString] ||
- [self WOTest_typeIsUnsignedInt:typeString] ||
+ [self WOTest_typeIsUnsignedInt:typeString] ||
[self WOTest_typeIsUnsignedShort:typeString] ||
- [self WOTest_typeIsUnsignedLong:typeString] ||
+ [self WOTest_typeIsUnsignedLong:typeString] ||
[self WOTest_typeIsUnsignedLongLong:typeString] ||
- [self WOTest_typeIsFloat:typeString] ||
+ [self WOTest_typeIsFloat:typeString] ||
[self WOTest_typeIsDouble:typeString] ||
[self WOTest_typeIsC99Bool:typeString]);
}
{
if (!typeString) return NO;
const char *type = [typeString UTF8String];
- return ((strlen(type) == 1) && *type == _C_SHT);
+ return ((strlen(type) == 1) && *type == _C_SHT);
}
+ (BOOL)WOTest_typeIsLong:(NSString *)typeString
{
if (!typeString) return NO;
const char *type = [typeString UTF8String];
- return ((strlen(type) == 1) && *type == _C_LNG);
+ return ((strlen(type) == 1) && *type == _C_LNG);
}
+ (BOOL)WOTest_typeIsLongLong:(NSString *)typeString
{
if (!typeString) return NO;
const char *type = [typeString UTF8String];
- return ((strlen(type) == 1) && *type == _C_ULNGLNG);
+ return ((strlen(type) == 1) && *type == _C_ULNGLNG);
}
+ (BOOL)WOTest_typeIsFloat:(NSString *)typeString
{
if (!typeString) return NO;
const char *type = [typeString UTF8String];
- return ((strlen(type) == 1) && *type == _C_DBL);
+ return ((strlen(type) == 1) && *type == _C_DBL);
}
+ (BOOL)WOTest_typeIsC99Bool:(NSString *)typeString
{
if (!typeString) return NO;
const char *type = [typeString UTF8String];
- return ((strlen(type) == 1) && *type == _C_99BOOL);
+ return ((strlen(type) == 1) && *type == _C_99BOOL);
}
+ (BOOL)WOTest_typeIsVoid:(NSString *)typeString
return ((strlen(type) == 1) && *type == _C_UNDEF);
}
-#pragma mark -
+#pragma mark -
#pragma mark High-level test methods
- (BOOL)WOTest_testIsEqualToValue:(NSValue *)otherValue
return YES;
@try {
- if (selfObject && otherObject && [NSObject WOTest_object:selfObject respondsToSelector:@selector(isEqual:)])
+ if (selfObject && otherObject && [NSObject WOTest_object:selfObject respondsToSelector:@selector(isEqual:)])
return [selfObject isEqual:otherObject];
}
@catch (id e) {
if (strcmp([otherValue objCType], @encode(typeof(nil))) == 0)
{
typeof(nil) nilId = nil;
- NSValue *nilValue = [NSValue valueWithBytes:&nilId objCType:@encode(typeof(nil))];
+ NSValue *nilValue = [NSValue valueWithBytes:&nilId objCType:@encode(typeof(nil))];
if ([otherValue WOTest_compare:nilValue] == NSOrderedSame) // comparing other value (nil) with self object
return ([self nonretainedObjectValue] == nil);
}
-
+
// will raise exception (comparing numeric scalar with object)
return ([self WOTest_compare:otherValue] == NSOrderedSame);
}
{
// check for special case: comparing with nil
typeof(nil) nilId = nil;
- NSValue *nilValue = [NSValue valueWithBytes:&nilId objCType:@encode(typeof(nil))];
- if ((strcmp([self objCType], @encode(typeof(nil))) == 0) && ([self WOTest_compare:nilValue] == NSOrderedSame))
+ NSValue *nilValue = [NSValue valueWithBytes:&nilId objCType:@encode(typeof(nil))];
+ if ((strcmp([self objCType], @encode(typeof(nil))) == 0) && ([self WOTest_compare:nilValue] == NSOrderedSame))
{
// self is nil (or at least looks like nil)
if ([otherValue WOTest_isObject]) // comparing self (nil) with otherObject
else if ([otherValue WOTest_isPointerToVoid]) // special case can compare to pointer to void if zero
return ((id)[otherValue pointerValue] == nil);
}
-
+
// could raise exception (comparing numeric scalar with object)
return ([self WOTest_compare:otherValue] == NSOrderedSame);
}
else if ([otherValue WOTest_isPointerToVoid])
// this special case already necessary on Leopard, otherwise nil-to-nil comparison fails
return ([self pointerValue] == [otherValue pointerValue]);
-
+
// fall through to standard case
return ([self WOTest_compare:otherValue] == NSOrderedSame);
}
- else if (([self WOTest_isCharArray] || [self WOTest_isCharacterString] || [self WOTest_isConstantCharacterString]) &&
- ([otherValue WOTest_isCharArray] || [otherValue WOTest_isCharacterString] ||
+ else if (([self WOTest_isCharArray] || [self WOTest_isCharacterString] || [self WOTest_isConstantCharacterString]) &&
+ ([otherValue WOTest_isCharArray] || [otherValue WOTest_isCharacterString] ||
[otherValue WOTest_isConstantCharacterString]))
{
// another special case
{
if (!aValue)
[NSException raise:NSInvalidArgumentException format:@"cannot compare to nil"];
-
+
// object case
if ([self WOTest_isObject])
{
if (![aValue WOTest_isObject])
[NSException raise:NSInvalidArgumentException format:@"cannot compare object with non-object"];
-
+
id selfObject = [self nonretainedObjectValue];
id otherObject = [aValue nonretainedObjectValue];
-
+
if ([selfObject isKindOfClass:[otherObject class]] && [selfObject respondsToSelector:@selector(compare:)])
- return ((NSComparisonResult (*)(id, SEL, id))objc_msgSend)(selfObject, @selector(compare:), otherObject);
+ return ((NSComparisonResult (*)(id, SEL, id))objc_msgSend)(selfObject, @selector(compare:), otherObject);
else if ([otherObject isKindOfClass:[selfObject class]] && [otherObject respondsToSelector:@selector(compare:)])
return ((NSComparisonResult (*)(id, SEL, id))objc_msgSend)(otherObject, @selector(compare:), selfObject);
-
+
[NSException raise:NSInvalidArgumentException format:@"compared objects must be of same class and implement compare:"];
}
-
+
// numeric scalar case
if ([self WOTest_isNumericScalar] && [aValue WOTest_isNumericScalar])
{
else if ([aValue WOTest_isC99Bool])
return [self WOTest_compareWithC99Bool:[aValue WOTest_C99BoolValue]];
}
-
+
[NSException raise:NSInvalidArgumentException format:@"non-numeric value(s) passed"];
// never reached, but necessary to suppress compiler warning
- return NSOrderedSame;
+ return NSOrderedSame;
}
-#pragma mark -
+#pragma mark -
#pragma mark Utility methods
- (size_t)WOTest_bufferSize
- (void)WOTest_printSignCompareWarning:(NSString *)warning
{
NSParameterAssert(warning != nil);
-
+
// this conditional in here so that the warnings can be turned off in WOTest self-testing
if ([[WOTest sharedInstance] warnsAboutSignComparisons])
{
if ([NSObject WOTest_object:valueContents isKindOfClass:[NSString class]])
return [[valueContents retain] autorelease];
else if ([NSObject WOTest_object:valueContents respondsToSelector:@selector(description)] &&
- [NSObject WOTest_isIdReturnType:[NSObject WOTest_returnTypeForObject:valueContents
+ [NSObject WOTest_isIdReturnType:[NSObject WOTest_returnTypeForObject:valueContents
selector:@selector(description)]])
{
NSString *description = objc_msgSend(valueContents, @selector(description));
else if ([self WOTest_isSelector])
return [NSString stringWithFormat:@"(SEL)%@", NSStringFromSelector([self WOTest_selectorValue])];
else if ([self WOTest_isPointerToVoid])
- return [NSString stringWithFormat:@"(void *)%#08x", [self WOTest_pointerToVoidValue]];
+ return [NSString stringWithFormat:@"(void *)%#08x", [self WOTest_pointerToVoidValue]];
return [self description]; // fallback case
}
- (unsigned)WOTest_arrayCount
{
- NSAssert([self WOTest_isArray],
+ NSAssert([self WOTest_isArray],
@"WOTest_arrayCount sent but receiver does not contain an array");
NSScanner *scanner = [NSScanner scannerWithString:[self WOTest_objCTypeString]];
unichar startMarker;
int count = 0;
-
+
// attempt the scan: it should work
- if (!([scanner WOTest_scanCharacter:&startMarker] && (startMarker == _C_ARY_B) && [scanner scanInt:&count]))
+ if (!([scanner WOTest_scanCharacter:&startMarker] && (startMarker == _C_ARY_B) && [scanner scanInt:&count]))
[NSException raise:NSInternalInconsistencyException format:@"scanner error in WOTest_arrayCount"];
return (unsigned)count;
- (NSString *)WOTest_arrayType
{
- NSAssert([self WOTest_isArray], @"WOTest_arrayType sent but receiver does not contain an array");
+ NSAssert([self WOTest_isArray], @"WOTest_arrayType sent but receiver does not contain an array");
NSScanner *scanner = [NSScanner scannerWithString:[self WOTest_objCTypeString]];
[scanner setScanLocation:1];
NSString *typeString;
if (!([scanner scanInt:nil] && [scanner WOTest_scanTypeIntoString:&typeString]))
- [NSException raise:NSInternalInconsistencyException format:@"scanner error in WOTest_arrayType"];
+ [NSException raise:NSInternalInconsistencyException format:@"scanner error in WOTest_arrayType"];
return typeString;
}
unichar startMarker, flag, endMarker;
int count;
return ([scanner WOTest_scanCharacter:&startMarker] && (startMarker == _C_ARY_B) &&
- [scanner scanInt:&count] &&
- [scanner WOTest_scanCharacter:&flag] && (flag == _C_CHR) &&
+ [scanner scanInt:&count] &&
+ [scanner WOTest_scanCharacter:&flag] && (flag == _C_CHR) &&
[scanner WOTest_scanCharacter:&endMarker] && (endMarker == _C_ARY_E) &&
[scanner isAtEnd]);
}
{
@try {
if ([self WOTest_isCharacterString] || [self WOTest_isConstantCharacterString])
- return [NSString stringWithUTF8String:(const char *)[self pointerValue]];
+ return [NSString stringWithUTF8String:(const char *)[self pointerValue]];
else // see if this is a char array
{
- NSScanner *scanner = [NSScanner scannerWithString:[self WOTest_objCTypeString]];
+ NSScanner *scanner = [NSScanner scannerWithString:[self WOTest_objCTypeString]];
unichar startMarker, flag, endMarker;
int count;
- if ([scanner WOTest_scanCharacter:&startMarker] &&
- (startMarker == _C_ARY_B) && [scanner scanInt:&count] &&
- [scanner WOTest_scanCharacter:&flag] && (flag == _C_CHR) &&
+ if ([scanner WOTest_scanCharacter:&startMarker] &&
+ (startMarker == _C_ARY_B) && [scanner scanInt:&count] &&
+ [scanner WOTest_scanCharacter:&flag] && (flag == _C_CHR) &&
[scanner WOTest_scanCharacter:&endMarker] && (endMarker == _C_ARY_E) &&
[scanner isAtEnd])
{
if (count > 0)
{
char *buffer = malloc(count * sizeof(char));
- NSAssert1(buffer != NULL, @"malloc() failed (size %d)",
+ NSAssert1(buffer != NULL, @"malloc() failed (size %d)",
(count * sizeof(char)));
[self getValue:buffer];
-
+
// confirm that this is a null-terminated string
for (int i = 0; i < count; i++)
{
@catch (id e) {
// fall through
}
- return nil;
+ return nil;
}
-#pragma mark -
+#pragma mark -
#pragma mark Low-level test methods
/* Unfortunately there is a lot of very similar code repeated across these methods but it seems to be a necessary evil (600 lines of necessary evil). Firstly, it's necessary to explicitly declare the type of the right-hand value of the comparison. There are lots of permuations for implicit casts, explicit casts (and warnings), and GCC seems to warn about signed to unsigned comparisons differently depending on the types. */
else if ([self WOTest_isUnsignedInt])
{
[self WOTest_printSignCompareWarning:@"comparison between signed and unsigned, to avoid this warning use an explicit cast"];
- return WO_COMPARE_SCALARS([self WOTest_unsignedIntValue], (unsigned char)other); // explicit cast
+ return WO_COMPARE_SCALARS([self WOTest_unsignedIntValue], (unsigned char)other); // explicit cast
}
else if ([self WOTest_isUnsignedShort])
return WO_COMPARE_SCALARS([self WOTest_unsignedShortValue], other); // implicit cast
return WO_COMPARE_SCALARS([self WOTest_doubleValue], other); // implicit cast
else if ([self WOTest_isC99Bool])
return WO_COMPARE_SCALARS([self WOTest_C99BoolValue], other); // implicit cast
-
+
// all other cases
- [NSException raise:NSInvalidArgumentException
+ [NSException raise:NSInvalidArgumentException
format:@"cannot compare type \"%s\" with type \"%s\"", [self objCType], @encode(typeof(other))];
-
+
return NSOrderedSame; // never reached, but necessary to suppress compiler warning
}
return WO_COMPARE_SCALARS([self WOTest_doubleValue], other); // implicit cast
else if ([self WOTest_isC99Bool])
return WO_COMPARE_SCALARS([self WOTest_C99BoolValue], other); // implicit cast
-
+
// all other cases
- [NSException raise:NSInvalidArgumentException
+ [NSException raise:NSInvalidArgumentException
format:@"cannot compare type \"%s\" with type \"%s\"", [self objCType], @encode(typeof(other))];
-
+
return NSOrderedSame; // never reached, but necessary to suppress compiler warning
}
return WO_COMPARE_SCALARS([self WOTest_C99BoolValue], other); // implicit cast
// all other cases
- [NSException raise:NSInvalidArgumentException
+ [NSException raise:NSInvalidArgumentException
format:@"cannot compare type \"%s\" with type \"%s\"", [self objCType], @encode(typeof(other))];
-
+
return NSOrderedSame; // never reached, but necessary to suppress compiler warning
}
else if ([self WOTest_isUnsignedInt])
{
[self WOTest_printSignCompareWarning:@"comparison between signed and unsigned, to avoid this warning use an explicit cast"];
- return WO_COMPARE_SCALARS([self WOTest_unsignedIntValue], (unsigned long)other); // explicit cast
+ return WO_COMPARE_SCALARS([self WOTest_unsignedIntValue], (unsigned long)other); // explicit cast
}
else if ([self WOTest_isUnsignedShort])
return WO_COMPARE_SCALARS([self WOTest_unsignedShortValue], other); // implicit cast
return WO_COMPARE_SCALARS([self WOTest_doubleValue], other); // implicit cast
else if ([self WOTest_isC99Bool])
return WO_COMPARE_SCALARS([self WOTest_C99BoolValue], other); // implicit cast
-
+
// all other cases
- [NSException raise:NSInvalidArgumentException
+ [NSException raise:NSInvalidArgumentException
format:@"cannot compare type \"%s\" with type \"%s\"", [self objCType], @encode(typeof(other))];
-
+
return NSOrderedSame; // never reached, but necessary to suppress compiler warning
}
return WO_COMPARE_SCALARS([self WOTest_doubleValue], other); // implicit cast
else if ([self WOTest_isC99Bool])
return WO_COMPARE_SCALARS([self WOTest_C99BoolValue], other); // implicit cast
-
+
// all other cases
- [NSException raise:NSInvalidArgumentException
+ [NSException raise:NSInvalidArgumentException
format:@"cannot compare type \"%s\" with type \"%s\"", [self objCType], @encode(typeof(other))];
-
+
return NSOrderedSame; // never reached, but necessary to suppress compiler warning
}
return WO_COMPARE_SCALARS([self WOTest_doubleValue], other); // implicit cast
else if ([self WOTest_isC99Bool])
return WO_COMPARE_SCALARS([self WOTest_C99BoolValue], other); // implicit cast
-
+
// all other cases
- [NSException raise:NSInvalidArgumentException
+ [NSException raise:NSInvalidArgumentException
format:@"cannot compare type \"%s\" with type \"%s\"", [self objCType], @encode(typeof(other))];
-
+
return NSOrderedSame; // never reached, but necessary to suppress compiler warning
}
return WO_COMPARE_SCALARS([self WOTest_doubleValue], other); // implicit cast
else if ([self WOTest_isC99Bool])
return WO_COMPARE_SCALARS([self WOTest_C99BoolValue], other); // implicit cast
-
+
// all other cases
- [NSException raise:NSInvalidArgumentException
+ [NSException raise:NSInvalidArgumentException
format:@"cannot compare type \"%s\" with type \"%s\"", [self objCType], @encode(typeof(other))];
-
+
return NSOrderedSame; // never reached, but necessary to suppress compiler warning
}
return WO_COMPARE_SCALARS([self WOTest_C99BoolValue], other); // implicit cast
// all other cases
- [NSException raise:NSInvalidArgumentException
+ [NSException raise:NSInvalidArgumentException
format:@"cannot compare type \"%s\" with type \"%s\"", [self objCType], @encode(typeof(other))];
-
+
return NSOrderedSame; // never reached, but necessary to suppress compiler warning
}
return WO_COMPARE_SCALARS([self WOTest_C99BoolValue], other); // implicit cast
// all other cases
- [NSException raise:NSInvalidArgumentException
+ [NSException raise:NSInvalidArgumentException
format:@"cannot compare type \"%s\" with type \"%s\"", [self objCType], @encode(typeof(other))];
-
+
return NSOrderedSame; // never reached, but necessary to suppress compiler warning
}
if ([self WOTest_isChar]) // (also BOOL)
{
[self WOTest_printSignCompareWarning:@"comparison between signed and unsigned, to avoid this warning use an explicit cast"];
- return WO_COMPARE_SCALARS((unsigned char)[self WOTest_charValue], other); // explicit cast
+ return WO_COMPARE_SCALARS((unsigned char)[self WOTest_charValue], other); // explicit cast
}
else if ([self WOTest_isInt])
{
return WO_COMPARE_SCALARS([self WOTest_doubleValue], other); // implicit cast
else if ([self WOTest_isC99Bool])
return WO_COMPARE_SCALARS([self WOTest_C99BoolValue], other); // implicit cast
-
+
// all other cases
- [NSException raise:NSInvalidArgumentException
+ [NSException raise:NSInvalidArgumentException
format:@"cannot compare type \"%s\" with type \"%s\"", [self objCType], @encode(typeof(other))];
-
+
return NSOrderedSame; // never reached, but necessary to suppress compiler warning
}
return WO_COMPARE_SCALARS([self WOTest_C99BoolValue], other); // implicit cast
// all other cases
- [NSException raise:NSInvalidArgumentException
+ [NSException raise:NSInvalidArgumentException
format:@"cannot compare type \"%s\" with type \"%s\"", [self objCType], @encode(typeof(other))];
-
+
return NSOrderedSame; // never reached, but necessary to suppress compiler warning
}
return WO_COMPARE_SCALARS([self WOTest_C99BoolValue], other); // implicit cast
// all other cases
- [NSException raise:NSInvalidArgumentException
+ [NSException raise:NSInvalidArgumentException
format:@"cannot compare type \"%s\" with type \"%s\"", [self objCType], @encode(typeof(other))];
-
+
return NSOrderedSame; // never reached, but necessary to suppress compiler warning
}
return WO_COMPARE_SCALARS([self WOTest_doubleValue], other); // implicit cast
else if ([self WOTest_isC99Bool])
return WO_COMPARE_SCALARS([self WOTest_C99BoolValue], other); // no cast
-
+
// all other cases
- [NSException raise:NSInvalidArgumentException
+ [NSException raise:NSInvalidArgumentException
format:@"cannot compare type \"%s\" with type \"%s\"", [self objCType], @encode(typeof(other))];
-
+
return NSOrderedSame; // never reached, but necessary to suppress compiler warning
}
Consider:
[mock expectSelector:@selector(substringFromIndex:)
- return:@"foo"
+ return:@"foo"
arguments:3];
Regressions:
-- write WOMultithreadedCrash class for WOTest (regression test for multithreaded low level exception handling failure); for now just
+- write WOMultithreadedCrash class for WOTest (regression test for multithreaded low level exception handling failure); for now just
WO_TEST_FAIL
-- also write WOLocaleFormatterCrash class (copy and refactor WOLocaleFormatter class and tests so that the WOCommon crash problem
+- also write WOLocaleFormatterCrash class (copy and refactor WOLocaleFormatter class and tests so that the WOCommon crash problem
can be manifested in the WOTest tests); again, for now will just be WO_TEST_FAIL
- for Leopard: use RubyCocoa bridge for writing specs in Ruby
\ No newline at end of file
{
// description for nil should be "(nil)"
WO_TEST_EQ([NSObject WOTest_descriptionForObject:nil], @"(nil)");
-
+
// NSString objects should be returned as-is
WO_TEST_EQ([NSObject WOTest_descriptionForObject:@"foo"], @"foo");
-
+
// NSNumber is a special case:
// when an NSValue is initialized with an int NSNumber, the NSValue behaves as though it were initialized with an int
NSNumber *number = [NSNumber numberWithInt:1];
WO_TEST_EQ([NSObject WOTest_descriptionForObject:number], @"(int)1");
-
+
// other objects should return "description"
NSButton *button = [[NSButton alloc] init];
WO_TEST_EQ([NSObject WOTest_descriptionForObject:button], [button description]);
-
- // custom classes that do not respond to "description" return class name
+
+ // custom classes that do not respond to "description" return class name
WOLightweightRoot *root = [WOLightweightRoot newLightweightRoot];
WO_TEST_EQ([NSObject WOTest_descriptionForObject:root], @"WOLightweightRoot");
[root dealloc];
-
+
// special case: NSValues that contain NSStrings should return the string
NSValue *value = [NSValue WOTest_valueWithObject:@"foo"];
WO_TEST_EQ([NSObject WOTest_descriptionForObject:value], @"foo");
-
+
// standard case: other NSValues should return "description"
NSRange range;
range.location = 0; // can't use NSMakeRange (Intel release warnings)
range.length = 0;
value = [NSValue valueWithRange:range];
WO_TEST_EQ([NSObject WOTest_descriptionForObject:value], [value WOTest_description]);
-
+
// pointers to void should be formatted as "(void *)<00000000 >", as returned by WOTest_description
value = [NSValue valueWithNonretainedObject:@"bar"];
WO_TEST_EQ([NSObject WOTest_descriptionForObject:value], [value WOTest_description]);
id object = @"foo";
id subobject = [NSMutableString stringWithString:@"bar"];
id otherObject = [WOLightweightRoot newLightweightRoot];
-
+
// should raise if passed a non-class pointer
WO_TEST_THROWS([NSObject WOTest_object:self isKindOfClass:(Class)self]);
WO_TEST_DOES_NOT_THROW([NSObject WOTest_object:self isKindOfClass:[self class]]);
-
+
// nil object or NULL class should always return NO
WO_TEST_FALSE([NSObject WOTest_object:nil isKindOfClass:NULL]);
WO_TEST_FALSE([NSObject WOTest_object:self isKindOfClass:NULL]);
WO_TEST_FALSE([NSObject WOTest_object:nil isKindOfClass:[self class]]);
-
+
// basic test cases
WO_TEST([NSObject WOTest_object:object isKindOfClass:[NSString class]]);
- WO_TEST_FALSE([NSObject WOTest_object:object isKindOfClass:[NSNumber class]]);
-
+ WO_TEST_FALSE([NSObject WOTest_object:object isKindOfClass:[NSNumber class]]);
+
// subclass should be considered of same kind as superclass
WO_TEST([NSObject WOTest_object:subobject isKindOfClass:[NSString class]]);
-
+
// superclass should not be considered as same kind as subclass
WO_TEST_FALSE([NSObject WOTest_object:[[[NSObject alloc] init] autorelease]
isKindOfClass:[self class]]);
-
+
// initial attempt at this test failed because the NSString object had a
// superclass of "%NSCFString", which happened to match NSMutableString!
//WO_TEST_FALSE([NSObject WOTest_object:object
// isKindOfClass:[NSMutableString class]]);
// note that the Cocoa isKindOfClass: method also produces this behaviour:
//WO_TEST_FALSE([@"constant string" isKindOfClass:[NSMutableString class]]);
-
+
// should handle custom root classes without problems
- WO_TEST([NSObject WOTest_object:otherObject
+ WO_TEST([NSObject WOTest_object:otherObject
isKindOfClass:NSClassFromString(@"WOLightweightRoot")]);
WO_TEST_FALSE([NSObject WOTest_object:otherObject isKindOfClass:[NSString class]]);
- WO_TEST_FALSE([NSObject WOTest_object:self
+ WO_TEST_FALSE([NSObject WOTest_object:self
isKindOfClass:NSClassFromString(@"WOLightweightRoot")]);
-
+
// cleanup
[otherObject dealloc];
}
Class class = [NSString class];
Class subclass = [NSMutableString class];
Class otherClass = NSClassFromString(@"WOLightweightRoot");
-
+
// should raise if passed non-class pointers
WO_TEST_THROWS([NSObject WOTest_instancesOfClass:(Class)self areKindOfClass:(Class)self]);
WO_TEST_THROWS([NSObject WOTest_instancesOfClass:(Class)self areKindOfClass:[NSString class]]);
WO_TEST_THROWS([NSObject WOTest_instancesOfClass:[NSString class] areKindOfClass:(Class)self]);
WO_TEST_DOES_NOT_THROW([NSObject WOTest_instancesOfClass:[self class] areKindOfClass:[NSString class]]);
-
+
// if either class is NULL should always return NO
WO_TEST_FALSE([NSObject WOTest_instancesOfClass:NULL areKindOfClass:NULL]);
WO_TEST_FALSE([NSObject WOTest_instancesOfClass:[self class] areKindOfClass:NULL]);
WO_TEST_FALSE([NSObject WOTest_instancesOfClass:NULL areKindOfClass:[self class]]);
-
+
// basic tests
WO_TEST([NSObject WOTest_instancesOfClass:[NSString class] areKindOfClass:[NSString class]]);
WO_TEST_FALSE([NSObject WOTest_instancesOfClass:[NSString class] areKindOfClass:[NSNumber class]]);
-
+
// a subclass should be considered of same kind as superclass
WO_TEST([NSObject WOTest_instancesOfClass:subclass areKindOfClass:class]);
-
+
// a superclass should not be considered as same kind as subclass
WO_TEST_FALSE([NSObject WOTest_instancesOfClass:class areKindOfClass:subclass]);
-
+
// should handle custom root classes without problems
WO_TEST([NSObject WOTest_instancesOfClass:otherClass areKindOfClass:otherClass]);
WO_TEST_FALSE([NSObject WOTest_instancesOfClass:class areKindOfClass:otherClass]);
id object = @"foobar";
id subobject = [NSMutableString stringWithString:object];
id root = [WOLightweightRoot newLightweightRoot];
-
+
// test returns NO for nil object or NULL selector
WO_TEST_FALSE([NSObject WOTest_object:nil respondsToSelector:NULL]);
WO_TEST_FALSE([NSObject WOTest_object:nil respondsToSelector:@selector(length)]);
WO_TEST_FALSE([NSObject WOTest_object:self respondsToSelector:NULL]);
-
+
// basic tests
- WO_TEST([NSObject WOTest_object:self
+ WO_TEST([NSObject WOTest_object:self
respondsToSelector:@selector(testObjectRespondsToSelector)]);
WO_TEST_FALSE([NSObject WOTest_object:self respondsToSelector:@selector(foo)]);
-
+
// should work for subclasses
WO_TEST([NSObject WOTest_object:object respondsToSelector:@selector(length)]);
WO_TEST([NSObject WOTest_object:subobject respondsToSelector:@selector(length)]);
WO_TEST_FALSE([NSObject WOTest_object:object respondsToSelector:@selector(bar)]);
- WO_TEST_FALSE([NSObject WOTest_object:subobject
+ WO_TEST_FALSE([NSObject WOTest_object:subobject
respondsToSelector:@selector(bar)]);
-
+
// should handle custom root classes without problems
WO_TEST([NSObject WOTest_object:root respondsToSelector:@selector(dealloc)]);
WO_TEST_FALSE([NSObject WOTest_object:root respondsToSelector:@selector(foobar)]);
-
+
// cleanup
[root dealloc];
}
// should raise if passed non-class pointer
WO_TEST_THROWS([NSObject WOTest_class:(Class)self respondsToSelector:@selector(init)]);
WO_TEST_DOES_NOT_THROW([NSObject WOTest_class:[self class] respondsToSelector:@selector(init)]);
-
+
// test that NULL class or NULL selector return NO
WO_TEST_FALSE([NSObject WOTest_class:NULL respondsToSelector:NULL]);
WO_TEST_FALSE([NSObject WOTest_class:NULL respondsToSelector:@selector(init)]);
WO_TEST_FALSE([NSObject WOTest_class:[self class] respondsToSelector:NULL]);
-
+
// basic tests
WO_TEST([NSObject WOTest_class:[self class] respondsToSelector:@selector(initialize)]);
WO_TEST_FALSE([NSObject WOTest_class:[self class] respondsToSelector:@selector(unimplimentedClassMethod)]);
{
// should raise if passed non-class pointer
WO_TEST_THROWS([NSObject WOTest_instancesOfClass:(Class)self respondToSelector:@selector(init)]);
- WO_TEST_DOES_NOT_THROW([NSObject WOTest_instancesOfClass:[self class] respondToSelector:@selector(init)]);
-
+ WO_TEST_DOES_NOT_THROW([NSObject WOTest_instancesOfClass:[self class] respondToSelector:@selector(init)]);
+
// test that NULL class or NULL selector return NO
WO_TEST_FALSE([NSObject WOTest_instancesOfClass:NULL respondToSelector:NULL]);
WO_TEST_FALSE([NSObject WOTest_instancesOfClass:NULL respondToSelector:@selector(length)]);
WO_TEST_FALSE([NSObject WOTest_instancesOfClass:[self class] respondToSelector:NULL]);
-
+
// basic tests
WO_TEST([NSObject WOTest_instancesOfClass:[NSString class] respondToSelector:@selector(length)]);
WO_TEST_FALSE([NSObject WOTest_instancesOfClass:[NSString class] respondToSelector:@selector(longitude)]);
-
+
// subclasses should work as well
WO_TEST([NSObject WOTest_instancesOfClass:[NSMutableString class] respondToSelector:@selector(length)]);
WO_TEST_FALSE([NSObject WOTest_instancesOfClass:[NSMutableString class] respondToSelector:@selector(longitude)]);
-
+
// should work with custom root classes
WO_TEST([NSObject WOTest_instancesOfClass:NSClassFromString(@"WOLightweightRoot") respondToSelector:@selector(forward::)]);
WO_TEST([NSObject WOTest_instancesOfClass:NSClassFromString(@"WOLightweightRoot") respondToSelector:@selector(dealloc)]);
// should throw if passed non-class pointer
WO_TEST_THROWS([NSObject WOTest_instancesOfClass:(Class)self conformToProtocol:@protocol(NSLocking)]);
WO_TEST_DOES_NOT_THROW([NSObject WOTest_instancesOfClass:[self class] conformToProtocol:@protocol(NSObject)]);
-
+
// test that NULL class or NULL protocol return NO
WO_TEST_FALSE([NSObject WOTest_instancesOfClass:NULL conformToProtocol:NULL]);
WO_TEST_FALSE([NSObject WOTest_instancesOfClass:[self class] conformToProtocol:NULL]);
WO_TEST_FALSE([NSObject WOTest_instancesOfClass:NULL conformToProtocol:@protocol(WOTest)]);
-
+
// basic tests
WO_TEST([NSObject WOTest_instancesOfClass:[NSLock class] conformToProtocol:@protocol(NSLocking)]);
WO_TEST_FALSE([NSObject WOTest_instancesOfClass:[NSString class] conformToProtocol:@protocol(NSLocking)]);
WO_TEST([NSObject WOTest_instancesOfClass:[self class] conformToProtocol:@protocol(WOTest)]);
WO_TEST_FALSE([NSObject WOTest_instancesOfClass:[self class] conformToProtocol:@protocol(NSTextAttachmentCell)]);
-
+
// test with subclasses (subclasses should inherit protocol conformance)
WO_TEST([NSObject WOTest_instancesOfClass:[NSMutableString class] conformToProtocol:@protocol(NSCopying)]);
-
+
// should handle custom root classes
WO_TEST_FALSE
([NSObject WOTest_instancesOfClass:NSClassFromString(@"WOLightweightRoot") conformToProtocol:@protocol(NSLocking)]);
WO_TEST_THROWS([NSObject WOTest_returnTypeForClass:NULL selector:NULL]);
WO_TEST_THROWS([NSObject WOTest_returnTypeForClass:NULL selector:@selector(init)]);
WO_TEST_THROWS([NSObject WOTest_returnTypeForClass:[self class] selector:NULL]);
-
+
// raises if passed non-class pointer
WO_TEST_THROWS([NSObject WOTest_returnTypeForClass:(Class)self selector:@selector(init)]);
-
+
// basic test
WO_TEST_EQ([NSObject WOTest_returnTypeForClass:[self class] selector:@selector(initialize)], @"v");
-
+
// returns nil for unrecognized selector
WO_TEST_EQ([NSObject WOTest_returnTypeForClass:[self class] selector:@selector(poodle)], nil);
}
WO_TEST_THROWS([NSObject WOTest_returnTypeForObject:nil selector:NULL]);
WO_TEST_THROWS([NSObject WOTest_returnTypeForObject:self selector:NULL]);
WO_TEST_THROWS([NSObject WOTest_returnTypeForObject:nil selector:@selector(init)]);
-
+
// basic test
WO_TEST_EQ([NSObject WOTest_returnTypeForObject:self selector:@selector(init)], @"@");
-
+
// returns nil for unrecognized selector
WO_TEST_EQ([NSObject WOTest_returnTypeForObject:self selector:@selector(beagle:dog:)], nil);
}
{
WO_TEST([NSObject WOTest_isConstantCharacterStringReturnType:@"r*"]);
WO_TEST_FALSE([NSObject WOTest_isConstantCharacterStringReturnType:@"^v"]);
-
+
// passing nil should return NO, not raise an exception
WO_TEST_FALSE([NSObject WOTest_isConstantCharacterStringReturnType:nil]);
}
WO_TEST_THROWS([NSObject WOTest_objectReturnsId:nil forSelector:NULL]);
WO_TEST_THROWS([NSObject WOTest_objectReturnsId:self forSelector:NULL]);
WO_TEST_THROWS([NSObject WOTest_objectReturnsId:nil forSelector:@selector(init)]);
-
+
// basic tests
WO_TEST([NSObject WOTest_objectReturnsId:self forSelector:@selector(init)]);
WO_TEST_FALSE([NSObject WOTest_objectReturnsId:self forSelector:@selector(dealloc)]);
-
+
// passing unrecognized selector should return NO, not raise an exception
WO_TEST_FALSE([NSObject WOTest_objectReturnsId:self forSelector:@selector(initWithChicken:)]);
}
WO_TEST_THROWS([NSObject WOTest_objectReturnsCharacterString:nil forSelector:NULL]);
WO_TEST_THROWS([NSObject WOTest_objectReturnsCharacterString:self forSelector:NULL]);
WO_TEST_THROWS([NSObject WOTest_objectReturnsCharacterString:nil forSelector:@selector(init)]);
-
+
// basic tests
- char *string = "foo";
+ char *string = "foo";
NSValue *value = [NSValue WOTest_valueWithCharacterString:string];
WO_TEST([NSObject WOTest_objectReturnsCharacterString:value forSelector:@selector(WOTest_characterStringValue)]);
WO_TEST_FALSE([NSObject WOTest_objectReturnsCharacterString:self forSelector:@selector(init)]);
-
+
// passing unrecognized selector should return NO, not raise an exception
WO_TEST_FALSE([NSObject WOTest_objectReturnsCharacterString:self forSelector:@selector(initWithChicken:)]);
}
WO_TEST_THROWS([NSObject WOTest_objectReturnsConstantCharacterString:nil forSelector:NULL]);
WO_TEST_THROWS([NSObject WOTest_objectReturnsConstantCharacterString:self forSelector:NULL]);
WO_TEST_THROWS([NSObject WOTest_objectReturnsConstantCharacterString:nil forSelector:@selector(init)]);
-
+
// basic tests
NSValue *value = [NSValue WOTest_valueWithConstantCharacterString:"foobar"];
SEL selector = @selector(WOTest_constantCharacterStringValue);
WO_TEST([NSObject WOTest_objectReturnsConstantCharacterString:value forSelector:selector]);
WO_TEST_FALSE([NSObject WOTest_objectReturnsConstantCharacterString:self forSelector:@selector(init)]);
-
+
// passing unrecognized selector should return NO, not raise an exception
WO_TEST_FALSE([NSObject WOTest_objectReturnsConstantCharacterString:self forSelector:@selector(getTurkey)]);
}
NSString *string = @"foobar";
NSScanner *scanner = [NSScanner scannerWithString:string];
unichar character;
-
+
WO_TEST_THROWS([scanner WOTest_peekCharacter:NULL]); // test response to NULL
[scanner setScanLocation:0]; // move to start
WO_TEST([scanner WOTest_peekCharacter:&character]); // scans
NSString *string = @"foobar";
NSScanner *scanner = [NSScanner scannerWithString:string];
unichar character = 0;
-
+
WO_TEST_DOES_NOT_THROW([scanner WOTest_scanCharacter:NULL]); // test with NULL
[scanner setScanLocation:0]; // move to start
WO_TEST_TRUE([scanner WOTest_scanCharacter:&character]); // scans
- (void)testScanReturnTypeIntoString
{
// handles nil correctly
-
+
// return types must be at beginning of string
}
- (void)testScanTypeIntoString
{
// handles nil correctly
-
-
-
+
+
+
}
- (void)testScanQualifiersIntoString
{
// handles nil correctly
-
+
}
- (void)testScanNonCompoundTypeIntoString
{
// test handles nil correctly
-
+
}
- (void)testScanBitfieldIntoString
{
// test handles nil correctly
-
+
}
- (void)testScanArrayIntoString
{
// test handles nil correctly
-
+
}
- (void)testScanIdentifierIntoString
{
// test handles nil correctly
-
+
}
- (void)testScanStructIntoString
{
// test handles nil correctly
-
+
}
- (void)testScanUnionIntoString
{
// test handles nil correctly
-
+
}
- (void)testScanPointerIntoString
NSString *string = @"^i";
NSScanner *scanner = [NSScanner scannerWithString:string];
NSString *result = nil;
-
+
// test handles nil correctly
WO_TEST_TRUE([scanner scanPointerIntoString:nil]);
-
+
// test scanning a pointer to something
[scanner setScanLocation:0];
WO_TEST_TRUE([scanner scanPointerIntoString:&result]);
WO_TEST_EQUAL(string, result);
-
+
// test scanning a pointer to a pointer to something
string = @"^^{WOStruct=fi@}";
scanner = [NSScanner scannerWithString:string];
result = nil;
WO_TEST_TRUE([scanner scanPointerIntoString:&result]);
WO_TEST_EQUAL(string, result);
-
+
// test against a non-pointer
string = @"{WOStruct=^fi@}";
scanner = [NSScanner scannerWithString:string];
(@"{_NSRect={_NSPoint=ff}{_NSSize=ff}}"
@"28@0:4{_NSRect={_NSPoint=ff}{_NSSize=ff}}8I24")];
NSScanner *scanner9 = [NSScanner scannerWithString:@"@12@0:4@8"];
-
+
// WOTest_peekCharacter: and WOTest_scanCharacter:
unichar character;
[scanner1 WOTest_scanCharacter:&character];
- WO_TEST_EQUAL(character, '@');
+ WO_TEST_EQUAL(character, '@');
WO_TEST_EQUAL([scanner1 scanLocation], (unsigned)1); // should advance
[scanner1 WOTest_peekCharacter:&character];
WO_TEST_EQUAL(character, '8');
WO_TEST_FALSE([scanner1 WOTest_peekCharacter:&character]); // atEnd
WO_TEST_FALSE([scanner1 WOTest_scanCharacter:&character]); // atEnd
[scanner1 setScanLocation:0]; // reset
-
+
// using higher level scanning methods to parse: @8@0:4
NSString *type;
WO_TEST_TRUE([scanner1 WOTest_scanNonCompoundTypeIntoString:&type]);
WO_TEST_FALSE([scanner1 WOTest_scanUnionIntoString:&type]);
WO_TEST_FALSE([scanner1 scanPointerIntoString:&type]);
WO_TEST_EQUAL([scanner1 scanLocation], (unsigned)0); // still at start
-
+
// parsing: r*8@0:4
WO_TEST_FALSE([scanner2 WOTest_scanNonCompoundTypeIntoString:&type]);
WO_TEST_TRUE([scanner2 WOTest_scanTypeIntoString:&type]);
WO_TEST_FALSE([scanner2 WOTest_scanUnionIntoString:&type]);
WO_TEST_FALSE([scanner2 scanPointerIntoString:&type]);
WO_TEST_EQUAL([scanner2 scanLocation], (unsigned)0); // still at start
-
+
// parse: ^v8@0:4
type = nil;
WO_TEST_TRUE([scanner3 WOTest_scanReturnTypeIntoString:&type]);
WO_TEST_EQUAL(type, @"^v");
-
+
// parse: c12@0:4@8
type = nil;
WO_TEST_TRUE([scanner4 WOTest_scanReturnTypeIntoString:&type]);
WO_TEST_EQUAL(type, @"c");
-
+
// parse: @12@0:4^{_NSZone=}8
type = nil;
WO_TEST_TRUE([scanner5 WOTest_scanReturnTypeIntoString:&type]);
WO_TEST_EQUAL(type, @"@");
-
+
// parse: #8@0:4
type = nil;
WO_TEST_TRUE([scanner6 WOTest_scanReturnTypeIntoString:&type]);
WO_TEST_EQUAL(type, @"#");
-
+
// parse: v20@0:4@8:12@16
type = nil;
WO_TEST_TRUE([scanner7 WOTest_scanReturnTypeIntoString:&type]);
WO_TEST_EQUAL(type, @"v");
-
+
// parse: {_NSRect={_NSPoint=ff}{_NSSize=ff}}28@0:4{_NSRect={_NSPoint=f...
type = nil;
WO_TEST_TRUE([scanner8 WOTest_scanReturnTypeIntoString:&type]);
WO_TEST_EQUAL(type, @"{_NSRect={_NSPoint=ff}{_NSSize=ff}}");
-
+
// parse: @12@0:4@8
type = nil;
WO_TEST_TRUE([scanner9 WOTest_scanReturnTypeIntoString:&type]);
unsigned short fye;
NSRect foe;
NSPoint fum;
-} WOSubstruct;
+} WOSubstruct;
typedef union WOSubunion {
NSPoint a;
unsigned int /* no identifier */ : 6;
unsigned int bitfield_d : 2;
float xavier;
- char zach;
+ char zach;
} WOComplicatedUnion;
// anonymous struct (no identifier)
unsigned long long ull;
float f;
double d;
-
+
// pointers etc
id object;
Class class;
char *pChar;
const char *pConstChar;
int *pInt;
-
+
// compound types
WOComplicatedStruct aStruct;
WOComplicatedUnion aUnion;
-
+
// special case: function pointers
float (*pFunction)(float, float, float);
-
+
// test assumption that @encode() returns the same as @encode(typeof())
WO_TEST_EQ(@encode(_Bool), @encode(typeof(b)));
WO_TEST_EQ(@encode(char), @encode(typeof(c)));
WO_TEST_EQ(@encode(float (*)(float, float, float)), @encode(typeof(pFunction)));
}
-#pragma mark -
+#pragma mark -
#pragma mark Creation and retrieval convenience methods
- (void)testCharConvenienceMethods
// test valueWithChar
char aChar = 'a';
NSValue *value = [NSValue WOTest_valueWithChar:aChar];
-
+
// check type
- WO_TEST_EQ([value objCType], @encode(char));
-
+ WO_TEST_EQ([value objCType], @encode(char));
+
// check that the value extracts as expected
char extracted = 0;
[value getValue:&extracted];
WO_TEST_EQ(extracted, aChar);
-
+
// also test WOTest_charValue method
WO_TEST_EQ([value WOTest_charValue], aChar);
}
// test valueWithInt
int anInt = 20;
NSValue *value = [NSValue WOTest_valueWithInt:anInt];
-
+
// check type
- WO_TEST_EQ([value objCType], @encode(int));
-
+ WO_TEST_EQ([value objCType], @encode(int));
+
// check that the value extracts as expected
int extracted = 0;
[value getValue:&extracted];
WO_TEST_EQ(extracted, anInt);
-
+
// also test WOTest_intValue method
WO_TEST_EQ([value WOTest_intValue], anInt);
}
// test valueWithShort
short aShort = 100;
NSValue *value = [NSValue WOTest_valueWithShort:aShort];
-
+
// check type
- WO_TEST_EQ([value objCType], @encode(short));
-
+ WO_TEST_EQ([value objCType], @encode(short));
+
// check that the value extracts as expected
short extracted = 0;
[value getValue:&extracted];
WO_TEST_EQ(extracted, aShort);
-
+
// also test WOTest_shortValue method
WO_TEST_EQ([value WOTest_shortValue], aShort);
}
// test valueWithLong
long aLong = 200;
NSValue *value = [NSValue WOTest_valueWithLong:aLong];
-
+
// check type
- WO_TEST_EQ([value objCType], @encode(long));
-
+ WO_TEST_EQ([value objCType], @encode(long));
+
// check that the value extracts as expected
long extracted = 0;
[value getValue:&extracted];
WO_TEST_EQ(extracted, aLong);
-
+
// also test WOTest_longValue method
WO_TEST_EQ([value WOTest_longValue], aLong);
}
// test valueWithLongLong
long long aLongLong = 5;
NSValue *value = [NSValue WOTest_valueWithLongLong:aLongLong];
-
+
// check type
- WO_TEST_EQ([value objCType], @encode(long long));
-
+ WO_TEST_EQ([value objCType], @encode(long long));
+
// check that the value extracts as expected
long long extracted = 0;
[value getValue:&extracted];
WO_TEST_EQ(extracted, aLongLong);
-
+
// also test WOTest_longLongValue method
WO_TEST_EQ([value WOTest_longLongValue], aLongLong);
}
// test valueWithUnsignedChar
unsigned char anUnsignedChar = 'a';
NSValue *value = [NSValue WOTest_valueWithUnsignedChar:anUnsignedChar];
-
+
// check type
- WO_TEST_EQ([value objCType], @encode(unsigned char));
-
+ WO_TEST_EQ([value objCType], @encode(unsigned char));
+
// check that the value extracts as expected
unsigned char extracted = 0;
[value getValue:&extracted];
WO_TEST_EQ(extracted, anUnsignedChar);
-
+
// also test WOTest_unsignedCharValue method
WO_TEST_EQ([value WOTest_unsignedCharValue], anUnsignedChar);
}
// test valueWithUnsignedInt
unsigned int anUnsignedInt = 100;
NSValue *value = [NSValue WOTest_valueWithUnsignedInt:anUnsignedInt];
-
+
// check type
- WO_TEST_EQ([value objCType], @encode(unsigned int));
-
+ WO_TEST_EQ([value objCType], @encode(unsigned int));
+
// check that the value extracts as expected
unsigned int extracted = 0;
[value getValue:&extracted];
WO_TEST_EQ(extracted, anUnsignedInt);
-
+
// also test WOTest_unsignedIntValue method
WO_TEST_EQ([value WOTest_unsignedIntValue], anUnsignedInt);
}
// test valueWithUnsignedShort
unsigned short anUnsignedShort = 40;
NSValue *value = [NSValue WOTest_valueWithUnsignedShort:anUnsignedShort];
-
+
// check type
- WO_TEST_EQ([value objCType], @encode(unsigned short));
-
+ WO_TEST_EQ([value objCType], @encode(unsigned short));
+
// check that the value extracts as expected
unsigned short extracted = 0;
[value getValue:&extracted];
WO_TEST_EQ(extracted, anUnsignedShort);
-
+
// also test WOTest_unsignedShortValue method
WO_TEST_EQ([value WOTest_unsignedShortValue], anUnsignedShort);
}
// test valueWithUnsignedLong
unsigned long anUnsignedLong = 2000;
NSValue *value = [NSValue WOTest_valueWithUnsignedLong:anUnsignedLong];
-
+
// check type
- WO_TEST_EQ([value objCType], @encode(unsigned long));
-
+ WO_TEST_EQ([value objCType], @encode(unsigned long));
+
// check that the value extracts as expected
unsigned long extracted = 0;
[value getValue:&extracted];
WO_TEST_EQ(extracted, anUnsignedLong);
-
+
// also test WOTest_unsignedLongValue method
WO_TEST_EQ([value WOTest_unsignedLongValue], anUnsignedLong);
}
// test valueWithUnsignedLongLong
unsigned long long anUnsignedLongLong = 20, extracted = 0;
NSValue *value = [NSValue WOTest_valueWithUnsignedLongLong:anUnsignedLongLong];
-
+
// check type
- WO_TEST_EQ([value objCType], @encode(unsigned long long));
-
+ WO_TEST_EQ([value objCType], @encode(unsigned long long));
+
// check that the value extracts as expected
[value getValue:&extracted];
WO_TEST_EQ(extracted, anUnsignedLongLong);
-
+
// also test WOTest_unsignedLongLongValue method
WO_TEST_EQ([value WOTest_unsignedLongLongValue], anUnsignedLongLong);
}
// test valueWithFloat
float aFloat = 10.0, extracted = 0.0;
NSValue *value = [NSValue WOTest_valueWithFloat:aFloat];
-
+
// check type
- WO_TEST_EQ([value objCType], @encode(float));
-
+ WO_TEST_EQ([value objCType], @encode(float));
+
// check that the value extracts as expected
[value getValue:&extracted];
WO_TEST_EQ(extracted, aFloat);
-
+
// also test WOTest_floatValue method
WO_TEST_EQ([value WOTest_floatValue], aFloat);
}
// test valueWithObject
const char *string = "foo";
NSValue *value = [NSValue WOTest_valueWithConstantCharacterString:string];
-
+
// check type
- WO_TEST_EQ([value objCType], @encode(const char *));
-
+ WO_TEST_EQ([value objCType], @encode(const char *));
+
// check that the value extracts as expected
const char *extracted;
[value getValue:&extracted];
WO_TEST_EQ(extracted, string);
-
+
// also test WOTest_constantCharacterStringValue method
WO_TEST_EQ([value WOTest_constantCharacterStringValue], string);
}
// test valueWithObject
char *string = "foo";
NSValue *value = [NSValue WOTest_valueWithCharacterString:string];
-
+
// check type
- WO_TEST_EQ([value objCType], @encode(char *));
-
+ WO_TEST_EQ([value objCType], @encode(char *));
+
// check that the value extracts as expected
char *extracted = NULL;
[value getValue:&extracted];
WO_TEST_EQ(extracted, string);
-
+
// also test WOTest_characterStringValue method
WO_TEST_EQ([value WOTest_characterStringValue], string);
}
NSValue *value = [NSValue WOTest_valueWithObject:self];
// check type
- WO_TEST_EQ([value objCType], @encode(id));
-
+ WO_TEST_EQ([value objCType], @encode(id));
+
// check that the value extracts as expected
id extracted = nil;
[value getValue:&extracted];
WO_TEST_EQ(extracted, self);
-
+
// also test WOTest_objectValue method
WO_TEST_EQ([value WOTest_objectValue], self);
}
-
+
- (void)testClassConvenienceMethods
{
// test valueWithClass
NSValue *value = [NSValue WOTest_valueWithClass:[self class]];
-
+
// check type
WO_TEST_EQ([value objCType], @encode(Class));
-
+
// check that the value extracts as expected
Class extracted = NULL;
[value getValue:&extracted];
WO_TEST_EQ(extracted, [self class]);
-
+
// also test WOTest_classValue method
WO_TEST_EQ([value WOTest_classValue], [self class]);
}
{
// test valueWithSelector
NSValue *value = [NSValue WOTest_valueWithSelector:_cmd];
-
+
// check type
WO_TEST_EQ([value objCType], @encode(SEL));
-
+
// check that the value extracts as expected
SEL extracted = NULL;
[value getValue:&extracted];
WO_TEST_EQ(extracted, _cmd);
-
+
// also test WOTest_selectorValue method
WO_TEST_EQ([value WOTest_selectorValue], _cmd);
}
{
// preliminaries
NSValue *value = nil;
-
+
// test with int
int i = 0;
value = [NSValue value:&i withObjCType:@encode(int)];
value = [NSValue value:&ui withObjCType:@encode(unsigned int)];
WO_TEST_GTE([NSValue WOTest_sizeForType:[value WOTest_objCTypeString]], sizeof(unsigned int));
WO_TEST_GTE([value WOTest_bufferSize], sizeof(unsigned int));
-
+
// test with short
short s = 0;
value = [NSValue value:&s withObjCType:@encode(short)];
value = [NSValue value:&us withObjCType:@encode(unsigned short)];
WO_TEST_GTE([NSValue WOTest_sizeForType:[value WOTest_objCTypeString]], sizeof(unsigned short));
WO_TEST_GTE([value WOTest_bufferSize], sizeof(unsigned short));
-
+
// test with long
long l = 0;
value = [NSValue value:&l withObjCType:@encode(int)];
WO_TEST_GTE([NSValue WOTest_sizeForType:[value WOTest_objCTypeString]], sizeof(int));
WO_TEST_GTE([value WOTest_bufferSize], sizeof(int));
-
+
// test with unsigned long
unsigned long ul = 0;
value = [NSValue value:&ul withObjCType:@encode(unsigned long)];
WO_TEST_GTE([NSValue WOTest_sizeForType:[value WOTest_objCTypeString]], sizeof(unsigned long));
WO_TEST_GTE([value WOTest_bufferSize], sizeof(unsigned long));
-
+
// test with long long
long long ll = 0;
value = [NSValue value:&ll withObjCType:@encode(long long)];
WO_TEST_GTE([NSValue WOTest_sizeForType:[value WOTest_objCTypeString]], sizeof(long long));
WO_TEST_GTE([value WOTest_bufferSize], sizeof(long long));
-
+
// test with unsigned long long
unsigned long long ull = 0;
value = [NSValue value:&ull withObjCType:@encode(unsigned long long)];
WO_TEST_GTE([NSValue WOTest_sizeForType:[value WOTest_objCTypeString]], sizeof(unsigned long long));
WO_TEST_GTE([value WOTest_bufferSize], sizeof(unsigned long long));
-
+
// test with float
float f = 0;
value = [NSValue value:&f withObjCType:@encode(float)];
WO_TEST_GTE([NSValue WOTest_sizeForType:[value WOTest_objCTypeString]], sizeof(float));
WO_TEST_GTE([value WOTest_bufferSize], sizeof(float));
-
+
// test with double
double d = 0;
value = [NSValue value:&d withObjCType:@encode(double)];
value = [NSValue value:&c withObjCType:@encode(char)];
WO_TEST_GTE([NSValue WOTest_sizeForType:[value WOTest_objCTypeString]], sizeof(char));
WO_TEST_GTE([value WOTest_bufferSize], sizeof(char));
-
+
// test with unsigned char
unsigned char uc = 0;
value = [NSValue value:&uc withObjCType:@encode(unsigned char)];
WO_TEST_GTE([NSValue WOTest_sizeForType:[value WOTest_objCTypeString]], sizeof(unsigned char));
WO_TEST_GTE([value WOTest_bufferSize], sizeof(unsigned char));
-
+
// test with C99 _Bool
_Bool b = 0;
value = [NSValue value:&b withObjCType:@encode(_Bool)];
WO_TEST_GTE([NSValue WOTest_sizeForType:[value WOTest_objCTypeString]], sizeof(_Bool));
WO_TEST_GTE([value WOTest_bufferSize], sizeof(_Bool));
-}
-
+}
+
- (void)testSizeCalculationsForStructs
{
// preliminaries
NSValue *value = nil;
- // test with NSRange
+ // test with NSRange
NSRange range = NSMakeRange(100, 100);
value = [NSValue valueWithRange:range];
WO_TEST_GTE([NSValue WOTest_sizeForType:[value WOTest_objCTypeString]], sizeof(NSRange));
WO_TEST_GTE([value WOTest_bufferSize], sizeof(NSRange));
-
+
// test with NSPoint
NSPoint point;
point.x = 100.0f; // can't use NSMakePoint (warnings on Intel release builds)
value = [NSValue valueWithPoint:point];
WO_TEST_GTE([NSValue WOTest_sizeForType:[value WOTest_objCTypeString]], sizeof(NSPoint));
WO_TEST_GTE([value WOTest_bufferSize], sizeof(NSPoint));
-
+
// test with NSRect
NSRect rect = NSMakeRect(100.0, 100.0, 100.0, 100.0);
value = [NSValue valueWithRect:rect];
WO_TEST_GTE([NSValue WOTest_sizeForType:[value WOTest_objCTypeString]], sizeof(NSRect));
WO_TEST_GTE([value WOTest_bufferSize], sizeof(NSRect));
-
+
// test with simple custom struct
WOSimpleStruct simple;
value = [NSValue valueWithBytes:&simple objCType:@encode(WOSimpleStruct)];
WO_TEST_GTE([NSValue WOTest_sizeForType:[value WOTest_objCTypeString]], sizeof(WOSimpleStruct));
WO_TEST_GTE([value WOTest_bufferSize], sizeof(WOSimpleStruct));
-
+
// test with complicated custom structs
WOSubstruct substruct;
value = [NSValue valueWithBytes:&substruct objCType:@encode(WOSubstruct)];
WO_TEST_GTE([NSValue WOTest_sizeForType:[value WOTest_objCTypeString]], sizeof(WOSubstruct));
WO_TEST_GTE([value WOTest_bufferSize], sizeof(WOSubstruct));
-
+
WOComplicatedStruct complicated;
value = [NSValue valueWithBytes:&complicated objCType:@encode(WOComplicatedStruct)];
WO_TEST_GTE([NSValue WOTest_sizeForType:[value WOTest_objCTypeString]], sizeof(WOComplicatedStruct));
WO_TEST_GTE([value WOTest_bufferSize], sizeof(WOComplicatedStruct));
-
+
// test with anonymous struct
WOAnonymousStruct anonymous;
value = [NSValue valueWithBytes:&anonymous objCType:@encode(WOAnonymousStruct)];
value = [NSValue valueWithBytes:&simple objCType:@encode(WOSimpleUnion)];
WO_TEST_GTE([NSValue WOTest_sizeForType:[value WOTest_objCTypeString]], sizeof(WOSimpleUnion));
WO_TEST_GTE([value WOTest_bufferSize], sizeof(WOSimpleUnion));
-
+
// test with WOSubunion
WOSubunion subunion;
value = [NSValue valueWithBytes:&subunion objCType:@encode(WOSubunion)];
WO_TEST_GTE([NSValue WOTest_sizeForType:[value WOTest_objCTypeString]], sizeof(WOSubunion));
WO_TEST_GTE([value WOTest_bufferSize], sizeof(WOSubunion));
-
+
// test with WOComplicatedUnion
WOComplicatedUnion complicated;
value = [NSValue valueWithBytes:&complicated objCType:@encode(WOComplicatedUnion)];
WO_TEST_GTE([NSValue WOTest_sizeForType:[value WOTest_objCTypeString]], sizeof(WOComplicatedUnion));
- WO_TEST_GTE([value WOTest_bufferSize], sizeof(WOComplicatedUnion));
+ WO_TEST_GTE([value WOTest_bufferSize], sizeof(WOComplicatedUnion));
// test with anonymous union
WOAnonymousUnion anonymous;
value = [NSValue valueWithBytes:&anonymous objCType:@encode(WOAnonymousUnion)];
WO_TEST_GTE([NSValue WOTest_sizeForType:[value WOTest_objCTypeString]], sizeof(WOAnonymousUnion));
WO_TEST_GTE([value WOTest_bufferSize], sizeof(WOAnonymousUnion));
-}
+}
// tests fo id, Class, SEL (really just pointers)
- (void)testSizeCalculationsForObjects
value = [NSValue valueWithBytes:&i objCType:@encode(id)];
WO_TEST_GTE([NSValue WOTest_sizeForType:[value WOTest_objCTypeString]], sizeof(id));
WO_TEST_GTE([value WOTest_bufferSize], sizeof(id));
-
- // test with Class
+
+ // test with Class
Class c = [self class];
value = [NSValue valueWithBytes:&c objCType:@encode(Class)];
WO_TEST_GTE([NSValue WOTest_sizeForType:[value WOTest_objCTypeString]], sizeof(Class));
WO_TEST_GTE([value WOTest_bufferSize], sizeof(Class));
-
+
// test with SEL
SEL s = _cmd;
value = [NSValue valueWithBytes:&s objCType:@encode(SEL)];
WO_TEST_GTE([NSValue WOTest_sizeForType:[value WOTest_objCTypeString]], sizeof(SEL));
WO_TEST_GTE([value WOTest_bufferSize], sizeof(SEL));
-}
+}
- (void)testSizeCalculationsForPointers
{
NSValue *value = nil;
// test with function pointers
-
-
-
-}
+
+
+
+}
- (void)testSizeCalculationsForArrays
{
{
// preliminaries
NSString *typeString;
-
+
// numeric scalar types
_Bool b;
char c;
char *pChar;
const char *pConstChar;
int *pInt;
-
+
// compound types
WOComplicatedStruct aStruct;
WOComplicatedUnion aUnion;
// special case: function pointers
float (*pFunction)(float, float, float);
-
+
// test type is _Bool
typeString = [NSString stringWithUTF8String:@encode(typeof(b))];
WO_TEST([NSValue WOTest_typeIsNumericScalar:typeString]);
WO_TEST_FALSE([NSValue WOTest_typeIsUnion:typeString]);
WO_TEST_FALSE([NSValue WOTest_typeIsBitfield:typeString]);
WO_TEST_FALSE([NSValue WOTest_typeIsUnknown:typeString]);
-
+
// test type is char
typeString = [NSString stringWithUTF8String:@encode(typeof(c))];
WO_TEST([NSValue WOTest_typeIsNumericScalar:typeString]);
WO_TEST_FALSE([NSValue WOTest_typeIsUnion:typeString]);
WO_TEST_FALSE([NSValue WOTest_typeIsBitfield:typeString]);
WO_TEST_FALSE([NSValue WOTest_typeIsUnknown:typeString]);
-
+
// test type is unsigned char
typeString = [NSString stringWithUTF8String:@encode(typeof(uc))];
WO_TEST([NSValue WOTest_typeIsNumericScalar:typeString]);
WO_TEST_FALSE([NSValue WOTest_typeIsUnion:typeString]);
WO_TEST_FALSE([NSValue WOTest_typeIsBitfield:typeString]);
WO_TEST_FALSE([NSValue WOTest_typeIsUnknown:typeString]);
-
+
// test type is short
typeString = [NSString stringWithUTF8String:@encode(typeof(s))];
WO_TEST([NSValue WOTest_typeIsNumericScalar:typeString]);
WO_TEST_FALSE([NSValue WOTest_typeIsUnion:typeString]);
WO_TEST_FALSE([NSValue WOTest_typeIsBitfield:typeString]);
WO_TEST_FALSE([NSValue WOTest_typeIsUnknown:typeString]);
-
+
// test type is unsigned short
typeString = [NSString stringWithUTF8String:@encode(typeof(us))];
WO_TEST([NSValue WOTest_typeIsNumericScalar:typeString]);
WO_TEST_FALSE([NSValue WOTest_typeIsUnion:typeString]);
WO_TEST_FALSE([NSValue WOTest_typeIsBitfield:typeString]);
WO_TEST_FALSE([NSValue WOTest_typeIsUnknown:typeString]);
-
+
// test type is int
typeString = [NSString stringWithUTF8String:@encode(typeof(i))];
WO_TEST([NSValue WOTest_typeIsNumericScalar:typeString]);
WO_TEST_FALSE([NSValue WOTest_typeIsUnion:typeString]);
WO_TEST_FALSE([NSValue WOTest_typeIsBitfield:typeString]);
WO_TEST_FALSE([NSValue WOTest_typeIsUnknown:typeString]);
-
+
// test type is unsigned int
typeString = [NSString stringWithUTF8String:@encode(typeof(ui))];
WO_TEST([NSValue WOTest_typeIsNumericScalar:typeString]);
WO_TEST_FALSE([NSValue WOTest_typeIsUnion:typeString]);
WO_TEST_FALSE([NSValue WOTest_typeIsBitfield:typeString]);
WO_TEST_FALSE([NSValue WOTest_typeIsUnknown:typeString]);
-
+
// test type is long
typeString = [NSString stringWithUTF8String:@encode(typeof(l))];
WO_TEST([NSValue WOTest_typeIsNumericScalar:typeString]);
WO_TEST_FALSE([NSValue WOTest_typeIsUnion:typeString]);
WO_TEST_FALSE([NSValue WOTest_typeIsBitfield:typeString]);
WO_TEST_FALSE([NSValue WOTest_typeIsUnknown:typeString]);
-
+
// test type is unsigned long
typeString = [NSString stringWithUTF8String:@encode(typeof(ul))];
WO_TEST([NSValue WOTest_typeIsNumericScalar:typeString]);
WO_TEST_FALSE([NSValue WOTest_typeIsUnion:typeString]);
WO_TEST_FALSE([NSValue WOTest_typeIsBitfield:typeString]);
WO_TEST_FALSE([NSValue WOTest_typeIsUnknown:typeString]);
-
+
// test type is long long
typeString = [NSString stringWithUTF8String:@encode(typeof(ll))];
WO_TEST([NSValue WOTest_typeIsNumericScalar:typeString]);
WO_TEST_FALSE([NSValue WOTest_typeIsUnion:typeString]);
WO_TEST_FALSE([NSValue WOTest_typeIsBitfield:typeString]);
WO_TEST_FALSE([NSValue WOTest_typeIsUnknown:typeString]);
-
+
// test type is unsigned long long
typeString = [NSString stringWithUTF8String:@encode(typeof(ull))];
WO_TEST([NSValue WOTest_typeIsNumericScalar:typeString]);
WO_TEST_FALSE([NSValue WOTest_typeIsUnion:typeString]);
WO_TEST_FALSE([NSValue WOTest_typeIsBitfield:typeString]);
WO_TEST_FALSE([NSValue WOTest_typeIsUnknown:typeString]);
-
+
// test type is float
typeString = [NSString stringWithUTF8String:@encode(typeof(f))];
WO_TEST([NSValue WOTest_typeIsNumericScalar:typeString]);
WO_TEST_FALSE([NSValue WOTest_typeIsUnion:typeString]);
WO_TEST_FALSE([NSValue WOTest_typeIsBitfield:typeString]);
WO_TEST_FALSE([NSValue WOTest_typeIsUnknown:typeString]);
-
+
// test type is double
typeString = [NSString stringWithUTF8String:@encode(typeof(d))];
WO_TEST([NSValue WOTest_typeIsNumericScalar:typeString]);
WO_TEST_FALSE([NSValue WOTest_typeIsUnion:typeString]);
WO_TEST_FALSE([NSValue WOTest_typeIsBitfield:typeString]);
WO_TEST_FALSE([NSValue WOTest_typeIsUnknown:typeString]);
-
+
// test type is id
typeString = [NSString stringWithUTF8String:@encode(typeof(object))];
WO_TEST_FALSE([NSValue WOTest_typeIsNumericScalar:typeString]);
WO_TEST_FALSE([NSValue WOTest_typeIsUnion:typeString]);
WO_TEST_FALSE([NSValue WOTest_typeIsBitfield:typeString]);
WO_TEST_FALSE([NSValue WOTest_typeIsUnknown:typeString]);
-
+
// test type is Class
typeString = [NSString stringWithUTF8String:@encode(typeof(class))];
WO_TEST_FALSE([NSValue WOTest_typeIsNumericScalar:typeString]);
WO_TEST_FALSE([NSValue WOTest_typeIsUnion:typeString]);
WO_TEST_FALSE([NSValue WOTest_typeIsBitfield:typeString]);
WO_TEST_FALSE([NSValue WOTest_typeIsUnknown:typeString]);
-
+
// test type is SEL
typeString = [NSString stringWithUTF8String:@encode(typeof(selector))];
WO_TEST_FALSE([NSValue WOTest_typeIsNumericScalar:typeString]);
WO_TEST_FALSE([NSValue WOTest_typeIsUnion:typeString]);
WO_TEST_FALSE([NSValue WOTest_typeIsBitfield:typeString]);
WO_TEST_FALSE([NSValue WOTest_typeIsUnknown:typeString]);
-
+
// test type is pointer to void
typeString = [NSString stringWithUTF8String:@encode(typeof(pVoid))];
WO_TEST_FALSE([NSValue WOTest_typeIsNumericScalar:typeString]);
WO_TEST_FALSE([NSValue WOTest_typeIsUnion:typeString]);
WO_TEST_FALSE([NSValue WOTest_typeIsBitfield:typeString]);
WO_TEST_FALSE([NSValue WOTest_typeIsUnknown:typeString]);
-
+
// test type is character string
typeString = [NSString stringWithUTF8String:@encode(typeof(pChar))];
WO_TEST_FALSE([NSValue WOTest_typeIsNumericScalar:typeString]);
WO_TEST_FALSE([NSValue WOTest_typeIsUnion:typeString]);
WO_TEST_FALSE([NSValue WOTest_typeIsBitfield:typeString]);
WO_TEST_FALSE([NSValue WOTest_typeIsUnknown:typeString]);
-
+
// test type is constant character string
typeString = [NSString stringWithUTF8String:@encode(typeof(pConstChar))];
WO_TEST_FALSE([NSValue WOTest_typeIsNumericScalar:typeString]);
WO_TEST_FALSE([NSValue WOTest_typeIsUnion:typeString]);
WO_TEST_FALSE([NSValue WOTest_typeIsBitfield:typeString]);
WO_TEST_FALSE([NSValue WOTest_typeIsUnknown:typeString]);
-
+
// test type is pointer to int
typeString = [NSString stringWithUTF8String:@encode(typeof(pInt))];
WO_TEST_FALSE([NSValue WOTest_typeIsNumericScalar:typeString]);
WO_TEST_FALSE([NSValue WOTest_typeIsUnion:typeString]);
WO_TEST_FALSE([NSValue WOTest_typeIsBitfield:typeString]);
WO_TEST_FALSE([NSValue WOTest_typeIsUnknown:typeString]);
-
+
// test type is struct
typeString = [NSString stringWithUTF8String:@encode(typeof(aStruct))];
WO_TEST_FALSE([NSValue WOTest_typeIsNumericScalar:typeString]);
WO_TEST_FALSE([NSValue WOTest_typeIsUnion:typeString]);
WO_TEST_FALSE([NSValue WOTest_typeIsBitfield:typeString]);
WO_TEST_FALSE([NSValue WOTest_typeIsUnknown:typeString]);
-
+
// test type is union
typeString = [NSString stringWithUTF8String:@encode(typeof(aUnion))];
WO_TEST_FALSE([NSValue WOTest_typeIsNumericScalar:typeString]);
WO_TEST([NSValue WOTest_typeIsUnion:typeString]);
WO_TEST_FALSE([NSValue WOTest_typeIsBitfield:typeString]);
WO_TEST_FALSE([NSValue WOTest_typeIsUnknown:typeString]);
-
+
// test type is array
typeString = [NSString stringWithUTF8String:@encode(typeof(anArray))];
WO_TEST_FALSE([NSValue WOTest_typeIsNumericScalar:typeString]);
WO_TEST_FALSE([NSValue WOTest_typeIsUnion:typeString]);
WO_TEST_FALSE([NSValue WOTest_typeIsBitfield:typeString]);
WO_TEST_FALSE([NSValue WOTest_typeIsUnknown:typeString]);
-
+
// test type is a function pointer ("^?")
typeString = [NSString stringWithUTF8String:@encode(typeof(pFunction))];
WO_TEST_FALSE([NSValue WOTest_typeIsNumericScalar:typeString]);
// preliminaries
BOOL warns = [WO_TEST_SHARED_INSTANCE warnsAboutSignComparisons];
[WO_TEST_SHARED_INSTANCE setWarnsAboutSignComparisons:NO];
-
+
// due to some bad casts, comparing values too large to fit in an unsigned char was failing in specific cases
// the signed value was being cast to unsigned char in these cases, thus getting truncated
// this meant that tests would fail with messages like "expected (int)1000, got (unsigned int)1000"
unsigned long long ullValue = 1000;
WO_TEST_EQ(ullValue, 1000); // same bug for unsigned long long compared with int
-
+
short shortValue = 1000;
WO_TEST_EQ(1000U, shortValue); // same bug for unsigned compared with short
WO_TEST_EQ(1000UL, shortValue); // and unsigned long compared with short
WO_TEST_EQ(ullValue, shortValue); // and unsigned long long compared with short
-
+
WO_TEST_EQ(1000U, 1000L); // and unsigned int versus long
WO_TEST_EQ(1000UL, 1000L); // and unsigned long compared with long
WO_TEST_EQ(ullValue, 1000L); // and unsigned long long compared with long
-
+
long long llValue = 1000;
WO_TEST_EQ(ullValue, llValue); // and unsigned long long compared with long long
-
+
// cleanup
[WO_TEST_SHARED_INSTANCE setWarnsAboutSignComparisons:warns];
}
{
// preliminaries
WOClassMock *mock = nil;
-
+
// should throw if passed NULL
mock = [WOClassMock alloc];
WO_TEST_THROWS([mock initWithClass:NULL]);
[mock release];
-
+
// should throw if passed non-class pointer
mock = [WOClassMock alloc];
WO_TEST_THROWS([mock initWithClass:(Class)self]);
[mock release];
-
+
// otherwise should work
WO_TEST_DOES_NOT_THROW
([[[WOClassMock alloc] initWithClass:[self class]] autorelease]);
-
+
// should throw if passed a meta class
Class class = [NSString class];
Class metaclass = object_getClass(class);
id mock = [WOClassMock mockForClass:[NSString class]];
WO_TEST_DOES_NOT_THROW([[mock accept] stringWithString:@"foo"]);
WO_TEST_DOES_NOT_THROW([mock stringWithString:@"foo"]);
-
+
// should throw for instance methods
WO_TEST_THROWS([[mock accept] lowercaseString]);
-
+
// should throw for unknown methods
WO_TEST_THROWS(objc_msgSend([mock accept], @selector(foobar)));
}
//WOObjectMock *mock = [WOMock mockForObjectClass:[NSString class]];
//[[mock expect] lowercaseString];
//[mock lowercaseString]; // "warning: 'WOObjectMock' may not respond to '-lowercaseString'"
- //[mock verify];
-
+ //[mock verify];
+
// one way of avoiding compiler warnings when using mocks: cast to id
WOObjectMock *mock1 = [WOMock mockForObjectClass:[NSString class]];
[[mock1 expect] lowercaseString];
[(id)mock1 lowercaseString];
[mock1 verify];
-
+
// another way of avoiding compiler warnings: use id type from beginning
id mock2 = [WOMock mockForObjectClass:[NSString class]];
[[mock2 expect] lowercaseString];
[mock2 lowercaseString];
[mock2 verify];
-
+
// another way: cast to mocked class
NSString *mock3 = [WOMock mockForObjectClass:[NSString class]];
[[(WOMock *)mock3 expect] lowercaseString];
[mock3 lowercaseString];
[(WOMock *)mock3 verify];
-
+
// another way: alternative way of casting to mocked class
WOObjectMock *mock4 = [WOMock mockForObjectClass:[NSString class]];
[[mock4 expect] lowercaseString];
[(NSString *)mock4 lowercaseString];
[mock4 verify];
-
+
// yet another way: use objc_msgSend
WOObjectMock *mock5 = [WOMock mockForObjectClass:[NSString class]];
[[mock5 expect] lowercaseString];
- (void)testMockForObjectClass
{
WOObjectMock *mock = [WOMock mockForObjectClass:[self class]];
-
+
// make sure WOObjectMock class is returned
WO_TEST_EQ([mock class], [WOObjectMock class]);
-
+
// make sure mocked class is correctly set
WO_TEST_EQ([mock mockedClass], [self class]);
-
+
// should throw exception instead of entering infinite loop
WO_TEST_THROWS([WOObjectMock mockForObjectClass:[self class]]);
}
- (void)testMockForClass
{
WOClassMock *mock = [WOMock mockForClass:[self class]];
-
+
// make sure WOClassMock class is returned
WO_TEST_EQ([mock class], [WOClassMock class]);
-
+
// make sure mocked class is correctly set
Class class = [self class];
Class metaclass = object_getClass(class);
WO_TEST_EQ([mock mockedClass], metaclass);
-
+
// should throw exception instead of entering infinite loop
// cannot test this because subclass implements that method directly
//WO_TEST_THROWS([WOClassMock mockForClass:[self class]]);
- (void)testMockForProtocol
{
WOProtocolMock *mock = [WOMock mockForProtocol:@protocol(WOTest)];
-
+
// make sure WOProtocolMock class is returned
WO_TEST_EQ([mock class], [WOProtocolMock class]);
-
+
// make sure mocked protocol is correctly set
WO_TEST_EQ([mock mockedProtocol], @protocol(WOTest));
-
+
// should throw exception instead of entering infinite loop
// cannot test this because subclass implements that method directly
//WO_TEST_THROWS([WOProtocolMock mockForProtocol:@protocol(WOTest)]);
- (void)testInitWithObjectClass
{
- WOObjectMock *mock =
+ WOObjectMock *mock =
[[[WOMock alloc] initWithObjectClass:[self class]] autorelease];
-
+
// make sure WOObjectMock class is returned
WO_TEST_EQ([mock class], [WOObjectMock class]);
-
+
// make sure mocked class is correctly set
WO_TEST_EQ([mock mockedClass], [self class]);
-
+
// should throw exception instead of entering infinite loop
mock = [WOObjectMock alloc];
WO_TEST_THROWS([mock initWithObjectClass:[self class]]);
- (void)testInitWithClass
{
- WOClassMock *mock =
+ WOClassMock *mock =
[[[WOMock alloc] initWithClass:[self class]] autorelease];
-
+
// make sure WOClassMock class is returned
WO_TEST_EQ([mock class], [WOClassMock class]);
-
+
// make sure mocked class is correctly set
Class class = [self class];
Class metaclass = object_getClass(class);
WO_TEST_EQ([mock mockedClass], metaclass);
-
+
// should throw exception instead of entering infinite loop
// cannot test this because subclass implements that method directly
//mock = [WOClassMock alloc];
- (void)testInitWithProtocol
{
- WOProtocolMock *mock =
+ WOProtocolMock *mock =
[[[WOMock alloc] initWithProtocol:@protocol(WOTest)] autorelease];
-
+
// make sure WOProtocolMock class is returned
WO_TEST_EQ([mock class], [WOProtocolMock class]);
-
+
// make sure mocked protocol is correctly set
WO_TEST_EQ([mock mockedProtocol], @protocol(WOTest));
-
+
// should throw exception instead of entering infinite loop
// cannot test this because subclass implements that method directly
//mock = [WOProtocolMock alloc];
- (void)secondaryThreadCrasher:(id)sender
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
-
+
// Apple's InstallExceptionHandler doesn't catch crashes on secondary threads
// - in the case of Carbon threads a separate handler is automatically installed for each thread
// - pthreads and Cocoa threads don't get extra handlers automatically installed
// - these are per-thread handlers because the per-process handler port is used by the crash reporter
-
+
// TODO: write a Mach per-process exception handler
return; // don't continue (would crash WOTestRunner)
-
+
WO_TEST_PASS; // force update of "lastKnownLocation"
id *object = NULL; // cause a crash, but WOTest should keep running
*object = @"foo"; // SIGBUS here
@implementation WOObjectMockTests
-#pragma mark -
+#pragma mark -
#pragma mark High-level tests
- (void)testMockForClass
{
// should throw if passed NULL
WO_TEST_THROWS([WOObjectMock mockForClass:NULL]);
-
+
// should throw if passed non-class pointer
WO_TEST_THROWS([WOObjectMock mockForClass:(Class)self]);
-
+
// otherwise should work
WO_TEST_DOES_NOT_THROW([WOObjectMock mockForClass:[self class]]);
-
+
// should throw if passed a meta class
Class class = [NSString class];
Class metaclass = object_getClass(class);
{
// preliminaries
WOObjectMock *mock = nil;
-
+
// should throw if passed NULL
mock = [WOObjectMock alloc];
WO_TEST_THROWS([mock initWithClass:NULL]);
[mock release];
-
+
// should throw if passed non-class pointer
mock = [WOObjectMock alloc];
WO_TEST_THROWS([mock initWithClass:(Class)self]);
[mock release];
-
+
// otherwise should work
WO_TEST_DOES_NOT_THROW
([[[WOObjectMock alloc] initWithClass:[self class]] autorelease]);
-
+
// should throw if passed a meta class
Class class = [NSString class];
Class metaclass = object_getClass(class);
{
// basic test
id mock = [WOObjectMock mockForClass:[NSString class]];
-
+
[[mock expectInOrder] lowercaseString];
[[mock expectInOrder] uppercaseString];
[[mock expectInOrder] stringByExpandingTildeInPath];
[[mock expectInOrder] uppercaseString];
-
+
[mock lowercaseString];
[mock uppercaseString];
[mock stringByExpandingTildeInPath];
[mock uppercaseString];
-
+
WO_TEST_DOES_NOT_THROW([mock verify]);
-
+
// repeat test: this time omit one of the expected methods
[mock clear];
[[mock expectInOrder] lowercaseString];
[[mock expectInOrder] uppercaseString];
[[mock expectInOrder] stringByAbbreviatingWithTildeInPath];
[[mock expectInOrder] uppercaseString];
-
+
[mock lowercaseString];
[mock uppercaseString];
[mock stringByAbbreviatingWithTildeInPath];
-
+
WO_TEST_THROWS([mock verify]);
// repeat test: this time invoke methods in wrong order
[[mock expectInOrder] uppercaseString];
[[mock expectInOrder] stringByAbbreviatingWithTildeInPath];
[[mock expectInOrder] uppercaseString];
-
+
[mock lowercaseString];
WO_TEST_THROWS([mock stringByAbbreviatingWithTildeInPath]);
-
+
// test with arguments
[mock clear];
[[mock expectInOrder] stringByAppendingFormat:@"foobar"];
[[mock expectInOrder] uppercaseString];
[[mock expectInOrder] stringByAbbreviatingWithTildeInPath];
[[mock expectInOrder] uppercaseString];
-
+
[mock stringByAppendingFormat:@"foobar"];
[mock uppercaseString];
[mock stringByAbbreviatingWithTildeInPath];
[mock uppercaseString];
-
+
WO_TEST_DOES_NOT_THROW([mock verify]);
-
+
// repeat test: this time pass unexpected argument
[mock clear];
[[mock expectInOrder] stringByAppendingFormat:@"foobar"];
[[mock expectInOrder] uppercaseString];
[[mock expectInOrder] stringByAbbreviatingWithTildeInPath];
[[mock expectInOrder] uppercaseString];
-
+
WO_TEST_THROWS([mock stringByAppendingFormat:@"other"]);
-
+
// test with object return value
NSValue *value = [NSValue WOTest_valueWithObject:@"foobar"];
[mock clear];
[[[mock expectInOrder] returning:value] stringByAppendingString:@"bar"];
WO_TEST_EQ(@"foobar", [mock stringByAppendingString:@"bar"]);
WO_TEST_DOES_NOT_THROW([mock verify]);
-
+
// test with scalar return value
value = [NSValue WOTest_valueWithUnsignedInt:6];
[mock clear];
[[[mock expectInOrder] returning:value] length];
WO_TEST_EQ((unsigned int)6, [mock length]);
WO_TEST_DOES_NOT_THROW([mock verify]);
-
+
// test with raising exception
[mock clear];
[[[mock expectInOrder] raising:self] lowercaseString];
WO_TEST_THROWS([mock lowercaseString]);
-
+
// test raising named exception
- NSException *exception = [NSException exceptionWithName:@"Robert"
+ NSException *exception = [NSException exceptionWithName:@"Robert"
reason:@"Robert exception"
userInfo:nil];
[mock clear];
WO_TEST_DOES_NOT_THROW([mock lowercaseString]);
WO_TEST_THROWS([mock lowercaseString]);
WO_TEST_DOES_NOT_THROW([mock verify]);
-
+
// test with arguments
[mock clear];
[[mock expectOnce] stringByAppendingFormat:@"foo"];
WO_TEST_DOES_NOT_THROW([mock stringByAppendingFormat:@"foo"]);
WO_TEST_THROWS([mock stringByAppendingFormat:@"bar"]);
WO_TEST_DOES_NOT_THROW([mock verify]);
-
+
// repeat test: this time pass unexpected argument
[mock clear];
[[mock expectOnce] stringByAppendingFormat:@"foo"];
WO_TEST_THROWS([mock verify]);
WO_TEST_THROWS([mock stringByAppendingFormat:@"bar"]);
WO_TEST_THROWS([mock verify]);
-
+
// test with return value
NSValue *value = [NSValue WOTest_valueWithObject:@"foobar"];
[mock clear];
WO_TEST_THROWS([mock verify]);
WO_TEST_EQ(@"foobar", [mock stringByAppendingString:@"bar"]);
WO_TEST_DOES_NOT_THROW([mock verify]);
-
+
// test with raising exception
[mock clear];
[[[mock expectOnce] raising:self] lowercaseString];
WO_TEST_THROWS([mock verify]);
WO_TEST_THROWS([mock lowercaseString]);
WO_TEST_DOES_NOT_THROW([mock verify]);
-
+
// test raising named exception
- NSException *exception = [NSException exceptionWithName:@"Robert"
+ NSException *exception = [NSException exceptionWithName:@"Robert"
reason:@"Robert exception"
userInfo:nil];
[mock clear];
WO_TEST_DOES_NOT_THROW([mock lowercaseString]);
WO_TEST_DOES_NOT_THROW([mock verify]);
WO_TEST_THROWS([mock uppercaseString]);
-
+
// test with return value (no parameters)
NSValue *value = [NSValue WOTest_valueWithObject:@".txt"];
[mock clear];
[[[mock expect] returning:value] stringByAppendingPathExtension:@"txt"];
WO_TEST_EQ([mock stringByAppendingPathExtension:@"txt"], @".txt");
WO_TEST_DOES_NOT_THROW([mock verify]);
-
+
// test with parameters and return value
[mock clear];
value = [NSValue WOTest_valueWithObject:@"foo.txt"];
[[[mock expect] returning:value] stringByAppendingFormat:@".txt"];
WO_TEST_EQ([mock stringByAppendingFormat:@".txt"], @"foo.txt");
WO_TEST_THROWS([mock stringByAppendingFormat:@".m"]); // wrong argument
-
+
// test with parameters but without return value
[mock clear];
[[mock expect] stringByAppendingFormat:@".mov"];
id mock = [WOObjectMock mockForClass:[NSString class]];
[[mock acceptOnce] lowercaseString];
WO_TEST_DOES_NOT_THROW([mock lowercaseString]);
- WO_TEST_THROWS([mock lowercaseString]);
-
+ WO_TEST_THROWS([mock lowercaseString]);
+
// test with arguments
[mock clear];
[[mock acceptOnce] stringByAppendingFormat:@"foo"];
WO_TEST_DOES_NOT_THROW([mock stringByAppendingFormat:@"foo"]);
WO_TEST_THROWS([mock stringByAppendingFormat:@"foo"]);
-
+
// repeat test: this time pass unexpected argument
[mock clear];
[[mock acceptOnce] stringByAppendingFormat:@"foo"];
WO_TEST_THROWS([mock stringByAppendingFormat:@"bar"]);
WO_TEST_DOES_NOT_THROW([mock stringByAppendingFormat:@"foo"]);
- WO_TEST_THROWS([mock stringByAppendingFormat:@"foo"]);
-
+ WO_TEST_THROWS([mock stringByAppendingFormat:@"foo"]);
+
// test with return value
NSValue *value = [NSValue WOTest_valueWithObject:@"foobar"];
[mock clear];
[[[mock acceptOnce] returning:value] stringByAppendingFormat:@"bar"];
- WO_TEST_EQ([mock stringByAppendingFormat:@"bar"], @"foobar");
+ WO_TEST_EQ([mock stringByAppendingFormat:@"bar"], @"foobar");
WO_TEST_THROWS([mock stringByAppendingFormat:@"bar"]);
-
+
// test raising exception
[mock clear];
[[[mock acceptOnce] raising:@"foo"] lowercaseString];
WO_TEST_THROWS([mock lowercaseString]);
-
+
// test raising named exception
- NSException *exception = [NSException exceptionWithName:@"Robert"
+ NSException *exception = [NSException exceptionWithName:@"Robert"
reason:@"Robert exception"
- userInfo:nil];
+ userInfo:nil];
[mock clear];
[[[mock acceptOnce] raising:exception] lowercaseString];
WO_TEST_THROWS_EXCEPTION_NAMED([mock lowercaseString], @"Robert");
{
// preliminaries
id mock = nil;
-
+
// should throw (NSString instances do not respond to -stringWithString)
// they do respond to the +stringWithString class method
mock = [WOObjectMock mockForClass:[NSString class]];
WO_TEST_THROWS([[mock accept] stringWithString:@"Hello"]);
WO_TEST_THROWS([mock stringWithString:@"Hello"]);
-
+
// should throw even for valid selectors if you haven't set them up first
mock = [WOObjectMock mockForClass:[NSString class]];
[[mock expect] lowercaseString]; // a valid NSString selector
WO_TEST_DOES_NOT_THROW([mock retain]); // ok (inherited from NSProxy)
WO_TEST_DOES_NOT_THROW([mock release]); // ok (inherited from NSProxy)
WO_TEST_THROWS([mock uppercaseString]); // fail (not explicitly expected)
-
+
// should throw for class methods
mock = [WOObjectMock mockForClass:[NSString class]];
WO_TEST_THROWS([[mock expect] stringWithString:@"foo"]);
WO_TEST_DOES_NOT_THROW([mock lowercaseString]); // you like... should work
[mock clear];
WO_TEST_THROWS([mock lowercaseString]); // but fail on clear
-
+
// should be able to clear and re-set the same selector (was a bug)
[[mock accept] lowercaseString];
WO_TEST_DOES_NOT_THROW([mock lowercaseString]);
[[mock accept] lowercaseString];
WO_TEST_DOES_NOT_THROW([mock lowercaseString]);
[mock clear];
-
+
// same for acceptOnce
[[mock acceptOnce] lowercaseString];
[mock clear];
WO_TEST_THROWS([mock lowercaseString]);
-
+
// expect
[[mock expect] lowercaseString];
[mock clear];
WO_TEST_THROWS([mock lowercaseString]);
-
+
// expectOnce
[[mock expectOnce] lowercaseString];
[mock clear];
WO_TEST_THROWS([mock lowercaseString]);
-
+
// expectInOrder
[[mock expectInOrder] lowercaseString];
[mock clear];
WO_TEST_THROWS([mock stringByAppendingString:@"bar"]);
WO_TEST_DOES_NOT_THROW([mock stringByAppendingString:@"foo"]);
WO_TEST_THROWS([mock stringByAppendingString:nil]);
-
+
// but should also be able to accept any argument
[mock clear];
[[[mock accept] anyArguments] stringByAppendingString:@"irrelevant"];
// unrecognised selector should always throw
WO_TEST_THROWS(objc_msgSend(mock, @selector(foobar)));
-
+
[mock setAcceptsByDefault:NO];
WO_TEST_THROWS([mock lowercaseString]);
}
WO_TEST_EQ([mock length], (unsigned int)20);
}
-#pragma mark -
+#pragma mark -
#pragma mark Low-level tests
- (void)testMock
{
// preliminaries
Class aClass = [self class];
-
+
// should raise if passed nil class
WO_TEST_THROWS([WOObjectMock mockForClass:nil]);
WO_TEST_THROWS([[[WOObjectMock alloc] initWithClass:nil] release]);
WO_TEST_DOES_NOT_THROW([WOObjectMock mockForClass:aClass]);
WO_TEST_DOES_NOT_THROW([[[WOObjectMock alloc] initWithClass:aClass] release]);
-
+
// test if passed a non-class object (ie. an instance)
-
- //
+
+ //
}
- (void)testObjectStub
// preliminaries
id stub = nil;
Class aClass = [self class];
-
+
// raise if initialized with nil class pointer
WO_TEST_DOES_NOT_THROW([WOObjectStub stubForClass:aClass withDelegate:nil]);
WO_TEST_THROWS([WOObjectStub stubForClass:nil withDelegate:nil]);
WO_TEST_DOES_NOT_THROW([[[WOObjectStub alloc] initWithClass:aClass delegate:nil] release]);
WO_TEST_THROWS([[[WOObjectStub alloc] initWithClass:nil delegate:nil] release]);
-
+
// test if passed a non-class object (ie. an instance)
-
-
+
+
// shouldn't crash even if passed non-NSObject descendant
-
-
+
+
// test hashes
-
+
// make sure methodSignatureForSelector: doesn't go into an infinite loop
- stub = [WOObjectStub stubForClass:[WOObjectStub class] withDelegate:nil];
+ stub = [WOObjectStub stubForClass:[WOObjectStub class] withDelegate:nil];
SEL selector = @selector(methodSignatureForSelector:);
WO_TEST_EQUAL([stub methodSignatureForSelector:selector], nil);
-
+
// not with subclasses either
-
-
+
+
// raise if returning: is invoked twice
stub = [WOObjectStub stubForClass:[NSString class] withDelegate:nil];
[stub lowercaseString];
WO_TEST_DOES_NOT_THROW([stub returning:@"foo"]);
WO_TEST_THROWS([stub returning:@"bar"]);
-
+
// raise if sent new message when message previously recorded
stub = [WOObjectStub stubForClass:[NSString class] withDelegate:nil];
WO_TEST_DOES_NOT_THROW([stub lowercaseString]);
WO_TEST_THROWS([stub lowercaseString]);
-
+
// raise if recordedInvocation called but no message previously recorded
WO_TEST_DOES_NOT_THROW(stub = [WOObjectStub stubForClass:aClass withDelegate:nil]);
WO_TEST_THROWS([stub recordedInvocation]);
-
+
// test automatic verify on dealloc
}
WOObjectStub *stub = nil;
WOObjectStub *otherStub = nil;
Class aClass = [self class];
-
+
// pointer equality
stub = [WOObjectStub stubForClass:aClass withDelegate:nil];
WO_TEST_EQUAL(stub, stub);
WO_TEST_TRUE([stub isEqual:stub]); // another way to write the same test
-
+
// compare against non-stub class
stub = [WOObjectStub stubForClass:aClass withDelegate:nil];
otherStub = (WOObjectStub *)@"foobar";
WO_TEST_NOT_EQUAL(stub, otherStub);
WO_TEST_FALSE([stub isEqual:otherStub]);
-
+
// comparison with nil
stub = [WOObjectStub stubForClass:aClass withDelegate:nil];
WO_TEST_NOT_EQUAL(stub, nil);
WO_TEST_NOT_EQUAL(nil, stub);
WO_TEST_FALSE([stub isEqual:nil]);
-
+
// same class, different instance
stub = [WOObjectStub stubForClass:aClass withDelegate:nil];
otherStub = [WOObjectStub stubForClass:aClass withDelegate:nil];
WO_TEST_EQUAL(stub, otherStub);
WO_TEST_TRUE([stub isEqual:otherStub]);
-
+
// stubs with mismatching classes
stub = [WOObjectStub stubForClass:aClass withDelegate:nil];
otherStub = [WOObjectStub stubForClass:[NSString class] withDelegate:nil];
// mismatching invocations
// mismatching return values
-
-
+
+
}
- (void)testNonExistentSelector
{
WO_TEST_START;
-
+
id mock = [WOObjectMock mockForClass:[NSString class]];
[mock setObjCTypes:@"@@:@" forSelector:@selector(totallyRandom:)];
// this causes a compiler warning
//[[[mock expect] returning:[NSValue WOTest_valueWithObject:@"bar"]] totallyRandom:@"foo"];
-
+
// so do it this way instead
id stub = [[mock expect] returning:[NSValue WOTest_valueWithObject:@"bar"]];
objc_msgSend(stub, @selector(totallyRandom:), @"foo");
-
+
// likewise, this causes a warning
- //WO_TEST_EQ([mock totallyRandom:@"foo"], @"bar");
-
+ //WO_TEST_EQ([mock totallyRandom:@"foo"], @"bar");
+
// so do it like this:
WO_TEST_EQ(objc_msgSend(mock, @selector(totallyRandom:), @"foo"), @"bar");
}
id mock = nil;
WOObjectStub *stub = nil;
NSValue *value = [NSValue WOTest_valueWithObject:@"foobar"];
-
+
// should raise if returning: invoked but return value already recorded
stub = [WOObjectStub stubForClass:[NSString class] withDelegate:nil];
WO_TEST_DOES_NOT_THROW([stub returning:value]);
WO_TEST_THROWS([stub returning:value]);
-
+
// should return expected value
mock = [WOObjectMock mockForClass:[NSString class]];
[[[mock accept] returning:value] lowercaseString];
NSException *exception = [NSException exceptionWithName:@"WOFooException"
reason:@"foo exception"
userInfo:nil];
-
+
// should raise if raising: invoked but exception already recorded
stub = [WOObjectStub stubForClass:[NSString class] withDelegate:nil];
WO_TEST_DOES_NOT_THROW([stub raising:exception]);
WO_TEST_THROWS([stub raising:exception]);
-
+
// try with different kind of exception object (not NSException)
stub = [WOObjectStub stubForClass:[NSString class] withDelegate:nil];
WO_TEST_DOES_NOT_THROW([stub raising:@"foo"]);
WO_TEST_THROWS([stub raising:@"bar"]);
-
- // should raise if raising: passed an object that does not respond to
+
+ // should raise if raising: passed an object that does not respond to
// retain, release or autorelease
WOLightweightRoot *root = [WOLightweightRoot newLightweightRoot];
stub = [WOObjectStub stubForClass:[NSString class] withDelegate:nil];
WO_TEST_THROWS([stub raising:root]);
[root dealloc];
-
+
// should raise expected exception
mock = [WOObjectMock mockForClass:[NSString class]];
[[[mock accept] raising:exception] lowercaseString];
WOProtocolStub *stub = [WOProtocolStub alloc];
WO_TEST_THROWS([stub initWithProtocol:NULL delegate:nil]);
[stub dealloc];
-
+
// otherwise works
stub = [WOProtocolStub alloc];
WO_TEST_DOES_NOT_THROW([stub initWithProtocol:@protocol(WOTest) delegate:nil]);
- (void)testMethodSignatureForSelector
{
// throws if selector not present in protocol, otherwise works
- WOProtocolStub *stub =
+ WOProtocolStub *stub =
[WOProtocolStub stubForProtocol:@protocol(NSCopying) withDelegate:nil];
WO_TEST_THROWS([stub methodSignatureForSelector:@selector(retain)]);
WO_TEST_DOES_NOT_THROW
// raises if sent nil
WO_TEST_THROWS([stub matchesInvocation:nil]);
-
+
// raises if no recorded invocation
NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:
[self methodSignatureForSelector:@selector(testMatchesInvocation)]];
WO_TEST_THROWS([stub matchesInvocation:invocation]);
[stub setInvocation:invocation];
WO_TEST_DOES_NOT_THROW([stub matchesInvocation:invocation]);
-
+
// test strict matching
-
-
+
+
// test loose matching (arguments not checked)
-
-
+
+
}
@end
// WOTest
//
// Created by Wincent Colaiuta on 15 December 2006.
-//
+//
// Copyright 2006-2007 Wincent Colaiuta.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
{
WOEmptyClassMethodInvocations =
[[NSMutableArray alloc] initWithCapacity:3];
- WOEmptyInstanceMethodInvocations =
+ WOEmptyInstanceMethodInvocations =
[[NSMutableArray alloc] initWithCapacity:3];
}
// cleanup
[WOEmptyClassMethodInvocations autorelease];
[WOEmptyInstanceMethodInvocations autorelease];
-
+
// were class methods called in order?
NSArray *expectedClassMethods = [NSArray arrayWithObjects:
@"preflight", @"testClassMethod", @"postflight", nil];
}
+ (void)preflight
-{
+{
[WOEmptyClassMethodInvocations addObject:NSStringFromSelector(_cmd)];
}
[WOEmptyClassMethodInvocations addObject:NSStringFromSelector(_cmd)];
}
-- (void)preflight
+- (void)preflight
{
[WOEmptyInstanceMethodInvocations addObject:NSStringFromSelector(_cmd)];
}
+ (id)new
{
- Class class = object_getClass(self);
- return class_createInstance(class, 0);
+ Class class = object_getClass(self);
+ return class_createInstance(class, 0);
}
- (void)dealloc
- forward:(SEL)sel :(marg_list)args
{
return self; // although it behaves equally if I return nil here
-
+
/*
-
+
TODO: figure out how to make it crash if you send it a selector it doesn't recognize
-
+
[Object crashes]; // crashes
[Protocol foobar]; // crashes (inherits behavior from Object)
[NSObject foobar]; // raises exception, selector not recognized
[WORootClass foobar]; // continues execution, no warning
-
+
*/
}
{
// seeding with 1 produces repeatable test results across runs
[WO_TEST_SHARED_INSTANCE seedRandomNumberGenerator:1];
-
+
// TODO: set up mock object here to expect that +testClassMethods gets run
}
+ (void)testClassMethods
-{
+{
// make sure that class methods run (not just instance methods)
// TODO: do I need a mock object here to test that the test is run?
WO_TEST_PASS;
NSSet *actualMethods =[NSSet setWithArray:
[WO_TEST_SHARED_INSTANCE testableMethodsFrom:[self class]]];
-
+
WO_TEST_EQ(expectedMethods, actualMethods);
//WO_TEST_ARRAYS_EQUAL(expectedMethods, actualMethods);
// TODO: write WO_TEST_SETS_EQUAL
// TODO: write shorthand macros for like WO_TEST_ARRAYS_EQ
-
+
WO_TEST_THROWS([WO_TEST_SHARED_INSTANCE runTestsForClassName:nil]);
WO_TEST_THROWS([WO_TEST_SHARED_INSTANCE runTestsForClass:nil]);
}
{
// should throw (but not crash) when passed an "id" instead of a "Class"
WO_TEST_THROWS([WO_TEST_SHARED_INSTANCE testableMethodsFrom:(Class)self]);
-
+
// should find class and instance methods beginning with "test"
NSSet *expectedMethods = [NSSet setWithObjects:
@"+testClassMethod", @"-testInstanceMethod", nil];
- (void)testPreAndPostflightMethods
{
/*
-
+
Testing whether methods get called in order requires some tricky runtime
hackery. First of all we start with the WOEmpty class which is not marked
with the WOTest protocol. This prevents its test methods from being run
until we are ready to run them.
-
+
We then add the marker protocol at runtime so that the tests can be run.
-
+
It would be nice to be able to use mock objects to verify that the methods
on the WOEmpty class are being called but unfortunately it's not possible
for two reasons: firstly, mock objects are just that (objects) whereas the
test running methods work at a very low level in the runtime we can't just
use a WOClassMock -- once again, a class mock is just an object whereas the
low-level test running methods work directly with classes in the runtime.
-
+
TODO: use objc_allocateClassPair() to create classes on the fly (better class mock implementation)
-
+
So we unfortunately have to upgrade WOEmpty to be a real stub and we can't
benefit from the shortcuts provided by the WOMock cluster.
-
+
The runtime hackery cannot be avoided by labelling the WOEmpty class with
the WOTest marker at compile time because we have no way of knowing the
order in which classes will be tested and so we cannot know when to fire
the verify method. The hackery is the only way in which we can have total
control over the timing of the WOEmpty tests.
-
+
*/
-
+
// confirm that WOEmpty does not conform to protocol
NSAssert([WOEmpty conformsToProtocol:@protocol(WOTest)] == NO, @"WOEmpty already conforms to WOTest protocol");
-
+
// build new protocol entry
Protocol *protocol = @protocol(WOTest);
struct objc_protocol_list *new;
NSAssert1(new != NULL, @"calloc() failed (size %d)", sizeof(struct objc_protocol_list));
new->count = 1;
new->list[0] = protocol;
- NSAssert(class_addProtocol([WOEmpty class], protocol), @"class_addProtocol failed");
- NSAssert([WOEmpty conformsToProtocol:@protocol(WOTest)], @"WOEmpty class does not conform to WOTest protocol");
-
+ NSAssert(class_addProtocol([WOEmpty class], protocol), @"class_addProtocol failed");
+ NSAssert([WOEmpty conformsToProtocol:@protocol(WOTest)], @"WOEmpty class does not conform to WOTest protocol");
+
// perform the actual "tests" (even though WOEmpty contains no real tests)
[WO_TEST_SHARED_INSTANCE runTestsForClass:[WOEmpty class]];
WO_TEST_DOES_NOT_THROW([WOEmpty verify]);
{
// should pass
WO_TEST_PASS;
-
+
// should fail
[WO_TEST_SHARED_INSTANCE setExpectFailures:YES];
WO_TEST_FAIL;
}
- (void)testBooleanTests
-{
+{
// should pass
WO_TEST_TRUE(YES);
WO_TEST_FALSE(NO);
// should fail
[WO_TEST_SHARED_INSTANCE setExpectFailures:YES];
-
+
WO_TEST_TRUE(NO);
WO_TEST_FALSE(YES);
-
+
[WO_TEST_SHARED_INSTANCE setExpectFailures:NO];
}
NSArray *array4 = [NSArray array];
NSArray *array5 = nil;
NSArray *array6 = nil;
-
+
WO_TEST_EQUAL(string1, string2);
WO_TEST_EQUAL(string2, string1); // order shouldn't matter
- WO_TEST_EQUAL(string5, string6); // nil equals nil
+ WO_TEST_EQUAL(string5, string6); // nil equals nil
WO_TEST_EQUAL(nil, nil);
WO_TEST_EQUAL(nil, string5);
WO_TEST_EQUAL(string5, nil);
WO_TEST_NOT_EQUAL(string5, string4);
WO_TEST_NOT_EQUAL(string5, string3);
WO_TEST_NOT_EQUAL(string3, string5);
-
+
WO_TEST_EQUAL(array1, array2);
WO_TEST_EQUAL(array2, array1);
WO_TEST_EQUAL(array5, array6);
WO_TEST_NOT_EQUAL(array5, array4);
WO_TEST_NOT_EQUAL(array5, array3);
WO_TEST_NOT_EQUAL(array3, array5);
-
+
WO_TEST_EQUAL(string5, array5); // (id)nil == (id)nil
WO_TEST_EQUAL(array5, string5);
WO_TEST_NOT_EQUAL(string4, array4);
- WO_TEST_NOT_EQUAL(array4, string4);
+ WO_TEST_NOT_EQUAL(array4, string4);
WO_TEST_NOT_EQUAL(string2, array2);
WO_TEST_NOT_EQUAL(array2, string2);
- WO_TEST_NOT_EQUAL(string1, array1);
+ WO_TEST_NOT_EQUAL(string1, array1);
WO_TEST_NOT_EQUAL(array1, string1);
-
+
// class objects
Class class1 = [NSString class];
Class class2 = [NSString class];
Class class4 = [NSDictionary class];
Class class5 = nil;
Class class6 = nil;
-
+
WO_TEST_EQUAL(class1, class2);
WO_TEST_EQUAL(class2, class1); // order shouldn't matter
WO_TEST_EQUAL(class5, class6); // nil equals nil
WO_TEST_NOT_EQUAL(class4, class3);
WO_TEST_NOT_EQUAL(class4, class5);
WO_TEST_NOT_EQUAL(class5, class4);
-
+
WO_TEST_NOT_EQUAL(string5, class5); // different types (even if both nil)
WO_TEST_NOT_EQUAL(class5, string5);
WO_TEST_NOT_EQUAL(string1, class1); // class obj is not an instance obj
WO_TEST_NOT_EQUAL(class1, string1);
WO_TEST_NOT_EQUAL(string4, class1); // even if instance obj is empty
WO_TEST_NOT_EQUAL(class1, string4);
-
+
// selectors
SEL selector1 = @selector(stringWithString:);
SEL selector2 = @selector(stringWithString:);
SEL selector3 = @selector(init);
SEL selector4 = NULL;
SEL selector5 = NULL;
-
+
WO_TEST_EQUAL(selector1, selector2);
WO_TEST_EQUAL(selector2, selector1);
WO_TEST_NOT_EQUAL(selector2, selector3);
WO_TEST_NOT_EQUAL(selector4, selector3);
WO_TEST_EQUAL(selector4, selector5);
WO_TEST_EQUAL(selector5, selector4);
-
- WO_TEST_NOT_EQUAL(selector1, class1); // different types
+
+ WO_TEST_NOT_EQUAL(selector1, class1); // different types
WO_TEST_NOT_EQUAL(class1, selector1);
WO_TEST_NOT_EQUAL(selector1, string1);
WO_TEST_NOT_EQUAL(string1, selector1);
WO_TEST_NOT_EQUAL(class5, selector5);
WO_TEST_NOT_EQUAL(selector5, string6);
WO_TEST_NOT_EQUAL(string6, selector5);
-
+
// values of matching types
char char1 = 'a';
char char2 = 'a';
WO_TEST_NOT_EQUAL(int3, int2);
// need to test all of the different kinds of casts
-
-
+
+
// char, char
// char, int
// char, short
// char, double
// char, C99 _Bool
// char, void *
- // char, char *
-
-
+ // char, char *
+
+
// int, char
// int, int
// int, short
// int, double
// int, C99 _Bool
// int, void *
- // int, char *
-
+ // int, char *
+
// short, char
// short, int
// short, short
// short, double
// short, C99 _Bool
// short, void *
- // short, char *
-
+ // short, char *
+
// long, char
// long, int
// long, short
// long, double
// long, C99 _Bool
// long, void *
- // long, char *
+ // long, char *
// long long, char
// long long, int
// long long, double
// long long, C99 _Bool
// long long, void *
- // long long, char *
+ // long long, char *
// unsigned char, char
// unsigned char, int
// unsigned char, double
// unsigned char, C99 _Bool
// unsigned char, void *
- // unsigned char, char *
+ // unsigned char, char *
// unsigned int, char
// unsigned int, int
// unsigned int, double
// unsigned int, C99 _Bool
// unsigned int, void *
- // unsigned int, char *
+ // unsigned int, char *
// unsigned short, char
// unsigned short, int
// unsigned short, double
// unsigned short, C99 _Bool
// unsigned short, void *
- // unsigned short, char *
+ // unsigned short, char *
// unsigned long, char
// unsigned long, int
// unsigned long, double
// unsigned long, C99 _Bool
// unsigned long, void *
- // unsigned long, char *
+ // unsigned long, char *
// unsigned long long, char
// unsigned long long, int
// unsigned long long, double
// unsigned long long, C99 _Bool
// unsigned long long, void *
- // unsigned long long, char *
+ // unsigned long long, char *
// float, char
// float, int
// float, double
// float, C99 _Bool
// float, void *
- // float, char *
+ // float, char *
// double, char
// double, int
// double, double
// double, C99 _Bool
// double, void *
- // double, char *
+ // double, char *
// C99 _Bool, char
// C99 _Bool, int
// C99 _Bool, double
// C99 _Bool, C99 _Bool
// C99 _Bool, void *
- // C99 _Bool, char *
+ // C99 _Bool, char *
// void *, char
// void *, int
// void *, double
// void *, C99 _Bool
// void *, void *
- // void *, char *
-
+ // void *, char *
+
// char *, char
// char *, int
// char *, short
// char *, double
// char *, C99 _Bool
// char *, void *
- // char *, char *
-
-
-
+ // char *, char *
+
+
+
// literal values
WO_TEST_EQUAL(1000, 1000);
WO_TEST_NOT_EQUAL(2000, 4000);
-
+
// literal values with casts
WO_TEST_EQUAL((float)10.0, (float)10.0);
WO_TEST_NOT_EQUAL((float)10.0, (float)200.0);
-
+
// literal values with mismatched casts
WO_TEST_EQUAL((int)100, (long)100);
WO_TEST_NOT_EQUAL((int)100, (long)1000);
// compound values (variables)
-
-
-
+
+
+
// compound values (literals)
-
-
-
+
+
+
// compound values (variables + literals)
-
+
// arrays
-
-
+
+
// structures
NSPoint point1 = {10.0f, 300.0f};
NSPoint point2 = {10.0f, 300.0f};
WO_TEST_NOT_EQUAL(size2, point2); // incompatible types
WO_TEST_NOT_EQUAL(size2, range2); // incompatible types
WO_TEST_NOT_EQUAL(size2, rect2); // incompatible types
-
+
// pointers
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
// >, <, >=, <=
char small = 'd';
char big = 'z';
char other = 'd';
-
+
WO_TEST_GREATER_THAN(big, small);
WO_TEST_NOT_GREATER_THAN(small, big);
WO_TEST_NOT_GREATER_THAN(small, other);
-
+
WO_TEST_LESS_THAN(small, big);
WO_TEST_NOT_LESS_THAN(big, small);
WO_TEST_NOT_LESS_THAN(small, other);
-
+
int negative = -100;
int middle = 50;
int positive = 75;
int otherMiddle = 50;
-
+
WO_TEST_GREATER_THAN(middle, negative);
WO_TEST_GREATER_THAN(positive, negative);
WO_TEST_GREATER_THAN(positive, middle);
-
+
WO_TEST_NOT_GREATER_THAN(middle, positive);
WO_TEST_NOT_GREATER_THAN(negative, middle);
WO_TEST_NOT_GREATER_THAN(negative, positive);
WO_TEST_NOT_GREATER_THAN(middle, otherMiddle);
-
+
WO_TEST_LESS_THAN(negative, middle);
WO_TEST_LESS_THAN(negative, positive);
WO_TEST_LESS_THAN(middle, positive);
-
+
WO_TEST_NOT_LESS_THAN(middle, negative);
WO_TEST_NOT_LESS_THAN(positive, middle);
WO_TEST_NOT_LESS_THAN(positive, negative);
WO_TEST_NOT_LESS_THAN(middle, otherMiddle);
-
+
// casts to signed types
WO_TEST_GREATER_THAN((short)big, (short)small);
WO_TEST_NOT_GREATER_THAN((short)small, (short)big);
WO_TEST_NOT_LESS_THAN((short)positive, (short)middle);
WO_TEST_NOT_LESS_THAN((short)positive, (short)negative);
WO_TEST_NOT_LESS_THAN((short)middle, (short)otherMiddle);
-
+
WO_TEST_GREATER_THAN((long)big, (long)small);
WO_TEST_NOT_GREATER_THAN((long)small, (long)big);
WO_TEST_NOT_GREATER_THAN((long)small, (long)other);
WO_TEST_NOT_LESS_THAN((long)positive, (long)middle);
WO_TEST_NOT_LESS_THAN((long)positive, (long)negative);
WO_TEST_NOT_LESS_THAN((long)middle, (long)otherMiddle);
-
+
WO_TEST_GREATER_THAN((long long)big, (long long)small);
WO_TEST_NOT_GREATER_THAN((long long)small, (long long)big);
WO_TEST_NOT_GREATER_THAN((long long)small, (long long)other);
WO_TEST_NOT_LESS_THAN((long long)positive, (long long)middle);
WO_TEST_NOT_LESS_THAN((long long)positive, (long long)negative);
WO_TEST_NOT_LESS_THAN((long long)middle, (long long)otherMiddle);
-
+
WO_TEST_GREATER_THAN((float)big, (float)small);
WO_TEST_NOT_GREATER_THAN((float)small, (float)big);
WO_TEST_NOT_GREATER_THAN((float)small, (float)other);
WO_TEST_NOT_LESS_THAN((float)positive, (float)middle);
WO_TEST_NOT_LESS_THAN((float)positive, (float)negative);
WO_TEST_NOT_LESS_THAN((float)middle, (float)otherMiddle);
-
+
WO_TEST_GREATER_THAN((double)big, (double)small);
WO_TEST_NOT_GREATER_THAN((double)small, (double)big);
WO_TEST_NOT_GREATER_THAN((double)small, (double)other);
WO_TEST_NOT_LESS_THAN((double)positive, (double)middle);
WO_TEST_NOT_LESS_THAN((double)positive, (double)negative);
WO_TEST_NOT_LESS_THAN((double)middle, (double)otherMiddle);
-
+
// casts to unsigned types
WO_TEST_GREATER_THAN((unsigned char)big, (unsigned char)small);
WO_TEST_NOT_GREATER_THAN((unsigned char)small, (unsigned char)big);
WO_TEST_LESS_THAN((unsigned char)middle, (unsigned char)positive);
WO_TEST_NOT_LESS_THAN((unsigned char)positive, (unsigned char)middle);
WO_TEST_NOT_LESS_THAN((unsigned char)middle, (unsigned char)otherMiddle);
-
+
WO_TEST_GREATER_THAN((unsigned int)big, (unsigned int)small);
WO_TEST_NOT_GREATER_THAN((unsigned int)small, (unsigned int)big);
WO_TEST_NOT_GREATER_THAN((unsigned int)small, (unsigned int)other);
WO_TEST_LESS_THAN((unsigned int)middle, (unsigned int)positive);
WO_TEST_NOT_LESS_THAN((unsigned int)positive, (unsigned int)middle);
WO_TEST_NOT_LESS_THAN((unsigned int)middle, (unsigned int)otherMiddle);
-
+
WO_TEST_GREATER_THAN((unsigned long)big, (unsigned long)small);
WO_TEST_NOT_GREATER_THAN((unsigned long)small, (unsigned long)big);
WO_TEST_NOT_GREATER_THAN((unsigned long)small, (unsigned long)other);
WO_TEST_LESS_THAN((unsigned long)middle, (unsigned long)positive);
WO_TEST_NOT_LESS_THAN((unsigned long)positive, (unsigned long)middle);
WO_TEST_NOT_LESS_THAN((unsigned long)middle, (unsigned long)otherMiddle);
-
+
WO_TEST_GREATER_THAN((unsigned short)big, (unsigned short)small);
WO_TEST_NOT_GREATER_THAN((unsigned short)small, (unsigned short)big);
WO_TEST_NOT_GREATER_THAN((unsigned short)small, (unsigned short)other);
WO_TEST_NOT_LESS_THAN((unsigned short)small, (unsigned short)other);
WO_TEST_GREATER_THAN((unsigned short)positive, (unsigned short)middle);
WO_TEST_NOT_GREATER_THAN((unsigned short)middle, (unsigned short)positive);
- WO_TEST_NOT_GREATER_THAN ((unsigned short)middle, (unsigned short)otherMiddle);
- WO_TEST_LESS_THAN((unsigned short)middle, (unsigned short)positive);
- WO_TEST_NOT_LESS_THAN((unsigned short)positive, (unsigned short)middle);
- WO_TEST_NOT_LESS_THAN((unsigned short)middle, (unsigned short)otherMiddle);
- WO_TEST_GREATER_THAN((unsigned long long)big, (unsigned long long)small);
- WO_TEST_NOT_GREATER_THAN ((unsigned long long)small, (unsigned long long)big);
+ WO_TEST_NOT_GREATER_THAN ((unsigned short)middle, (unsigned short)otherMiddle);
+ WO_TEST_LESS_THAN((unsigned short)middle, (unsigned short)positive);
+ WO_TEST_NOT_LESS_THAN((unsigned short)positive, (unsigned short)middle);
+ WO_TEST_NOT_LESS_THAN((unsigned short)middle, (unsigned short)otherMiddle);
+ WO_TEST_GREATER_THAN((unsigned long long)big, (unsigned long long)small);
+ WO_TEST_NOT_GREATER_THAN ((unsigned long long)small, (unsigned long long)big);
WO_TEST_NOT_GREATER_THAN ((unsigned long long)small, (unsigned long long)other);
WO_TEST_LESS_THAN((unsigned long long)small, (unsigned long long)big);
WO_TEST_NOT_LESS_THAN((unsigned long long)big, (unsigned long long)small);
WO_TEST_NOT_LESS_THAN((unsigned long long)small, (unsigned long long)other);
- WO_TEST_GREATER_THAN ((unsigned long long)positive, (unsigned long long)middle);
- WO_TEST_NOT_GREATER_THAN ((unsigned long long)middle, (unsigned long long)positive);
- WO_TEST_NOT_GREATER_THAN ((unsigned long long)middle, (unsigned long long)otherMiddle);
- WO_TEST_LESS_THAN((unsigned long long)middle, (unsigned long long)positive);
+ WO_TEST_GREATER_THAN ((unsigned long long)positive, (unsigned long long)middle);
+ WO_TEST_NOT_GREATER_THAN ((unsigned long long)middle, (unsigned long long)positive);
+ WO_TEST_NOT_GREATER_THAN ((unsigned long long)middle, (unsigned long long)otherMiddle);
+ WO_TEST_LESS_THAN((unsigned long long)middle, (unsigned long long)positive);
WO_TEST_NOT_LESS_THAN ((unsigned long long)positive, (unsigned long long)middle);
WO_TEST_NOT_LESS_THAN((unsigned long long)middle, (unsigned long long)otherMiddle);
-
-
-
-
-
-
-
+
+
+
+
+
+
+
// casts to non-matching types
-
-
-
-
-
-
+
+
+
+
+
+
// objects: strings
WO_TEST_GREATER_THAN(@"foo", @"bar");
WO_TEST_GREATER_THAN(@"food", @"foo");
WO_TEST_NOT_LESS_THAN(@"foo", @"bar");
WO_TEST_NOT_LESS_THAN(@"foo", @"foo");
WO_TEST_NOT_LESS_THAN(@"food", @"foo");
-
+
// objects: numbers
NSNumber *smallNumber = [NSNumber numberWithInt:3];
NSNumber *bigNumber = [NSNumber numberWithFloat:10.0];
NSNumber *otherNumber = [NSNumber numberWithLongLong:10];
-
+
WO_TEST_GREATER_THAN(bigNumber, smallNumber);
WO_TEST_NOT_GREATER_THAN(smallNumber, bigNumber);
WO_TEST_NOT_GREATER_THAN(bigNumber, otherNumber);
-
+
WO_TEST_LESS_THAN(smallNumber, bigNumber);
WO_TEST_NOT_LESS_THAN(bigNumber, smallNumber);
WO_TEST_NOT_LESS_THAN(bigNumber, otherNumber);
-
+
// objects that don't implement compare: should raise exception
NSFileManager *manager = [NSFileManager defaultManager];
NSValue *managerValue = [NSValue valueWithNonretainedObject:manager];
NSString *compareString = @"hello";
- NSValue *stringValue = [NSValue valueWithNonretainedObject:compareString];
+ NSValue *stringValue = [NSValue valueWithNonretainedObject:compareString];
WO_TEST_THROWS([managerValue WOTest_compare:stringValue]);
-
+
// can't compare objects and non-objects
int scalar = 1234;
const void *scalarPtr = &scalar;
WO_TEST_THROWS([stringValue WOTest_compare:[NSValue value:scalarPtr withObjCType:@encode(typeof(scalar))]]);
WO_TEST_THROWS([stringValue WOTest_compare:[NSValue valueWithPoint:NSZeroPoint]]);
-
-
+
+
typeof(int) dastardlyScalar = 10000;
WO_TEST_THROWS
- ([[NSValue valueWithBytes:&dastardlyScalar
+ ([[NSValue valueWithBytes:&dastardlyScalar
objCType:@encode(int)] WOTest_testIsEqualToValue:[NSValue valueWithNonretainedObject:@"foo"]]);
-
+
typeof(nil) nilVar = nil;
NSValue *nilValue = [NSValue valueWithBytes:&nilVar objCType:@encode(typeof(nil))];
NSString *objectString = @"foo";
WO_TEST_TRUE([nonVoidValue WOTest_isObject]);
WO_TEST_DOES_NOT_THROW([nonVoidValue WOTest_testIsEqualToValue:nilValue]);
WO_TEST_DOES_NOT_THROW([nilValue WOTest_testIsEqualToValue:nonVoidValue]);
-
+
// can also compare pointers to void to nil
NSValue *objectValue = [NSValue valueWithNonretainedObject:[NSString stringWithFormat:@"bar"]];
WO_TEST_FALSE([objectValue WOTest_isObject]); // due to valueWithNonretainedObject
WO_TEST_TRUE([objectValue WOTest_isPointerToVoid]);
WO_TEST_DOES_NOT_THROW([objectValue WOTest_testIsEqualToValue:nilValue]);
WO_TEST_DOES_NOT_THROW([nilValue WOTest_testIsEqualToValue:objectValue]);
-
+
NSValue *realObjectValue = [NSValue valueWithNonretainedObject:[[[NSObject alloc] init] autorelease]];
WO_TEST_FALSE([realObjectValue WOTest_isObject]);
WO_TEST_TRUE([realObjectValue WOTest_isPointerToVoid]);
WO_TEST_DOES_NOT_THROW([realObjectValue WOTest_testIsEqualToValue:nilValue]);
WO_TEST_DOES_NOT_THROW([nilValue WOTest_testIsEqualToValue:realObjectValue]);
-
+
NSValue *otherValue = [NSValue valueWithNonretainedObject:@"bar"];
WO_TEST_FALSE([otherValue WOTest_isObject]);
WO_TEST_TRUE([otherValue WOTest_isPointerToVoid]);
-
+
typeof("^v") myCoolVar = ("^v");
NSValue *charArray = [NSValue valueWithBytes:&myCoolVar objCType:@encode(typeof("^v"))];
WO_TEST_TRUE([charArray WOTest_isCharArray]);
WO_TEST_EQUAL([charArray WOTest_stringValue], @"^v");
-
+
char *constChar = "^v";
NSValue *constCharValue = [NSValue valueWithBytes:&constChar objCType:@encode(char*)];
WO_TEST_TRUE([constCharValue WOTest_isCharacterString]);
WO_TEST_EQUAL([constCharValue WOTest_stringValue], @"^v");
- WO_TEST_EQUAL([charArray WOTest_stringValue], [constCharValue WOTest_stringValue]);
-
+ WO_TEST_EQUAL([charArray WOTest_stringValue], [constCharValue WOTest_stringValue]);
+
WO_TEST_EQUAL([otherValue objCType], "^v");
-
+
WO_TEST_EQUAL(strcmp([nilValue objCType], @encode(typeof(nil))), 0);
typeof(nil) otherNilVar = nil;
NSValue *otherNilValue = [NSValue valueWithBytes:&otherNilVar objCType:@encode(typeof(nil))];
WO_TEST_EQUAL([nilValue WOTest_compare:otherNilValue], NSOrderedSame);
WO_TEST_NOT_EQUAL([otherValue nonretainedObjectValue], nil);
- WO_TEST_DOES_NOT_THROW([nilValue WOTest_testIsEqualToValue:otherValue]);
-
+ WO_TEST_DOES_NOT_THROW([nilValue WOTest_testIsEqualToValue:otherValue]);
+
const char *constCharArray = "my char array";
char *nonConstCharArray = "my char array";
-
+
WO_TEST_EQUAL("my char array", "my char array");
WO_TEST_EQUAL(constCharArray, nonConstCharArray);
WO_TEST_EQUAL(nonConstCharArray, constCharArray);
WO_TEST_EQUAL(constCharArray, "my char array");
WO_TEST_NOT_EQUAL("my char array", "my other char array");
WO_TEST_NOT_EQUAL("hello", 0);
-
+
// should fail
[WO_TEST_SHARED_INSTANCE setExpectFailures:YES];
-
-
-
+
+
+
[WO_TEST_SHARED_INSTANCE setExpectFailures:NO]; // restore to default
}
- (void)testNSStringCategory
{
- // should pass
+ // should pass
NSString *string1 = @"Fun\n \nFun ";
NSString *string2 = @"Fun Fun ";
NSString *string3 = [string1 WOTest_stringByCollapsingWhitespace];
-
+
WO_TEST_EQUAL(string2, string3);
WO_TEST_EQUAL(string3, string2);
-
+
NSString *string4 = @"\n\r Not fun at all...";
NSString *string5 = @" Not fun at all...";
NSString *string6 = [string4 WOTest_stringByCollapsingWhitespace];
-
+
WO_TEST_EQUAL(string5, string6);
WO_TEST_EQUAL(string6, string5);
-
+
// should fail
[WO_TEST_SHARED_INSTANCE setExpectFailures:YES];
WO_TEST_NOT_EQUAL(string3, string2);
WO_TEST_NOT_EQUAL(string5, string6);
WO_TEST_NOT_EQUAL(string6, string5);
-
- [WO_TEST_SHARED_INSTANCE setExpectFailures:NO]; // restore to default
+
+ [WO_TEST_SHARED_INSTANCE setExpectFailures:NO]; // restore to default
}
- (void)testNSExceptionCategory
{
- NSException *exception1 =
+ NSException *exception1 =
[NSException exceptionWithName:@"foo" reason:@"bar" userInfo:nil];
WO_TEST_EQUAL([NSException WOTest_descriptionForException:exception1], @"foo: bar");
-
+
// NSImage responds to name but not reason
NSImage *exception2 = [[[NSImage alloc] initWithSize:NSZeroSize] autorelease];
[exception2 setName:@"Roger Smith"];
WO_TEST_EQUAL([NSException WOTest_descriptionForException:exception2],
([NSString stringWithFormat:@"%@ (%x)", [exception2 name], exception2]));
-
+
// NSObject responds to description but not to name or reason
NSObject *exception3 = [[[NSObject alloc] init] autorelease];
WO_TEST_EQUAL([NSException WOTest_descriptionForException:exception3], [exception3 description]);
-
+
WO_TEST_EQUAL([NSException WOTest_nameForException:nil], @"no exception");
WO_TEST_EQUAL([NSException WOTest_nameForException:@"hello"], @"hello");
-
+
// should fail
[WO_TEST_SHARED_INSTANCE setExpectFailures:YES];
-
+
WO_TEST_EQUAL([NSException WOTest_descriptionForException:exception1], @"welcome");
WO_TEST_NOT_EQUAL([NSException WOTest_descriptionForException:exception1], @"foo: bar");
-
+
WO_TEST_NOT_EQUAL([NSException WOTest_nameForException:nil], @"no exception");
WO_TEST_NOT_EQUAL([NSException WOTest_nameForException:@"hello"], @"hello");
-
- [WO_TEST_SHARED_INSTANCE setExpectFailures:NO]; // restore to default
+
+ [WO_TEST_SHARED_INSTANCE setExpectFailures:NO]; // restore to default
}
- (void)testPointerToVoidTests
{
// should pass
-
+
// should fail
[WO_TEST_SHARED_INSTANCE setExpectFailures:YES];
-
-
+
+
[WO_TEST_SHARED_INSTANCE setExpectFailures:NO]; // restore to default
}
- (void)testIntTests
{
// should pass
-
+
WO_TEST_IS_INT((int)-2000);
WO_TEST_IS_INT((int)-1000);
WO_TEST_IS_INT((int)-10);
WO_TEST_IS_NOT_INT((unsigned)1000);
WO_TEST_IS_NOT_INT((float)50000.0);
WO_TEST_IS_NOT_INT((double)1350000.0);
-
+
WO_TEST_INT_POSITIVE((int)1);
WO_TEST_INT_POSITIVE((int)2);
WO_TEST_INT_POSITIVE((int)5);
WO_TEST_INT_POSITIVE((int)1000);
WO_TEST_INT_POSITIVE((int)50000);
WO_TEST_INT_POSITIVE((int)1350000);
-
+
WO_TEST_INT_NEGATIVE((int)-1);
WO_TEST_INT_NEGATIVE((int)-2);
WO_TEST_INT_NEGATIVE((int)-5);
WO_TEST_INT_NEGATIVE((int)-1000);
WO_TEST_INT_NEGATIVE((int)-50000);
WO_TEST_INT_NEGATIVE((int)-1350000);
-
+
WO_TEST_INT_ZERO((int)0);
-
+
WO_TEST_INT_NOT_ZERO((int)1);
WO_TEST_INT_NOT_ZERO((int)2);
WO_TEST_INT_NOT_ZERO((int)200);
WO_TEST_INT_NOT_ZERO((int)-2);
WO_TEST_INT_NOT_ZERO((int)-200);
WO_TEST_INT_NOT_ZERO((int)-50000);
-
+
WO_TEST_INTS_EQUAL((int)0, (int)0);
WO_TEST_INTS_EQUAL((int)2, (int)2);
WO_TEST_INTS_EQUAL((int)20, (int)20);
WO_TEST_INTS_EQUAL((int)-100, (int)-100);
WO_TEST_INTS_EQUAL((int)-200, (int)-200);
WO_TEST_INTS_EQUAL((int)-1350000, (int)-1350000);
-
+
WO_TEST_INTS_NOT_EQUAL((int)1, (int)2);
WO_TEST_INTS_NOT_EQUAL((int)2, (int)1);
WO_TEST_INTS_NOT_EQUAL((int)10, (int)20);
WO_TEST_INTS_NOT_EQUAL((int)0, (int)-1);
WO_TEST_INTS_NOT_EQUAL((int)-10, (int)10);
WO_TEST_INTS_NOT_EQUAL((int)-100, (int)-200);
-
+
WO_TEST_INT_GREATER_THAN((int)1, (int)0);
WO_TEST_INT_GREATER_THAN((int)10, (int)5);
WO_TEST_INT_GREATER_THAN((int)0, (int)-5);
WO_TEST_INT_GREATER_THAN((int)1000, (int)999);
WO_TEST_INT_GREATER_THAN((int)1350000, (int)5000);
WO_TEST_INT_GREATER_THAN((int)5000000, (int)-5000000);
-
+
WO_TEST_INT_NOT_GREATER_THAN((int)1, (int)1);
WO_TEST_INT_NOT_GREATER_THAN((int)1, (int)2);
WO_TEST_INT_NOT_GREATER_THAN((int)0, (int)1);
WO_TEST_INT_NOT_GREATER_THAN((int)-500, (int)-400);
WO_TEST_INT_NOT_GREATER_THAN((int)-1600, (int)-1599);
WO_TEST_INT_NOT_GREATER_THAN((int)400, (int)400);
-
+
WO_TEST_INT_LESS_THAN((int)0, (int)1);
WO_TEST_INT_LESS_THAN((int)1, (int)2);
WO_TEST_INT_LESS_THAN((int)-1, (int)0);
WO_TEST_INT_LESS_THAN((int)1000, (int)1001);
WO_TEST_INT_LESS_THAN((int)1350, (int)1000000);
WO_TEST_INT_LESS_THAN((int)-5000000, (int)1);
-
+
WO_TEST_INT_NOT_LESS_THAN((int)0, (int)0);
WO_TEST_INT_NOT_LESS_THAN((int)1, (int)0);
WO_TEST_INT_NOT_LESS_THAN((int)2, (int)1);
WO_TEST_INT_NOT_LESS_THAN((int)2000, (int)1000);
WO_TEST_INT_NOT_LESS_THAN((int)5000, (int)5000);
WO_TEST_INT_NOT_LESS_THAN((int)-10000, (int)-12000);
-
+
// should fail
[WO_TEST_SHARED_INSTANCE setExpectFailures:YES];
WO_TEST_IS_INT((unsigned)1000);
WO_TEST_IS_INT((unsigned)50000);
WO_TEST_IS_INT((unsigned)1350000);
-
+
WO_TEST_IS_NOT_INT((int)-2000);
WO_TEST_IS_NOT_INT((int)-1000);
WO_TEST_IS_NOT_INT((int)-10);
WO_TEST_IS_NOT_INT((int)1000);
WO_TEST_IS_NOT_INT((int)50000);
WO_TEST_IS_NOT_INT((int)1350000);
-
+
WO_TEST_INT_POSITIVE((int)0);
WO_TEST_INT_POSITIVE((int)-2);
WO_TEST_INT_POSITIVE((int)-5);
WO_TEST_INT_POSITIVE((int)-1000);
WO_TEST_INT_POSITIVE((int)-50000);
WO_TEST_INT_POSITIVE((int)-1350000);
-
+
WO_TEST_INT_NEGATIVE((int)0);
WO_TEST_INT_NEGATIVE((int)2);
WO_TEST_INT_NEGATIVE((int)5);
WO_TEST_INT_NEGATIVE((int)1000);
WO_TEST_INT_NEGATIVE((int)50000);
WO_TEST_INT_NEGATIVE((int)1350000);
-
+
WO_TEST_INT_ZERO((int)1);
WO_TEST_INT_ZERO((int)2);
WO_TEST_INT_ZERO((int)200);
WO_TEST_INT_ZERO((int)-2);
WO_TEST_INT_ZERO((int)-200);
WO_TEST_INT_ZERO((int)-50000);
-
+
WO_TEST_INT_NOT_ZERO((int)0);
-
+
WO_TEST_INTS_EQUAL((int)0, (int)10);
WO_TEST_INTS_EQUAL((int)2, (int)1);
WO_TEST_INTS_EQUAL((int)20, (int)-20);
WO_TEST_INT_GREATER_THAN((int)999, (int)1000);
WO_TEST_INT_GREATER_THAN((int)1350000, (int)5000000);
WO_TEST_INT_GREATER_THAN((int)-5000000, (int)5000000);
-
+
WO_TEST_INT_NOT_GREATER_THAN((int)1, (int)0);
WO_TEST_INT_NOT_GREATER_THAN((int)2, (int)1);
WO_TEST_INT_NOT_GREATER_THAN((int)1, (int)-10);
WO_TEST_INT_NOT_GREATER_THAN((int)-400, (int)-500);
WO_TEST_INT_NOT_GREATER_THAN((int)-1599, (int)-1600);
WO_TEST_INT_NOT_GREATER_THAN((int)400, (int)1);
-
+
WO_TEST_INT_LESS_THAN((int)1, (int)0);
WO_TEST_INT_LESS_THAN((int)2, (int)1);
WO_TEST_INT_LESS_THAN((int)0, (int)-1);
WO_TEST_INT_LESS_THAN((int)1001, (int)1000);
WO_TEST_INT_LESS_THAN((int)1000000, (int)1350);
WO_TEST_INT_LESS_THAN((int)1, (int)-5000000);
-
+
WO_TEST_INT_NOT_LESS_THAN((int)0, (int)1);
WO_TEST_INT_NOT_LESS_THAN((int)1, (int)2);
WO_TEST_INT_NOT_LESS_THAN((int)2, (int)3);
WO_TEST_INT_NOT_LESS_THAN((int)1000, (int)2000);
WO_TEST_INT_NOT_LESS_THAN((int)2000, (int)5000);
WO_TEST_INT_NOT_LESS_THAN((int)-16000, (int)-12000);
-
+
[WO_TEST_SHARED_INSTANCE setExpectFailures:NO]; // restore to default
}
- (void)testUnsignedTests
{
// should pass
-
+
WO_TEST_UNSIGNED_ZERO((unsigned)0);
-
+
WO_TEST_UNSIGNED_NOT_ZERO((unsigned)1);
WO_TEST_UNSIGNED_NOT_ZERO((unsigned)2);
WO_TEST_UNSIGNED_NOT_ZERO((unsigned)200);
WO_TEST_UNSIGNED_NOT_ZERO((unsigned)65200);
WO_TEST_UNSIGNED_NOT_ZERO((unsigned)100000);
WO_TEST_UNSIGNED_NOT_ZERO((unsigned)5000000);
-
+
WO_TEST_UNSIGNEDS_EQUAL((unsigned)0, (unsigned)0);
WO_TEST_UNSIGNEDS_EQUAL((unsigned)2, (unsigned)2);
WO_TEST_UNSIGNEDS_EQUAL((unsigned)20, (unsigned)20);
WO_TEST_UNSIGNEDS_EQUAL((unsigned)23000, (unsigned)23000);
WO_TEST_UNSIGNEDS_EQUAL((unsigned)165200, (unsigned)165200);
WO_TEST_UNSIGNEDS_EQUAL((unsigned)1350000, (unsigned)1350000);
-
+
WO_TEST_UNSIGNEDS_NOT_EQUAL((unsigned)1, (unsigned)2);
WO_TEST_UNSIGNEDS_NOT_EQUAL((unsigned)2, (unsigned)1);
WO_TEST_UNSIGNEDS_NOT_EQUAL((unsigned)10, (unsigned)20);
WO_TEST_UNSIGNEDS_NOT_EQUAL((unsigned)0, (unsigned)1);
WO_TEST_UNSIGNEDS_NOT_EQUAL((unsigned)10, (unsigned)1230);
WO_TEST_UNSIGNEDS_NOT_EQUAL((unsigned)100, (unsigned)200);
-
+
WO_TEST_UNSIGNED_GREATER_THAN((unsigned)1, (unsigned)0);
WO_TEST_UNSIGNED_GREATER_THAN((unsigned)10, (unsigned)5);
WO_TEST_UNSIGNED_GREATER_THAN((unsigned)6, (unsigned)5);
WO_TEST_UNSIGNED_GREATER_THAN((unsigned)1000, (unsigned)999);
WO_TEST_UNSIGNED_GREATER_THAN((unsigned)1350000, (unsigned)5000);
WO_TEST_UNSIGNED_GREATER_THAN((unsigned)5000000, (unsigned)50);
-
+
WO_TEST_UNSIGNED_NOT_GREATER_THAN((unsigned)1, (unsigned)1);
WO_TEST_UNSIGNED_NOT_GREATER_THAN((unsigned)1, (unsigned)2);
WO_TEST_UNSIGNED_NOT_GREATER_THAN((unsigned)0, (unsigned)1);
WO_TEST_UNSIGNED_NOT_GREATER_THAN((unsigned)500, (unsigned)4500);
WO_TEST_UNSIGNED_NOT_GREATER_THAN((unsigned)1599, (unsigned)1600);
WO_TEST_UNSIGNED_NOT_GREATER_THAN((unsigned)400, (unsigned)400);
-
+
WO_TEST_UNSIGNED_LESS_THAN((unsigned)0, (unsigned)1);
WO_TEST_UNSIGNED_LESS_THAN((unsigned)1, (unsigned)2);
WO_TEST_UNSIGNED_LESS_THAN((unsigned)1, (unsigned)1200);
WO_TEST_UNSIGNED_LESS_THAN((unsigned)1000, (unsigned)1001);
WO_TEST_UNSIGNED_LESS_THAN((unsigned)1350, (unsigned)1000000);
WO_TEST_UNSIGNED_LESS_THAN((unsigned)5000000, (unsigned)10000000);
-
+
WO_TEST_UNSIGNED_NOT_LESS_THAN((unsigned)0, (unsigned)0);
WO_TEST_UNSIGNED_NOT_LESS_THAN((unsigned)1, (unsigned)0);
WO_TEST_UNSIGNED_NOT_LESS_THAN((unsigned)2, (unsigned)1);
WO_TEST_UNSIGNED_NOT_LESS_THAN((unsigned)2000, (unsigned)1000);
WO_TEST_UNSIGNED_NOT_LESS_THAN((unsigned)5000, (unsigned)5000);
WO_TEST_UNSIGNED_NOT_LESS_THAN((unsigned)12000, (unsigned)10000);
-
+
// should fail
[WO_TEST_SHARED_INSTANCE setExpectFailures:YES];
-
+
WO_TEST_UNSIGNED_ZERO((unsigned)1);
WO_TEST_UNSIGNED_ZERO((unsigned)2);
WO_TEST_UNSIGNED_ZERO((unsigned)200);
WO_TEST_UNSIGNED_ZERO((unsigned)20);
WO_TEST_UNSIGNED_ZERO((unsigned)2000);
WO_TEST_UNSIGNED_ZERO((unsigned)500000);
-
+
WO_TEST_UNSIGNED_NOT_ZERO((unsigned)0);
-
+
WO_TEST_UNSIGNEDS_EQUAL((unsigned)0, (unsigned)10);
WO_TEST_UNSIGNEDS_EQUAL((unsigned)2, (unsigned)1);
WO_TEST_UNSIGNEDS_EQUAL((unsigned)20, (unsigned)21);
WO_TEST_UNSIGNED_GREATER_THAN((unsigned)999, (unsigned)1000);
WO_TEST_UNSIGNED_GREATER_THAN((unsigned)1350000, (unsigned)5000000);
WO_TEST_UNSIGNED_GREATER_THAN((unsigned)5000000, (unsigned)5000000);
-
+
WO_TEST_UNSIGNED_NOT_GREATER_THAN((unsigned)1, (unsigned)0);
WO_TEST_UNSIGNED_NOT_GREATER_THAN((unsigned)2, (unsigned)1);
WO_TEST_UNSIGNED_NOT_GREATER_THAN((unsigned)11, (unsigned)10);
WO_TEST_UNSIGNED_NOT_GREATER_THAN((unsigned)600, (unsigned)599);
WO_TEST_UNSIGNED_NOT_GREATER_THAN((unsigned)1600, (unsigned)1599);
WO_TEST_UNSIGNED_NOT_GREATER_THAN((unsigned)400, (unsigned)1);
-
+
WO_TEST_UNSIGNED_LESS_THAN((unsigned)1, (unsigned)0);
WO_TEST_UNSIGNED_LESS_THAN((unsigned)2, (unsigned)1);
WO_TEST_UNSIGNED_LESS_THAN((unsigned)0, (unsigned)0);
WO_TEST_UNSIGNED_LESS_THAN((unsigned)1001, (unsigned)1000);
WO_TEST_UNSIGNED_LESS_THAN((unsigned)1000000, (unsigned)1350);
WO_TEST_UNSIGNED_LESS_THAN((unsigned)12, (unsigned)4);
-
+
WO_TEST_UNSIGNED_NOT_LESS_THAN((unsigned)0, (unsigned)1);
WO_TEST_UNSIGNED_NOT_LESS_THAN((unsigned)1, (unsigned)2);
WO_TEST_UNSIGNED_NOT_LESS_THAN((unsigned)2, (unsigned)3);
WO_TEST_UNSIGNED_NOT_LESS_THAN((unsigned)1000, (unsigned)2000);
WO_TEST_UNSIGNED_NOT_LESS_THAN((unsigned)2000, (unsigned)5000);
WO_TEST_UNSIGNED_NOT_LESS_THAN((unsigned)16000, (unsigned)18000);
-
+
[WO_TEST_SHARED_INSTANCE setExpectFailures:NO]; // restore to default
}
- (void)testFloatTests
{
// should pass
-
+
WO_TEST_FLOAT_POSITIVE((float)1);
WO_TEST_FLOAT_POSITIVE((float)2);
WO_TEST_FLOAT_POSITIVE((float)5);
WO_TEST_FLOAT_POSITIVE((float)1000);
WO_TEST_FLOAT_POSITIVE((float)50000);
WO_TEST_FLOAT_POSITIVE((float)1350000);
-
+
WO_TEST_FLOAT_NEGATIVE((float)-1);
WO_TEST_FLOAT_NEGATIVE((float)-2);
WO_TEST_FLOAT_NEGATIVE((float)-5);
WO_TEST_FLOAT_NEGATIVE((float)-1000);
WO_TEST_FLOAT_NEGATIVE((float)-50000);
WO_TEST_FLOAT_NEGATIVE((float)-1350000);
-
+
WO_TEST_FLOAT_ZERO((float)0);
-
+
WO_TEST_FLOAT_NOT_ZERO((float)1);
WO_TEST_FLOAT_NOT_ZERO((float)2);
WO_TEST_FLOAT_NOT_ZERO((float)200);
WO_TEST_FLOAT_NOT_ZERO((float)-2);
WO_TEST_FLOAT_NOT_ZERO((float)-200);
WO_TEST_FLOAT_NOT_ZERO((float)-50000);
-
+
WO_TEST_FLOATS_EQUAL((float)0, 0);
WO_TEST_FLOATS_EQUAL((float)2, 2);
WO_TEST_FLOATS_EQUAL((float)20, 20);
WO_TEST_FLOATS_EQUAL((float)-100, -100);
WO_TEST_FLOATS_EQUAL((float)-200, -200);
WO_TEST_FLOATS_EQUAL((float)-1350000, -1350000);
-
+
WO_TEST_FLOATS_NOT_EQUAL((float)1, 2);
WO_TEST_FLOATS_NOT_EQUAL((float)2, 1);
WO_TEST_FLOATS_NOT_EQUAL((float)10, 20);
WO_TEST_FLOATS_NOT_EQUAL((float)0, -1);
WO_TEST_FLOATS_NOT_EQUAL((float)-10, 10);
WO_TEST_FLOATS_NOT_EQUAL((float)-100, -200);
-
+
WO_TEST_FLOAT_GREATER_THAN((float)1, 0);
WO_TEST_FLOAT_GREATER_THAN((float)10, 5);
WO_TEST_FLOAT_GREATER_THAN((float)0, -5);
WO_TEST_FLOAT_GREATER_THAN((float)1000, 999);
WO_TEST_FLOAT_GREATER_THAN((float)1350000, 5000);
WO_TEST_FLOAT_GREATER_THAN((float)5000000, -5000000);
-
+
WO_TEST_FLOAT_NOT_GREATER_THAN((float)1, 1);
WO_TEST_FLOAT_NOT_GREATER_THAN((float)1, 2);
WO_TEST_FLOAT_NOT_GREATER_THAN((float)0, 1);
WO_TEST_FLOAT_NOT_GREATER_THAN((float)-500, -400);
WO_TEST_FLOAT_NOT_GREATER_THAN((float)-1600, -1599);
WO_TEST_FLOAT_NOT_GREATER_THAN((float)400, 400);
-
+
WO_TEST_FLOAT_LESS_THAN((float)0, 1);
WO_TEST_FLOAT_LESS_THAN((float)1, 2);
WO_TEST_FLOAT_LESS_THAN((float)-1, 0);
WO_TEST_FLOAT_LESS_THAN((float)1000, 1001);
WO_TEST_FLOAT_LESS_THAN((float)1350, 1000000);
WO_TEST_FLOAT_LESS_THAN((float)-5000000, 1);
-
+
WO_TEST_FLOAT_NOT_LESS_THAN((float)0, 0);
WO_TEST_FLOAT_NOT_LESS_THAN((float)1, 0);
WO_TEST_FLOAT_NOT_LESS_THAN((float)2, 1);
WO_TEST_FLOAT_NOT_LESS_THAN((float)-1, -2);
WO_TEST_FLOAT_NOT_LESS_THAN((float)2000, 1000);
WO_TEST_FLOAT_NOT_LESS_THAN((float)5000, 5000);
- WO_TEST_FLOAT_NOT_LESS_THAN((float)-10000, -12000);
-
+ WO_TEST_FLOAT_NOT_LESS_THAN((float)-10000, -12000);
+
// should fail
[WO_TEST_SHARED_INSTANCE setExpectFailures:YES];
-
-
+
+
[WO_TEST_SHARED_INSTANCE setExpectFailures:NO]; // restore to default
}
- (void)testFloatWithErrorMarginTests
{
// should pass
-
+
// should fail
[WO_TEST_SHARED_INSTANCE setExpectFailures:YES];
-
-
+
+
[WO_TEST_SHARED_INSTANCE setExpectFailures:NO]; // restore to default
}
- (void)testDoubleTests
{
// should pass
-
+
// should fail
[WO_TEST_SHARED_INSTANCE setExpectFailures:YES];
-
-
+
+
[WO_TEST_SHARED_INSTANCE setExpectFailures:NO]; // restore to default
}
- (void)testDoubleWithErrorMarginTests
{
// should pass
-
+
// should fail
[WO_TEST_SHARED_INSTANCE setExpectFailures:YES];
-
-
+
+
[WO_TEST_SHARED_INSTANCE setExpectFailures:NO]; // restore to default
}
{
// should pass
-
+
// should freak out if object does not conform to NSObject protocol
-
-
+
+
// should fail
[WO_TEST_SHARED_INSTANCE setExpectFailures:YES];
-
-
+
+
[WO_TEST_SHARED_INSTANCE setExpectFailures:NO]; // restore to default
}
- (void)testStringTests
{
// should pass
-
+
// should freak out if object does not conform to NSObject protocol
-
+
// should throw an exception when passed an object that is not a subclass of NSString
-
+
// specifically should throw an WO_TEST_CLASS_MISMATCH_EXCEPTION
-
+
// should handle nil string1
-
+
// should handle nil string2
-
+
// should handle nil string1 and nil string2
-
+
// should handle empty string1
-
+
// should handle empty string2
-
+
// should handle empty string1 and empty string2
// shorthand macros should work
-
-
+
+
// in the case of prefix, suffix and contains tests should die if passed nil "expected" parameter
-
+
// should fail
[WO_TEST_SHARED_INSTANCE setExpectFailures:YES];
-
-
+
+
[WO_TEST_SHARED_INSTANCE setExpectFailures:NO]; // restore to default
}
- (void)testArrayTests
{
// should pass
-
+
// should fail
[WO_TEST_SHARED_INSTANCE setExpectFailures:YES];
-
-
+
+
[WO_TEST_SHARED_INSTANCE setExpectFailures:NO]; // restore to default
}
- (void)testDictionaryTests
{
// should pass
-
+
// should fail
[WO_TEST_SHARED_INSTANCE setExpectFailures:YES];
-
-
+
+
[WO_TEST_SHARED_INSTANCE setExpectFailures:NO]; // restore to default
}
- (void)testShorthandMacros
{
// make sure that the shorthand and longhand test macros are equivalent
-
+
// should pass
WO_TEST_TRUE(YES);
WO_TEST(YES);
-
+
WO_TEST_EQUAL(100, 100);
WO_TEST_EQ(100, 100);
-
+
WO_TEST_NOT_EQUAL(100, 101);
WO_TEST_NE(100, 101);
-
+
WO_TEST_GREATER_THAN(200, 100);
WO_TEST_GT(200, 100);
-
+
WO_TEST_NOT_GREATER_THAN(100, 200);
WO_TEST_LTE(100, 200);
WO_TEST_NGT(100, 200);
-
+
WO_TEST_NOT_GREATER_THAN(100, 100);
WO_TEST_LTE(100, 100);
WO_TEST_NGT(100, 100);
-
+
WO_TEST_LESS_THAN(100, 200);
WO_TEST_LT(100, 200);
-
+
WO_TEST_NOT_LESS_THAN(200, 100);
WO_TEST_GTE(200, 100);
WO_TEST_NLT(200, 100);
// should fail
[WO_TEST_SHARED_INSTANCE setExpectFailures:YES];
-
+
WO_TEST_TRUE(NO);
WO_TEST(NO);
-
+
WO_TEST_EQUAL(100, 200);
WO_TEST_EQ(100, 200);
-
+
WO_TEST_NOT_EQUAL(100, 100);
WO_TEST_NE(100, 100);
-
+
WO_TEST_GREATER_THAN(100, 200);
WO_TEST_GT(100, 200);
-
+
WO_TEST_NOT_GREATER_THAN(200, 100);
WO_TEST_LTE(200, 100);
WO_TEST_NGT(200, 100);
-
+
WO_TEST_LESS_THAN(200, 100);
WO_TEST_LT(200, 100);
-
+
WO_TEST_NOT_LESS_THAN(100, 200);
WO_TEST_GTE(100, 200);
WO_TEST_NLT(100, 200);
-
- [WO_TEST_SHARED_INSTANCE setExpectFailures:NO]; // restore to default
+
+ [WO_TEST_SHARED_INSTANCE setExpectFailures:NO]; // restore to default
}
- (void)testExceptionTests
WO_TEST_THROWS([self raiseException]);
WO_TEST_THROWS([self throwWOEnigmaException]);
WO_TEST_THROWS([self throwString]);
-
- // BUG: busted on Leopard
- //WO_TEST_THROWS([self throwWORootClassObject]);
+
+ // BUG: busted on Leopard
+ //WO_TEST_THROWS([self throwWORootClassObject]);
WO_TEST_THROWS([self throwObject]);
WO_TEST_THROWS([self makeCocoaThrowException]);
WO_TEST_THROWS([self makeCocoaThrowNSRangeException]);
-
+
WO_TEST_DOES_NOT_THROW([self doNotThrowException]);
-
+
WO_TEST_THROWS_EXCEPTION_NAMED
([self throwWOEnigmaException], @"WOEnigmaException");
WO_TEST_THROWS_EXCEPTION_NAMED([self throwString], @"party");
-
+
WO_TEST_DOES_NOT_THROW_EXCEPTION_NAMED([self doNotThrowException], @"Roy");
WO_TEST_DOES_NOT_THROW_EXCEPTION_NAMED([self throwException], @"Other");
- // BUG: busted on Leopard
+ // BUG: busted on Leopard
//WO_TEST_DOES_NOT_THROW_EXCEPTION_NAMED([self throwWORootClassObject], @"x");
//WO_TEST_THROWS_EXCEPTION_NAMED([self throwWORootClassObject], @"WORootClass");
-
+
// should fail
[WO_TEST_SHARED_INSTANCE setExpectFailures:YES];
WO_TEST_DOES_NOT_THROW([self raiseException]);
WO_TEST_DOES_NOT_THROW([self throwWOEnigmaException]);
WO_TEST_DOES_NOT_THROW([self throwString]);
-
- // BUG: Busted on Leopard
- //WO_TEST_DOES_NOT_THROW([self throwWORootClassObject]);
+
+ // BUG: Busted on Leopard
+ //WO_TEST_DOES_NOT_THROW([self throwWORootClassObject]);
WO_TEST_DOES_NOT_THROW([self throwObject]);
WO_TEST_DOES_NOT_THROW([self makeCocoaThrowException]);
WO_TEST_DOES_NOT_THROW([self makeCocoaThrowNSRangeException]);
-
+
WO_TEST_THROWS([self doNotThrowException]);
-
+
WO_TEST_DOES_NOT_THROW_EXCEPTION_NAMED
([self throwWOEnigmaException], @"WOEnigmaException");
WO_TEST_DOES_NOT_THROW_EXCEPTION_NAMED([self throwString], @"party");
-
+
WO_TEST_THROWS_EXCEPTION_NAMED([self doNotThrowException], @"Roy");
WO_TEST_THROWS_EXCEPTION_NAMED([self throwException], @"Other");
-
- // BUG: busted on Leopard
+
+ // BUG: busted on Leopard
//WO_TEST_THROWS_EXCEPTION_NAMED([self throwWORootClassObject], @"x");
//WO_TEST_DOES_NOT_THROW_EXCEPTION_NAMED([self throwWORootClassObject], @"WORootClass");
-
+
[WO_TEST_SHARED_INSTANCE setExpectFailures:NO]; // restore to default
}
- (void)testLowLevelExceptionTests
{
- // BUG: this stuff busted on Leopard
- return;
-
+ // BUG: this stuff busted on Leopard
+ return;
+
[WO_TEST_SHARED_INSTANCE setExpectLowLevelExceptions:YES]; // will be reset to NO in preflight prior to next method
WO_TEST_PASS; // force update of "lastKnownLocation"
id *object = NULL; // cause a crash, but WOTest should keep running
{
// should pass
WO_TEST_PASS;
-
+
WO_TEST_IS_INT([WO_TEST_SHARED_INSTANCE anInt]);
WO_TEST_IS_INT([WO_TEST_SHARED_INSTANCE aPositiveInt]);
WO_TEST_IS_INT([WO_TEST_SHARED_INSTANCE aNegativeInt]);
WO_TEST_IS_INT([WO_TEST_SHARED_INSTANCE aSmallInt]);
WO_TEST_IS_INT([WO_TEST_SHARED_INSTANCE aSmallPositiveInt]);
WO_TEST_IS_INT([WO_TEST_SHARED_INSTANCE aSmallNegativeInt]);
-
+
WO_TEST_IS_UNSIGNED([WO_TEST_SHARED_INSTANCE anUnsigned]);
WO_TEST_IS_UNSIGNED([WO_TEST_SHARED_INSTANCE aZeroUnsigned]);
WO_TEST_IS_UNSIGNED([WO_TEST_SHARED_INSTANCE aBigUnsigned]);
WO_TEST_IS_UNSIGNED([WO_TEST_SHARED_INSTANCE aSmallUnsigned]);
-
+
WO_TEST_IS_FLOAT([WO_TEST_SHARED_INSTANCE aFloat]);
WO_TEST_IS_FLOAT([WO_TEST_SHARED_INSTANCE aPositiveFloat]);
WO_TEST_IS_FLOAT([WO_TEST_SHARED_INSTANCE aNegativeFloat]);
WO_TEST_IS_FLOAT([WO_TEST_SHARED_INSTANCE aSmallFloat]);
WO_TEST_IS_FLOAT([WO_TEST_SHARED_INSTANCE aSmallPositiveFloat]);
WO_TEST_IS_FLOAT([WO_TEST_SHARED_INSTANCE aSmallNegativeFloat]);
-
+
WO_TEST_IS_DOUBLE([WO_TEST_SHARED_INSTANCE aDouble]);
WO_TEST_IS_DOUBLE([WO_TEST_SHARED_INSTANCE aPositiveDouble]);
WO_TEST_IS_DOUBLE([WO_TEST_SHARED_INSTANCE aNegativeDouble]);
WO_TEST_IS_DOUBLE([WO_TEST_SHARED_INSTANCE aSmallDouble]);
WO_TEST_IS_DOUBLE([WO_TEST_SHARED_INSTANCE aSmallPositiveDouble]);
WO_TEST_IS_DOUBLE([WO_TEST_SHARED_INSTANCE aSmallNegativeDouble]);
-
+
WO_TEST_INT_POSITIVE([WO_TEST_SHARED_INSTANCE aPositiveInt]);
WO_TEST_INT_NEGATIVE([WO_TEST_SHARED_INSTANCE aNegativeInt]);
WO_TEST_INT_ZERO([WO_TEST_SHARED_INSTANCE aZeroInt]);
-
- WO_TEST_INT_NOT_LESS_THAN(abs([WO_TEST_SHARED_INSTANCE aBigInt]),
+
+ WO_TEST_INT_NOT_LESS_THAN(abs([WO_TEST_SHARED_INSTANCE aBigInt]),
(WO_BIG_TEST_VALUE - WO_RANDOMIZATION_RANGE));
WO_TEST_INT_NOT_LESS_THAN([WO_TEST_SHARED_INSTANCE aBigPositiveInt],
(WO_BIG_TEST_VALUE - WO_RANDOMIZATION_RANGE));
WO_TEST_INT_NOT_GREATER_THAN([WO_TEST_SHARED_INSTANCE aBigNegativeInt],
(-WO_BIG_TEST_VALUE + WO_RANDOMIZATION_RANGE));
-
+
WO_TEST_INT_NOT_LESS_THAN(abs([WO_TEST_SHARED_INSTANCE aSmallInt]),
(WO_SMALL_TEST_VALUE - WO_RANDOMIZATION_RANGE));
WO_TEST_INT_NOT_LESS_THAN([WO_TEST_SHARED_INSTANCE aSmallPositiveInt],
(WO_SMALL_TEST_VALUE - WO_RANDOMIZATION_RANGE));
WO_TEST_INT_NOT_GREATER_THAN([WO_TEST_SHARED_INSTANCE aSmallNegativeInt],
(-WO_SMALL_TEST_VALUE + WO_RANDOMIZATION_RANGE));
-
+
WO_TEST_UNSIGNED_ZERO([WO_TEST_SHARED_INSTANCE aZeroUnsigned]);
-
+
WO_TEST_UNSIGNED_NOT_LESS_THAN([WO_TEST_SHARED_INSTANCE aBigUnsigned],
(WO_BIG_TEST_VALUE - WO_RANDOMIZATION_RANGE));
-
+
WO_TEST_UNSIGNED_NOT_LESS_THAN([WO_TEST_SHARED_INSTANCE aSmallUnsigned],
- (WO_SMALL_TEST_VALUE - WO_RANDOMIZATION_RANGE));
-
+ (WO_SMALL_TEST_VALUE - WO_RANDOMIZATION_RANGE));
+
WO_TEST_FLOAT_POSITIVE([WO_TEST_SHARED_INSTANCE aPositiveFloat]);
WO_TEST_FLOAT_NEGATIVE([WO_TEST_SHARED_INSTANCE aNegativeFloat]);
WO_TEST_FLOAT_ZERO([WO_TEST_SHARED_INSTANCE aZeroFloat]);
-
- WO_TEST_FLOAT_NOT_LESS_THAN(fabsf([WO_TEST_SHARED_INSTANCE aBigFloat]),
+
+ WO_TEST_FLOAT_NOT_LESS_THAN(fabsf([WO_TEST_SHARED_INSTANCE aBigFloat]),
(WO_BIG_TEST_VALUE - WO_RANDOMIZATION_RANGE));
WO_TEST_FLOAT_NOT_LESS_THAN([WO_TEST_SHARED_INSTANCE aBigPositiveFloat],
(WO_BIG_TEST_VALUE - WO_RANDOMIZATION_RANGE));
WO_TEST_FLOAT_NOT_GREATER_THAN([WO_TEST_SHARED_INSTANCE aBigNegativeFloat],
(-WO_BIG_TEST_VALUE + WO_RANDOMIZATION_RANGE));
-
+
WO_TEST_FLOAT_NOT_LESS_THAN(fabsf([WO_TEST_SHARED_INSTANCE aSmallFloat]),
(WO_SMALL_TEST_VALUE - WO_RANDOMIZATION_RANGE));
WO_TEST_FLOAT_NOT_LESS_THAN([WO_TEST_SHARED_INSTANCE aSmallPositiveFloat],
(WO_SMALL_TEST_VALUE - WO_RANDOMIZATION_RANGE));
WO_TEST_FLOAT_NOT_GREATER_THAN([WO_TEST_SHARED_INSTANCE aSmallNegativeFloat],
(-WO_SMALL_TEST_VALUE + WO_RANDOMIZATION_RANGE));
-
+
WO_TEST_DOUBLE_POSITIVE([WO_TEST_SHARED_INSTANCE aPositiveDouble]);
WO_TEST_DOUBLE_NEGATIVE([WO_TEST_SHARED_INSTANCE aNegativeDouble]);
WO_TEST_DOUBLE_ZERO([WO_TEST_SHARED_INSTANCE aZeroDouble]);
-
- WO_TEST_DOUBLE_NOT_LESS_THAN(fabs([WO_TEST_SHARED_INSTANCE aBigDouble]),
+
+ WO_TEST_DOUBLE_NOT_LESS_THAN(fabs([WO_TEST_SHARED_INSTANCE aBigDouble]),
(WO_BIG_TEST_VALUE - WO_RANDOMIZATION_RANGE));
WO_TEST_DOUBLE_NOT_LESS_THAN([WO_TEST_SHARED_INSTANCE aBigPositiveDouble],
(WO_BIG_TEST_VALUE - WO_RANDOMIZATION_RANGE));
WO_TEST_DOUBLE_NOT_GREATER_THAN([WO_TEST_SHARED_INSTANCE aBigNegativeDouble],
(-WO_BIG_TEST_VALUE + WO_RANDOMIZATION_RANGE));
-
+
WO_TEST_DOUBLE_NOT_LESS_THAN(fabs([WO_TEST_SHARED_INSTANCE aSmallDouble]),
(WO_SMALL_TEST_VALUE - WO_RANDOMIZATION_RANGE));
WO_TEST_DOUBLE_NOT_LESS_THAN([WO_TEST_SHARED_INSTANCE aSmallPositiveDouble],
(WO_SMALL_TEST_VALUE - WO_RANDOMIZATION_RANGE));
WO_TEST_DOUBLE_NOT_GREATER_THAN([WO_TEST_SHARED_INSTANCE aSmallNegativeDouble],
(-WO_SMALL_TEST_VALUE + WO_RANDOMIZATION_RANGE));
-
+
// should fail
[WO_TEST_SHARED_INSTANCE setExpectFailures:YES];
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
[WO_TEST_SHARED_INSTANCE setExpectFailures:NO];
}
- (id)initWithClass:(Class)aClass
{
NSParameterAssert(aClass != NULL);
- NSParameterAssert([NSObject WOTest_isRegisteredClass:aClass]); // only registered classes pass (do not pass meta classes)
+ NSParameterAssert([NSObject WOTest_isRegisteredClass:aClass]); // only registered classes pass (do not pass meta classes)
if ((self = [super initWithClass:aClass]))
- [self setMockedClass:object_getClass(aClass)]; // look up the meta class and use that
+ [self setMockedClass:object_getClass(aClass)]; // look up the meta class and use that
return self;
}
+ (id)newLightweightRoot
{
- Class class = object_getClass(self);
- return class_createInstance(class, 0);
+ Class class = object_getClass(self);
+ return class_createInstance(class, 0);
}
- (void)dealloc
#import <Foundation/Foundation.h>
-/*!
+/*!
-There are a small number of methods defined in the WOMock class that you can use to create a mock object and then tell it how to behave. The accept, acceptOnce, reject, expect, expectOnce methods tell the mock object which selectors to accept, reject and expect.
+There are a small number of methods defined in the WOMock class that you can use to create a mock object and then tell it how to behave. The accept, acceptOnce, reject, expect, expectOnce methods tell the mock object which selectors to accept, reject and expect.
Each of these methods returns an object of type id which allows you to chain selectors together using the standard Objective-C pattern:
/*! Selectors that should be accepted. */
NSMutableSet *accepted;
-
+
/*! Selectors that should be accepted once only. */
NSMutableSet *acceptedOnce;
-
+
/*! Selectors that should be expected. */
NSMutableSet *expected;
-
+
/*! Selectors that should be expected once only. */
NSMutableSet *expectedOnce;
-
+
/*! Selectors that should be expected in a specific order. */
NSMutableArray *expectedInOrder;
/*! Selectors that should be rejected. */
- NSMutableSet *rejected;
-
+ NSMutableSet *rejected;
+
NSMutableDictionary *methodSignatures;
-
+
BOOL acceptsByDefault;
}
These are recording methods used for setting up expectations about which selectors should be rejected, accepted, accepted once, expected, expected once, or expected in order.
When the mock receives a message it checks its internal lists in the following order (in order of decreasing specificity):
-
+
-# rejected
-# expected in order
-# expected once
-# accepted
Rejected selectors cause an exception to be raised.
-
+
By default, if a selector does not appear in any of the internal lists an exception is raised. This latter behaviour requires you to be explicit about <em>all</em> selectors which a mock object may receive. For example, you may have a mock object that stands in for an NSString instance and expect that it be sent a "lowercaseString" selector. If during your test you also send an "uppercaseString" selector then an exception will be raised (because the selector does not appear in the internal lists, even though it is a valid NSString selector). A small number of methods will be accepted even without being explicitly added the the lists; these include methods like retain and release and other NSObject protocol methods. These are accepted because they are inherited from the parent class of WOMock (NSProxy).
-
+
If you wish to override this behaviour you may send the setAcceptsByDefault message passing a flag of YES, but be aware that selectors which fall through to the "accepts by default" cannot return any defined value. For control over return values the selector in question must be explicitly set up with the expectInOrder, expectOnce, expect, acceptOnce or accept methods.
-
+
If a selector does appear in the lists but has been set to throw an exception an exception will be raised. It is the responsibility of the caller to avoid ambiguous list membership; for example, it does not make any sense to add a selector to both the "expected once" and the "accepted" lists.
-
+
\startgroup
*/
/*! Instructs the receiver to accept a selector. The following example shows how to instruct the WOMock instance mock to accept the connect selector:
-
+
\code
[[mock accept] connect];
\endcode
\code
[[mock accept] connectTo:server] anyArguments];
\endcode
-
+
You can explicitly instruct a mock to reject selectors by using the reject method. Selectors added with the accept method will be accepted by the receiver at any time, in any order, until removed with the reject method.
See the WOMockTests class in WOTestSelfTests for usage examples.
-
+
\see WOStub::anyArguments */
- (id)accept;
If the selector takes arguments then the arguments passed to the mock must match those used when registering the selector with the expect method, otherwise an exception is raised. */
- (id)expect;
-/*! Instructs the receiver to expect the selector once and only once. If the selector is performed twice then the second invocation will cause an exception to be raised.
+/*! Instructs the receiver to expect the selector once and only once. If the selector is performed twice then the second invocation will cause an exception to be raised.
\see accept */
- (id)expectOnce;
/*! Instructs the receiver to expect the selector as part of an ordered sequence. You can build a list of expected selectors by repeatedly calling expectInOrder with the selectors that should appear in the sequence as illustrated in this example:
-
+
\code
[[mock expectInOrder] connect];
[[mock expectInOrder] logStats];
#pragma mark -
#pragma mark Accessors
-//! \name Accessor methods
+//! \name Accessor methods
//! Note that the majority of instance variables in this class do not have accessors so as to avoid namespace pollution.
-//! \startgroup
+//! \startgroup
- (BOOL)acceptsByDefault;
- (void)setAcceptsByDefault:(BOOL)flag;
{
// avoid infinite loops if called by subclass
if (self != [WOMock class])
- [NSException raise:NSInternalInconsistencyException format:@"mockForObjectClass: called from WOMock subclass"];
-
+ [NSException raise:NSInternalInconsistencyException format:@"mockForObjectClass: called from WOMock subclass"];
+
return [WOObjectMock mockForClass:aClass];
}
{
// avoid infinite loops if called by subclass
if (self != [WOMock class])
- [NSException raise:NSInternalInconsistencyException format:@"mockForClass: called from WOMock subclass"];
+ [NSException raise:NSInternalInconsistencyException format:@"mockForClass: called from WOMock subclass"];
return [WOClassMock mockForClass:aClass];
}
{
// avoid infinite loops if called by subclass
if (self != [WOMock class])
- [NSException raise:NSInternalInconsistencyException format:@"mockForProtocol: called from WOMock subclass"];
+ [NSException raise:NSInternalInconsistencyException format:@"mockForProtocol: called from WOMock subclass"];
return [WOProtocolMock mockForProtocol:aProtocol];
}
- (id)initWithObjectClass:(Class)aClass
{
// avoid infinite loops if called by subclass
- if ([self class] != [WOMock class])
+ if ([self class] != [WOMock class])
[NSException raise:NSInternalInconsistencyException format:@"initWithObjectClass: called from WOMock subclass"];
-
+
id subclass = [[WOObjectMock allocWithZone:[self zone]] initWithClass:aClass];
[self dealloc];
{
// avoid infinite loops if called by subclass
if ([self class] != [WOMock class])
- [NSException raise:NSInternalInconsistencyException format:@"initWithClass: called from WOMock subclass"];
-
- id subclass = [[WOClassMock allocWithZone:[self zone]] initWithClass:aClass];
+ [NSException raise:NSInternalInconsistencyException format:@"initWithClass: called from WOMock subclass"];
+
+ id subclass = [[WOClassMock allocWithZone:[self zone]] initWithClass:aClass];
[self dealloc];
- return subclass;
+ return subclass;
}
// a true Apple-style cluster would do this by allocating a placeholder object
{
// avoid infinite loops if called by subclass
if ([self class] != [WOMock class])
- [NSException raise:NSInternalInconsistencyException format:@"initWithProtocol: called from WOMock subclass"];
-
- id subclass = [[WOProtocolMock allocWithZone:[self zone]] initWithProtocol:aProtocol];
+ [NSException raise:NSInternalInconsistencyException format:@"initWithProtocol: called from WOMock subclass"];
+
+ id subclass = [[WOProtocolMock allocWithZone:[self zone]] initWithProtocol:aProtocol];
[self dealloc];
- return subclass;
+ return subclass;
}
- (id)init
- (id)accept
{
- [NSException raise:NSInternalInconsistencyException format:@"accept invoked on WOMock abstract class"];
+ [NSException raise:NSInternalInconsistencyException format:@"accept invoked on WOMock abstract class"];
return nil;
}
- (id)acceptOnce
{
- [NSException raise:NSInternalInconsistencyException format:@"acceptOnce invoked on WOMock abstract class"];
+ [NSException raise:NSInternalInconsistencyException format:@"acceptOnce invoked on WOMock abstract class"];
return nil;
}
- (id)reject
{
- [NSException raise:NSInternalInconsistencyException format:@"reject invoked on WOMock abstract class"];
+ [NSException raise:NSInternalInconsistencyException format:@"reject invoked on WOMock abstract class"];
return nil;
}
- (id)expect
{
- [NSException raise:NSInternalInconsistencyException format:@"expect invoked on WOMock abstract class"];
+ [NSException raise:NSInternalInconsistencyException format:@"expect invoked on WOMock abstract class"];
return nil;
}
- (id)expectOnce
{
- [NSException raise:NSInternalInconsistencyException format:@"expectOnce invoked on WOMock abstract class"];
+ [NSException raise:NSInternalInconsistencyException format:@"expectOnce invoked on WOMock abstract class"];
return nil;
}
- (id)expectInOrder
{
- [NSException raise:NSInternalInconsistencyException format:@"expectInOrder invoked on WOMock abstract class"];
+ [NSException raise:NSInternalInconsistencyException format:@"expectInOrder invoked on WOMock abstract class"];
return nil;
}
#pragma mark -
#pragma mark Utility methods
-- (void)storeReturnValue:(NSValue *)aValue forInvocation:(NSInvocation *)invocation
+- (void)storeReturnValue:(NSValue *)aValue forInvocation:(NSInvocation *)invocation
{
NSParameterAssert(invocation != nil);
if (!aValue) return; // nothing to do
size_t bufferSize = [aValue WOTest_bufferSize];
void *buffer = malloc(bufferSize);
- NSAssert1((buffer != NULL), @"malloc() failed (size %d)", bufferSize);
+ NSAssert1((buffer != NULL), @"malloc() failed (size %d)", bufferSize);
[aValue getValue:buffer];
[invocation setReturnValue:buffer];
}
- (void)setObjCTypes:(NSString *)types forSelector:(SEL)aSelector
{
- [methodSignatures setObject:[NSMethodSignature WOTest_signatureBasedOnObjCTypes:[types UTF8String]]
+ [methodSignatures setObject:[NSMethodSignature WOTest_signatureBasedOnObjCTypes:[types UTF8String]]
forKey:NSStringFromSelector(aSelector)];
}
// fallback to internal lookup
NSMethodSignature *signature = [methodSignatures objectForKey:NSStringFromSelector(sel)];
-
+
// at this point it would be great to be able to improvise but it's not possible to figure out an accurate method signature
NSAssert((signature != nil), ([NSString stringWithFormat:@"no method signature for selector %@", NSStringFromSelector(sel)]));
-
+
NSInvocation *forwardInvocation = [NSInvocation invocationWithMethodSignature:signature];
[forwardInvocation setSelector:sel];
-
+
// store arguments in invocation
int offset = 0;
for (unsigned i = 0, max = [signature numberOfArguments]; i < max; i++)
{
const char *type = [signature getArgumentTypeAtIndex:i]; // always id, SEL, ...
-
+
#if defined(__ppc__)
// TODO: finish version in WOStub and copy it here
// leave the compiler warnings about "unused variable 'type'" and "unused variable 'offset'" to remind me to do it
- // may be able to use libffi to help here
-
+ // may be able to use libffi to help here
+
#elif defined(__i386__)
-
+
// on i386 the marg_getRef macro and its helper, marg_adjustedOffset, should work fine
if (strcmp(type, @encode(id)) == 0)
{
[forwardInvocation WOTest_setArgumentValue:[NSValue valueWithBytes:ref objCType:type] atIndex:i];
}
else
- [NSException raise:NSGenericException format:@"type %s not supported", type];
-
+ [NSException raise:NSGenericException format:@"type %s not supported", type];
+
offset += [NSValue WOTest_sizeForType:[NSString stringWithUTF8String:type]];
-
+
#elif defined(__ppc64__)
// there is no objc-msg-ppc.s so for now just omit support rather than make assumptions
#error ppc64 not supported yet
-
+
#else
-
+
#error Unsupported architecture
-
+
#endif
-
+
}
[self forwardInvocation:forwardInvocation]; // stores return value in invocation
-
+
unsigned bufferSize = [signature methodReturnLength];
void *returnBuffer = malloc(bufferSize);
NSAssert1((returnBuffer != NULL), @"malloc() failed (size %d)", bufferSize);
[forwardInvocation getReturnValue:&returnBuffer];
return returnBuffer; // TODO: cast according to the return type
}
-
+
#pragma mark -
#pragma mark Accessors
#pragma mark Accessors
/*!
- \name Accessor methods
- \startgroup
+ \name Accessor methods
+ \startgroup
*/
- (Class)mockedClass;
NSParameterAssert([NSObject WOTest_isRegisteredClass:aClass]); // only registered classes pass (do not pass meta classes)
if ((self = [super init]))
- [self setMockedClass:aClass];
+ [self setMockedClass:aClass];
return self;
}
}
#pragma mark -
-#pragma mark Proxy methods
+#pragma mark Proxy methods
- (void)forwardInvocation:(NSInvocation *)anInvocation
{
NSParameterAssert(anInvocation != nil);
-
+
// check if in reject list
WO_ENUMERATE(rejected, stub)
if ([stub matchesInvocation:anInvocation])
NSStringFromSelector([anInvocation selector]), NSStringFromClass([self mockedClass])];
return;
}
-
+
// check if expectedInOrder
WO_ENUMERATE(expectedInOrder, stub)
if ([stub matchesInvocation:anInvocation])
{
NSAssert2(([expectedInOrder objectAtIndex:0] == stub), @"Invocation selector %@ class %@ received out of order",
NSStringFromSelector([anInvocation selector]), NSStringFromClass([self mockedClass]));
-
+
[expectedInOrder removeObjectAtIndex:0]; // if in order, remove from head of list
-
+
// and move to "accepted"
[accepted addObject:stub];
[self storeReturnValue:[stub returnValue] forInvocation:anInvocation];
if ([stub exception]) @throw [stub exception];
return;
}
-
+
// check if expected
WO_ENUMERATE(expected, stub)
if ([stub matchesInvocation:anInvocation])
if ([stub exception]) @throw [stub exception];
return;
}
-
+
// check if accepted once
WO_ENUMERATE(acceptedOnce, stub)
if ([stub matchesInvocation:anInvocation])
if ([stub exception]) @throw [stub exception];
return;
}
-
+
// check if accepted
WO_ENUMERATE(accepted, stub)
if ([stub matchesInvocation:anInvocation])
if ([stub exception]) @throw [stub exception];
return;
}
-
+
if ([self acceptsByDefault]) return;
-
+
// no matches! (should never get here)
[NSException raise:NSInternalInconsistencyException format:@"No matching invocations found (selector %@, class %@)",
NSStringFromSelector([anInvocation selector]), NSStringFromClass([self mockedClass])];
- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector
{
- // avoid an infinite loop (docs warn "Be sure to avoid an infinite loop when necessary by checking that aSelector isn't the
+ // avoid an infinite loop (docs warn "Be sure to avoid an infinite loop when necessary by checking that aSelector isn't the
// selector for this method itself and by not sending any message that might invoke this method.")
if (([self mockedClass] == [self class]) && (aSelector == _cmd)) return nil;
-
- // search only for instance methods here; forcing the programmer to use WOClassMock for searching for class methods avoids
+
+ // search only for instance methods here; forcing the programmer to use WOClassMock for searching for class methods avoids
// ambiguity in cases where an instance method and a class method share the same name
return [[self mockedClass] instanceMethodSignatureForSelector:aSelector];
}
@interface WOObjectStub : WOStub {
Class mockedClass;
-
+
}
#pragma mark -
- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector
{
- // avoid an infinite loop (docs warn "Be sure to avoid an infinite loop when necessary by checking that aSelector isn't the
+ // avoid an infinite loop (docs warn "Be sure to avoid an infinite loop when necessary by checking that aSelector isn't the
// selector for this method itself and by not sending any message that might invoke this method.")
if (([self mockedClass] == [self class]) && (aSelector == _cmd)) return nil;
-
+
// see if method really exists in mocked class, if not forward:: will have to do something special
return [[self mockedClass] instanceMethodSignatureForSelector:aSelector];
-}
+}
#pragma mark -
#pragma mark NSObject protocol
NSValue *otherValue = [anObject returnValue];
id thisException = [self exception];
id otherException = [anObject exception];
-
+
if ([self mockedClass] != [anObject mockedClass])
return NO;
-
+
if ([self acceptsAnyArguments] != [anObject acceptsAnyArguments])
return NO;
-
+
if (!thisInvocation && !otherInvocation) // both nil
invocationsAreEqual = YES;
else if (thisInvocation && otherInvocation) // both non-nil
else
invocationsAreEqual = [thisInvocation WOTest_isEqualToInvocation:otherInvocation];
}
-
+
if (!thisValue && !otherValue) // both nil
returnValuesAreEqual = YES;
else if (thisValue && otherValue) // both non-nil
returnValuesAreEqual = [thisValue isEqual:otherValue];
-
+
if (!thisException && !otherException) // both nil
exceptionsAreEqual = YES;
else if (thisException && otherException) // both non-nil
exceptionsAreEqual = [thisException isEqual:otherException];
-
- if (invocationsAreEqual && returnValuesAreEqual &&
+
+ if (invocationsAreEqual && returnValuesAreEqual &&
exceptionsAreEqual)
return YES;
}
@interface WOProtocolMock : WOMock {
Protocol *mockedProtocol;
-
+
}
#pragma mark -
NSString *WOStringFromProtocol(Protocol *aProtocol)
{
if (aProtocol == NULL) return nil;
- return [NSString stringWithUTF8String:protocol_getName(aProtocol)];
+ return [NSString stringWithUTF8String:protocol_getName(aProtocol)];
}
@implementation WOProtocolMock
NSParameterAssert(aProtocol != NULL);
// TODO: test for validity of the Protocol by checking with the runtime
-
+
if ((self = [super init]))
[self setMockedProtocol:aProtocol];
return self;
}
#pragma mark -
-#pragma mark Proxy methods
+#pragma mark Proxy methods
- (void)forwardInvocation:(NSInvocation *)anInvocation
{
NSParameterAssert(anInvocation != nil);
-
+
// check if in reject list
WO_ENUMERATE(rejected, stub)
if ([anInvocation WOTest_isEqualToInvocation:[stub recordedInvocation]])
NSStringFromSelector([anInvocation selector]), WOStringFromProtocol([self mockedProtocol])];
return;
}
-
+
// check if expectedInOrder
WO_ENUMERATE(expectedInOrder, stub)
if ([anInvocation WOTest_isEqualToInvocation:[stub recordedInvocation]])
{
NSAssert(([expectedInOrder objectAtIndex:0] != stub), @"invocation received out of order");
-
+
// if in order, remove from head of list
[expectedInOrder removeObjectAtIndex:0];
-
+
// and move to "accepted"
[accepted addObject:stub];
[self storeReturnValue:[stub returnValue] forInvocation:anInvocation];
if ([stub exception]) @throw [stub exception];
return;
}
-
+
// check if expected once
WO_ENUMERATE(expectedOnce, stub)
if ([anInvocation WOTest_isEqualToInvocation:[stub recordedInvocation]])
if ([stub exception]) @throw [stub exception];
return;
}
-
+
// check if expected
WO_ENUMERATE(expected, stub)
if ([anInvocation WOTest_isEqualToInvocation:[stub recordedInvocation]])
if ([stub exception]) @throw [stub exception];
return;
}
-
+
// check if accepted once
WO_ENUMERATE(acceptedOnce, stub)
if ([anInvocation WOTest_isEqualToInvocation:[stub recordedInvocation]])
if ([stub exception]) @throw [stub exception];
return;
}
-
+
// check if accepted
WO_ENUMERATE(accepted, stub)
if ([anInvocation WOTest_isEqualToInvocation:[stub recordedInvocation]])
if ([stub exception]) @throw [stub exception];
return;
}
-
-
+
+
if ([self acceptsByDefault]) return;
-
+
// no matches! (should never get here)
[NSException raise:NSInternalInconsistencyException format:@"No matching invocations found (selector %@, protocol %@)",
NSStringFromSelector([anInvocation selector]), WOStringFromProtocol([self mockedProtocol])];
- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector
{
- // avoid an infinite loop (docs warn "Be sure to avoid an infinite loop when necessary by checking that aSelector isn't the
+ // avoid an infinite loop (docs warn "Be sure to avoid an infinite loop when necessary by checking that aSelector isn't the
// selector for this method itself and by not sending any message that might invoke this method.")
if (aSelector == _cmd) return nil;
-
- BOOL isRequiredMethod = YES; // no idea what to pass here
- struct objc_method_description description = protocol_getMethodDescription([self mockedProtocol], aSelector, isRequiredMethod, YES);
+
+ BOOL isRequiredMethod = YES; // no idea what to pass here
+ struct objc_method_description description = protocol_getMethodDescription([self mockedProtocol], aSelector, isRequiredMethod, YES);
return [NSMethodSignature WOTest_signatureBasedOnObjCTypes:description.types];
}
- (Protocol *)mockedProtocol
{
- return mockedProtocol;
+ return mockedProtocol;
}
- (void)setMockedProtocol:(Protocol *)aMockedProtocol
@interface WOProtocolStub : WOStub {
Protocol *mockedProtocol;
-
+
}
#pragma mark -
- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector
{
// avoid an infinite loop (docs warn "Be sure to avoid an infinite loop when necessary by checking that aSelector isn't the
- // selector for this method itself and by not sending any message that might invoke this method.")
+ // selector for this method itself and by not sending any message that might invoke this method.")
if (aSelector == _cmd) return nil;
- Protocol *protocol = [self mockedProtocol];
- BOOL isRequiredMethod = YES; // no idea what to pass here
- struct objc_method_description description = protocol_getMethodDescription(protocol, aSelector, isRequiredMethod, YES);
-
- // TODO: not sure how to test for missing method signatures... protocol_getMethodDescription() is not documented
- if (description.name == NULL)
+ Protocol *protocol = [self mockedProtocol];
+ BOOL isRequiredMethod = YES; // no idea what to pass here
+ struct objc_method_description description = protocol_getMethodDescription(protocol, aSelector, isRequiredMethod, YES);
+
+ // TODO: not sure how to test for missing method signatures... protocol_getMethodDescription() is not documented
+ if (description.name == NULL)
[NSException raise:NSInternalInconsistencyException format:@"No method signature for selector %@ in %@ protocol",
- NSStringFromSelector(aSelector), WOStringFromProtocol(protocol)];
+ NSStringFromSelector(aSelector), WOStringFromProtocol(protocol)];
return [NSMethodSignature WOTest_signatureBasedOnObjCTypes:description.types];
-}
+}
#pragma mark -
#pragma mark NSObject protocol
NSValue *otherValue = [anObject returnValue];
id thisException = [self exception];
id otherException = [anObject exception];
-
+
if ([self mockedProtocol] != [anObject mockedProtocol])
return NO;
-
+
if ([self acceptsAnyArguments] != [anObject acceptsAnyArguments])
return NO;
-
+
if (!thisInvocation && !otherInvocation) // both nil
invocationsAreEqual = YES;
else if (thisInvocation && otherInvocation) // both non-nil
else
invocationsAreEqual = [thisInvocation WOTest_isEqualToInvocation:otherInvocation];
}
-
+
if (!thisValue && !otherValue) // both nil
returnValuesAreEqual = YES;
else if (thisValue && otherValue) // both non-nil
returnValuesAreEqual = [thisValue isEqual:otherValue];
-
+
if (!thisException && !otherException) // both nil
exceptionsAreEqual = YES;
else if (thisException && otherException) // both non-nil
exceptionsAreEqual = [thisException isEqual:otherException];
-
- if (invocationsAreEqual && returnValuesAreEqual &&
+
+ if (invocationsAreEqual && returnValuesAreEqual &&
exceptionsAreEqual)
return YES;
}
- (Protocol *)mockedProtocol
{
- return mockedProtocol;
+ return mockedProtocol;
}
@end
/*! The WOStub class provides a temporary "trampoline" object that can be used to record invocations (selectors and arguments) and desired return values. It is a "stub" because it is a temporary object that operates behind the scenes and is effectively indistinguishable from the object for which it temporarily stands in. It is a "trampoline" because it serves to bounce back the invocations and desired return values to the object for which it temporarily stands in. */
@interface WOStub : NSProxy {
-
+
id delegate;
-
+
NSInvocation *invocation;
-
+
NSValue *returnValue;
-
+
id exception;
-
+
/*! YES if the stub should accept any arguments. The default behaviour (NO) indicates that the stub should only accept the arguments that were passed when it was first created and any discrepancies will result in an exception. */
BOOL acceptsAnyArguments;
}
- (id)init
{
- return self; // super (NSProxy) has no init method
+ return self; // super (NSProxy) has no init method
}
- (void)dealloc
}
#pragma mark -
-#pragma mark Proxy methods
+#pragma mark Proxy methods
- (void)forwardInvocation:(NSInvocation *)anInvocation
{
}
/*
-
+
http://lists.apple.com/archives/cocoa-dev/2004/Jun/msg00990.html
-
+
"On PPC, the prearg area is used to store the 13 floating-point parameter registers, which may contain method parameters that need to be restored when the marg_list is used. The i386 function call ABI has no additional registers to be saved, so its prearg area is empty. The implementations of _objc_msgForward() and objc_msgSendv() in objc4's objc-msg-ppc.s contain more details that may be useful to you.
-
- In general, you probably want to avoid marg_list and objc_msgSendv(). Together they are primarily an implementation detail of forward:: ."
+
+ In general, you probably want to avoid marg_list and objc_msgSendv(). Together they are primarily an implementation detail of forward:: ."
(Greg Parker, Apple)
-
+
*/
- forward:(SEL)sel :(marg_list)args
// let standard event flow take place (but note that NSProxy implementation raises so subclasses must do the real work)
if ([self methodSignatureForSelector:sel])
return [super forward:sel :args];
-
+
// fallback to internal lookup
NSMethodSignature *signature = [[delegate methodSignatures] objectForKey:NSStringFromSelector(sel)];
-
+
// at this point it would be great to be able to improvise but it's not possible to figure out an accurate method signature
NSAssert((signature != nil), ([NSString stringWithFormat:@"no method signature for selector %@", NSStringFromSelector(sel)]));
-
+
NSInvocation *forwardInvocation = [NSInvocation invocationWithMethodSignature:signature];
[forwardInvocation setSelector:sel];
-
-
+
+
// store arguments in invocation
int offset = 0;
for (unsigned i = 0, max = [signature numberOfArguments]; i < max; i++)
{
const char *type = [signature getArgumentTypeAtIndex:i]; // always id, SEL, ...
-
+
#if defined(__ppc__)
// TODO: finish this implementation and copy it (or otherwise make it available) to WOMock.m
// leave the compiler warnings about "unused variable 'type'" and "unused variable 'offset'" to remind me to do it
-
+
// the PPC ABI has special conventions for floats, doubles, structs
// contents of floating point registers f1 through f13 stored at args + 0 through args + 96
// 6th param: r8 args + (13 * 8) + 44
// 7th param: r9 args + (13 * 8) + 48
// 8th param: r10 args + (13 * 8) + 52
- // the remaining parameters are on the stack (starting at args + (13 * 8) + 56)
+ // the remaining parameters are on the stack (starting at args + (13 * 8) + 56)
// note that marg_prearg_size is defined in the headers for ppc and equals 128 (13 * 8 + 24 bytes for linkage area)
-
+
// from http://darwinsource.opendarwin.org/10.4.3/objc4-267/runtime/Messengers.subproj/objc-msg-ppc.s
// typedef struct objc_sendv_margs {
-// double floatingPointArgs[13];
-// int linkageArea[6];
-// int registerArgs[8];
-// int stackArgs[variable];
+// double floatingPointArgs[13];
+// int linkageArea[6];
+// int registerArgs[8];
+// int stackArgs[variable];
// };
-//
+//
// if (strcmp(type, @encode(float)) == 0)
// {}
// else if (strcmp(type, @encode(double)) == 0)
// {}
// else
-
+
#elif defined(__i386__)
// on i386 the marg_getRef macro and its helper, marg_adjustedOffset, should work fine
}
else
[NSException raise:NSGenericException format:@"type %s not supported", type];
-
+
offset += [NSValue WOTest_sizeForType:[NSString stringWithUTF8String:type]];
#elif defined(__ppc64__)
// there is no objc-msg-ppc.s so for now just omit support rather than make assumptions
#error ppc64 not supported yet
-
+
#else
#error Unsupported architecture
#endif
-
+
}
[self forwardInvocation:forwardInvocation];
return nil; // nobody cares what a stub returns
- (NSInvocation *)recordedInvocation
{
NSInvocation *recordedInvocation = [self invocation];
- NSAssert((recordedInvocation != nil), @"WOStub sent recordedInvocation but no invocation yet recorded");
+ NSAssert((recordedInvocation != nil), @"WOStub sent recordedInvocation but no invocation yet recorded");
return recordedInvocation;
}
- (NSInvocation *)invocation
{
- return [[invocation retain] autorelease];
+ return [[invocation retain] autorelease];
}
- (void)setInvocation:(NSInvocation *)anInvocation
- (NSValue *)returnValue
{
- return [[returnValue retain] autorelease];
+ return [[returnValue retain] autorelease];
}
- (void)setReturnValue:(NSValue *)aReturnValue
- (id)exception
{
- return [[exception retain] autorelease];
+ return [[exception retain] autorelease];
}
- (void)setException:(id)anException
@interface WOTestApplicationTestsController : NSObject {
unsigned _trimPathComponents;
-
+
}
//! For example, if your test controller was implemented in a source file at:
{
static int32_t initialized = 0;
if (OSAtomicIncrement32Barrier(&initialized) != 1) return; // do this once only
-
+
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
(void)[[self alloc] initWithPath:__FILE__ keepComponents:3]; // will release self after running tests
[pool release];
unsigned componentCount = [components count];
NSAssert(componentCount > count, @"componentCount must be greater than count");
_trimPathComponents = componentCount - count;
-
+
// wait until the app has finish launching before running the tests; means we can test stuff in nibs etc
NSAssert((NSApplicationDidFinishLaunchingNotification != NULL), @"NSApplicationDidFinishLaunchingNotification not defined");
- [[NSNotificationCenter defaultCenter] addObserver:self
- selector:@selector(runTests:)
+ [[NSNotificationCenter defaultCenter] addObserver:self
+ selector:@selector(runTests:)
name:NSApplicationDidFinishLaunchingNotification
object:nil];
-
+
[self performSelector:@selector(applicationFailedToFinishLaunching:) withObject:nil afterDelay:10.0];
}
return self;
- (void)runTests:(NSNotification *)aNotification
{
[NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(applicationFailedToFinishLaunching:) object:nil];
-
+
WOTest *tester = [WOTest sharedInstance];
[tester setTrimInitialPathComponents:_trimPathComponents];
[tester runAllTests];
-
+
[[NSNotificationCenter defaultCenter] removeObserver:self];
[self release]; // balance alloc/init in load method
}
static int32_t initialized = 0;
if (OSAtomicIncrement32Barrier(&initialized) != 1)
return;
-
+
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
char *inject = getenv("WOTestInjectBundle");
if (inject)
@interface WOTest : NSObject {
NSDate *startDate;
-
+
unsigned classesWithTests;
unsigned classesWithoutTests;
unsigned methodsWithTests;
unsigned testsPassed;
unsigned testsFailed;
unsigned uncaughtExceptions;
-
+
//! test sense inversion: should only be used during WOTest self-testing
unsigned testsFailedExpected;
unsigned testsPassedUnexpected;
BOOL expectFailures;
-
+
//! low-level exception handling inversion: should only be used during WOTest self-testing
unsigned lowLevelExceptionsExpected;
unsigned lowLevelExceptionsUnexpected;
//! Optionally refrain from handling low level exceptions
BOOL handlesLowLevelExceptions;
-
+
//! Internal use only: used for keeping track of whether low-level exception handlers have been installed or not
//! Necessary because tested methods may change the low-level-exception-catching status mid-test
BOOL lowLevelExceptionHandlerInstalled;
-
+
//! 0 = mostly silent operation; 1 = verbose; 2 = very verbose
unsigned verbosity;
-
+
//! Optionally trim leading path components when printing path names to console.
unsigned trimInitialPathComponents;
-
+
//! Cache last reported path and last reported line number for use when printing warnings and errors which don't include file and line information
NSString *lastReportedFile;
int lastReportedLine;
-
+
//! Defaults to YES.
BOOL warnsAboutSignComparisons;
}
#pragma mark -
#pragma mark Singleton pattern enforcement methods
-/*! \name Singleton pattern enforcement methods
+/*! \name Singleton pattern enforcement methods
\startgroup */
+ (WOTest *)sharedInstance;
#pragma mark -
#pragma mark Utility methods
-/*! \name Utility methods
+/*! \name Utility methods
\startgroup */
/*! Returns an NSString based on sending the "description" selector to anObject, compressing whitespace and truncating if necessary at index and appending an ellipsis. Returns nil if anObject is nil. Optionally returns YES or NO indirectyl via /p didTruncate to indicate whether truncation actually occurred. Pass \p index of 0 to return an untruncated, uncompressed description. */
/*! \endgroup */
-#pragma mark -
+#pragma mark -
#pragma mark Test-running methods
-/*! \name Test-running test methods
+/*! \name Test-running test methods
\startgroup */
/*! Runs all tests currently visible in the runtime. Returns YES if all tests pass, NO if any test fails. */
- (void)growlNotifyTitle:(NSString *)title message:(NSString *)message isWarning:(BOOL)isWarning sticky:(BOOL)sticky;
-#pragma mark -
+#pragma mark -
#pragma mark Logging methods
-//! \name Logging methods
+//! \name Logging methods
//! \startgroup
//! Keep track of last known file and line number
//! \endgroup
-#pragma mark -
+#pragma mark -
#pragma mark Empty (do-nothing) test methods
-/*! \name Empty (do-nothing) test methods
+/*! \name Empty (do-nothing) test methods
\startgroup */
/*! An empty test which always passes. */
/*! \endgroup */
-#pragma mark -
+#pragma mark -
#pragma mark Boolean test methods
-/*! \name Boolean test methods
+/*! \name Boolean test methods
\startgroup */
- (void)testTrue:(BOOL)expr inFile:(char *)path atLine:(int)line;
#pragma mark -
#pragma mark NSValue-based tests
-/*! \name NSValue-based tests
+/*! \name NSValue-based tests
\startgroup */
- (void)testValue:(NSValue *)actual isEqualTo:(NSValue *)expected inFile:(char *)path atLine:(int)line;
/*! \endgroup */
-#pragma mark -
+#pragma mark -
#pragma mark Pointer to void test methods
-/*! \name Pointer to void test methods
+/*! \name Pointer to void test methods
\startgroup */
- (void)testNil:(void *)pointer inFile:(char *)path atLine:(int)line;
#pragma mark -
#pragma mark int test methods
-/*! \name int test methods
+/*! \name int test methods
\startgroup */
/*! The WO_TEST_IS_INT macro uses \@encode(typeof()) to pass a string encoding of the type. */
#pragma mark -
#pragma mark unsigned test methods
-/*! \name unsigned test methods
+/*! \name unsigned test methods
\startgroup */
/*! The WO_TEST_IS_UNSIGNED macro uses \@encode(typeof()) to pass a string encoding of the type. */
#pragma mark -
#pragma mark float test methods without error margins
-/*! \name float test methods without error margins
+/*! \name float test methods without error margins
\startgroup */
/*! The WO_TEST_IS_FLOAT macro uses \@encode(typeof()) to pass a string encoding of the type. */
#pragma mark -
#pragma mark float test methods with error margins
-/*! \name float test methods with error margins
+/*! \name float test methods with error margins
\startgroup */
- (void)testFloatPositive:(float)aFloat withinError:(float)error inFile:(char *)path atLine:(int)line;
#pragma mark -
#pragma mark double test methods without error margins
-/*! \name double test methods without error margins
+/*! \name double test methods without error margins
\startgroup */
/*! The WO_TEST_IS_DOUBLE macro uses \@encode(typeof()) to pass a string encoding of the type. */
#pragma mark -
#pragma mark double test methods with error margins
-/*! \name double test methods with error margins
+/*! \name double test methods with error margins
\startgroup */
- (void)testDoublePositive:(double)aDouble withinError:(double)error inFile:(char *)path atLine:(int)line;
#pragma mark -
#pragma mark Object test methods
-/*! \name Object test methods
+/*! \name Object test methods
\startgroup */
- (void)testObject:(id)actual isEqualTo:(id)expected inFile:(char *)path atLine:(int)line;
#pragma mark -
#pragma mark NSString test methods
-/*! \name NSString test methods
+/*! \name NSString test methods
\startgroup */
- (void)testString:(NSString *)actual isEqualTo:(NSString *)expected inFile:(char *)path atLine:(int)line;
#pragma mark -
#pragma mark NSArray test methods
-/*! \name NSArray test methods
+/*! \name NSArray test methods
\startgroup */
- (void)testArray:(NSArray *)actual isEqualTo:(NSArray *)expected inFile:(char *)path atLine:(int)line;
#pragma mark -
#pragma mark NSDictionary test methods
-/*! \name NSDictionary test methods
+/*! \name NSDictionary test methods
\startgroup */
- (void)testDictionary:(NSDictionary *)actual isEqualTo:(NSDictionary *)expected inFile:(char *)path atLine:(int)line;
#pragma mark -
#pragma mark Exception test methods
-/*! \name Exception test methods
+/*! \name Exception test methods
\startgroup */
- (void)testThrowsException:(id)exception inFile:(char *)path atLine:(int)line;
/*! \endgroup */
-#pragma mark -
+#pragma mark -
#pragma mark Random value generator methods
/*! \name Random value generator methods
/*! \endgroup */
-#pragma mark -
+#pragma mark -
#pragma mark Accessors
-//! \name Accessors
+//! \name Accessors
//! \startgroup
- (NSDate *)startDate;
typedef struct WOJumpBuffer {
unsigned long eax; // store/restore
unsigned long ebx; // store/restore
- unsigned long ecx;
+ unsigned long ecx;
unsigned long edx;
unsigned long edi; // store/restore
unsigned long esi; // store/restore
unsigned long ebp; // store/restore
unsigned long esp; // store/restore
- unsigned long ss;
- unsigned long eflags;
- unsigned long cs;
- unsigned long ds;
- unsigned long es;
- unsigned long fs;
+ unsigned long ss;
+ unsigned long eflags;
+ unsigned long cs;
+ unsigned long ds;
+ unsigned long es;
+ unsigned long fs;
unsigned long gs;
} WOJumpBuffer;
static volatile WOJumpBuffer WOLowLevelExceptionJumpBuffer;
fprintf(stderr, "error: WOTest internal error (unexpected exception in WOLowLevelExceptionHandler)\n");
fprintf(stderr, "Exception type: %lu\n", (unsigned long)(theException->theKind));
fflush(NULL);
-
+
// forwarding to old exception handler doesn't seem to work (get into infinite loop)
//return InvokeExceptionHandlerUPP(theException, WOOldLowLevelExceptionHandler);
_exit(EXIT_FAILURE);
}
-
+
WOLastLowLevelException = theException->theKind;
WOTestCanJump = NO;
// set flag to indicate that an exception was triggerd
WOTestExceptionTriggered = 1;
-
+
// will resume execution at previously marked "safe place": longjmp would be fine here
#ifdef __i386__
// set only the registers that setjmp() saves and longjmp() restores
theException->registerImage->EDI = WOLowLevelExceptionJumpBuffer.edi;
theException->registerImage->ESI = WOLowLevelExceptionJumpBuffer.esi;
theException->registerImage->ESP = WOLowLevelExceptionJumpBuffer.esp;
-
+
// clear out exception state (probably not necessary)
theException->info.memoryInfo = NULL;
-
+
#elif defined (__ppc__)
theException->machineState->PC = WOProgramCounter;
// TODO: must restore more state here
if ((self = [super init]))
{
// once-off initialization and setting of defaults:
- self->handlesLowLevelExceptions = YES;
+ self->handlesLowLevelExceptions = YES;
self->warnsAboutSignComparisons = YES;
}
WOTestSharedInstance = self;
{
if (didTruncate) *didTruncate = NO;
NSString *description = nil;
- if (!anObject)
+ if (!anObject)
description = @"(nil)";
else
{
NSDate *startMethod = [NSDate date];
SEL preflight = @selector(preflight);
SEL postflight = @selector(postflight);
-
+
_WOLog(@"Running test method %@", method);
@try
{
// minimize time spent with exception handlers in place
[self installLowLevelExceptionHandler];
-
+
// record program counter and some other registers right now
#ifdef __i386__
- // LowLevelABI.pdf says "EDI, ESI, EBX, EBP" are the preserved registers (across function calls)
+ // LowLevelABI.pdf says "EDI, ESI, EBX, EBP" are the preserved registers (across function calls)
// ebp is the "saved frame pointer": "the base address of the caller's stack frame"
// eax is used to return pointer and integral results to callers: "The called function places integral or pointer results in EAX"
-
+
// info on inline assembly: http://www.ibiblio.org/gferg/ldp/GCC-Inline-Assembly-HOWTO.html
__asm__ volatile("movl %%eax, %0\n" : "=m" (WOLowLevelExceptionJumpBuffer.eax));
__asm__ volatile("movl %%ebx, %0\n" : "=m" (WOLowLevelExceptionJumpBuffer.ebx));
#error Unsupported architecture
#endif
WOTestCanJump = YES;
-
+
goto jump_point; // necessary to silence compiler warning about unused label
jump_point:
// if flag set, that means we crashed: throw an exception
if (WOTestExceptionTriggered)
{
- WOTestExceptionTriggered = 0;
+ WOTestExceptionTriggered = 0;
@throw [WOTestLowLevelException exceptionWithType:WOLastLowLevelException];
}
-
+
if ([self isClassMethod:method])
{
if ([NSObject WOTest_class:aClass respondsToSelector:preflight])
}
else
{
- [self writeError:@"Class %@ must respond to the alloc, init and release selectors",
+ [self writeError:@"Class %@ must respond to the alloc, init and release selectors",
NSStringFromClass(aClass)];
[self writeLastKnownLocation];
}
}
@catch (id e)
{
- [self writeError:@"uncaught exception (%@) in test method %@", [NSException WOTest_descriptionForException:e],
+ [self writeError:@"uncaught exception (%@) in test method %@", [NSException WOTest_descriptionForException:e],
method];
[self writeLastKnownLocation];
noTestFailed = NO;
}
@catch (id e)
{
- [self writeError:@"uncaught exception (%@) testing class %@", [NSException WOTest_descriptionForException:e],
+ [self writeError:@"uncaught exception (%@) testing class %@", [NSException WOTest_descriptionForException:e],
NSStringFromClass(aClass)];
[self writeLastKnownLocation];
noTestFailed = NO;
{
// return an array of class names
NSMutableArray *testableClasses = [NSMutableArray array];
-
+
unsigned classCount = 0; // the total number of classes
unsigned conformingClassCount = 0; // classes conforming to WOTest
unsigned nonconformingClassCount = 0; // unconforming classes
unsigned excludedClassCount = 0; // excluded classes
- unsigned exceptionCount = 0; // classes provoking exceptions
-
+ unsigned exceptionCount = 0; // classes provoking exceptions
+
int numClasses = 0;
int newNumClasses = objc_getClassList(NULL, 0);
Class *classes = NULL;
-
+
// get a list of all classes on the system
while (numClasses < newNumClasses)
{
NSAssert1((classes != NULL), @"realloc() failed (size %d)", bufferSize);
newNumClasses = objc_getClassList(classes, numClasses);
}
-
- @try
+
+ @try
{
if (classes)
- {
+ {
// skip over some classes because they not only cause exceptions but also spew out ugly console messages
SInt32 systemVersion;
Gestalt(gestaltSystemVersion, &systemVersion);
- systemVersion = systemVersion & 0x0000ffff; // Apple instructs to ignore the high-order word
+ systemVersion = systemVersion & 0x0000ffff; // Apple instructs to ignore the high-order word
NSArray *excludedClasses = (systemVersion < 0x00001040) ?
[NSArray arrayWithObjects: @"Protocol", @"List", @"Object", @"_NSZombie", nil] : // 10.3
[NSArray arrayWithObjects: @"Protocol", @"List", @"Object", @"_NSZombie", @"NSATSGlyphGenerator", nil]; // 10.4
-
+
if ([self verbosity] > 1)
_WOLog(@"Examining classes for WOTest protocol compliance");
-
+
for (int i = 0; i < newNumClasses; i++)
{
classCount++;
-
+
Class aClass = classes[i];
NSString *className = NSStringFromClass(aClass);
-
+
@try
{
if ([excludedClasses containsObject:className])
}
free(classes);
}
-
+
}
@catch (id e)
{
_WOLog(@"Uncaught exception...");
}
-
+
_WOLog(@"Runtime Summary:\n"
@"Total classes: %d\n"
@"Classes which conform to the WOTest protocol: %d\n"
nonconformingClassCount,
excludedClassCount,
exceptionCount);
-
+
return [testableClasses sortedArrayUsingSelector:@selector(compare:)];
}
{
NSArray *allClasses = [self testableClasses];
NSMutableArray *classNames = [NSMutableArray array];
-
+
if (aBundle) // only search if actually passed a non-nil bundle
{
// add only classes that match the passed bundle and conform to WOTest
[classNames addObject:className];
}
}
-
+
// return autoreleased, immutable NSArray
return [NSArray arrayWithArray:classNames];
}
{
// catch crashes caused by passing an "id" instead of a "Class"
NSParameterAssert([NSObject WOTest_isRegisteredClass:aClass] || [NSObject WOTest_isMetaClass:aClass]);
-
+
NSMutableArray *methodNames = [NSMutableArray array];
- @try
+ @try
{
NSString *prefix = @"-"; // default prefix (instance methods)
if (class_isMetaClass(aClass))
Class metaClass = object_getClass(aClass);
NSArray *classMethods = [self testableMethodsFrom:metaClass];
[methodNames addObjectsFromArray:classMethods];
- }
-
- unsigned int count;
- Method *methods = class_copyMethodList(aClass, &count);
- if (methods)
- {
- for (unsigned int i = 0, max = count; i < max; i++)
- {
- SEL aSelector = method_getName(methods[i]);
- NSString *name = NSStringFromSelector(aSelector);
- if (name && [name hasPrefix:@"test"])
- [methodNames addObject:[NSString stringWithFormat:@"%@%@", prefix, name]];
- }
- free(methods);
- }
+ }
+
+ unsigned int count;
+ Method *methods = class_copyMethodList(aClass, &count);
+ if (methods)
+ {
+ for (unsigned int i = 0, max = count; i < max; i++)
+ {
+ SEL aSelector = method_getName(methods[i]);
+ NSString *name = NSStringFromSelector(aSelector);
+ if (name && [name hasPrefix:@"test"])
+ [methodNames addObject:[NSString stringWithFormat:@"%@%@", prefix, name]];
+ }
+ free(methods);
+ }
}
@catch (id e)
{
NSStringFromClass(aClass)];
[self writeError:error];
}
-
+
return [methodNames sortedArrayUsingSelector:@selector(compare:)];
}
testsPassed, testsFailedExpected, successRate,
testsFailed, testsPassedUnexpected, failureRate,
uncaughtExceptions,
- lowLevelExceptionsUnexpected, lowLevelExceptionsExpected,
+ lowLevelExceptionsUnexpected, lowLevelExceptionsExpected,
-[[self startDate] timeIntervalSinceNow]);
-
+
if (testsRun == 0)
_WOLog(@"warning: no tests were run\n");
-
+
// TODO: make Growl notifications optional
// TODO: include information about project being tested in Growl notification title
// TODO: add options for showing coalesced growl notifications showing individual test failures (with path and line info)
// TODO: make clicking on notification bring Xcode to the front, or open the file with the last failure in it etc
- NSString *status = [NSString stringWithFormat:@"%d tests passed, %d tests failed",
+ NSString *status = [NSString stringWithFormat:@"%d tests passed, %d tests failed",
testsPassed + testsFailedExpected, testsFailed + testsPassedUnexpected];
-
+
if ([self testsWereSuccessful])
[self growlNotifyTitle:@"WOTest run successful" message:status isWarning:NO sticky:NO];
else
{
- _WOLog(@"error: testing did not complete without errors\n");
+ _WOLog(@"error: testing did not complete without errors\n");
[self growlNotifyTitle:@"WOTest run failed" message:status isWarning:YES sticky:YES];
-
+
}
-
+
// reset start date
[self setStartDate:nil];
}
}
- (void)removeLowLevelExceptionHandler
-{
+{
if (lowLevelExceptionHandlerInstalled)
{
DisposeExceptionHandlerUPP(InstallExceptionHandler(WOOldLowLevelExceptionHandler));
{
NSParameterAssert(title != nil);
NSParameterAssert(message != nil);
-
+
// clean up enviroment a bit (hides possible warnings caused if these set for WOTestRunner)
NSMutableDictionary *environment = [NSMutableDictionary dictionaryWithDictionary:[[NSProcessInfo processInfo] environment]];
[environment removeObjectForKey:@"DYLD_INSERT_LIBRARIES"];
[environment removeObjectForKey:@"WOTestBundleInjector"];
-
+
NSTask *task = [[[NSTask alloc] init] autorelease];
[task setLaunchPath:@"/usr/bin/env"]; // use env so as to pick up PATH, if set
[task setEnvironment:environment];
NSMutableArray *arguments = [NSMutableArray arrayWithObjects:@"growlnotify",
- @"--name", @"com.wincent.WOTest",
- @"--appIcon", @"Xcode",
+ @"--name", @"com.wincent.WOTest",
+ @"--appIcon", @"Xcode",
@"--priority", (isWarning ? @"2" : @"0"),
@"--message", message,
title, nil];
{
NSParameterAssert(path != NULL);
NSString *pathString = [NSString stringWithUTF8String:path];
-
+
unsigned trim = [self trimInitialPathComponents];
if (trim == 0) return pathString;
if (![pathString isAbsolutePath]) return pathString; // only trim absolute paths
return [NSString pathWithComponents:[components subarrayWithRange:NSMakeRange(trim + 1, count - trim - 1)]];
}
-- (void)writePassed:(BOOL)passed
- inFile:(char *)path
+- (void)writePassed:(BOOL)passed
+ inFile:(char *)path
atLine:(int)line
message:(NSString *)message, ...
{
{
[self writeErrorInFile:path atLine:line message:[NSString stringWithFormat:@"Failed: %@", string]];
testsFailed++;
- }
+ }
}
}
va_end(args);
}
-- (void)writeWarningInFile:(char *)path atLine:(int)line message:(NSString *)message, ...
+- (void)writeWarningInFile:(char *)path atLine:(int)line message:(NSString *)message, ...
{
va_list args;
va_start(args, message);
uncaughtExceptions++;
}
-- (void)writeStatusInFile:(char *)path atLine:(int)line message:(NSString *)message, ...
+- (void)writeStatusInFile:(char *)path atLine:(int)line message:(NSString *)message, ...
{
va_list args;
va_start(args, message);
va_start(args, message);
NSString *status = [NSString WOTest_stringWithFormat:message arguments:args];
_WOLog(@"%@", status);
- va_end(args);
+ va_end(args);
}
- (void)writeWarning:(NSString *)message, ...
va_start(args, message);
NSString *warning = [NSString WOTest_stringWithFormat:message arguments:args];
_WOLog(@"warning: %@", warning); // older versions of Xcode required initial colons "::" to show this as a warning
- va_end(args);
+ va_end(args);
}
- (void)writeError:(NSString *)message, ...
va_end(args);
}
-#pragma mark -
+#pragma mark -
#pragma mark Empty (do-nothing) test methods
- (void)passTestInFile:(char *)path atLine:(int)line
[self writePassed:NO inFile:path atLine:line message:@"(always fails)"];
}
-#pragma mark -
+#pragma mark -
#pragma mark Boolean test methods
- (void)testTrue:(BOOL)expr inFile:(char *)path atLine:(int)line
NSParameterAssert(actual);
NSParameterAssert(expected);
BOOL equal = NO;
-
+
// NSValue category will throw an exception for invalid input(s)
@try {
equal = [actual WOTest_testIsEqualToValue:expected];
NSParameterAssert(actual);
NSParameterAssert(expected);
BOOL equal = NO;
-
+
// NSValue category will throw an exception for invalid input(s)
@try {
equal = [actual WOTest_testIsEqualToValue:expected];
NSParameterAssert(actual);
NSParameterAssert(expected);
BOOL greaterThan = NO;
-
+
// NSValue category will throw an exception for invalid input(s)
@try {
greaterThan = [actual WOTest_testIsGreaterThanValue:expected];
NSParameterAssert(actual);
NSParameterAssert(expected);
BOOL notGreaterThan = NO;
-
+
// NSValue category will throw an exception for invalid input(s)
@try {
notGreaterThan = [actual WOTest_testIsNotGreaterThanValue:expected];
NSParameterAssert(actual);
NSParameterAssert(expected);
BOOL lessThan = NO;
-
+
// NSValue category will throw an exception for invalid input(s)
@try {
lessThan = [actual WOTest_testIsLessThanValue:expected];
NSParameterAssert(actual);
NSParameterAssert(expected);
BOOL notLessThan = NO;
-
+
// NSValue category will throw an exception for invalid input(s)
@try {
notLessThan = [actual WOTest_testIsNotLessThanValue:expected];
- (void)testNil:(void *)pointer inFile:(char *)path atLine:(int)line
{
BOOL result = (pointer ? NO : YES);
- [self writePassed:result inFile:path atLine:line message:@"expected nil, got %@",
+ [self writePassed:result inFile:path atLine:line message:@"expected nil, got %@",
(result ? @"nil" : [NSString stringWithFormat:@"%x", pointer])];
}
#pragma mark -
#pragma mark int test methods
-- (void)testIsInt:(char *)type inFile:(char *)path atLine:(int)line
+- (void)testIsInt:(char *)type inFile:(char *)path atLine:(int)line
{
- BOOL result = (strcmp(type, "i") == 0);
- [self writePassed:result inFile:path atLine:line message:[NSString stringWithFormat: @"expected type \"i\", got \"%s\"", type]];
+ BOOL result = (strcmp(type, "i") == 0);
+ [self writePassed:result inFile:path atLine:line message:[NSString stringWithFormat: @"expected type \"i\", got \"%s\"", type]];
}
- (void)testIsNotInt:(char *)type inFile:(char *)path atLine:(int)line
[self testInt:aInt isNotEqualTo:(int)0 inFile:path atLine:line];
}
-- (void)testInt:(int)actual isEqualTo:(int)expected inFile:(char *)path atLine:(int)line
+- (void)testInt:(int)actual isEqualTo:(int)expected inFile:(char *)path atLine:(int)line
{
- BOOL result = (actual == expected);
- [self writePassed:result inFile:path atLine:line message:[NSString stringWithFormat:@"expected %d, got %d", expected, actual]];
+ BOOL result = (actual == expected);
+ [self writePassed:result inFile:path atLine:line message:[NSString stringWithFormat:@"expected %d, got %d", expected, actual]];
}
-- (void)testInt:(int)actual isNotEqualTo:(int)expected inFile:(char *)path atLine:(int)line
+- (void)testInt:(int)actual isNotEqualTo:(int)expected inFile:(char *)path atLine:(int)line
{
- BOOL result = (actual != expected);
- [self writePassed:result
- inFile:path
- atLine:line
- message:[NSString stringWithFormat:@"expected (not) %d, got %d", expected, actual]];
+ BOOL result = (actual != expected);
+ [self writePassed:result
+ inFile:path
+ atLine:line
+ message:[NSString stringWithFormat:@"expected (not) %d, got %d", expected, actual]];
}
-- (void)testInt:(int)actual greaterThan:(int)expected inFile:(char *)path atLine:(int)line
+- (void)testInt:(int)actual greaterThan:(int)expected inFile:(char *)path atLine:(int)line
{
- BOOL result = (actual > expected);
- [self writePassed:result
- inFile:path
- atLine:line
- message:[NSString stringWithFormat:@"expected > %d, got %d", expected, actual]];
+ BOOL result = (actual > expected);
+ [self writePassed:result
+ inFile:path
+ atLine:line
+ message:[NSString stringWithFormat:@"expected > %d, got %d", expected, actual]];
}
-- (void)testInt:(int)actual notGreaterThan:(int)expected inFile:(char *)path atLine:(int)line
+- (void)testInt:(int)actual notGreaterThan:(int)expected inFile:(char *)path atLine:(int)line
{
- BOOL result = (actual <= expected);
- [self writePassed:result
- inFile:path
- atLine:line
- message:[NSString stringWithFormat:@"expected <= %d, got %d", expected, actual]];
+ BOOL result = (actual <= expected);
+ [self writePassed:result
+ inFile:path
+ atLine:line
+ message:[NSString stringWithFormat:@"expected <= %d, got %d", expected, actual]];
}
-- (void)testInt:(int)actual lessThan:(int)expected inFile:(char *)path atLine:(int)line
+- (void)testInt:(int)actual lessThan:(int)expected inFile:(char *)path atLine:(int)line
{
- BOOL result = (actual < expected);
- [self writePassed:result
- inFile:path
- atLine:line
- message:[NSString stringWithFormat:@"expected < %d, got %d", expected, actual]];
+ BOOL result = (actual < expected);
+ [self writePassed:result
+ inFile:path
+ atLine:line
+ message:[NSString stringWithFormat:@"expected < %d, got %d", expected, actual]];
}
-- (void)testInt:(int)actual notLessThan:(int)expected inFile:(char *)path atLine:(int)line
+- (void)testInt:(int)actual notLessThan:(int)expected inFile:(char *)path atLine:(int)line
{
- BOOL result = (actual >= expected);
- [self writePassed:result
- inFile:path
- atLine:line
- message:[NSString stringWithFormat:@"expected >= %d, got %d", expected, actual]];
+ BOOL result = (actual >= expected);
+ [self writePassed:result
+ inFile:path
+ atLine:line
+ message:[NSString stringWithFormat:@"expected >= %d, got %d", expected, actual]];
}
#pragma mark -
#pragma mark unsigned test methods
-- (void)testIsUnsigned:(char *)type inFile:(char *)path atLine:(int)line
+- (void)testIsUnsigned:(char *)type inFile:(char *)path atLine:(int)line
{
- BOOL result = (strcmp(type, "I") == 0);
- [self writePassed:result inFile:path atLine:line message:[NSString stringWithFormat: @"expected type \"I\", got \"%s\"", type]];
+ BOOL result = (strcmp(type, "I") == 0);
+ [self writePassed:result inFile:path atLine:line message:[NSString stringWithFormat: @"expected type \"I\", got \"%s\"", type]];
}
- (void)testIsNotUnsigned:(char *)type inFile:(char *)path atLine:(int)line
message:[NSString stringWithFormat:@"expected type (not) \"I\", got \"%s\"", type]];
}
-- (void)testUnsignedZero:(unsigned)aUnsigned inFile:(char *)path atLine:(int)line
+- (void)testUnsignedZero:(unsigned)aUnsigned inFile:(char *)path atLine:(int)line
{
- return [self testUnsigned:aUnsigned isEqualTo:(unsigned)0 inFile:path atLine:line];
+ return [self testUnsigned:aUnsigned isEqualTo:(unsigned)0 inFile:path atLine:line];
}
-- (void)testUnsignedNotZero:(unsigned)aUnsigned inFile:(char *)path atLine:(int)line
+- (void)testUnsignedNotZero:(unsigned)aUnsigned inFile:(char *)path atLine:(int)line
{
- return [self testUnsigned:aUnsigned isNotEqualTo:(unsigned)0 inFile:path atLine:line];
+ return [self testUnsigned:aUnsigned isNotEqualTo:(unsigned)0 inFile:path atLine:line];
}
- (void)testUnsigned:(unsigned)actual isEqualTo:(unsigned)expected inFile:(char *)path atLine:(int)line
{
- BOOL result = (actual == expected);
- [self writePassed:result
- inFile:path
+ BOOL result = (actual == expected);
+ [self writePassed:result
+ inFile:path
atLine:line
message:[NSString stringWithFormat:@"expected %u, got %u", expected, actual]];
}
-- (void)testUnsigned:(unsigned)actual isNotEqualTo:(unsigned)expected inFile:(char *)path atLine:(int)line
+- (void)testUnsigned:(unsigned)actual isNotEqualTo:(unsigned)expected inFile:(char *)path atLine:(int)line
{
- BOOL result = (actual != expected);
- [self writePassed:result
- inFile:path
+ BOOL result = (actual != expected);
+ [self writePassed:result
+ inFile:path
atLine:line
message:[NSString stringWithFormat:@"expected (not) %u, got %u", expected, actual]];
}
-- (void)testUnsigned:(unsigned)actual greaterThan:(unsigned)expected inFile:(char *)path atLine:(int)line
+- (void)testUnsigned:(unsigned)actual greaterThan:(unsigned)expected inFile:(char *)path atLine:(int)line
{
- BOOL result = (actual > expected);
- [self writePassed:result
- inFile:path
+ BOOL result = (actual > expected);
+ [self writePassed:result
+ inFile:path
atLine:line
message:[NSString stringWithFormat:@"expected > %u, got %u", expected, actual]];
}
-- (void)testUnsigned:(unsigned)actual notGreaterThan:(unsigned)expected inFile:(char *)path atLine:(int)line
+- (void)testUnsigned:(unsigned)actual notGreaterThan:(unsigned)expected inFile:(char *)path atLine:(int)line
{
- BOOL result = (actual <= expected);
- [self writePassed:result
- inFile:path
- atLine:line
- message:[NSString stringWithFormat:@"expected <= %u, got %u", expected, actual]];
+ BOOL result = (actual <= expected);
+ [self writePassed:result
+ inFile:path
+ atLine:line
+ message:[NSString stringWithFormat:@"expected <= %u, got %u", expected, actual]];
}
-- (void)testUnsigned:(unsigned)actual lessThan:(unsigned)expected inFile:(char *)path atLine:(int)line
+- (void)testUnsigned:(unsigned)actual lessThan:(unsigned)expected inFile:(char *)path atLine:(int)line
{
- BOOL result = (actual < expected);
- [self writePassed:result
- inFile:path
- atLine:line
- message:[NSString stringWithFormat:@"expected < %u, got %u", expected, actual]];
+ BOOL result = (actual < expected);
+ [self writePassed:result
+ inFile:path
+ atLine:line
+ message:[NSString stringWithFormat:@"expected < %u, got %u", expected, actual]];
}
-- (void)testUnsigned:(unsigned)actual notLessThan:(unsigned)expected inFile:(char *)path atLine:(int)line
+- (void)testUnsigned:(unsigned)actual notLessThan:(unsigned)expected inFile:(char *)path atLine:(int)line
{
- BOOL result = (actual >= expected);
- [self writePassed:result
- inFile:path
- atLine:line
- message:[NSString stringWithFormat:@"expected >= %u, got %u", expected, actual]];
+ BOOL result = (actual >= expected);
+ [self writePassed:result
+ inFile:path
+ atLine:line
+ message:[NSString stringWithFormat:@"expected >= %u, got %u", expected, actual]];
}
#pragma mark -
- (void)testIsFloat:(char *)type inFile:(char *)path atLine:(int)line
{
BOOL result = (strcmp(type, "f") == 0);
- [self writePassed:result inFile:path atLine:line message:[NSString stringWithFormat: @"expected type \"f\", got \"%s\"", type]];
+ [self writePassed:result inFile:path atLine:line message:[NSString stringWithFormat: @"expected type \"f\", got \"%s\"", type]];
}
- (void)testIsNotFloat:(char *)type inFile:(char *)path atLine:(int)line
message:[NSString stringWithFormat:@"expected type (not) \"f\", got \"%s\"", type]];
}
-- (void)testFloatPositive:(float)aFloat inFile:(char *)path atLine:(int)line
+- (void)testFloatPositive:(float)aFloat inFile:(char *)path atLine:(int)line
{
- return [self testFloat:aFloat greaterThan:(float)0.0 withinError:(float)0.0 inFile:path atLine:line];
+ return [self testFloat:aFloat greaterThan:(float)0.0 withinError:(float)0.0 inFile:path atLine:line];
}
-- (void)testFloatNegative:(float)aFloat inFile:(char *)path atLine:(int)line
+- (void)testFloatNegative:(float)aFloat inFile:(char *)path atLine:(int)line
{
- return [self testFloat:aFloat lessThan:(float)0.0 withinError:(float)0.0 inFile:path atLine:line];
+ return [self testFloat:aFloat lessThan:(float)0.0 withinError:(float)0.0 inFile:path atLine:line];
}
-- (void)testFloatZero:(float)aFloat inFile:(char *)pat