From db00a318ececa8fdf9845190baa594a2b6f578ed Mon Sep 17 00:00:00 2001 From: Brian Gesiak Date: Sat, 27 Sep 2014 14:33:28 -0400 Subject: [PATCH 1/2] QCKDSL: no 'qck_' prefix unless shorthand disabled Users may now use Quick in Objective-C using the following syntax (notice the lack of the `qck_` prefix): ```objc QuickSpecBegin(DolphinSpec) describe(@"a dolphin", ^{ it(@"is the smartest animal in the ocean", ^{ // ... }); }); QuickSpecEnd ``` To namespace the `describe`, `it`, and other macros with the `qck_` prefix, users must `#define QUICK_DISABLE_SHORT_SYNTAX 1` before importing the Quick header. Addresses issue #66. --- Quick/Quick/QCKDSL.h | 17 +++++++++++++ Quick/QuickTests/FunctionalTests+ObjC.m | 32 ++++++++++++------------- 2 files changed, 33 insertions(+), 16 deletions(-) diff --git a/Quick/Quick/QCKDSL.h b/Quick/Quick/QCKDSL.h index 5b5ea58d1..d53a49afb 100644 --- a/Quick/Quick/QCKDSL.h +++ b/Quick/Quick/QCKDSL.h @@ -30,6 +30,7 @@ @end \ + #define qck_beforeSuite(...) [QCKDSL beforeSuite:__VA_ARGS__] #define qck_afterSuite(...) [QCKDSL afterSuite:__VA_ARGS__] #define qck_sharedExamples(name, ...) [QCKDSL sharedExamples:name closure:__VA_ARGS__] @@ -44,6 +45,22 @@ #define qck_xcontext(description, ...) [QCKDSL xcontext:description closure:__VA_ARGS__] #define qck_xit(description, ...) [QCKDSL xit:description closure:__VA_ARGS__] +#ifndef QUICK_DISABLE_SHORT_SYNTAX +#define beforeSuite(...) qck_beforeSuite(__VA_ARGS__) +#define afterSuite(...) qck_afterSuite(__VA_ARGS__) +#define sharedExamples(name, ...) qck_sharedExamples(name, __VA_ARGS__) +#define describe(description, ...) qck_describe(description, __VA_ARGS__) +#define context(description, ...) qck_context(description, __VA_ARGS__) +#define beforeEach(...) qck_beforeEach(__VA_ARGS__) +#define afterEach(...) qck_afterEach(__VA_ARGS__) +#define it(description, ...) qck_it(description, __VA_ARGS__) +#define itBehavesLike(name, ...) qck_itBehavesLike(name, __VA_ARGS__) +#define pending(description, ...) qck_pending(description, __VA_ARGS__) +#define xdescribe(description, ...) qck_xdescribe(description, __VA_ARGS__) +#define xcontext(description, ...) qck_xcontext(description, __VA_ARGS__) +#define xit(description, ...) qck_xit(description, __VA_ARGS__) +#endif + typedef NSDictionary *(^QCKDSLSharedExampleContext)(void); typedef void (^QCKDSLSharedExampleBlock)(QCKDSLSharedExampleContext); diff --git a/Quick/QuickTests/FunctionalTests+ObjC.m b/Quick/QuickTests/FunctionalTests+ObjC.m index 1f9bc18ef..2f68fd86b 100644 --- a/Quick/QuickTests/FunctionalTests+ObjC.m +++ b/Quick/QuickTests/FunctionalTests+ObjC.m @@ -12,13 +12,13 @@ QuickSharedExampleGroupsBegin(FunctionalTestsObjCSharedExampleGroups) -qck_sharedExamples(@"a truthy value", ^(QCKDSLSharedExampleContext context) { +sharedExamples(@"a truthy value", ^(QCKDSLSharedExampleContext sharedExampleContext) { __block NSNumber *value = nil; - qck_beforeEach(^{ - value = context()[@"value"]; + beforeEach(^{ + value = sharedExampleContext()[@"value"]; }); - qck_it(@"is true", ^{ + it(@"is true", ^{ expect(value).to(beTruthy()); }); }); @@ -31,40 +31,40 @@ QuickSpecBegin(FunctionalTestsObjC) -qck_beforeSuite(^{ +beforeSuite(^{ beforeSuiteExecuted_afterSuiteNotYetExecuted = YES; }); -qck_afterSuite(^{ +afterSuite(^{ beforeSuiteExecuted_afterSuiteNotYetExecuted = NO; }); -qck_describe(@"a describe block", ^{ - qck_it(@"contains an it block", ^{ +describe(@"a describe block", ^{ + it(@"contains an it block", ^{ expect(@(beforeSuiteExecuted_afterSuiteNotYetExecuted)).to(beTruthy()); }); - qck_itBehavesLike(@"a truthy value", ^{ return @{ @"value": @YES }; }); + itBehavesLike(@"a truthy value", ^{ return @{ @"value": @YES }; }); - qck_pending(@"a pending block", ^{ - qck_it(@"contains a failing it block", ^{ + pending(@"a pending block", ^{ + it(@"contains a failing it block", ^{ expect(@NO).to(beTruthy()); }); }); - qck_xdescribe(@"a pending (shorthand) describe block", ^{ - qck_it(@"contains a failing it block", ^{ + xdescribe(@"a pending (shorthand) describe block", ^{ + it(@"contains a failing it block", ^{ expect(@NO).to(beTruthy()); }); }); - qck_xcontext(@"a pending (shorthand) context block", ^{ - qck_it(@"contains a failing it block", ^{ + xcontext(@"a pending (shorthand) context block", ^{ + it(@"contains a failing it block", ^{ expect(@NO).to(beTruthy()); }); }); - qck_xit(@"contains a pending (shorthand) it block", ^{ + xit(@"contains a pending (shorthand) it block", ^{ expect(@NO).to(beTruthy()); }); }); From a733262890abc5b80d694cd1d8db5889957aabe6 Mon Sep 17 00:00:00 2001 From: Brian Gesiak Date: Sat, 27 Sep 2014 14:51:21 -0400 Subject: [PATCH 2/2] README: Use shorthand Objective-C syntax - Use shorthand Objective-C syntax - Add note on disabling Objective-C shorthand - Update table of contents --- Quick/Quick/QCKDSL.h | 1 - README.md | 86 +++++++++++++++++++++++++++----------------- 2 files changed, 54 insertions(+), 33 deletions(-) diff --git a/Quick/Quick/QCKDSL.h b/Quick/Quick/QCKDSL.h index d53a49afb..4a0c24d53 100644 --- a/Quick/Quick/QCKDSL.h +++ b/Quick/Quick/QCKDSL.h @@ -30,7 +30,6 @@ @end \ - #define qck_beforeSuite(...) [QCKDSL beforeSuite:__VA_ARGS__] #define qck_afterSuite(...) [QCKDSL afterSuite:__VA_ARGS__] #define qck_sharedExamples(name, ...) [QCKDSL sharedExamples:name closure:__VA_ARGS__] diff --git a/README.md b/README.md index 0a47570ec..20e635434 100644 --- a/README.md +++ b/README.md @@ -44,8 +44,10 @@ class TableOfContentsSpec: QuickSpec { - [Sharing Setup/Teardown Code Using `beforeEach` and `afterEach`](#sharing-setupteardown-code-using-beforeeach-and-aftereach) - [Specifying Conditional Behavior Using `context`](#specifying-conditional-behavior-using-context) - [Temporarily Disabling Examples or Groups Using `pending`](#temporarily-disabling-examples-or-groups-using-pending) + - [Shorthand syntax](#shorthand-syntax) - [Global Setup/Teardown Using `beforeSuite` and `afterSuite`](#global-setupteardown-using-beforesuite-and-aftersuite) - [Sharing Examples](#sharing-examples) +- [Using Quick in Objective-C: The Optional Shorthand Syntax](#using-quick-in-objective-c-the-optional-shorthand-syntax) - [Nimble: Assertions Using `expect(...).to`](#nimble-assertions-using-expectto) - [Testing UIKit with Quick](#testing-uikit-with-quick) - [How to Install Quick](#how-to-install-quick) @@ -105,11 +107,11 @@ class DolphinSpec: QuickSpec { QuickSpecBegin(DolphinSpec) -qck_it(@"is friendly", ^{ +it(@"is friendly", ^{ expect(@([[Dolphin new] isFriendly])).to(beTruthy()); }); -qck_it(@"is smart", ^{ +it(@"is smart", ^{ expect(@([[Dolphin new] isSmart])).to(beTruthy()); }); @@ -164,14 +166,14 @@ class DolphinSpec: QuickSpec { QuickSpecBegin(DolphinSpec) -qck_describe(@"a dolphin", ^{ - qck_describe(@"its click", ^{ - qck_it(@"is loud", ^{ +describe(@"a dolphin", ^{ + describe(@"its click", ^{ + it(@"is loud", ^{ Click *click = [[Dolphin new] click]; expect(@(click.isLoud)).to(beTruthy()); }); - qck_it(@"has a high frequency", ^{ + it(@"has a high frequency", ^{ Click *click = [[Dolphin new] click]; expect(@(click.hasHighFrequency)).to(beTruthy()); }); @@ -231,23 +233,23 @@ class DolphinSpec: QuickSpec { QuickSpecBegin(DolphinSpec) -qck_describe(@"a dolphin", ^{ +describe(@"a dolphin", ^{ __block Dolphin *dolphin = nil; - qck_beforeEach(^{ + beforeEach(^{ dolphin = [Dolphin new]; }); - qck_describe(@"its click", ^{ + describe(@"its click", ^{ __block Click *click = nil; - qck_beforeEach(^{ + beforeEach(^{ click = [dolphin click]; }); - qck_it(@"is loud", ^{ + it(@"is loud", ^{ expect(@(click.isLoud)).to(beTruthy()); }); - qck_it(@"has a high frequency", ^{ + it(@"has a high frequency", ^{ expect(@(click.hasHighFrequency)).to(beTruthy()); }); }); @@ -320,24 +322,24 @@ class DolphinSpec: QuickSpec { QuickSpecBegin(DolphinSpec) -qck_describe(@"a dolphin", ^{ +describe(@"a dolphin", ^{ __block Dolphin *dolphin = nil; - qck_beforeEach(^{ dolphin = [Dolphin new]; }); + beforeEach(^{ dolphin = [Dolphin new]; }); - qck_describe(@"its click", ^{ - qck_context(@"when the dolphin is not near anything interesting", ^{ - qck_it(@"is only emitted once", ^{ + describe(@"its click", ^{ + context(@"when the dolphin is not near anything interesting", ^{ + it(@"is only emitted once", ^{ expect(@([[dolphin click] count])).to(equal(@1)); }); }); - qck_context(@"when the dolphin is near something interesting", ^{ - qck_beforeEach(^{ + context(@"when the dolphin is near something interesting", ^{ + beforeEach(^{ [[Jamaica dolphinCove] add:[SunkenShip new]]; [[Jamaica dolphinCove] add:dolphin]; }); - qck_it(@"is emitted three times", ^{ + it(@"is emitted three times", ^{ expect(@([[dolphin click] count])).to(equal(@3)); }); }); @@ -349,9 +351,8 @@ QuickSpecEnd ### Temporarily Disabling Examples or Groups Using `pending` -For examples that don't pass yet, use `pending` in Swift, or -`qck_pending` in Objective-C. Pending examples are not run, -but are printed out along with the test results. +For examples that don't pass yet, use `pending`. Pending examples +are not run, but are printed out along with the test results. The example below marks the cases in which the dolphin is close to something interesting as "pending"--perhaps that functionality hasn't @@ -369,7 +370,7 @@ pending("when the dolphin is near something interesting") { ```objc // Objective-C -qck_pending(@"when the dolphin is near something interesting", ^{ +pending(@"when the dolphin is near something interesting", ^{ // ...none of the code in this closure will be run. }); ``` @@ -377,8 +378,7 @@ qck_pending(@"when the dolphin is near something interesting", ^{ #### Shorthand syntax Examples and groups can also be marked as pending by using -`xdescribe`, `xcontext`, and `xit` in Swift, and `qck_xdescribe`, -`qck_xcontext`, and `qck_xit` in Objective-C. +`xdescribe`, `xcontext`, and `xit`: ```swift // Swift @@ -399,15 +399,15 @@ xit("is only emitted once") { ```objc // Objective-C -qck_xdescribe(@"its click", ^{ +xdescribe(@"its click", ^{ // ...none of the code in this closure will be run. }); -qck_xcontext(@"when the dolphin is not near anything interesting", ^{ +xcontext(@"when the dolphin is not near anything interesting", ^{ // ...none of the code in this closure will be run. }); -qck_xit(@"is only emitted once", ^{ +xit(@"is only emitted once", ^{ // ...none of the code in this closure will be run. }); ``` @@ -451,16 +451,16 @@ class DolphinSpec: QuickSpec { QuickSpecBegin(DolphinSpec) -qck_beforeSuite(^{ +beforeSuite(^{ [OceanDatabase createDatabase:@"test.db"]; [OceanDatabase connectToDatabase:@"test.db"]; }); -qck_afterSuite(^{ +afterSuite(^{ [OceanDatabase teardownDatabase:@"test.db"]; }); -qck_describe(@"a dolphin", ^{ +describe(@"a dolphin", ^{ // ... }); @@ -594,6 +594,28 @@ itBehavesLike("everything under the sea") argument. Sorry, but that's the way the cookie crumbles! :cookie: :bomb: +## Using Quick in Objective-C: The Optional Shorthand Syntax + +Quick works equally well in both Swift and Objective-C. + +Importing Quick in an Objective-C file defines macros such as `it`, +`context`, and `describe`. It's possible that the project you are +testing also defines symbols with these same names. In that case, you +can avoid namespace collision by turning off Quick's optional "shorthand" syntax: + +```objc +#define QUICK_DISABLE_SHORT_SYNTAX 1 + +#import + +QuickSpecBegin(DolphinSpec) +// ... +QuickSpecEnd +``` + +You must define the `QUICK_DISABLE_SHORT_SYNTAX` macro *before* +importing the Quick header. + ## Nimble: Assertions Using `expect(...).to` Quick provides an easy language to define examples and example groups. Within those