diff --git a/Cedar.xcodeproj/project.pbxproj b/Cedar.xcodeproj/project.pbxproj index d83dcf13..8a8f4398 100644 --- a/Cedar.xcodeproj/project.pbxproj +++ b/Cedar.xcodeproj/project.pbxproj @@ -23,16 +23,16 @@ /* End PBXAggregateTarget section */ /* Begin PBXBuildFile section */ - 66AEB6BE123C7CEE001C3DF1 /* CppSpecSpec.mm in Sources */ = {isa = PBXBuildFile; fileRef = AEEE1FEA11DC27B800029872 /* CppSpecSpec.mm */; }; - 66E33E53123CA82A00D326CC /* CppSpecSpec.mm in Sources */ = {isa = PBXBuildFile; fileRef = AEEE1FEA11DC27B800029872 /* CppSpecSpec.mm */; }; - AE0B8563135F94DC001EEA23 /* ActualValue.mm in Sources */ = {isa = PBXBuildFile; fileRef = AEEE1FE511DC27B800029872 /* ActualValue.mm */; }; - AE0B8564135F94DC001EEA23 /* ActualValue.mm in Sources */ = {isa = PBXBuildFile; fileRef = AEEE1FE511DC27B800029872 /* ActualValue.mm */; }; AE135D4011DEA6F400A922D4 /* OCMock.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = AE135D3111DEA6A900A922D4 /* OCMock.framework */; }; AE135D4111DEA6F400A922D4 /* OCHamcrest.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = AE135D2111DEA69A00A922D4 /* OCHamcrest.framework */; }; AE135E7011DEB46F00A922D4 /* libOCMock-StaticLib.a in Frameworks */ = {isa = PBXBuildFile; fileRef = AE135D3511DEA6A900A922D4 /* libOCMock-StaticLib.a */; }; AE135E7111DEB46F00A922D4 /* libOCHamcrest-StaticLib.a in Frameworks */ = {isa = PBXBuildFile; fileRef = AE135D2311DEA69A00A922D4 /* libOCHamcrest-StaticLib.a */; }; AE8C867D135FAE76006C9305 /* ActualValue.h in Headers */ = {isa = PBXBuildFile; fileRef = AEEE1FE411DC27B800029872 /* ActualValue.h */; settings = {ATTRIBUTES = (Public, ); }; }; AE8C8680135FB4F7006C9305 /* ActualValue.h in Headers */ = {isa = PBXBuildFile; fileRef = AEEE1FE411DC27B800029872 /* ActualValue.h */; settings = {ATTRIBUTES = (Public, ); }; }; + AE8C87541360CF02006C9305 /* AllMatchers.h in Headers */ = {isa = PBXBuildFile; fileRef = AE8C87531360CF02006C9305 /* AllMatchers.h */; settings = {ATTRIBUTES = (); }; }; + AE8C877A1360F9EF006C9305 /* Equal.h in Headers */ = {isa = PBXBuildFile; fileRef = AE8C874D135FD1DB006C9305 /* Equal.h */; }; + AE8C87A11362071E006C9305 /* EqualSpec.mm in Sources */ = {isa = PBXBuildFile; fileRef = AE8C87A01362071E006C9305 /* EqualSpec.mm */; }; + AE8C87A21362071E006C9305 /* EqualSpec.mm in Sources */ = {isa = PBXBuildFile; fileRef = AE8C87A01362071E006C9305 /* EqualSpec.mm */; }; AE91CA6C11DE64A3002BA6B9 /* CDRSharedExampleGroupPool.h in Headers */ = {isa = PBXBuildFile; fileRef = AEFD17B311DD1E8200F4448A /* CDRSharedExampleGroupPool.h */; settings = {ATTRIBUTES = (Public, ); }; }; AE91CA6D11DE64B3002BA6B9 /* CDRSharedExampleGroupPool.h in Copy headers to framework */ = {isa = PBXBuildFile; fileRef = AEFD17B311DD1E8200F4448A /* CDRSharedExampleGroupPool.h */; }; AE9855AE1236E7080024094E /* CDRSharedExampleGroupPool.m in Sources */ = {isa = PBXBuildFile; fileRef = AEFD17B111DD1E7200F4448A /* CDRSharedExampleGroupPool.m */; }; @@ -216,6 +216,9 @@ AE135D1611DEA69A00A922D4 /* OCHamcrest.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = OCHamcrest.xcodeproj; path = OCHamcrest/Source/OCHamcrest.xcodeproj; sourceTree = ""; }; AE135D2611DEA6A900A922D4 /* OCMock.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = OCMock.xcodeproj; path = OCMock/Source/OCMock.xcodeproj; sourceTree = ""; }; AE135E8311DEB4E400A922D4 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = folder; name = Foundation.framework; sourceTree = SDKROOT; }; + AE8C874D135FD1DB006C9305 /* Equal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Equal.h; sourceTree = ""; }; + AE8C87531360CF02006C9305 /* AllMatchers.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AllMatchers.h; sourceTree = ""; }; + AE8C87A01362071E006C9305 /* EqualSpec.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = EqualSpec.mm; sourceTree = ""; }; AEC9DEEA12C2CC7E0039512D /* CDRColorizedReporter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CDRColorizedReporter.h; sourceTree = ""; }; AEC9DEEB12C2CC7E0039512D /* CDRColorizedReporter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CDRColorizedReporter.m; sourceTree = ""; }; AEEE1FB611DC271300029872 /* Cedar.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Cedar.framework; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -249,11 +252,9 @@ AEEE1FE111DC27B800029872 /* CDRSpecStatusViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CDRSpecStatusViewController.m; sourceTree = ""; }; AEEE1FE211DC27B800029872 /* CedarApplicationDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CedarApplicationDelegate.m; sourceTree = ""; }; AEEE1FE411DC27B800029872 /* ActualValue.h */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.h; fileEncoding = 4; path = ActualValue.h; sourceTree = ""; }; - AEEE1FE511DC27B800029872 /* ActualValue.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = ActualValue.mm; sourceTree = ""; }; AEEE1FE611DC27B800029872 /* SpecHelper.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SpecHelper.m; sourceTree = ""; }; AEEE1FE811DC27B800029872 /* CDRExampleGroupSpec.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CDRExampleGroupSpec.m; sourceTree = ""; }; AEEE1FE911DC27B800029872 /* CDRExampleSpec.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CDRExampleSpec.m; sourceTree = ""; }; - AEEE1FEA11DC27B800029872 /* CppSpecSpec.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = CppSpecSpec.mm; sourceTree = ""; }; AEEE1FEC11DC27B800029872 /* CDRExampleStateMapSpec.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CDRExampleStateMapSpec.m; sourceTree = ""; }; AEEE1FED11DC27B800029872 /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; AEEE1FEE11DC27B800029872 /* SlowSpec.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SlowSpec.m; sourceTree = ""; }; @@ -338,6 +339,14 @@ name = Products; sourceTree = ""; }; + AE8C879F1362068A006C9305 /* Matchers */ = { + isa = PBXGroup; + children = ( + AE8C87A01362071E006C9305 /* EqualSpec.mm */, + ); + path = Matchers; + sourceTree = ""; + }; AEEE1FA411DC26EA00029872 = { isa = PBXGroup; children = ( @@ -433,7 +442,8 @@ isa = PBXGroup; children = ( AEEE1FE411DC27B800029872 /* ActualValue.h */, - AEEE1FE511DC27B800029872 /* ActualValue.mm */, + AE8C87531360CF02006C9305 /* AllMatchers.h */, + AE8C874D135FD1DB006C9305 /* Equal.h */, ); path = Matchers; sourceTree = ""; @@ -442,9 +452,9 @@ isa = PBXGroup; children = ( AEEE1FEB11DC27B800029872 /* iPhone */, + AE8C879F1362068A006C9305 /* Matchers */, AEEE1FE811DC27B800029872 /* CDRExampleGroupSpec.m */, AEEE1FE911DC27B800029872 /* CDRExampleSpec.m */, - AEEE1FEA11DC27B800029872 /* CppSpecSpec.mm */, AEEE1FEF11DC27B800029872 /* main.m */, AEEE1FF011DC27B800029872 /* SpecHelperSpec.m */, AEEE1FF111DC27B800029872 /* SpecSpec.m */, @@ -491,6 +501,8 @@ AEEE200811DC27B800029872 /* SpecHelper.h in Headers */, AE91CA6C11DE64A3002BA6B9 /* CDRSharedExampleGroupPool.h in Headers */, AEC9DEED12C2CC7E0039512D /* CDRColorizedReporter.h in Headers */, + AE8C87541360CF02006C9305 /* AllMatchers.h in Headers */, + AE8C877A1360F9EF006C9305 /* Equal.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -726,7 +738,6 @@ AEEE201111DC27B800029872 /* SpecHelper.m in Sources */, AEFD17BB11DD1E9E00F4448A /* CDRSharedExampleGroupPool.m in Sources */, AEC9DEEE12C2CC7E0039512D /* CDRColorizedReporter.m in Sources */, - AE0B8563135F94DC001EEA23 /* ActualValue.mm in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -740,7 +751,7 @@ AEEE21C211DC290400029872 /* SpecHelperSpec.m in Sources */, AEEE21C311DC290400029872 /* SpecSpec.m in Sources */, AEEE21C411DC290400029872 /* SpecSpec2.m in Sources */, - 66E33E53123CA82A00D326CC /* CppSpecSpec.mm in Sources */, + AE8C87A11362071E006C9305 /* EqualSpec.mm in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -763,7 +774,6 @@ AEEE223D11DC2B6D00029872 /* CedarApplicationDelegate.m in Sources */, AE9855AE1236E7080024094E /* CDRSharedExampleGroupPool.m in Sources */, AEC9DEF412C2CC8F0039512D /* CDRColorizedReporter.m in Sources */, - AE0B8564135F94DC001EEA23 /* ActualValue.mm in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -779,7 +789,7 @@ AEEE228611DC2D5800029872 /* CDRExampleStateMapSpec.m in Sources */, AEEE228711DC2D5800029872 /* main.m in Sources */, AEEE228811DC2D5800029872 /* SlowSpec.m in Sources */, - 66AEB6BE123C7CEE001C3DF1 /* CppSpecSpec.mm in Sources */, + AE8C87A21362071E006C9305 /* EqualSpec.mm in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/Source/Headers/CDRSpec.h b/Source/Headers/CDRSpec.h index c6ea3cf0..80b4ec69 100644 --- a/Source/Headers/CDRSpec.h +++ b/Source/Headers/CDRSpec.h @@ -21,6 +21,7 @@ void fail(NSString *); } #import "ActualValue.h" +#import "AllMatchers.h" #endif diff --git a/Source/Matchers/ActualValue.h b/Source/Matchers/ActualValue.h index 1e0c0872..33861503 100644 --- a/Source/Matchers/ActualValue.h +++ b/Source/Matchers/ActualValue.h @@ -19,38 +19,33 @@ namespace Cedar { namespace Matchers { public: ActualValue(const T &); - template - void toEqual(const U &) const; + template void to(const Matcher &) const; + template void to_not(const Matcher &) const; private: const T value_; }; - template - const ActualValue expect(const T & value) { - return ActualValue(value); + ActualValue::ActualValue(const T & value) : value_(value) { } template - ActualValue::ActualValue(const T & value) : value_(value) { + const ActualValue expect(const T & actualValue) { + return ActualValue(actualValue); } -#pragma mark toEqual - // Generic method must be defined here, not in the implementation file. - template template - void ActualValue::toEqual(const U & expectedValue) const { - if (expectedValue != value_) { - std::stringstream message; - message << "Expected <" << value_ << "> to equal <" << expectedValue << ">"; - - [[CDRSpecFailure specFailureWithReason:[NSString stringWithCString:message.str().c_str() encoding:NSUTF8StringEncoding]] raise]; + template template + void ActualValue::to(const Matcher & matcher) const { + if (!matcher.matches(value_)) { + [[CDRSpecFailure specFailureWithReason:matcher.failure_message()] raise]; } } - // Specialized methods must be declared here, but defined in the implementation file. - // If not declared here, OS X build will fail to pick up the specialization. If defined - // here, iOS builds will fail with duplicate symbol link errors. - template<> template<> - void ActualValue::toEqual(NSObject * const & expectedValue) const; + template template + void ActualValue::to_not(const Matcher & matcher) const { + if (matcher.matches(value_)) { + [[CDRSpecFailure specFailureWithReason:matcher.negative_failure_message()] raise]; + } + } }} diff --git a/Source/Matchers/ActualValue.mm b/Source/Matchers/ActualValue.mm deleted file mode 100644 index 56ade8ce..00000000 --- a/Source/Matchers/ActualValue.mm +++ /dev/null @@ -1,20 +0,0 @@ -#import "ActualValue.h" - -namespace Cedar { namespace Matchers { - - void fail(const NSString *failureMessage) { - [[CDRSpecFailure specFailureWithReason:[NSString stringWithFormat:@"Failure: %@", failureMessage]] raise]; - } - -#pragma mark toEqual - template<> template<> - void ActualValue::toEqual(NSObject * const & expectedValue) const { - if (![expectedValue isEqual:value_]) { - std::stringstream message; - message << "Expected NSObject <" << value_ << "> to equal NSObject <" << expectedValue << ">"; - - [[CDRSpecFailure specFailureWithReason:[NSString stringWithCString:message.str().c_str() encoding:NSUTF8StringEncoding]] raise]; - } - } - -}} diff --git a/Source/Matchers/AllMatchers.h b/Source/Matchers/AllMatchers.h new file mode 100644 index 00000000..f6117958 --- /dev/null +++ b/Source/Matchers/AllMatchers.h @@ -0,0 +1 @@ +#import "Equal.h" diff --git a/Source/Matchers/Equal.h b/Source/Matchers/Equal.h new file mode 100644 index 00000000..99204267 --- /dev/null +++ b/Source/Matchers/Equal.h @@ -0,0 +1,126 @@ +#import +#import "CDRExampleBase.h" + +#include +#include + +namespace Cedar { namespace Matchers { + template + class EqualMatcher { + private: + EqualMatcher & operator=(const EqualMatcher &); + + public: + EqualMatcher(const T & expectedValue); + ~EqualMatcher(); + // Allow default copy ctor. + + template + bool matches(const U &) const; + bool matches(const id &) const; + bool matches(NSObject * const &) const; + bool matches(NSString * const &) const; + + NSString * failure_message() const; + NSString * negative_failure_message() const; + + private: + template + NSString * stringFor(const U &) const; + NSString * stringFor(const id & value) const; + NSString * stringFor(NSObject * const &) const; + NSString * stringFor(NSString * const &) const; + + private: + const T & expectedValue_; + mutable NSString *actualValueString_; + }; + + template + EqualMatcher equal(const T & expectedValue) { + return EqualMatcher(expectedValue); + } + + template + EqualMatcher::EqualMatcher(const T & expectedValue) + : expectedValue_(expectedValue), actualValueString_(nil) { + } + + template + EqualMatcher::~EqualMatcher() { + [actualValueString_ release]; actualValueString_ = nil; + } + +#pragma mark Generic + template template + bool EqualMatcher::matches(const U & actualValue) const { + actualValueString_ = [this->stringFor(actualValue) retain]; + return expectedValue_ == actualValue; + } + + template template + NSString * EqualMatcher::stringFor(const U & value) const { + std::stringstream temp; + temp << value; + return [NSString stringWithCString:temp.str().c_str() encoding:NSUTF8StringEncoding]; + } + + template + NSString * EqualMatcher::failure_message() const { + return [NSString stringWithFormat:@"Expected <%@> to equal <%@>", actualValueString_, this->stringFor(expectedValue_)]; + } + + template + NSString * EqualMatcher::negative_failure_message() const { + return [NSString stringWithFormat:@"Expected <%@> to not equal <%@>", actualValueString_, this->stringFor(expectedValue_)]; + } + +#pragma mark id + template + bool EqualMatcher::matches(const id & actualValue) const { + actualValueString_ = [[NSString alloc] initWithFormat:@"%@", actualValue]; + return [actualValue isEqual:expectedValue_]; + } + + template<> template + bool EqualMatcher::matches(const U & actualValue) const { + [[CDRSpecFailure specFailureWithReason:@"Attempt to compare id to incomparable type"] raise]; + } + + template + NSString * EqualMatcher::stringFor(const id & value) const { + return [NSString stringWithFormat:@"%@", value]; + } + +#pragma mark NSObject + template + bool EqualMatcher::matches(NSObject * const & actualValue) const { + return this->matches(static_cast(actualValue)); + } + + template<> template + bool EqualMatcher::matches(const U & actualValue) const { + [[CDRSpecFailure specFailureWithReason:@"Attempt to compare NSObject * to incomparable type"] raise]; + } + + template + NSString * EqualMatcher::stringFor(NSObject * const & value) const { + return this->stringFor(static_cast(value)); + } + +#pragma mark NSString + template + bool EqualMatcher::matches(NSString * const & actualValue) const { + return this->matches(static_cast(actualValue)); + } + + template<> template + bool EqualMatcher::matches(const U & actualValue) const { + [[CDRSpecFailure specFailureWithReason:@"Attempt to compare NSString * to incomparable type"] raise]; + } + + template + NSString * EqualMatcher::stringFor(NSString * const & value) const { + return this->stringFor(static_cast(value)); + } +}} diff --git a/Spec/CppSpecSpec.mm b/Spec/CppSpecSpec.mm deleted file mode 100644 index e0f4321a..00000000 --- a/Spec/CppSpecSpec.mm +++ /dev/null @@ -1,46 +0,0 @@ -#define HC_SHORTHAND -#if TARGET_OS_IPHONE -#import -#import "OCMock.h" -#import "OCHamcrest.h" -#else -#import -#import -#import -#endif - -using namespace Cedar::Matchers; - -SPEC_BEGIN(CppSpecSpec) - -describe(@"CppSpec", ^{ - describe(@"Expectations", ^{ - describe(@"with built-in types", ^{ - __block int expectedValue; - - beforeEach(^ { - expectedValue = 1; - }); - - it(@"should run", ^{ - expect(1).toEqual(expectedValue); - }); - }); - - describe(@"with NSObject-based types", ^{ - __block NSObject *expectedValue; - int someInteger = 7; - - beforeEach(^ { - expectedValue = [NSString stringWithFormat:@"Value: %d", someInteger]; - }); - - it(@"should run", ^{ - NSObject *actualValue = [NSString stringWithFormat:@"Value: %d", someInteger]; - expect(actualValue).toEqual(expectedValue); - }); - }); - }); -}); - -SPEC_END diff --git a/Spec/Matchers/EqualSpec.mm b/Spec/Matchers/EqualSpec.mm new file mode 100644 index 00000000..8001be34 --- /dev/null +++ b/Spec/Matchers/EqualSpec.mm @@ -0,0 +1,555 @@ +#if TARGET_OS_IPHONE +#import +#import "OCMock.h" +#else +#import +#import +#endif + +using namespace Cedar::Matchers; + +void expectFailureWithMessage(NSString *message, CDRSpecBlock block) { + @try { + block(); + } + @catch (CDRSpecFailure *x) { + if (![message isEqualToString:x.reason]) { + fail([NSString stringWithFormat:@"Expected failure message: <%@> but received failure message <%@>", message, x.reason]); + } + return; + } + + fail(@"Expectation should have failed."); +} + +SPEC_BEGIN(EqualSpec) + +describe(@"Equal matcher", ^{ + describe(@"when the actual value is a built-in type", ^{ + int actualValue = 1; + + describe(@"and the expected value is the same built-in type", ^{ + __block int expectedValue; + + describe(@"and the values are equal", ^{ + beforeEach(^ { + expectedValue = 1; + }); + + describe(@"positive match", ^{ + it(@"should pass", ^{ + expect(actualValue).to(equal(expectedValue)); + }); + }); + + describe(@"negative match", ^{ + it(@"should fail with a sensible failure message", ^{ + expectFailureWithMessage(@"Expected <1> to not equal <1>", ^{ + expect(actualValue).to_not(equal(expectedValue)); + }); + }); + }); + }); + + describe(@"and the values are not equal", ^{ + beforeEach(^ { + expectedValue = 147; + }); + + describe(@"positive match", ^{ + it(@"should fail with a sensible failure message", ^{ + expectFailureWithMessage(@"Expected <1> to equal <147>", ^{ + expect(actualValue).to(equal(expectedValue)); + }); + }); + }); + + describe(@"negative match", ^{ + it(@"should pass", ^{ + expect(actualValue).to_not(equal(expectedValue)); + }); + }); + }); + }); + + describe(@"and the expected value is a different, but comparable, built-in type", ^{ + __block float expectedValue; + + describe(@"and the values are equal", ^{ + beforeEach(^ { + expectedValue = 1.0; + }); + + describe(@"positive match", ^{ + it(@"should pass", ^{ + expect(actualValue).to(equal(expectedValue)); + }); + }); + + describe(@"negative match", ^{ + it(@"should fail with a sensible failure message", ^{ + expectFailureWithMessage(@"Expected <1> to not equal <1>", ^{ + expect(actualValue).to_not(equal(expectedValue)); + }); + }); + }); + }); + + describe(@"and the values are not equal", ^{ + beforeEach(^ { + expectedValue = 0.87; + }); + + describe(@"positive match", ^{ + it(@"should fail with a sensible failure message", ^{ + expectFailureWithMessage(@"Expected <1> to equal <0.87>", ^{ + expect(actualValue).to(equal(expectedValue)); + }); + }); + }); + + describe(@"negative match", ^{ + it(@"should pass", ^{ + expect(actualValue).to_not(equal(expectedValue)); + }); + }); + }); + }); + + describe(@"and the expected value is an incomparable type", ^{ + it(@"should display an appropriate error for NSObject *", ^{ + NSObject *expectedValue = @"I am not an integer"; + expectFailureWithMessage(@"Attempt to compare NSObject * to incomparable type", ^{ + expect(actualValue).to(equal(expectedValue)); + }); + }); + + it(@"should display an appropriate error for id", ^{ + id expectedValue = @"I am not an integer"; + expectFailureWithMessage(@"Attempt to compare id to incomparable type", ^{ + expect(actualValue).to(equal(expectedValue)); + }); + }); + + it(@"should display an appropriate error for NSString *", ^{ + NSString *expectedValue = @"I am not an integer"; + expectFailureWithMessage(@"Attempt to compare NSString * to incomparable type", ^{ + expect(actualValue).to(equal(expectedValue)); + }); + }); + }); + }); + + describe(@"when the actual value is declared as an id", ^{ + int someInteger = 7; + id actualValue = [[NSString alloc] initWithFormat:@"%d", someInteger]; + + describe(@"and the expected value is declared as an NSObject *", ^{ + __block NSObject *expectedValue; + + describe(@"and the values are equal", ^{ + beforeEach(^{ + expectedValue = [NSString stringWithFormat:@"%d", someInteger]; + }); + + describe(@"positive match", ^{ + it(@"should pass", ^{ + expect(actualValue).to(equal(expectedValue)); + }); + }); + + describe(@"negative match", ^{ + it(@"should fail with a sensible failure message", ^{ + expectFailureWithMessage(@"Expected <7> to not equal <7>", ^{ + expect(actualValue).to_not(equal(expectedValue)); + }); + }); + }); + }); + + describe(@"and the values are not equal", ^{ + beforeEach(^{ + expectedValue = [NSString stringWithFormat:@"%d", someInteger + 1]; + }); + + describe(@"positive match", ^{ + it(@"should fail with a sensible failure message", ^{ + expectFailureWithMessage(@"Expected <7> to equal <8>", ^{ + expect(actualValue).to(equal(expectedValue)); + }); + }); + }); + + describe(@"negative match", ^{ + it(@"should pass", ^{ + expect(actualValue).to_not(equal(expectedValue)); + }); + }); + }); + }); + + describe(@"and the expected value is also declared as an id", ^{ + __block id expectedValue; + + describe(@"and the values are equal", ^{ + beforeEach(^{ + expectedValue = [NSString stringWithFormat:@"%d", someInteger]; + }); + + describe(@"positive match", ^{ + it(@"should pass", ^{ + expect(actualValue).to(equal(expectedValue)); + }); + }); + + describe(@"negative match", ^{ + it(@"should fail with a sensible failure message", ^{ + expectFailureWithMessage(@"Expected <7> to not equal <7>", ^{ + expect(actualValue).to_not(equal(expectedValue)); + }); + }); + }); + }); + + describe(@"and the values are not equal", ^{ + beforeEach(^{ + expectedValue = [NSString stringWithFormat:@"%d", someInteger + 1]; + }); + + describe(@"positive match", ^{ + it(@"should fail with a sensible failure message", ^{ + expectFailureWithMessage(@"Expected <7> to equal <8>", ^{ + expect(actualValue).to(equal(expectedValue)); + }); + }); + }); + + describe(@"negative match", ^{ + it(@"should pass", ^{ + expect(actualValue).to_not(equal(expectedValue)); + }); + }); + }); + }); + + describe(@"and the expected value is declared as an NSString *", ^{ + __block NSString *expectedValue; + + describe(@"and the values are equal", ^{ + beforeEach(^{ + expectedValue = [NSString stringWithFormat:@"%d", someInteger]; + }); + + describe(@"positive match", ^{ + it(@"should pass", ^{ + expect(actualValue).to(equal(expectedValue)); + }); + }); + + describe(@"negative match", ^{ + it(@"should fail with a sensible failure message", ^{ + expectFailureWithMessage(@"Expected <7> to not equal <7>", ^{ + expect(actualValue).to_not(equal(expectedValue)); + }); + }); + }); + }); + + describe(@"and the values are not equal", ^{ + beforeEach(^{ + expectedValue = [NSString stringWithFormat:@"%d", someInteger + 1]; + }); + + describe(@"positive match", ^{ + it(@"should fail with a sensible failure message", ^{ + expectFailureWithMessage(@"Expected <7> to equal <8>", ^{ + expect(actualValue).to(equal(expectedValue)); + }); + }); + }); + + describe(@"negative match", ^{ + it(@"should pass", ^{ + expect(actualValue).to_not(equal(expectedValue)); + }); + }); + }); + }); + }); + + describe(@"when the actual value is declared as an NSObject *", ^{ + int someInteger = 7; + NSObject *actualValue = [[NSString alloc] initWithFormat:@"%d", someInteger]; + + describe(@"and the expected value is also declared as an NSObject *", ^{ + __block NSObject *expectedValue; + + describe(@"and the values are equal", ^{ + beforeEach(^{ + expectedValue = [NSString stringWithFormat:@"%d", someInteger]; + }); + + describe(@"positive match", ^{ + it(@"should pass", ^{ + expect(actualValue).to(equal(expectedValue)); + }); + }); + + describe(@"negative match", ^{ + it(@"should fail with a sensible failure message", ^{ + expectFailureWithMessage(@"Expected <7> to not equal <7>", ^{ + expect(actualValue).to_not(equal(expectedValue)); + }); + }); + }); + }); + + describe(@"and the values are not equal", ^{ + beforeEach(^{ + expectedValue = [NSString stringWithFormat:@"%d", someInteger + 1]; + }); + + describe(@"positive match", ^{ + it(@"should fail with a sensible failure message", ^{ + expectFailureWithMessage(@"Expected <7> to equal <8>", ^{ + expect(actualValue).to(equal(expectedValue)); + }); + }); + }); + + describe(@"negative match", ^{ + it(@"should pass", ^{ + expect(actualValue).to_not(equal(expectedValue)); + }); + }); + }); + }); + + describe(@"and the expected value is declared as an id", ^{ + __block id expectedValue; + + describe(@"and the values are equal", ^{ + beforeEach(^{ + expectedValue = [NSString stringWithFormat:@"%d", someInteger]; + }); + + describe(@"positive match", ^{ + it(@"should pass", ^{ + expect(actualValue).to(equal(expectedValue)); + }); + }); + + describe(@"negative match", ^{ + it(@"should fail with a sensible failure message", ^{ + expectFailureWithMessage(@"Expected <7> to not equal <7>", ^{ + expect(actualValue).to_not(equal(expectedValue)); + }); + }); + }); + }); + + describe(@"and the values are not equal", ^{ + beforeEach(^{ + expectedValue = [NSString stringWithFormat:@"%d", someInteger + 1]; + }); + + describe(@"positive match", ^{ + it(@"should fail with a sensible failure message", ^{ + expectFailureWithMessage(@"Expected <7> to equal <8>", ^{ + expect(actualValue).to(equal(expectedValue)); + }); + }); + }); + + describe(@"negative match", ^{ + it(@"should pass", ^{ + expect(actualValue).to_not(equal(expectedValue)); + }); + }); + }); + }); + + describe(@"and the expected value is declared as an NSString *", ^{ + __block NSString *expectedValue; + + describe(@"and the values are equal", ^{ + beforeEach(^{ + expectedValue = [NSString stringWithFormat:@"%d", someInteger]; + }); + + describe(@"positive match", ^{ + it(@"should pass", ^{ + expect(actualValue).to(equal(expectedValue)); + }); + }); + + describe(@"negative match", ^{ + it(@"should fail with a sensible failure message", ^{ + expectFailureWithMessage(@"Expected <7> to not equal <7>", ^{ + expect(actualValue).to_not(equal(expectedValue)); + }); + }); + }); + }); + + describe(@"and the values are not equal", ^{ + beforeEach(^{ + expectedValue = [NSString stringWithFormat:@"%d", someInteger + 1]; + }); + + describe(@"positive match", ^{ + it(@"should fail with a sensible failure message", ^{ + expectFailureWithMessage(@"Expected <7> to equal <8>", ^{ + expect(actualValue).to(equal(expectedValue)); + }); + }); + }); + + describe(@"negative match", ^{ + it(@"should pass", ^{ + expect(actualValue).to_not(equal(expectedValue)); + }); + }); + }); + }); + }); + + describe(@"when the actual value is declared as an NSString *", ^{ + int someInteger = 7; + NSString *actualValue = [[NSString alloc] initWithFormat:@"%d", someInteger]; + + describe(@"and the expected value is declared as an NSObject *", ^{ + __block NSObject *expectedValue; + + describe(@"and the values are equal", ^{ + beforeEach(^{ + expectedValue = [NSString stringWithFormat:@"%d", someInteger]; + }); + + describe(@"positive match", ^{ + it(@"should pass", ^{ + expect(actualValue).to(equal(expectedValue)); + }); + }); + + describe(@"negative match", ^{ + it(@"should fail with a sensible failure message", ^{ + expectFailureWithMessage(@"Expected <7> to not equal <7>", ^{ + expect(actualValue).to_not(equal(expectedValue)); + }); + }); + }); + }); + + describe(@"and the values are not equal", ^{ + beforeEach(^{ + expectedValue = [NSString stringWithFormat:@"%d", someInteger + 1]; + }); + + describe(@"positive match", ^{ + it(@"should fail with a sensible failure message", ^{ + expectFailureWithMessage(@"Expected <7> to equal <8>", ^{ + expect(actualValue).to(equal(expectedValue)); + }); + }); + }); + + describe(@"negative match", ^{ + it(@"should pass", ^{ + expect(actualValue).to_not(equal(expectedValue)); + }); + }); + }); + }); + + describe(@"and the expected value is declared as an id", ^{ + __block id expectedValue; + + describe(@"and the values are equal", ^{ + beforeEach(^{ + expectedValue = [NSString stringWithFormat:@"%d", someInteger]; + }); + + describe(@"positive match", ^{ + it(@"should pass", ^{ + expect(actualValue).to(equal(expectedValue)); + }); + }); + + describe(@"negative match", ^{ + it(@"should fail with a sensible failure message", ^{ + expectFailureWithMessage(@"Expected <7> to not equal <7>", ^{ + expect(actualValue).to_not(equal(expectedValue)); + }); + }); + }); + }); + + describe(@"and the values are not equal", ^{ + beforeEach(^{ + expectedValue = [NSString stringWithFormat:@"%d", someInteger + 1]; + }); + + describe(@"positive match", ^{ + it(@"should fail with a sensible failure message", ^{ + expectFailureWithMessage(@"Expected <7> to equal <8>", ^{ + expect(actualValue).to(equal(expectedValue)); + }); + }); + }); + + describe(@"negative match", ^{ + it(@"should pass", ^{ + expect(actualValue).to_not(equal(expectedValue)); + }); + }); + }); + }); + + describe(@"and the expected value is also declared as an NSString *", ^{ + __block NSString *expectedValue; + + describe(@"and the values are equal", ^{ + beforeEach(^{ + expectedValue = [NSString stringWithFormat:@"%d", someInteger]; + }); + + describe(@"positive match", ^{ + it(@"should pass", ^{ + expect(actualValue).to(equal(expectedValue)); + }); + }); + + describe(@"negative match", ^{ + it(@"should fail with a sensible failure message", ^{ + expectFailureWithMessage(@"Expected <7> to not equal <7>", ^{ + expect(actualValue).to_not(equal(expectedValue)); + }); + }); + }); + }); + + describe(@"and the values are not equal", ^{ + beforeEach(^{ + expectedValue = [NSString stringWithFormat:@"%d", someInteger + 1]; + }); + + describe(@"positive match", ^{ + it(@"should fail with a sensible failure message", ^{ + expectFailureWithMessage(@"Expected <7> to equal <8>", ^{ + expect(actualValue).to(equal(expectedValue)); + }); + }); + }); + + describe(@"negative match", ^{ + it(@"should pass", ^{ + expect(actualValue).to_not(equal(expectedValue)); + }); + }); + }); + }); + }); +}); + +SPEC_END