PageRenderTime 48ms CodeModel.GetById 14ms app.highlight 29ms RepoModel.GetById 1ms app.codeStats 0ms

/test/passenger_pane/NuBacon/README.md

http://github.com/tgunr/passengerpane
Markdown | 305 lines | 217 code | 88 blank | 0 comment | 0 complexity | 2dc8ddc17cf9a63b7f4adaeaeea8fed5 MD5 | raw file
  1NuBacon -- small RSpec clone
  2============================
  3
  4    "Truth will sooner come out from error than from confusion."
  5                                               ---Francis Bacon
  6
  7NuBacon is a [Nu][nu] port of [Bacon][ba], a small [Ruby RSpec][rs] clone.
  8
  9It is a [Behavior-Driven Development][bdd] test library for Nu and in
 10extension for Objective-C. It is being developed while using in our iOS
 11application, more on that will be announced.
 12
 13
 14Installation
 15------------
 16
 17There's currently no Nu specific package manager, so you will have to
 18grab the source directly:
 19
 20As a zip archive:
 21
 22    $ curl https://github.com/alloy/NuBacon/zipball/0.1 -o NuBacon-0.1.zip
 23    $ unzip NuBacon-0.1.zip
 24
 25Or as a git clone:
 26
 27    $ git clone git@github.com:alloy/NuBacon.git
 28    $ cd NuBacon
 29    $ git checkout 0.1
 30
 31Or checkout master if you’re feeling adventurous. The runloop code,
 32for instance, is not yet available in a release.
 33
 34Whirl-wind tour
 35---------------
 36
 37    (load "bacon")
 38
 39    (set emptyArray (do (array) (eq (array count) 0)))
 40
 41    (describe "An array" `(
 42      (before (do ()
 43        (set @ary (NSArray array))
 44        (set @otherArray (`("noodles") array))
 45      ))
 46
 47      (it "is empty" (do ()
 48        (~ @ary should not containObject:1)
 49      ))
 50
 51      (it "has zero elements" (do ()
 52        (~ @ary count should be:0)
 53        (~ @ary count should not be closeTo:0.1) ; default delta of 0.00001
 54        (~ @ary count should be closeTo:0.1 delta:0.2)
 55      ))
 56
 57      (it "raises when trying to fetch an element" (do ()
 58        (set exception (-> (@ary objectAtIndex:0) should raise:"NSRangeException"))
 59        (~ (exception reason) should match:/beyond bounds/)
 60      ))
 61
 62      (it "compares to another object" (do ()
 63        (~ @ary should be:@ary)
 64        (~ @ary should equal:@ary)
 65        (~ @otherArray should not be:@ary)
 66        (~ @otherArray should not equal:@ary)
 67      ))
 68
 69      (it "changes the count when adding objects" (do ()
 70        (-> (@otherArray << "soup") should change:(do () (@otherArray count)) by:+1)
 71      ))
 72
 73      (it "performs a long running operation" (do ()
 74        (@otherArray performSelector:"addObject:" withObject:"soup" afterDelay:0.5)
 75        (wait 0.6 (do ()
 76          (~ (@otherArray count) should be:2)
 77        ))
 78      ))
 79
 80      ; Custom assertions are trivial to do, they are blocks returning
 81      ; a boolean value. The block is defined at the top.
 82      (it "uses a custom assertion to check if the array is empty" (do ()
 83        (~ @ary should be a: emptyArray)
 84        (~ @otherArray should not be a: emptyArray)
 85      ))
 86
 87      (it "has super powers" (do ()
 88        ; flunks when it contains no assertions
 89      ))
 90    ))
 91
 92    ((Bacon sharedInstance) run)
 93
 94Now run it:
 95
 96    $ nush readme_spec.nu
 97
 98    An array
 99    - is empty
