minitest-given 0.1.pre → 3.0.0.beta.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (44) hide show
  1. checksums.yaml +7 -0
  2. data/Gemfile +7 -0
  3. data/Gemfile.lock +27 -0
  4. data/{README.rdoc → MIT-LICENSE} +1 -29
  5. data/README.md +763 -0
  6. data/Rakefile +225 -15
  7. data/TODO +13 -0
  8. data/doc/main.rdoc +7 -0
  9. data/examples/example_helper.rb +10 -0
  10. data/examples/failing/natural_failing_spec.rb +48 -0
  11. data/examples/failing/sample_spec.rb +7 -0
  12. data/examples/integration/and_spec.rb +44 -0
  13. data/examples/integration/failing/eval_subexpression_spec.rb +9 -0
  14. data/examples/integration/failing/module_nesting_spec.rb +13 -0
  15. data/examples/integration/failing/undefined_method_spec.rb +9 -0
  16. data/examples/integration/failing_messages_spec.rb +38 -0
  17. data/examples/integration/focused_line_spec.rb +9 -0
  18. data/examples/integration/given_spec.rb +73 -0
  19. data/examples/integration/invariant_spec.rb +31 -0
  20. data/examples/integration/then_spec.rb +8 -0
  21. data/examples/loader.rb +4 -0
  22. data/examples/minitest_helper.rb +38 -0
  23. data/examples/other/line_example.rb +9 -0
  24. data/examples/stack/stack.rb +29 -0
  25. data/examples/stack/stack_spec.rb +60 -0
  26. data/examples/stack/stack_spec1.rb +3 -0
  27. data/lib/given.rb +2 -0
  28. data/lib/minitest/given.rb +1 -32
  29. data/lib/minitest-given.rb +9 -1
  30. data/rakelib/bundler_fix.rb +17 -0
  31. data/rakelib/gemspec.rake +161 -0
  32. data/rakelib/metrics.rake +30 -0
  33. data/rakelib/preview.rake +14 -0
  34. data/test/before_test.rb +22 -0
  35. data/test/meme_test.rb +36 -0
  36. metadata +69 -85
  37. data/.autotest +0 -23
  38. data/.gemtest +0 -0
  39. data/CHANGELOG.rdoc +0 -3
  40. data/Manifest.txt +0 -11
  41. data/minitest-given.gemspec +0 -42
  42. data/test/test_assertions.rb +0 -30
  43. data/test/test_comparison.rb +0 -25
  44. data/test/test_version.rb +0 -10
