Permalink
Browse files

Merge commit '6df998746f5d40c560143af7ec47aef428cf6845' as 'External/…

…RXAssertions'
  • Loading branch information...
robrix committed Nov 28, 2011
2 parents 98352df + 6df9987 commit b0f5663c5e7da1a3af771c516210542d39eaf563
@@ -0,0 +1,6 @@
+.DS_Store
+*.tmproj
+*.xcodeproj/*.pbxuser
+*.xcodeproj/*.mode*
+xcuserdata
+build
@@ -0,0 +1,9 @@
+Copyright (c) 2007-2009, Monochrome Industries
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
+
+Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
+Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
+Neither the name of Monochrome Industries nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
@@ -0,0 +1,115 @@
+#RXAssertions
+
+(Cleverly assertive macros for your testing enjoyment.)
+
+The key ideas here are simple:
+
+1. _Simple API._ Fewer assertion macros are better.
+2. _Simple asserting._ The macros should give you a smart enough error message that you don’t need to provide your own—but you can, optionally, if you want to.
+3. _Doesn’t replace `STAssert*`_. If you want or need to fall back on the SenTestingKit macros, you can.
+
+
+#Assertion Macros
+
+All of these log source for the condition/expression as appropriate. Anything else that gets logged is noted alongside.
+
+- **`RXAssert(condition[, message])`**
+
+ Asserts that `condition` is true. Failures look like this:
+
+ <condition> was unexpectedly false.
+
+ If you supply a message, it will be logged instead of the default message shown above.
+
+- **`RXAssertFalse(condition[, message])`**
+
+ Asserts that `condition` is false. Failures look like this:
+
+ <condition> was unexpectedly true.
+
+ If you supply a message, it will be logged instead of the default message shown above.
+
+- **`RXAssertEquals(actual, expected[, message])`**
+
+ Asserts that the actual value is equal to the expected value; if it’s not, it logs what it actually was.
+
+ This is valid for use with objects, scalars (including floats; see RXRound for more), structs, and really anything that you’ve registered a comparator for. See `RXAssertionHelper` for more info. Failures look like this:
+
+ <actual expression> has value <actual value>, not expected value <expected value>.
+
+ If you supply a message, it will be logged immediately after the default message shown above.
+
+- **`RXAssertNotEquals(actual, unexpected[, message])`**
+
+ Asserts that the actual value is not equal to the unexpected value; if it is, it logs what it unexpectedly was. Failures look like this:
+
+ <actual expression> has unexpected value <actual value>.
+
+ If you supply a message, it will be logged immediately after the default message shown above.
+
+- **`RXAssertNil(object[, message])`**
+
+ Asserts that the object is nil. If it isn’t, it logs what it actually was. Failures look like this:
+
+ <expression> was unexpectedly <expression value>, not nil.
+
+ If you supply a message, it will be logged instead of the default message shown above.
+
+- **`RXAssertNotNil(object[, message])`**
+
+ Asserts that the object is not nil.
+
+ <expression> was unexpectedly nil.
+
+ If you supply a message, it will be logged instead of the default message shown above.
+
+#Helper Macros
+
+These are helpful macros which are used by RXAssertions or which are intended for your use.
+
+- **`RXUnionCast(value, type)`**
+
+ Casts value to type using an on-the-fly union. This is safe for use with strict aliasing.
+
+- **`RXRound(value, place)`**
+
+ Rounds value to place, e.g. `RXRound(M_PI, 0.01)` will result in `3.14`. You can use this with `RXAssertEquals` to easily test against floating point fixtures without worrying about IEEE float precision problems:
+
+ RXAssertEquals(RXRound([thing returnPotentiallyImpreciseFloat], 0.01), 1.23);
+
+ However, see `+[RXAssertionHelper floatingPointComparisonAccuracy]` for an alternative.
+
+
+#`RXAssertionHelper`
+
+True to its name, `RXAssertionHelper` helps the assertion macros with some of their tasks, namely:
+
+- **Comparing values of arbitrary type.**
+
+ `+registerComparisonFunction:forObjCType:` and `+compareValue:withValue:ofObjCType:` are used to add new comparators.
+
+ RXAssertions ships with comparators for signed and unsigned integers of 8, 16, 32, and 64 bits of width; `float`s and `double`s; objects and classes; `NSPoint`s (and `CGPoint`s via the same function); and arbitrary pointers (and thus, unsupported types will be compared with pointer equality, which will presumably fail every time).
+
+ To add other comparators, simply write the comparison function (matching the `RXAssertionHelperComparisonFunction` typedef) and register it with `RXAssertionHelper` somewhere convenient before you call `RXAssertEquals` with values of this type, perhaps in your test suite’s `+initialize` method.
+
+ There is currently no support for comparing values of wildly different types! The expected value is assigned to a variable of the actual value’s type. If there is sufficient need for comparing `CGAffineTransform`s with tree frogs, this policy can be revised.
+
+- **Describing values of arbitrary type.**
+
+ `+registerDescriptionFunction:forObjCType` and `+descriptionForValue:ofObjCType:` are used to return an `NSString` instance describing the passed-in value.
+
+ These are widely used in the assertion macros for logging of actual and expected values. RXAssertions includes descriptors for signed and unsigned integers of 8, 16, 32, and 64 bits of width; `float`s and `double`s; objects and classes; `NSPoint`s (and `CGPoint`s via the same function); and arbitrary pointers (which includes pointers to any unsupported types—so if you see hex dumps of your compared values, you will want to add a descriptor).
+
+ Adding a descriptor is even simpler than adding a comparator; a `RXAssertionHelperDescriptionFunction` takes a reference to the value to be described, casts it (presumably using `RXUnionCast`) to the expected type, and builds an `NSString` from it.
+
+- **Controlling the accuracy at which `RXAssertEquals` compares `float` and `double` values.**
+
+ `+[RXAssertionHelper floatingPointComparisonAccuracy]` and `+[RXAssertionHelper setFloatingPointComparisonAccuracy:]` are used to get and set the floating point accuracy, by default 0, used by the comparators for `float` and `double` values, and thus by `RXAssertEquals`.
+
+ There is no support for managing separate `float` and `double` accuracies; if this would simplify things for you, it would be a simple change to make.
+
+
+#What’s Missing
+
+- Exception interaction of any kind. Continue using the `STAssert*` macros for exceptions until this is implemented.
+- Comparators and descriptors for `long double`, `CGSize`, `CGRect`, `CGAffineTransform`, `CFType` instances, and many other things. Patches welcome.
@@ -0,0 +1,25 @@
+// RXAssertionHelperTests.m
+// Created by Rob Rix on 2010-04-09
+// Copyright 2010 Monochrome Industries
+
+#import "RXAssertions.h"
+
+@interface RXAssertionHelperTests : SenTestCase
+@end
+
+@implementation RXAssertionHelperTests
+
+-(void)testCanTestRangesForEquality {
+ NSRange a = NSMakeRange(0, 1), b = NSMakeRange(0, 1), c = NSMakeRange(1, 2);
+ RXAssert([RXAssertionHelper compareValue: &a withValue: &b ofObjCType: @encode(NSRange)]);
+ RXAssertFalse([RXAssertionHelper compareValue: &a withValue: &c ofObjCType: @encode(NSRange)]);
+
+ // RXAssertEquals(NSMakeRange(0, 1), NSMakeRange(0, 1));
+ // RXAssertNotEquals(NSMakeRange(0, 1), NSMakeRange(1, 2));
+}
+
+-(void)testCanTestCoreFoundationStringsForEquality {
+ RXAssertEquals(CFSTR("foo"), (CFStringRef)@"foo");
+}
+
+@end
@@ -0,0 +1,82 @@
+// RXAssertions.h
+// Created by Rob Rix on 2009-08-20
+// Copyright 2009 Decimus Software, Inc.
+
+#import <SenTestingKit/SenTestingKit.h>
+
+// Assertion macros that don’t require you to describe the assertion. Perfect for use with intention-revealing code.
+
+// Don’t use this unless you’re writing your own assertions. The first argument is ignored, so the assertions can have optional messages appended to them without suffering a compiler error.
+#define RXOptionalMessageString(ignored, format, ...) [NSString stringWithFormat: (format), ## __VA_ARGS__]
+
+#define RXAssert(_expression, ...) do {\
+ __typeof__(_expression) __condition = (_expression);\
+ if(!__condition)\
+ STFail(RXOptionalMessageString(, ## __VA_ARGS__, @"%s was unexpectedly false.", #_expression));\
+} while(0)
+#define RXAssertFalse(_expression, ...) do {\
+ __typeof__(_expression) __condition = (_expression);\
+ if(__condition)\
+ STFail(RXOptionalMessageString(, ## __VA_ARGS__, @"%s was unexpectedly true.", #_expression));\
+} while(0)
+
+// casts the expected value to the type of the actual value. will fail (and rightly so) if you try crazy casts like struct to pointer.
+#define RXAssertEquals(_actual, _expected, ...) do {\
+ __typeof__(_actual) __actual = (_actual), __expected = (__typeof__(__actual))(_expected);\
+ if(![RXAssertionHelper compareValue: &__actual withValue: &__expected ofObjCType: @encode(__typeof__(__actual))]) {\
+ STFail(@"%s has value %@, not expected value %@. %@", #_actual, [RXAssertionHelper descriptionForValue: &__actual ofObjCType: @encode(__typeof__(__actual))], [RXAssertionHelper descriptionForValue: &__expected ofObjCType: @encode(__typeof__(__actual))], RXOptionalMessageString(, ## __VA_ARGS__, @""));\
+ }\
+} while(0)
+#define RXAssertNotEquals(_actual, _expected, ...) do {\
+ __typeof__(_actual) __actual = (_actual), __expected = (__typeof__(__actual))(_expected);\
+ if([RXAssertionHelper compareValue: &__actual withValue: &__expected ofObjCType: @encode(__typeof__(__actual))]) {\
+ STFail(@"%s has unexpected value %@. %@", #_actual, [RXAssertionHelper descriptionForValue: &__actual ofObjCType: @encode(__typeof__(__actual))], RXOptionalMessageString(, ## __VA_ARGS__, @""));\
+ }\
+} while(0)
+
+#define RXAssertNil(_thing, ...) do {\
+ __typeof__(_thing) __thing = (_thing);\
+ if(__thing != nil) STFail(RXOptionalMessageString(, ## __VA_ARGS__, @"%s was unexpectedly %@, not nil.", #_thing, __thing));\
+} while(0)
+#define RXAssertNotNil(_thing, ...) do {\
+ if((_thing) == nil) STFail(RXOptionalMessageString(, ## __VA_ARGS__, @"%s was unexpectedly nil.", #_thing));\
+} while(0)
+
+
+//#ifdef __clang__
+#if 0
+ // this is bad, as strict aliasing will break it, but clang doesn’t handle union casts correctly
+ #define RXCast(x, toType) *(toType *)&(x)
+#else
+ #define RXCast(x, toType) (((union{__typeof__(x) a; toType b;})x).b)
+#endif
+#define RXRound(value, place) (round((value) / (place)) * (place))
+
+
+typedef BOOL (*RXAssertionHelperComparisonFunction)(const void *aRef, const void *bRef);
+typedef NSString *(*RXAssertionHelperDescriptionFunction)(const void *ref);
+
+
+// making these functions available for registering Polymorph types
+BOOL RXAssertionHelperObjectComparison(const void *a, const void *b);
+NSString *RXAssertionHelperObjectDescription(const void *ref);
+
+BOOL RXAssertionHelperCFTypeRefComparison(const void *a, const void *b);
+NSString *RXAssertionHelperCFTypeRefDescription(const void *ref);
+
+
+@interface RXAssertionHelper : NSObject
+
++(void)registerComparisonFunction:(RXAssertionHelperComparisonFunction)comparator forObjCType:(const char *)type;
++(BOOL)compareValue:(const void *)aRef withValue:(const void *)bRef ofObjCType:(const char *)type;
+
++(void)registerDescriptionFunction:(RXAssertionHelperDescriptionFunction)descriptor forObjCType:(const char *)type;
++(NSString *)descriptionForValue:(const void *)ref ofObjCType:(const char *)type;
+
++(double)floatingPointComparisonAccuracy;
++(void)setFloatingPointComparisonAccuracy:(double)epsilon;
+
+// returns a nicely formatted name for the test case selector
++(NSString *)humanReadableNameForTestCaseSelector:(SEL)selector;
+
+@end
Oops, something went wrong.

0 comments on commit b0f5663

Please sign in to comment.