100    - has zero elements
101    - raises when trying to fetch an element
102    - compares to another object
103    - changes the count when adding objects
104    - performs a long running operation
105    - uses a custom assertion to check if the array is empty
106    - has super powers [FAILURE]
107
108    An array - has super powers: flunked [FAILURE]
109
110    8 specifications (14 requirements), 1 failures, 0 errors
111
112Implemented assertions
113----------------------
114
115* should:predicateBlock
116* should be:object
117* should (be) a:object
118* should equal:object
119* should (be) closeTo:__*float | list of floats*__
120* should (be) closeTo:__*float | list of floats*__ delta:float
121* should match:regexp
122* should change:valueBlock
123* should change:valueBlock by:delta
124* should raise
125* should raise:exceptionName
126* should __*predicate method*__
127* should __*dynamic predicate message matching*__
128* should satisfy:message block:block
129
130
131Predicate methods
132-----------------
133
134Any method of the object being tested, that can work as a predicate,
135can be called on the BaconShould instance that wraps it. The result
136of the method call will determine wether or not the assertion passes.
137Any return value that evaluates to `true` will pass, likewise any
138value that evaluates to `false` will fail. Unless the assertion has
139been negated with `not`.
140
141For instance, NSString has a `isAbsolutePath` predicate method:
142
143    (~ "/an/absolute/path" should isAbsolutePath)
144    (~ "a/relative/path" should not isAbsolutePath)
145
146However, as you can see this does not always lead to proper English,
147therefor there are a few special rules on how these methods can be
148called.
149
150If the predicate method starts with ‘is’ it can be omitted. The
151previous example can thus be rewritten as:
152
153    (~ "/an/absolute/path" should be an absolutePath)
154    (~ "a/relative/path" should not be an absolutePath)
155
156Method names in the third-person perspective can be called in the
157first-person perspective. For example, `respondsToSelector:` can be
158called by omitting the ‘s’ from ‘responds’:
159
160    (~ "foo" should respondToSelector:"isAbsolutePath")
161    (~ (NSArray array) should not respondToSelector:"isAbsolutePath")
162
163
164before/after
165------------
166
167`before` and `after` need to be defined before the first specification
168that should have them applied.
169
170
171Nested contexts
172---------------
173
174You can nest contexts, which will run before/after filters of parent
175contexts like so:
176
177    (describe "parent context" `(
178      (describe "child context" `(
179      ))
180    ))
181
182
183Shared contexts
184---------------
185
186You can define shared contexts in NuBacon like this:
187
188    (shared "an empty container" `(
189      (it "has size zero" (do ()
190        (~ (@ary count) should be:0)
191      ))
192
193      (it "is empty" (do ()
194        (~ @ary should be: emptyArray)
195      ))
196    ))
197
198    (describe "A new array" `(
199      (before (do ()
200        (set @ary (NSArray array))
201      )
202
203      (behaves_like "an empty container")
204    ))
205
206These contexts are not executed on their own, but can be included with
207behaves_like in other contexts.  You can use shared contexts to
208structure suites with many recurring specifications.
209
210
211The ‘wait’ macro
212----------------
213
214Often in Objective-C apps, code will __not__ execute immediately, but
215scheduled on a runloop for later execution. Therefor a mechanism is
216needed that will postpone execution of some assertions for a period of
217time. This is where the `wait` macro comes in:
218
219      (it "performs a long running operation" (do ()
220        ; Here a method call is scheduled to be performed ~0.5 seconds in the future
221        (@otherArray performSelector:"addObject:" withObject:"soup" afterDelay:0.5)
222        (wait 0.6 (do ()
223          ; This block is executed ~0.6 seconds in the future
224          (~ (@otherArray count) should be:2)
225        ))
226      ))
227
228The postponed block does __not__ halt the thread, but is scheduled on
229the runloop as well. This means that your runloop based code will have
230a chance to perform its job before the assertions in the block are
231executed.
232
233You can schedule as many blocks as you’d want and even nest them.
234
235
236Helper macros
237-------------
238
239Nesting calls to assertions can become unreadable quite fast:
240
241    (((((@ary count) should) not) be) closeTo:0.1 delta:0.2)
242
243For this purpose, the `~` macro has been introduced. It iterates over
244the symbols in the given list and sends those as messages to the
245object, which is the first item in the list:
246
247    (~ @ary count should not be closeTo:0.1 delta:0.2)
248
249-------------
250
251The `raise` and `raise:` assertions will execute the block, which is
252the wrapped object, and assert that an exception is, or isn't, raised.
253
254But creating a block and wrapping it in a BaconShould instance can
255look a bit arcane, and you have to remember to use `send`:
256
257    ((send (do () ((NSArray array) objectAtIndex:0)) should) raise:"NSRangeException")
258
259Therefore the `->` macro has been introduced:
260
261    (-> (@ary objectAtIndex:0) should raise:"NSRangeException")
262
263As you might have been able to tell, any extra messages are
264dynamically dispatched by the `~` macro.
265
266
267Thanks to
268---------
269
270* [Christian Neukirchen][cn], and other contributors, for Bacon itself!
271* Tim Burks for Nu
272* Laurent Sansonetti for brainwashing me about lisps ;)
273
274
275Contributing
276------------
277
278There's still plenty to do, see the [TODO][td] for things that need to be done.
279
280Once you've made your great commits:
281
2821. [Fork][fk] NuBacon
2832. Create a topic branch - `git checkout -b my_branch`
2843. Push to your branch - `git push origin my_branch`
2854. Create a pull request or [issue][is] with a link to your branch
2865. That's it!
287
288
289LICENSE
290-------
291
292Copyright (C) 2010 Eloy Durán <eloy.de.enige@gmail.com>, Fingertips BV <fngtps.com>
293
294NuBacon is freely distributable under the terms of an MIT-style license.
295See [LICENSE][li] or http://www.opensource.org/licenses/mit-license.php.
296
297[nu]:  https://github.com/timburks/nu
298[ba]:  https://github.com/chneukirchen/bacon
299[rs]:  http://rspec.rubyforge.org
300[bdd]: http://behaviour-driven.org
301[fk]:  http://help.github.com/forking
302[is]:  https://github.com/alloy/NuBacon/issues
303[li]:  https://github.com/alloy/NuBacon/blob/master/LICENSE
304[td]:  https://github.com/alloy/NuBacon/blob/master/TODO
305[cn]:  http://chneukirchen.org