data/README.md ADDED
@@ -0,0 +1,763 @@
1
+ # rspec-given
2
+
3
+ | Master |
4
+ | :----: |
5
+ | [![Master Build Status](https://secure.travis-ci.org/jimweirich/rspec-given.png?branch=master)](https://travis-ci.org/jimweirich/rspec-given) |
6
+
7
+ Covering rspec-given, minitest-given, and given-core, version 3.0.0.beta.1.
8
+
9
+ rspec-given and minitest-given are extensions to your favorite testing
10
+ framework to allow Given/When/Then notation when writing specs.
11
+
12
+ # Why Given/When/Then
13
+
14
+ RSpec has done a great job of making specifications more readable for
15
+ humans. However, I really like the given/when/then nature of Cucumber
16
+ stories and would like to follow the same structure in my unit tests.
17
+ rspec-given (and now minitest-given) allows a simple given/when/then
18
+ structure RSpec specifications.
19
+
20
+ ## Status
21
+
22
+ * rspec-given is ready for production use.
23
+ * minitest-given is experimental.
24
+
25
+ ### RSpec/Given
26
+
27
+ The rspec-given gem is the original given/when/then extension for
28
+ RSpec. It now depends on a given_core gem for the basic functionality
29
+ and then adds the RSpec specific code.
30
+
31
+ * rspec-given now require RSpec version 2.12 or better.
32
+
33
+ ### Minitest/Given
34
+
35
+ A new minitest-given gem allows Given/When/Then notation directly in
36
+ Minitest::Spec specifications.
37
+
38
+ To use minitest-given, just place the following require at the top of
39
+ the file (or in a convenient spec_helper).
40
+
41
+ ```ruby
42
+ require 'minitest/given'
43
+ ```
44
+
45
+ All the features of rspec-given are available in minitest-given.
46
+
47
+ When switching from RSpec/Given to Minitest/Given, here are some
48
+ things to watch out for:
49
+
50
+ * You need to use Minitest version 4.3 or better (yes, Minitest 5.x
51
+ should work as well).
52
+
53
+ * Minitest/Given adds the missing "context" block to Minitest::Spec.
54
+
55
+ * Only one before block is allowed in any given Minitest::Spec
56
+ describe block. This doesn't effect the number of Givens you are
57
+ allowed to use, but it may surprise if you are use to RSpec.
58
+
59
+ ### Auto Selecting
60
+
61
+ If you exclusively use natural assertions in your specs, it's quite
62
+ possible to write specs that run under both RSpec and Minitest::Spec.
63
+
64
+ Use this at the start of your spec file:
65
+
66
+ ```ruby
67
+ if defined?(RSpec)
68
+ require 'rspec/given'
69
+ else
70
+ require 'minitest/autorun'
71
+ require 'minitest/given'
72
+ end
73
+ ```
74
+
75
+ See
76
+ [stack_spec.rb](https://github.com/jimweirich/rspec-given/blob/minispec/examples/stack/stack_spec.rb)
77
+ and
78
+ [example_helper.rb](https://github.com/jimweirich/rspec-given/blob/minispec/examples/example_helper.rb)
79
+
80
+ ## Example
81
+
82
+ Here is a specification written in the rspec-given framework:
83
+
84
+ ```ruby
85
+ require 'rspec/given'
86
+ require 'spec_helper'
87
+ require 'stack'
88
+
89
+ describe Stack do
90
+ def stack_with(initial_contents)
91
+ stack = Stack.new
92
+ initial_contents.each do |item| stack.push(item) end
93
+ stack
94
+ end
95
+
96
+ Given(:stack) { stack_with(initial_contents) }
97
+ Invariant { stack.empty?.should == (stack.depth == 0) }
98
+
99
+ context "with no items" do
100
+ Given(:initial_contents) { [] }
101
+ Then { stack.depth.should == 0 }
102
+
103
+ context "when pushing" do
104
+ When { stack.push(:an_item) }
105
+
106
+ Then { stack.depth.should == 1 }
107
+ Then { stack.top.should == :an_item }
108
+ end
109
+
110
+ context "when popping" do
111
+ When(:result) { stack.pop }
112
+ Then { result.should have_failed(Stack::UnderflowError, /empty/) }
113
+ end
114
+ end
115
+
116
+ context "with one item" do
117
+ Given(:initial_contents) { [:an_item] }
118
+
119
+ context "when popping" do
120
+ When(:pop_result) { stack.pop }
121
+
122
+ Then { pop_result.should == :an_item }
123
+ Then { stack.depth.should == 0 }
124
+ end
125
+ end
126
+
127
+ context "with several items" do
128
+ Given(:initial_contents) { [:second_item, :top_item] }
129
+ Given!(:original_depth) { stack.depth }
130
+
131
+ context "when pushing" do
132
+ When { stack.push(:new_item) }
133
+
134
+ Then { stack.top.should == :new_item }
135
+ Then { stack.depth.should == original_depth + 1 }
136
+ end
137
+
138
+ context "when popping" do
139
+ When(:pop_result) { stack.pop }
140
+
141
+ Then { pop_result.should == :top_item }
142
+ Then { stack.top.should == :second_item }
143
+ Then { stack.depth.should == original_depth - 1 }
144
+ end
145
+ end
146
+ end
147
+ ```
148
+
149
+ Let's talk about the individual statements used in the Given
150
+ framework.
151
+
152
+ ### Given
153
+
154
+ The _Given_ section specifies a starting point, a set of preconditions
155
+ that must be true before the code under test is allowed to be run. In
156
+ standard test frameworks the preconditions are established with a
157
+ combination of setup methods (or :before actions in RSpec) and code in
158
+ the test.
159
+
160
+ In the example code above the preconditions are started with _Given_
161
+ statements. A top level _Given_ (that applies to the entire describe
162
+ block) says that one of the preconditions is that there is a stack
163
+ with some initial contents.
164
+
165
+ Note that initial contents are not specified in the top level describe
166
+ block, but are given in each of the nested contexts. By pushing the
167
+ definition of "initial_contents" into the nested contexts, we can vary
168
+ them as needed for that particular context.
169
+
170
+ A precondition in the form "Given(:var) {...}" creates an accessor
171
+ method named "var". The accessor is lazily initialized by the code
172
+ block. If you want a non-lazy given, use "Given!(:var) {...}".
173
+
174
+ A precondition in the form "Given {...}" just executes the code block
175
+ for side effects. Since there is no accessor, the code block is
176
+ executed immediately (i.e. no lazy evaluation).
177
+
178
+ The preconditions are run in order of definition. Nested contexts
179
+ will inherit the preconditions from the enclosing context, with outer
180
+ preconditions running before inner preconditions.
181
+
182
+ #### Given examples:
183
+
184
+ ```ruby
185
+ Given(:stack) { Stack.new }
186
+ ```
187
+
188
+ The block for the given clause is lazily run and its value bound to
189
+ 'stack' if 'stack' is ever referenced in the test.
190
+ The first reference to 'stack' in the specification will cause the
191
+ code block to execute. Futher references to 'stack' will reuse the
192
+ previously generated value.
193
+
194
+ ```ruby
195
+ Given!(:original_size) { stack.size }
196
+ ```
197
+
198
+ The code block is run unconditionally once before each test and the
199
+ value of the block is bound to 'original_size'. This form is useful
200
+ when you want to record the value of something that might be affected
201
+ by the When code.
202
+
203
+ ```ruby
204
+ Given { stack.clear }
205
+ ```
206
+
207
+ The block for the given clause is run unconditionally once before each
208
+ test. This form of given is used for code that is executed for side
209
+ effects.
210
+
211
+ ### When
212
+
213
+ The _When_ clause specifies the code to be tested ... oops, excuse me
214
+ ... specified. After the preconditions in the given section are met,
215
+ the when code block is run.
216
+
217
+ In general there should not be more than one _When_ clause for a given
218
+ direct context. However, a _When_ in an outer context will be run
219
+ after all the _Givens_ but before the inner _When_. You can think of
220
+ an outer _When_ as setting up additional given state for the inner
221
+ _When_.
222
+
223
+ E.g.
224
+
225
+ ```ruby
226
+ context "outer context" do
227
+ When { code specified in the outer context }
228
+ Then { assert something about the outer context }
229
+
230
+ context "inner context" do
231
+
232
+ # At this point, the _When_ of the outer context
233
+ # should be treated as a _Given_ of the inner context
234
+
235
+ When { code specified in the inner context }
236
+ Then { assert something about the inner context }
237
+ end
238
+ end
239
+ ```
240
+
241
+ #### When examples:
242
+
243
+ ```ruby
244
+ When { stack.push(:item) }
245
+ ```
246
+
247
+ The code block is executed once per test. The effect of the _When{}_
248
+ block is very similar to _Given{}_. However, When is used to identify
249
+ the particular code that is being specified in the current context or
250
+ describe block.
251
+
252
+ ```ruby
253
+ When(:result) { stack.pop }
254
+ ```
255
+
256
+ The code block is executed once per test and the value of the code
257
+ block is bound to 'result'. Use this form when the code under test
258
+ returns a value that you wish to interrogate in the _Then_ code.
259
+
260
+ If an exception occurs during the execution of the block for the When
261
+ clause, the exception is caught and a failure object is bound to
262
+ 'result'. The failure can be checked in a then block with the
263
+ 'have_failed' matcher.
264
+
265
+ The failure object will rethrow the captured exception if anything
266
+ other than have_failed matcher is used on the failure object.
267
+
268
+ For example, if the stack is empty when it is popped, then it is
269
+ reasonable for pop to raise an UnderflowError. This is how you might
270
+ specify that behavior:
271
+
272
+ ```ruby
273
+ When(:result) { stack.pop }
274
+ Then { result.should have_failed(UnderflowError, /empty/) }
275
+ ```
276
+
277
+ Note that the arguments to the 'have_failed' matcher are the same as
278
+ those given to the standard RSpec matcher 'raise_error'.
279
+
280
+ ### Then
281
+
282
+ The _Then_ clauses are the postconditions of the specification. These
283
+ then conditions must be true after the code under test (the _When_
284
+ clause) is run.
285
+
286
+ The code in the block of a _Then_ clause should be a single _should_
287
+ assertion. Code in _Then_ clauses should not have any side effects.
288
+
289
+ Let me repeat that: <b>_Then_ clauses should not have any side
290
+ effects!</b> _Then_ clauses with side effects are erroneous. _Then_
291
+ clauses need to be idempotent, so that running them once, twice, a
292
+ hundred times, or never does not change the state of the program. (The
293
+ same is true of _And_ and _Invariant_ clauses).
294
+
295
+ In RSpec terms, a _Then_ clause forms a RSpec Example that runs in the
296
+ context of an Example Group (defined by a describe or context clause).
297
+
298
+ Each Example Group must have at least one _Then_ clause, otherwise
299
+ there will be no examples to be run for that group. If all the
300
+ assertions in an example group are done via Invariants, then the group
301
+ should use an empty _Then_ clause, like this:
302
+
303
+ ```ruby
304
+ Then { }
305
+ ```
306
+
307
+ #### Then examples:
308
+
309
+ ```ruby
310
+ Then { stack.should be_empty }
311
+ ```
312
+
313
+ After the related block for the _When_ clause is run, the stack should
314
+ be empty. If it is not empty, the test will fail.
315
+
316
+ ### And
317
+
318
+ The _And_ clause is similar to _Then_, but does not form its own RSpec
319
+ example. This means that _And_ clauses reuse the setup from a sibling
320
+ _Then_ clause. Using a single _Then_ and multiple _And_ clauses in an
321
+ example group means the setup for that group is run only once (for the
322
+ _Then_ clause) and reused for all the _And_ clauses. This can be a
323
+ significant speed savings where the setup for an example group is
324
+ expensive.
325
+
326
+ Some things to keep in mind about _And_ clauses:
327
+
328
+ * There must be at least one _Then_ in the example group and it must
329
+ be declared before the _And_ clauses. Forgetting the _Then_ clause
330
+ is an error.
331
+
332
+ * The code in the _And_ clause is run immediately after the first
333
+ (executed) _Then_ of an example group.
334
+
335
+ * An assertion failure in a _Then_ clause or an _And_ clause will
336
+ cause all the subsequent _And_ clauses to be skipped.
337
+
338
+ * Since _And_ clauses do not form their own RSpec examples, they are
339
+ not represented in the formatted output of RSpec. That means _And_
340
+ clauses do not produce dots in the Progress format, nor do they
341
+ appear in the documentation, html or textmate formats (options
342
+ -fhtml, -fdoc, or -ftextmate).
343
+
344
+ * Like _Then_ clauses, _And_ clauses must be idempotent. That means
345
+ they should not execute any code that changes global program state.
346
+ (See the section on the _Then_ clause).
347
+
348
+ The choice to use an _And_ clause is primarily a speed consideration.
349
+ If an example group has expensive setup and there are a lot of _Then_
350
+ clauses, then choosing to make some of the _Then_ clauses into _And_
351
+ clauses will speed up the spec. Otherwise it is probably better to
352
+ stick with _Then_ clauses.
353
+
354
+ #### Then/And examples:
355
+
356
+ ```ruby
357
+ Then { pop_result.should == :top_item } # Required
358
+ And { stack.top.should == :second_item } # No Setup rerun
359
+ And { stack.depth.should == original_depth - 1 } # ... for these
360
+ ```
361
+
362
+ ### Invariant
363
+
364
+ The _Invariant_ clause is a new idea that doesn't have an analog in
365
+ RSpec or Test::Unit. The invariant allows you specify things that must
366
+ always be true in the scope of the invariant. In the stack example, the method
367
+ <tt>empty?</tt> is defined in term of <tt>size</tt>.
368
+
369
+ ```ruby
370
+ Invariant { stack.empty? == (stack.depth == 0) }
371
+ ```
372
+
373
+ This invariant states that <code>empty?</code> is true if and only if
374
+ the stack depth is zero, and that assertion is checked at every _Then_
375
+ clause that is in the same scope.
376
+
377
+ You can conceptually think of an _Invariant_ clause as a _Then_ block
378
+ that automatically gets added to every _Then_ within its scope.
379
+ Invariants nested within a context only apply to the _Then_ clauses
380
+ that are in the scope of that context.
381
+
382
+ Invariants that reference a _Given_ precondition accessor must only be
383
+ used in contexts that define that accessor.
384
+
385
+ Notes:
386
+
387
+ * Since Invariants do not form their own RSpec example, they are not
388
+ represented in the RSpec formatted output (e.g. the '--format html'
389
+ option).
390
+
391
+ ## Execution Ordering
392
+
393
+ When running the test for a specific _Then_ clause, the following will
394
+ be true:
395
+
396
+ * The non-lazy _Given_ clauses will be run in the order that they are
397
+ specified, from the outermost scope to the innermost scope
398
+ containing the _Then_. (The lazy _Given_ clauses will be run upon
399
+ demand).
400
+
401
+ * All of the _Given_ clauses in all of the relevant scopes will run
402
+ before the first (outermost) _When_ clause in those same scopes.
403
+ That means that the _When_ code can assume that the givens have been
404
+ established, even if the givens are in a more nested scope than the
405
+ When.
406
+
407
+ * _When_ clauses and RSpec _before_ blocks will be executed in the
408
+ order that they are specified, from the outermost block to the
409
+ innermost block. This makes _before_ blocks an excellent choice when
410
+ writing narrative tests to specify actions that happen between the
411
+ "whens" of a narrative-style test.
412
+
413
+ Note that the ordering between _Given_ clauses and _before_ blocks are
414
+ not strongly specified. Hoisting a _When_ clause out of an inner scope
415
+ to an outer scope may change the order of execution between related
416
+ _Given_ clauses and any _before_ blocks (hoisting the _When_ clause
417
+ might cause the related _Given_ clauses to possibly run earlier).
418
+ Because of this, do not split order dependent code between _Given_
419
+ clauses and _before_ blocks.
420
+
421
+ ## Natural Assertions
422
+
423
+ **NOTE:** <em>Natural assertions are currently an experimental feature
424
+ of RSpec/Given. They are currently disabled by default, but can be
425
+ enabled by a simple configuration option (see "use_natural_assertions"
426
+ below).</em>
427
+
428
+ RSpec/Given now supports the use of "natural assertions" in _Then_,
429
+ _And_, and _Invariant_ blocks. Natural assertions are just Ruby
430
+ conditionals, without the _should_ or _expect_ methods that RSpec
431
+ provides. Here are the Then/And examples from above, but written using
432
+ natural assertions:
433
+
434
+ ```ruby
435
+ Then { pop_result == :top_item }
436
+ And { stack.top == :second_item }
437
+ And { stack.depth == original_depth - 1 }
438
+ ```
439
+
440
+ Natural assertions must be enabled, either globally or on a per
441
+ context basis, to be recognized.
442
+
443
+ Here's a heads up: If you use natural assertions, but fail to enable
444
+ them, all your specs will mysteriously pass. This is why the **red**
445
+ part of _Red/Green/Refactor_ is so important.
446
+
447
+ ### Failure Messages with Natural Assertions
448
+
449
+ Since natural assertions do not depend upon matchers, you don't get
450
+ customized error messages from them. What you _do_ get is a complete
451
+ analsysis of the expression that failed.
452
+
453
+ For example, given the following failing specification:
454
+
455
+ ```ruby
456
+ Given.use_natural_assertions
457
+
458
+ describe "Natural Assertions" do
459
+ Given(:foo) { 1 }
460
+ Given(:bar) { 2 }
461
+ Then { foo + bar == 2 }
462
+ end
463
+ ```
464
+
465
+ You would get:
466
+
467
+ ```
468
+ 1) Natural Assertions
469
+ Failure/Error: Then { foo + bar == 2 }
470
+ Then expression failed at /Users/jim/working/git/rspec-given/examples/failing/sample_spec.rb:6
471
+ expected: 3
472
+ to equal: 2
473
+ false <- foo + bar == 2
474
+ 3 <- foo + bar
475
+ 1 <- foo
476
+ 2 <- bar
477
+ # ./examples/failing/sample_spec.rb:6:in `block in Then'
478
+ ```
479
+
480
+ Notice how the failing expression "<code>foo+bar == 2</code>" was
481
+ broken down into subexpressions and values for each subexpression.
482
+ This gives you all the information you need to figure out exactly what
483
+ part of the expression is causing the failure.
484
+
485
+ Natural assertions will give additional information (e.g. "expected:
486
+ 3 to equal: 2") for top level expressions involving any of the
487
+ comparison operators (==, !=, <, <=, >, >=) or matching operators (=~,
488
+ !~).
489
+
490
+ ### Checking for exceptions with Natural Assertions
491
+
492
+ If you wish to see if the result of a _When_ clause is an exception,
493
+ you can use the following:
494
+
495
+ ```ruby
496
+ When(:result) { stack.pop }
497
+ Then { result == Failure(UnderflowError, /empty/) }
498
+ ```
499
+
500
+ The <code>Failure()</code> method accepts the same arguments as
501
+ <code>have_failed</code> and <code>raise_error</code>.
502
+
503
+ ### Caveats on Natural Assertions
504
+
505
+ Keep the following in mind when using natural assertions.
506
+
507
+ * Only a single expression/assertion per _Then_. The single expression
508
+ of the _Then_ block will be considered when determining pass/fail
509
+ for the assertion. If you _want_ to express a complex condition for
510
+ the _Then_, you need to use ||, && or some other logical operation
511
+ to join the conditions into a single expression (and the failure
512
+ message will break down the values for each part).
513
+
514
+ * Then clauses need be **idempotent**. This is true in general, but it
515
+ is particularly important for natural assertions to obey this
516
+ restriction. This means that assertions in a Then clause should not
517
+ change anything. Since the Natural Assertion error message contains
518
+ the values of all the subexpressions, the expression and its
519
+ subexpressions will be evaluated multiple times. If the Then clause
520
+ is not idempotent, you will get changing answers as the
521
+ subexpressions are evaluated.
522
+
523
+ That last point is important. If you write code like this:
524
+
525
+ ```ruby
526
+ # DO NOT WRITE CODE LIKE THIS
527
+ context "Incorrect non-idempotent conditions" do
528
+ Given(:ary) { [1, 2, 3] }
529
+ Then { ary.delete(1) == nil }
530
+ end
531
+ ```
532
+
533
+ Then the assertion will fail (because <code>ary.delete(1)</code> will
534
+ initially return 1). But when the error message is formated, the
535
+ system reports that <code>ary.delete(1)</code> returns nil. You will
536
+ scratch your head over that for a good while.
537
+
538
+ Instead, move the state changing code into a _When(:result)_ block, then
539
+ assert what you need to about :result. Something
540
+ like this is good:
541
+
542
+ ```ruby
543
+ context "Correct idempotent conditions" do
544
+ Given(:ary) { [1, 2, 3] }
545
+ When(:result) { ary.delete(1) }
546
+ Then { result == nil }
547
+ end
548
+ ```
549
+
550
+ It is good to note that non-idempotent assertions will also cause
551
+ problems with And clauses.
552
+
553
+ ### Mixing Natural Assertions and RSpec Assertions
554
+
555
+ Natural assertions and RSpec assertions for the most part can be
556
+ intermixed in a single test suite, even within a single context.
557
+ Because there are a few corner cases that might cause problems, they
558
+ must be explicitly enabled before they will be considered.
559
+
560
+ To enable natural assertions in a context, call the
561
+ _use_natural_assertions_ method in that context. For example:
562
+
563
+ ```ruby
564
+ context "Outer" do
565
+ use_natural_assertions
566
+
567
+ context "Inner" do
568
+ end
569
+
570
+ context "Disabled" do
571
+ use_natural_assertions false
572
+ end
573
+ end
574
+ ```
575
+
576
+ Both the _Outer_ and _Inner_ contexts will use natural assertions. The
577
+ _Disabled_ context overrides the setting inherited from _Outer_ and
578
+ will not process natural assertions.
579
+
580
+ See the **configuration** section below to see how to enable natural
581
+ assertions project wide.
582
+
583
+ ### Matchers and Natural Assertions
584
+
585
+ In RSpec, matchers are used to provide nice, readable error messages
586
+ when an assertion is not met. Natural assertions provide
587
+ self-explanatory failure messages for most things without requiring
588
+ any special matchers from the programmer.
589
+
590
+ In the rare case that some extra information would be helpful, it is
591
+ useful to create special objects that respond to the == operator.
592
+
593
+ #### Asserting Nearly Equal with Fuzzy Numbers
594
+
595
+ Operations on floating point numbers rarely create numbers that are
596
+ exactly equal, therefore it is useful to assert that two floating
597
+ point numbers are nearly equal. We do that by creating a fuzzy number
598
+ that has a looser interpretation of what it means to be equal.
599
+
600
+ For example, the following asserts that the square root of 10 is about
601
+ 3.1523 with an accuracy of 1 percent.
602
+
603
+ ```ruby
604
+ Then { Math.sqrt(10) == about(3.1623).percent(1) }
605
+ ```
606
+
607
+ As long as the real value of <code>Math.sqrt(10)</code> is within plus
608
+ or minus 1% of 3.1623 (i.e. 3.1623 +/- 0.031623), then the assertion
609
+ will pass.
610
+
611
+ There are several ways of creating fuzzy numbers:
612
+
613
+ * <code>about(n).delta(d)</code> -- A fuzzy number matching the range
614
+ (n-d)..(n+d)
615
+
616
+ * <code>about(n).percent(p)</code> -- A fuzzy number matching the
617
+ range (n-(n*p/100)) .. (n+(n*p/100))
618
+
619
+ * <code>about(n).epsilon(neps)</code> -- A fuzzy number matching the
620
+ range (n-(neps*e)) .. (n+(neps*e)), where e is the difference
621
+ between 1.0 and the next smallest floating point number.
622
+
623
+ * <code>about(n)</code> -- Same as <code>about(n).epsilon(10)</code>.
624
+
625
+ When the file <code>rspec/given/fuzzy_shortcuts</code> is required,
626
+ the following unicode shortcut methods are added to Numeric to create
627
+ fuzzy numbers.
628
+
629
+ * <code>n.±(del)</code> is the same as <code>about(n).delta(del)</code>
630
+
631
+ * <code>n.‰(percentage)</code> is the same as <code>about(n).percent(percentage)</code>
632
+
633
+ * <code>n.€(neps)</code> is the same as <code>about(n).epsilon(neps)</code>
634
+
635
+ * <code>n.±</code>, <code>n.‰</code>, and <code>n.€</code> are all
636
+ the same as <code>about(n)</code>
637
+
638
+ #### Detecting Exceptions
639
+
640
+ The RSpec matcher used for detecting exceptions will work with natural
641
+ assertions out of the box. Just check for equality against the
642
+ <code>have_failed</code> return value.
643
+
644
+ For example, the following two Then clauses are equivalent:
645
+
646
+ ```ruby
647
+ # Using an RSpec matcher
648
+ Then { result.should have_failed(StandardError, /message/) }
649
+
650
+ # Using natural assertions
651
+ Then { result == have_failed(StandardError, /message/) }
652
+ ```
653
+
654
+ ### Processing Natural Assertions
655
+
656
+ When natural assertions are enabled, they are only used if all of the
657
+ following are true:
658
+
659
+ 1. The block does not throw an RSpec assertion failure (or any other
660
+ exception for that matter).
661
+
662
+ 1. The block returns false (blocks that return true pass the
663
+ assertion and don't need a failure message).
664
+
665
+ 1. The block does not use RSpec's _should_ or _expect_ methods.
666
+
667
+ Detecting that last point (the use of _should_ and _expect_) is done
668
+ by modifying the RSpec runtime to report uses of _should_ and
669
+ _expect_.
670
+
671
+ ### Platform Support
672
+
673
+ Natural assertions use the Ripper library to parse the failing
674
+ condition and find all the sub-expression values upon a failure.
675
+ Currently Ripper is not supported on JRuby 1.7.2. Charles Nutter has
676
+ said that Ripper support is coming soon and may arrive as early as
677
+ version 1.7.3. Until then, natural assertions are disabled when
678
+ running under JRuby. Never fear, JRuby supports all the other features
679
+ of rspec-given and will work just fine.
680
+
681
+ ### Further Reading
682
+
683
+ Natural assertions were inspired by the [wrong assertion
684
+ library](http://rubygems.org/gems/wrong) by [Alex
685
+ Chaffee](http://rubygems.org/profiles/alexch) and [Steve
686
+ Conover](http://rubygems.org/profiles/sconoversf).
687
+
688
+ ## Configuration
689
+
690
+ Just require 'rspec/given' in the spec helper of your project and it
691
+ is ready to go.
692
+
693
+ If the RSpec format option document, html or textmate is chosen,
694
+ RSpec/Given will automatically add additional source code information to
695
+ the examples to produce better looking output. If you don't care about
696
+ the pretty output and wish to disable source code caching
697
+ unconditionally, then add the following line to your spec helper file:
698
+
699
+ ```ruby
700
+ RSpec::Given.source_caching_disabled = true
701
+ ```
702
+
703
+ Natural assertions are disabled by default. To globally configure
704
+ natural assertions, add one of the following lines to your spec_helper
705
+ file:
706
+
707
+ ```ruby
708
+ Given.use_natural_assertions # Enable natural assertions
709
+ Given.use_natural_assertions true # Same as above
710
+ Given.use_natural_assertions false # Disable natural assertions
711
+ Given.use_natural_assertions :always # Always process natural assertions
712
+ # ... even when should/expect are detected
713
+ ```
714
+
715
+ # License
716
+
717
+ RSpec-Given is available under the MIT License. See the MIT-LICENSE
718
+ file in the source distribution.
719
+
720
+ # History
721
+
722
+ * Version 3.0.0
723
+
724
+ * Support for minitest added.
725
+
726
+ * Gems rspec-given and minitest-given both use the core
727
+ functionality of gem given_core.
728
+
729
+ * Version 2.4.4
730
+
731
+ * Support for RSpec 2.13 added.
732
+
733
+ * Version 2.4.3
734
+
735
+ * Better natural assertion messages when dealing with multi-line
736
+ output.
737
+
738
+ * Version 2.4.2
739
+
740
+ * Minor adjustment to natural assertion error messages to better
741
+ handle multi-line values.
742
+
743
+ * Remove flog, flay and other development tools from the bundle and
744
+ gemspec. The Rakefile was updated to suggest installing them if
745
+ they are not there.
746
+
747
+ * Version 2.4.1
748
+
749
+ * Fix bug where constants from nested modules were not properly
750
+ accessed.
751
+
752
+ * Version 2.4.0
753
+
754
+ * Add fuzzy number helper methods (with unicode method shortcuts).
755
+
756
+ * Fix bug caused by blank lines in Thens.
757
+
758
+ # Links
759
+
760
+ * Github: [https://github.com/jimweirich/rspec-given](https://github.com/jimweirich/rspec-given)
761
+ * Clone URL: git://github.com/jimweirich/rspec-given.git
762
+ * Bug/Issue Reporting: [https://github.com/jimweirich/rspec-given/issues](https://github.com/jimweirich/rspec-given/issues)
763
+ * Continuous Integration: [http://travis-ci.org/#!/jimweirich/rspec-given](http://travis-ci.org/#!/jimweirich/rspec-given)