/test/passenger_pane/NuBacon/README.md
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