rspec-given 2.3.0.beta.3 → 2.3.0
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.
- data/README.md +112 -42
- data/examples/failing/natural_failing_spec.rb +12 -0
- data/lib/rspec/given/configure.rb +2 -0
- data/lib/rspec/given/extensions.rb +2 -2
- data/lib/rspec/given/failure.rb +21 -1
- data/lib/rspec/given/fuzzy_number.rb +64 -0
- data/lib/rspec/given/have_failed.rb +12 -0
- data/lib/rspec/given/version.rb +0 -2
- metadata +6 -5
data/README.md
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# rspec-given
|
2
2
|
|
3
|
-
Covering rspec-given, version 2.3.0.
|
3
|
+
Covering rspec-given, version 2.3.0.
|
4
4
|
|
5
5
|
rspec-given is an RSpec extension to allow Given/When/Then notation in
|
6
6
|
RSpec specifications. It is a natural extension of the experimental
|
@@ -305,14 +305,19 @@ stick with _Then_ clauses.
|
|
305
305
|
|
306
306
|
The _Invariant_ clause is a new idea that doesn't have an analog in
|
307
307
|
RSpec or Test::Unit. The invariant allows you specify things that must
|
308
|
-
always be true in the scope of the invariant. In the stack example,
|
309
|
-
<tt>empty?</tt> is defined in term of <tt>size</tt>.
|
310
|
-
|
311
|
-
|
308
|
+
always be true in the scope of the invariant. In the stack example, the method
|
309
|
+
<tt>empty?</tt> is defined in term of <tt>size</tt>.
|
310
|
+
|
311
|
+
```ruby
|
312
|
+
Invariant { stack.empty? == (stack.depth == 0) }
|
313
|
+
```
|
314
|
+
|
315
|
+
This invariant states that <code>empty?</code> is true if and only if
|
316
|
+
the stack depth is zero, and that assertion is checked at every _Then_
|
317
|
+
clause that is in the same scope.
|
312
318
|
|
313
319
|
You can conceptually think of an _Invariant_ clause as a _Then_ block
|
314
320
|
that automatically gets added to every _Then_ within its scope.
|
315
|
-
|
316
321
|
Invariants nested within a context only apply to the _Then_ clauses
|
317
322
|
that are in the scope of that context.
|
318
323
|
|
@@ -325,10 +330,40 @@ Notes:
|
|
325
330
|
represented in the RSpec formatted output (e.g. the '--format html'
|
326
331
|
option).
|
327
332
|
|
333
|
+
## Execution Ordering
|
334
|
+
|
335
|
+
When running the test for a specific _Then_ clause, the following will
|
336
|
+
be true:
|
337
|
+
|
338
|
+
* The _Given_ clauses will be run in the order that they are
|
339
|
+
specified, from the outermost scope to the innermost scope
|
340
|
+
containing the _Then_.
|
341
|
+
|
342
|
+
* All of the _Given_ clauses in all of the relevant scopes will run
|
343
|
+
before the first (outermost) _When_ clause in those same scopes.
|
344
|
+
That means that the _When_ code can assume that the givens have been
|
345
|
+
established, even if the givens are in a more nested scope than the
|
346
|
+
When.
|
347
|
+
|
348
|
+
* _When_ clauses and RSpec _before_ blocks will be executed in the
|
349
|
+
order that they are specified, from the outermost block to the
|
350
|
+
innermost block. This makes _before_ blocks an excellent choice
|
351
|
+
when writing narrative tests to specify actions that happen between
|
352
|
+
the "whens" of a narrative.
|
353
|
+
|
354
|
+
Note that the ordering between _Given_ clauses and _before_ blocks are
|
355
|
+
a not strongly specified. Hoisting a _When_ clause out of an inner
|
356
|
+
scope to an outer scope may change the ordering of when the _Given_
|
357
|
+
clause runs in relation to a _before_ block (the hoisting will cause
|
358
|
+
the givens to possibly run earlier). Because of this, do not split
|
359
|
+
order dependent code between _Given_ clauses and _before_ blocks.
|
360
|
+
|
328
361
|
## Natural Assertions
|
329
362
|
|
330
363
|
**NOTE:** <em>Natural assertions are an experimental feature of
|
331
|
-
RSpec/Given. They are currently disabled by default
|
364
|
+
RSpec/Given. They are currently disabled by default. They can be
|
365
|
+
enabled by a simple configuration option (see "use_natural_assertions"
|
366
|
+
below).</em>
|
332
367
|
|
333
368
|
RSpec/Given now supports the use of "natural assertions" in _Then_,
|
334
369
|
_And_, and _Invariant_ blocks. Natural assertions are just Ruby
|
@@ -399,12 +434,14 @@ Keep the following in mind when using Natural Assertions.
|
|
399
434
|
to join the conditions into a single expression (and the failure
|
400
435
|
message will breakdown the values for each part).
|
401
436
|
|
402
|
-
*
|
403
|
-
|
437
|
+
* Then clauses need be **idempotent**. This is true in general, but it
|
438
|
+
is particularly important for Natural assertions to obey this
|
439
|
+
restriction. This means that assertions in a Then clause should not
|
440
|
+
change anything. Since the natural assertion error message contains
|
404
441
|
the values of all the subexpressions, the expression and its
|
405
|
-
subexpressions will be evaluated multiple times. If the
|
406
|
-
idempotent, you will get changing answers as the
|
407
|
-
evaluated.
|
442
|
+
subexpressions will be evaluated multiple times. If the Then clause
|
443
|
+
is not idempotent, you will get changing answers as the
|
444
|
+
subexpressions are evaluated.
|
408
445
|
|
409
446
|
That last point is important. If you write code like this:
|
410
447
|
|
@@ -433,6 +470,9 @@ like this is good:
|
|
433
470
|
end
|
434
471
|
```
|
435
472
|
|
473
|
+
It is good to note that non-idempotent assertions will also cause
|
474
|
+
problems with And clauses.
|
475
|
+
|
436
476
|
### Mixing Natural Assertions and RSpec Assertions
|
437
477
|
|
438
478
|
Natural assertions and RSpec assertions for the most part can be
|
@@ -463,49 +503,79 @@ will not process natural assertions.
|
|
463
503
|
See the **configuration** section below to see how to enable natural
|
464
504
|
assertions project wide.
|
465
505
|
|
466
|
-
###
|
506
|
+
### Matchers and Natural Assertions
|
467
507
|
|
468
|
-
|
508
|
+
In RSpec, matchers are used to provide nice, readable error messages
|
509
|
+
when an assertion is not met. Natural assertions provide
|
510
|
+
self-explanatory failure messages for most things without requiring
|
511
|
+
any special matchers from the programmer.
|
469
512
|
|
470
|
-
|
471
|
-
|
513
|
+
In the rare case that some extra information would be hepful, it is
|
514
|
+
useful to create special objects that respond to the == operator.
|
472
515
|
|
473
|
-
|
474
|
-
assertion and don't need a failure message).
|
516
|
+
#### Asserting Nearly Equal
|
475
517
|
|
476
|
-
|
477
|
-
|
518
|
+
Operations on floating point numbers rarely create numbers that are
|
519
|
+
exactly equal, therefore it is useful to assert that two floating
|
520
|
+
point numbers are nearly equal.
|
478
521
|
|
479
|
-
|
480
|
-
|
481
|
-
possible to correctly determine if _should_ and _expect_ are used
|
482
|
-
merely from the source. Fortunately you can always override the
|
483
|
-
automatic detection by either forcing natural assertions (with
|
484
|
-
:always) or disabling them (with false).
|
522
|
+
For example, the following asserts that the square root of 10 is about
|
523
|
+
3.1523 with an accuracy of 0.1 percent.
|
485
524
|
|
486
525
|
```ruby
|
487
|
-
|
488
|
-
context "sample" do
|
489
|
-
use_natural_assertions :always
|
490
|
-
Then { obj.should } # Non-rspec should is called
|
491
|
-
end
|
526
|
+
Then { Math.sqrt(10) == about(3.1623).percent(1) }
|
492
527
|
```
|
493
528
|
|
529
|
+
As long as the real value of <code>Math.sqrt(10)</code> is within plus
|
530
|
+
or minus 1% of 3.1623 (i.e. 3.1623 +/- 0.0031623), then the assertion
|
531
|
+
will pass.
|
532
|
+
|
533
|
+
There are several ways of creating approximate numbers:
|
534
|
+
|
535
|
+
* <code>about(n).delta(d)</code> -- A fuzzy number matching the range
|
536
|
+
(n-d)..(n+d)
|
537
|
+
|
538
|
+
* <code>about(n).percent(p)</code> -- A fuzzy number matching the
|
539
|
+
range (n-(n*p/100)) .. (n+(n*p/100))
|
540
|
+
|
541
|
+
* <code>about(n).epsilon(neps)</code> -- A fuzzy number matching the
|
542
|
+
range (n-(neps*e)) .. (n+(neps*e)), where e is the difference
|
543
|
+
between 1.0 and the next smallest floating point number.
|
544
|
+
|
545
|
+
* <code>about(n)</code> -- Same as <code>about(n).epsilon(10)</code>.
|
546
|
+
|
547
|
+
#### Detecting Exceptions
|
548
|
+
|
549
|
+
The RSpec matcher used for detecting exceptions will work with natural
|
550
|
+
assertions out of the box. Just check for equality against the
|
551
|
+
<code>have_failed</code> return value.
|
552
|
+
|
553
|
+
For example, the following two Then clauses are equivalent:
|
554
|
+
|
494
555
|
```ruby
|
495
|
-
|
496
|
-
|
497
|
-
use_natural_assertions false
|
498
|
-
Then { check_validations(obj) } # check_validations calls "should" internally
|
499
|
-
end
|
556
|
+
# Using an RSpec matcher
|
557
|
+
Then { result.should have_failed(StandardError, /message/) }
|
500
558
|
|
501
|
-
|
502
|
-
|
503
|
-
it "checks validations" do
|
504
|
-
check_validations(obj)
|
505
|
-
end
|
506
|
-
end
|
559
|
+
# Using natural assertions
|
560
|
+
Then { result == have_failed(StandardError, /message/) }
|
507
561
|
```
|
508
562
|
|
563
|
+
### Processing Natural Assertions
|
564
|
+
|
565
|
+
When natural assertions are enabled, they are only used if:
|
566
|
+
|
567
|
+
1. The block does not throw an RSpec assertion failure (or any other
|
568
|
+
exception for that matter).
|
569
|
+
|
570
|
+
1. The block returns false (blocks that return true pass the
|
571
|
+
assertion and don't need a failure message).
|
572
|
+
|
573
|
+
1. The block does not use RSpec's _should_ or _expect_ methods.
|
574
|
+
|
575
|
+
Detecting that last point (the use of _should_ and _expect_) is done
|
576
|
+
by modifying the RSpec runtime to report uses of _should_ and
|
577
|
+
_expect_.
|
578
|
+
|
509
579
|
### Further Reading
|
510
580
|
|
511
581
|
Natural assertions were inspired by the [wrong assertion
|
@@ -23,6 +23,18 @@ describe "Natural Assertions" do
|
|
23
23
|
(puts "Ha ha world", ! true)
|
24
24
|
}
|
25
25
|
|
26
|
+
Then { Math.sqrt(10) == about(3.1623).percent(0.0001) }
|
27
|
+
|
28
|
+
describe "Error Examples" do
|
29
|
+
When(:result) { fail "OUCH" }
|
30
|
+
Then { result == :ok }
|
31
|
+
end
|
32
|
+
|
33
|
+
describe "Non-Error Failures" do
|
34
|
+
When(:result) { :ok }
|
35
|
+
Then { result == have_failed(StandardError, /^O/) }
|
36
|
+
end
|
37
|
+
|
26
38
|
context "Incorrect non-idempotent conditions" do
|
27
39
|
Given(:ary) { [1, 2, 3] }
|
28
40
|
Then { ary.delete(1) == nil }
|
@@ -1,5 +1,6 @@
|
|
1
1
|
require 'rspec'
|
2
2
|
require 'rspec/given/extensions'
|
3
|
+
require 'rspec/given/fuzzy_number'
|
3
4
|
require 'rspec/given/have_failed'
|
4
5
|
require 'rspec/given/module_methods'
|
5
6
|
|
@@ -7,6 +8,7 @@ RSpec.configure do |c|
|
|
7
8
|
c.extend(RSpec::Given::ClassExtensions)
|
8
9
|
c.include(RSpec::Given::InstanceExtensions)
|
9
10
|
c.include(RSpec::Given::HaveFailed)
|
11
|
+
c.include(RSpec::Given::Fuzzy)
|
10
12
|
|
11
13
|
c.backtrace_clean_patterns << /lib\/rspec\/given/
|
12
14
|
|
@@ -159,7 +159,7 @@ module RSpec
|
|
159
159
|
# Scenario "a scenario description" do ... end
|
160
160
|
#
|
161
161
|
def Scenario(description, &block)
|
162
|
-
file, line = eval("[
|
162
|
+
file, line = eval("[__FILE__, __LINE__]", block.binding)
|
163
163
|
puts "WARNING: Scenario is deprecated, please use either describe or context (#{file}:#{line})"
|
164
164
|
context(description, &block)
|
165
165
|
end
|
@@ -190,7 +190,7 @@ module RSpec
|
|
190
190
|
# Given!(:name) { ... code ... }
|
191
191
|
#
|
192
192
|
def Given!(name, &block)
|
193
|
-
let
|
193
|
+
let(name, &block)
|
194
194
|
_rgc_givens << _rgc_trigger_given(name)
|
195
195
|
end
|
196
196
|
|
data/lib/rspec/given/failure.rb
CHANGED
@@ -14,9 +14,29 @@ module RSpec
|
|
14
14
|
klass == Failure
|
15
15
|
end
|
16
16
|
|
17
|
-
def
|
17
|
+
def ==(other)
|
18
|
+
if other.is_a?(::RSpec::Given::HaveFailed::HaveFailedMatcher)
|
19
|
+
other.matches?(self)
|
20
|
+
else
|
21
|
+
die
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def !=(other)
|
26
|
+
if other.is_a?(::RSpec::Given::HaveFailed::HaveFailedMatcher)
|
27
|
+
! other.matches?(self)
|
28
|
+
else
|
29
|
+
die
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def die
|
18
34
|
::Kernel.raise @exception
|
19
35
|
end
|
36
|
+
|
37
|
+
def method_missing(sym, *args, &block)
|
38
|
+
die
|
39
|
+
end
|
20
40
|
end
|
21
41
|
end
|
22
42
|
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
|
2
|
+
module RSpec
|
3
|
+
module Given
|
4
|
+
module Fuzzy
|
5
|
+
class FuzzyNumber
|
6
|
+
|
7
|
+
DEFAULT_EPSILON = 10 * Float::EPSILON
|
8
|
+
|
9
|
+
attr_reader :exact_value, :delta_amount
|
10
|
+
|
11
|
+
def initialize(exact_value)
|
12
|
+
@exact_value = exact_value
|
13
|
+
@delta_amount = exact_value * DEFAULT_EPSILON
|
14
|
+
end
|
15
|
+
|
16
|
+
# Low limit of the fuzzy number.
|
17
|
+
def low_limit
|
18
|
+
exact_value - delta_amount
|
19
|
+
end
|
20
|
+
|
21
|
+
# High limit of the fuzzy number.
|
22
|
+
def high_limit
|
23
|
+
exact_value + delta_amount
|
24
|
+
end
|
25
|
+
|
26
|
+
# True if the other number is in range of the fuzzy number.
|
27
|
+
def ==(other)
|
28
|
+
(other - exact_value).abs <= delta_amount
|
29
|
+
end
|
30
|
+
|
31
|
+
def to_s
|
32
|
+
"<Approximately #{exact_value} +/- #{delta_amount}>"
|
33
|
+
end
|
34
|
+
|
35
|
+
# Set the delta for a fuzzy number.
|
36
|
+
def delta(delta)
|
37
|
+
@delta_amount = delta.abs
|
38
|
+
self
|
39
|
+
end
|
40
|
+
|
41
|
+
# Specifying a percentage of the exact number to be used in
|
42
|
+
# setting the delta.
|
43
|
+
def percent(percentage)
|
44
|
+
delta(exact_value * (percentage / 100.0))
|
45
|
+
end
|
46
|
+
|
47
|
+
# Specifying the number of epsilons to be used in setting the
|
48
|
+
# delta.
|
49
|
+
def epsilon(neps)
|
50
|
+
delta(exact_value * (neps * Float::EPSILON))
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
# Create an approximate number that is approximately equal to
|
55
|
+
# the given number, plus or minus the delta value. If no
|
56
|
+
# explicit delta is given, then the default delta that is about
|
57
|
+
# 10X the size of the smallest possible change in the given
|
58
|
+
# number will be used.
|
59
|
+
def about(*args)
|
60
|
+
FuzzyNumber.new(*args)
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
@@ -24,6 +24,10 @@ module RSpec
|
|
24
24
|
super(lambda { })
|
25
25
|
end
|
26
26
|
end
|
27
|
+
|
28
|
+
def to_s
|
29
|
+
"<Failure matching #{@expected_error}: #{@expected_message.inspect}>"
|
30
|
+
end
|
27
31
|
end
|
28
32
|
|
29
33
|
else
|
@@ -36,6 +40,10 @@ module RSpec
|
|
36
40
|
super(lambda { })
|
37
41
|
end
|
38
42
|
end
|
43
|
+
|
44
|
+
def to_s
|
45
|
+
"<FailureMatcher on #{@expected_error}: #{@expected_message.inspect}>"
|
46
|
+
end
|
39
47
|
end
|
40
48
|
|
41
49
|
end
|
@@ -58,6 +66,10 @@ module RSpec
|
|
58
66
|
def have_failed(error=Exception, message=nil, &block)
|
59
67
|
HaveFailedMatcher.new(error, message, &block)
|
60
68
|
end
|
69
|
+
alias have_raised have_failed
|
70
|
+
|
71
|
+
def failure(error=Exception, message=nil, &block)
|
72
|
+
end
|
61
73
|
end
|
62
74
|
end
|
63
75
|
end
|
data/lib/rspec/given/version.rb
CHANGED
metadata
CHANGED
@@ -1,15 +1,15 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rspec-given
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.3.0
|
5
|
-
prerelease:
|
4
|
+
version: 2.3.0
|
5
|
+
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
8
8
|
- Jim Weirich
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2013-01-
|
12
|
+
date: 2013-01-18 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: rspec
|
@@ -112,6 +112,7 @@ files:
|
|
112
112
|
- lib/rspec/given/extensions.rb
|
113
113
|
- lib/rspec/given/failure.rb
|
114
114
|
- lib/rspec/given/file_cache.rb
|
115
|
+
- lib/rspec/given/fuzzy_number.rb
|
115
116
|
- lib/rspec/given/have_failed.rb
|
116
117
|
- lib/rspec/given/line_extractor.rb
|
117
118
|
- lib/rspec/given/module_methods.rb
|
@@ -153,9 +154,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
153
154
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
154
155
|
none: false
|
155
156
|
requirements:
|
156
|
-
- - ! '
|
157
|
+
- - ! '>='
|
157
158
|
- !ruby/object:Gem::Version
|
158
|
-
version:
|
159
|
+
version: '0'
|
159
160
|
requirements: []
|
160
161
|
rubyforge_project: given
|
161
162
|
rubygems_version: 1.8.24
|