riot 0.9.12 → 0.10.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +1 -0
- data/README.markdown +37 -45
- data/VERSION +1 -1
- data/lib/riot.rb +27 -18
- data/lib/riot/assertion_macros.rb +63 -53
- data/lib/riot/context.rb +26 -36
- data/lib/riot/reporter.rb +77 -0
- data/lib/riot/runnable.rb +50 -0
- data/lib/riot/situation.rb +6 -3
- data/riot.gemspec +30 -21
- data/test/assertion_macros/assigns_test.rb +24 -0
- data/test/assertion_macros/equals_test.rb +18 -0
- data/test/assertion_macros/exists_test.rb +17 -0
- data/test/assertion_macros/kind_of_test.rb +17 -0
- data/test/assertion_macros/matching_test.rb +12 -0
- data/test/assertion_macros/nil_test.rb +13 -0
- data/test/assertion_macros/raises_test.rb +33 -0
- data/test/assertion_macros/respond_to_test.rb +12 -0
- data/test/assertion_macros/same_elements_test.rb +17 -0
- data/test/assertion_test.rb +25 -22
- data/test/benchmark/riot_vs_minitest.rb +8 -8
- data/test/benchmark/same_elements_vs_set.rb +41 -0
- data/test/benchmark/simple_context_and_assertions.rb +8 -8
- data/test/context_test.rb +68 -83
- data/test/report_test.rb +44 -0
- data/test/setup_test.rb +17 -0
- data/test/situation_test.rb +16 -0
- data/test/teststrap.rb +31 -0
- metadata +30 -21
- data/lib/riot/assertion.rb +0 -37
- data/lib/riot/errors.rb +0 -15
- data/lib/riot/report.rb +0 -82
- data/test/assertion_macros/assertion_macro_assigns_test.rb +0 -40
- data/test/assertion_macros/assertion_macro_equals_test.rb +0 -13
- data/test/assertion_macros/assertion_macro_exists_test.rb +0 -17
- data/test/assertion_macros/assertion_macro_kind_of_test.rb +0 -13
- data/test/assertion_macros/assertion_macro_matching_test.rb +0 -17
- data/test/assertion_macros/assertion_macro_nil_test.rb +0 -13
- data/test/assertion_macros/assertion_macro_raises_test.rb +0 -43
- data/test/assertion_macros/assertion_macro_respond_to_test.rb +0 -16
data/.gitignore
CHANGED
data/README.markdown
CHANGED
@@ -2,6 +2,11 @@
|
|
2
2
|
|
3
3
|
An extremely fast, expressive, and context-driven unit-testing framework. Protest the slow test.
|
4
4
|
|
5
|
+
When you're done reading here, take a gander at:
|
6
|
+
|
7
|
+
* [Riot Rails](http://github.com/thumblemonks/riot_rails): Rails support for Riot testing. A definite work in progress (help welcomed). See [evoke-app](http://github.com/thumblemonks/evoke-app) for live examples.
|
8
|
+
* [Riot.js](http://github.com/alexyoung/riotjs): for you JavaScript people, a version of Riot just for you. Both implementations will be informing the other. Lots of stuff to learn.
|
9
|
+
|
5
10
|
#### Installation
|
6
11
|
|
7
12
|
The Riot gem is hosted on gemcutter.org. It used to be hosted on GitHub, but they turned of gem support while moving to Rackspace, so we moved to gemcutter. If you have not already done so, add gemcutter.org to your list of gem sources like so:
|
@@ -17,32 +22,34 @@ Then, simply install the Riot gem like so:
|
|
17
22
|
I have done a really simple benchmarking (10,000 runs), but right now, Riot is running about **2 times** faster than Test::unit and thusly Shoulda:
|
18
23
|
|
19
24
|
Rehearsal ----------------------------------------------
|
20
|
-
Riot 0.
|
21
|
-
Test::Unit 1.
|
22
|
-
Shoulda 1.
|
23
|
-
------------------------------------- total:
|
25
|
+
Riot 0.360000 0.000000 0.360000 ( 0.364236)
|
26
|
+
Test::Unit 1.250000 0.000000 1.250000 ( 1.258466)
|
27
|
+
Shoulda 1.270000 0.010000 1.280000 ( 1.277429)
|
28
|
+
------------------------------------- total: 2.890000sec
|
24
29
|
|
25
30
|
user system total real
|
26
|
-
Riot 0.
|
27
|
-
Test::Unit 1.
|
28
|
-
Shoulda 1.
|
31
|
+
Riot 0.360000 0.000000 0.360000 ( 0.353360)
|
32
|
+
Test::Unit 1.260000 0.000000 1.260000 ( 1.263777)
|
33
|
+
Shoulda 1.270000 0.000000 1.270000 ( 1.270957)
|
29
34
|
|
30
35
|
"Is it valid?", you ask. *I* think it is. I ain't no cheater, but I might be delusional.
|
31
36
|
|
32
37
|
To compare against MiniTest, I had to run the benchmark separately.
|
33
38
|
|
34
39
|
Rehearsal --------------------------------------------
|
35
|
-
Riot 0.
|
36
|
-
MiniTest 0.
|
37
|
-
----------------------------------- total: 1.
|
40
|
+
Riot 0.350000 0.000000 0.350000 ( 0.354331)
|
41
|
+
MiniTest 0.720000 0.070000 0.790000 ( 0.793093)
|
42
|
+
----------------------------------- total: 1.140000sec
|
38
43
|
|
39
44
|
user system total real
|
40
|
-
Riot 0.
|
41
|
-
MiniTest 0.730000 0.
|
45
|
+
Riot 0.350000 0.000000 0.350000 ( 0.348796)
|
46
|
+
MiniTest 0.730000 0.060000 0.790000 ( 0.801629)
|
47
|
+
|
48
|
+
Riot is currently about twice as fast as minitest. Riot is also half the code of MiniTest (`310 loc < 674 loc` :)
|
42
49
|
|
43
|
-
|
50
|
+
All tests ran with `ruby 1.8.7 (2009-06-12 patchlevel 174) [i686-darwin9.8.0], MBARI 0x8770, Ruby Enterprise Edition 2009.10`.
|
44
51
|
|
45
|
-
|
52
|
+
Riot also works very well with Ruby 1.9. The same benchmarks from above run through ruby-1.9 show Riot to be twice as fast as it is already. See our [benchmarks gist](http://gist.github.com/240353) for more details.
|
46
53
|
|
47
54
|
## Examples
|
48
55
|
|
@@ -50,7 +57,7 @@ All tests ran with `ruby 1.8.7 (2009-06-12 patchlevel 174) [i686-darwin9]`.
|
|
50
57
|
|
51
58
|
**NOTE:** For no specific reason, I'm going to use an ActiveRecord model in the following examples.
|
52
59
|
|
53
|
-
At it's very basic, Riot simply tries to assert that an expression is true or false. Riot does this through its `asserts` or `should` tests. An `asserts` test will pass if the result of running the test is neither `nil` or `false`. A `should` test does the exact same thing - they are in
|
60
|
+
At it's very basic, Riot simply tries to assert that an expression is true or false. Riot does this through its `asserts` or `should` tests. An `asserts` test will pass if the result of running the test is neither `nil` or `false`. A `should` test does the exact same thing - they are in effect, aliases. The only difference is in the way you write the assertion.
|
54
61
|
|
55
62
|
For instance, given a test file named `foo_test.rb`, you might have the following code in it:
|
56
63
|
|
@@ -72,7 +79,7 @@ Notice that you do not define a class anywhere. That would be the entire content
|
|
72
79
|
|
73
80
|
Sometimes it's more clear to say "this **should** be that" and sometimes it's better to say "**asserts** this is that". I promise you that Riot will get no more redundant than this, but also that besides speed, Riot will aim at being expressive with a minimal amount of syntax.
|
74
81
|
|
75
|
-
The other important thing to note in the examples above is the use of the `topic`. Calling `topic` within any assertion will actually return the value of whatever was evaluated and returned from calling setup in the given context. In the examples above, `User.new` was returned, and is therefor accessible as the `topic`.
|
82
|
+
The other important thing to note in the examples above is the use of the `topic`. Calling `topic` within any assertion will actually return the value of whatever was evaluated and returned from calling the last setup in the given context. In the examples above, `User.new` was returned, and is therefor accessible as the `topic`.
|
76
83
|
|
77
84
|
I'm going to use `asserts` for the rest of this introduction, but you should know that you can replace any instance of `asserts` with `should` and nothing would change.
|
78
85
|
|
@@ -90,7 +97,7 @@ This is awfully redundant - not to mention, contrived. So, we wrote a shortcut t
|
|
90
97
|
|
91
98
|
context "a billionaire" do
|
92
99
|
setup { MoneyMaker.build(:billionaire) }
|
93
|
-
|
100
|
+
asserts_topic.kind_of(Billionaire)
|
94
101
|
end
|
95
102
|
|
96
103
|
#### Example: Equality
|
@@ -104,7 +111,7 @@ For example:
|
|
104
111
|
asserts("email address") { topic.email }.equals('foo@bar.com')
|
105
112
|
end
|
106
113
|
|
107
|
-
Here, you should begin to notice that tests themselves return the actual value. You do not write assertions into the test. Assertions are "aspected" onto the test. If the test above did not return 'foo@bar.com' for
|
114
|
+
Here, you should begin to notice that tests themselves return the actual value. You do not write assertions into the test. Assertions are "aspected" onto the test. If the test above did not return 'foo@bar.com' for `topic.email`, the assertion would have failed.
|
108
115
|
|
109
116
|
The `equals` modifier works with any type of value, including nil's. However, if you wanted to test for nil explicitly, you could simply do this:
|
110
117
|
|
@@ -265,7 +272,7 @@ I should say that I love Shoulda in theory and in practice. It changed the way I
|
|
265
272
|
|
266
273
|
### How Riot is different
|
267
274
|
|
268
|
-
Riot differs primarily in that it does not rerun setup for each test in a context. I know this is going to shock
|
275
|
+
Riot differs primarily in that it does not rerun setup for each test in a context. I know this is going to shock a lot of folks. However, over the past several years of my doing TDD in some capacity or another, there are certain habits I have tried to pick up on any many others I have tried to drop.
|
269
276
|
|
270
277
|
For instance, I believe that no assertion should mangle the context of the test data it is running in. Following this allows me to require setup be run only once for a collection of related assertions. Even in a nested context where setups are inherited, the setup's are called only once per the specific context.
|
271
278
|
|
@@ -302,7 +309,7 @@ Basically, it's like setting up any other test runner. Then, from the command li
|
|
302
309
|
Riot definitely works with the latest Sinatra. I personally use it to run tests for [Chicago](http://github.com/thumblemonks/chicago) and [Slvu](http://github.com/jaknowlden/slvu). Setup is pretty easy and very much like getting your tests to run with Test::Unit. In a test helper file that gets loaded into all of your tests (that need it), enter the following:
|
303
310
|
|
304
311
|
require 'riot'
|
305
|
-
class Riot::
|
312
|
+
class Riot::Situation
|
306
313
|
include Rack::Test::Methods
|
307
314
|
def app; @app; end
|
308
315
|
end
|
@@ -356,18 +363,19 @@ And then in your actual test, you might do the following:
|
|
356
363
|
|
357
364
|
#### Assertion macros
|
358
365
|
|
359
|
-
If you want to add special macros to an Assertion, this is as easy as adding them to a Context.
|
366
|
+
If you want to add special macros to an Assertion, this is as easy as adding them to a Context. Assertion macros, however, have a special mechanism for adding themselves onto an assertion. Thus, you will want to open the Riot::Assertion class and then define your assertion macro.
|
360
367
|
|
361
368
|
For instance, let's say you wanted to add a macro for verifying that the result of an assertion is the same kind\_of object as you would expect. You would define the macro like so:
|
362
369
|
|
363
|
-
module
|
364
|
-
|
365
|
-
|
366
|
-
|
370
|
+
module Riot
|
371
|
+
class Assertion
|
372
|
+
|
373
|
+
assertion(:kind_of) do |actual, expected|
|
374
|
+
actual.kind_of?(expected) ? pass : fail("expected kind of #{expected}, not #{actual.inspect}")
|
367
375
|
end
|
368
|
-
|
369
|
-
|
370
|
-
|
376
|
+
|
377
|
+
end # Assertion
|
378
|
+
end # Riot
|
371
379
|
|
372
380
|
And in your context, you would use it like so:
|
373
381
|
|
@@ -375,20 +383,4 @@ And in your context, you would use it like so:
|
|
375
383
|
asserts("a hash is defined") { {:foo => 'bar'} }.kind_of(Hash)
|
376
384
|
end
|
377
385
|
|
378
|
-
|
379
|
-
|
380
|
-
## TODO
|
381
|
-
|
382
|
-
TONS OF STUFF
|
383
|
-
|
384
|
-
1. Documentation about the `topic` method
|
385
|
-
1. Better documentation for everything
|
386
|
-
1. Refactor reporting; some abstracting is needed for recording a result (for instance)
|
387
|
-
1. Need to know where in backtrace a test failed (line number, etc.); i.e. backtrace filtering for clarity
|
388
|
-
1. More assertion macros: throws, etc.
|
389
|
-
1. Aliases for context "with, without, when, ..."; add those words to test description
|
390
|
-
1. Optimization and simplification (ex. flog is complaining print\_result\_stack)
|
391
|
-
1. Better error messages?
|
392
|
-
1. Perhaps: Multiple setup blocks in one context
|
393
|
-
1. Perhaps: association macro chaining
|
394
|
-
1. Perhaps: Uhhhhh ... a teardown method (only maybe. not sold :)
|
386
|
+
If you think you might want to chain assertions checks together, this won't work out the box. The reason for this is that your assertion macro should call out to pass or fail, which each return a signal that will be used by the reporter. You could conceivably write an assertion as a filter macro instead, that would return `self`, but I can't decide why you would do that yet (in theory it would work, though).
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
0.10.0
|
data/lib/riot.rb
CHANGED
@@ -1,28 +1,37 @@
|
|
1
|
-
require 'riot/
|
2
|
-
require 'riot/report'
|
3
|
-
require 'riot/situation'
|
1
|
+
require 'riot/reporter'
|
4
2
|
require 'riot/context'
|
5
|
-
require 'riot/
|
3
|
+
require 'riot/situation'
|
4
|
+
require 'riot/runnable'
|
6
5
|
require 'riot/assertion_macros'
|
7
6
|
|
8
7
|
module Riot
|
8
|
+
def self.context(description, &definition)
|
9
|
+
root_contexts << Context.new(description, &definition)
|
10
|
+
end
|
9
11
|
|
10
|
-
|
12
|
+
def self.root_contexts; @root_contexts ||= []; end
|
11
13
|
|
12
|
-
def self.
|
13
|
-
|
14
|
-
|
15
|
-
|
14
|
+
def self.run
|
15
|
+
the_reporter = reporter.new
|
16
|
+
the_reporter.summarize do
|
17
|
+
root_contexts.each { |ctx| ctx.run(the_reporter) }
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def self.silently!; @silent = true; end
|
22
|
+
def self.silently?; @silent == true; end
|
23
|
+
|
24
|
+
def self.reporter
|
25
|
+
Riot.silently? ? Riot::SilentReporter : (@reporter_class || Riot::StoryReporter)
|
26
|
+
end
|
27
|
+
def self.reporter=(reporter_class) @reporter_class = reporter_class; end
|
28
|
+
def self.dots; Riot.reporter = Riot::DotMatrixReporter; end
|
16
29
|
|
17
|
-
at_exit
|
18
|
-
Riot.reporter.results
|
19
|
-
exit false unless reporter.passed?
|
20
|
-
end unless Riot.silently?
|
30
|
+
at_exit { run unless Riot.silently? }
|
21
31
|
end # Riot
|
22
32
|
|
23
|
-
|
24
|
-
def context(description,
|
25
|
-
|
26
|
-
reporter.time { Riot::Context.new(description, reporter, parent, &block) }
|
33
|
+
class Object
|
34
|
+
def context(description, &definition)
|
35
|
+
Riot.context(description, &definition)
|
27
36
|
end
|
28
|
-
end
|
37
|
+
end
|
@@ -1,17 +1,17 @@
|
|
1
1
|
module Riot
|
2
|
-
|
2
|
+
class Assertion
|
3
3
|
# Asserts that the result of the test equals the expected value
|
4
4
|
# asserts("test") { "foo" }.equals("foo")
|
5
5
|
# should("test") { "foo" }.equals("foo")
|
6
|
-
|
7
|
-
expected == actual
|
6
|
+
assertion(:equals) do |actual, expected|
|
7
|
+
expected == actual ? pass : fail("expected #{actual.inspect} to equal #{expected.inspect}")
|
8
8
|
end
|
9
9
|
|
10
10
|
# Asserts that the result of the test is nil
|
11
11
|
# asserts("test") { nil }.nil
|
12
12
|
# should("test") { nil }.nil
|
13
|
-
|
14
|
-
actual.nil?
|
13
|
+
assertion(:nil) do |actual|
|
14
|
+
actual.nil? ? pass : fail("expected nil, not #{actual.inspect}")
|
15
15
|
end
|
16
16
|
|
17
17
|
# Asserts that the result of the test is a non-nil value. This is useful in the case where you don't want
|
@@ -20,72 +20,82 @@ module Riot
|
|
20
20
|
# should("test") { 123 }.exists
|
21
21
|
# asserts("test") { "" }.exists
|
22
22
|
# asserts("test") { nil }.exists # This would fail
|
23
|
-
|
24
|
-
!actual.nil?
|
23
|
+
assertion(:exists) do |actual|
|
24
|
+
!actual.nil? ? pass : fail("expected a non-nil value")
|
25
25
|
end
|
26
26
|
|
27
|
-
# Asserts that the test
|
28
|
-
# asserts("test") {
|
29
|
-
# should("test") {
|
27
|
+
# Asserts that the result of the test is an object that is a kind of the expected type
|
28
|
+
# asserts("test") { "foo" }.kind_of(String)
|
29
|
+
# should("test") { "foo" }.kind_of(String)
|
30
|
+
assertion(:kind_of) do |actual, expected|
|
31
|
+
actual.kind_of?(expected) ? pass : fail("expected kind of #{expected}, not #{actual.inspect}")
|
32
|
+
end
|
33
|
+
|
34
|
+
# Asserts that an instance variable is defined for the result of the assertion. Value of instance
|
35
|
+
# variable is expected to not be nil
|
36
|
+
# setup { User.new(:email => "foo@bar.baz") }
|
37
|
+
# topic.assigns(:email)
|
30
38
|
#
|
31
|
-
#
|
32
|
-
#
|
33
|
-
#
|
34
|
-
#
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
return fail("expected #{expected_message} for message, not #{actual_error.message}")
|
39
|
+
# If a value is provided in addition to the variable name, the actual value of the instance variable
|
40
|
+
# must equal the expected value
|
41
|
+
# setup { User.new(:email => "foo@bar.baz") }
|
42
|
+
# topic.assigns(:email, "foo@bar.baz")
|
43
|
+
assertion(:assigns) do |actual, *expectings|
|
44
|
+
variable, expected_value = expectings
|
45
|
+
actual_value = actual.instance_variable_get("@#{variable}")
|
46
|
+
if actual_value.nil?
|
47
|
+
fail("expected @#{variable} to be assigned a value")
|
48
|
+
elsif !expected_value.nil? && expected_value != actual_value
|
49
|
+
fail(%Q[expected @#{variable} to be equal to #{expected_value.inspect}, not #{actual_value.inspect}])
|
50
|
+
else
|
51
|
+
pass
|
45
52
|
end
|
46
|
-
true
|
47
53
|
end
|
48
54
|
|
49
55
|
# Asserts that the result of the test equals matches against the proved expression
|
50
56
|
# asserts("test") { "12345" }.matches(/\d+/)
|
51
57
|
# should("test") { "12345" }.matches(/\d+/)
|
52
|
-
|
58
|
+
assertion(:matches) do |actual, expected|
|
53
59
|
expected = %r[#{Regexp.escape(expected)}] if expected.kind_of?(String)
|
54
|
-
actual =~ expected
|
55
|
-
end
|
56
|
-
|
57
|
-
# Asserts that the result of the test is an object that is a kind of the expected type
|
58
|
-
# asserts("test") { "foo" }.kind_of(String)
|
59
|
-
# should("test") { "foo" }.kind_of(String)
|
60
|
-
def kind_of(expected)
|
61
|
-
actual.kind_of?(expected) || fail("expected kind of #{expected}, not #{actual.inspect}")
|
60
|
+
actual =~ expected ? pass : fail("expected #{expected.inspect} to match #{actual.inspect}")
|
62
61
|
end
|
63
62
|
|
64
63
|
# Asserts that the result of the test is an object that responds to the given method
|
65
64
|
# asserts("test") { "foo" }.respond_to(:to_s)
|
66
65
|
# should("test") { "foo" }.respond_to(:to_s)
|
67
|
-
|
68
|
-
actual.respond_to?(expected)
|
66
|
+
assertion(:respond_to) do |actual, expected|
|
67
|
+
actual.respond_to?(expected) ? pass : fail("expected method #{expected.inspect} is not defined")
|
69
68
|
end
|
70
69
|
|
71
|
-
# Asserts that
|
72
|
-
#
|
73
|
-
#
|
74
|
-
|
70
|
+
# Asserts that two arrays contain the same elements, the same number of times.
|
71
|
+
# asserts("test") { ["foo", "bar"] }.same_elements(["bar", "foo"])
|
72
|
+
# should("test") { ["foo", "bar"] }.same_elements(["bar", "foo"])
|
73
|
+
assertion(:same_elements) do |actual, expected|
|
74
|
+
require 'set'
|
75
|
+
same = (Set.new(expected) == Set.new(actual))
|
76
|
+
same ? pass : fail("expected elements #{expected.inspect} to match #{actual.inspect}")
|
77
|
+
end
|
78
|
+
|
79
|
+
# Asserts that the test raises the expected Exception
|
80
|
+
# asserts("test") { raise My::Exception }.raises(My::Exception)
|
81
|
+
# should("test") { raise My::Exception }.raises(My::Exception)
|
75
82
|
#
|
76
|
-
#
|
77
|
-
#
|
78
|
-
#
|
79
|
-
#
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
83
|
+
# You can also check to see if the provided message equals or matches your expectations. The message
|
84
|
+
# from the actual raised exception will be converted to a string before any comparison is executed.
|
85
|
+
# asserts("test") { raise My::Exception, "Foo" }.raises(My::Exception, "Foo")
|
86
|
+
# asserts("test") { raise My::Exception, "Foo Bar" }.raises(My::Exception, /Bar/)
|
87
|
+
assertion(:raises, expect_exception=true) do |actual_exception, expected_class, expected_message|
|
88
|
+
actual_message = actual_exception && actual_exception.message
|
89
|
+
if actual_exception.nil?
|
90
|
+
fail("should have raised #{expected_class}, but raised nothing")
|
91
|
+
elsif expected_class != actual_exception.class
|
92
|
+
fail("should have raised #{expected_class}, not #{actual_exception.class}")
|
93
|
+
elsif expected_message && !(actual_message.to_s =~ %r[#{expected_message}])
|
94
|
+
fail("expected #{expected_message.inspect} for message, not #{actual_message.inspect}")
|
95
|
+
else
|
96
|
+
pass
|
85
97
|
end
|
86
|
-
true
|
87
98
|
end
|
88
|
-
end # AssertionMacros
|
89
|
-
end # Riot
|
90
99
|
|
91
|
-
|
100
|
+
end # Assertion
|
101
|
+
end # Riot
|
data/lib/riot/context.rb
CHANGED
@@ -1,48 +1,38 @@
|
|
1
1
|
module Riot
|
2
2
|
class Context
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
@setups, @assertions = [], []
|
8
|
-
@situation = Situation.new
|
9
|
-
bootstrap(@situation)
|
10
|
-
instance_eval(&context_block) if block_given? # running the context
|
11
|
-
report
|
3
|
+
def initialize(description, setups=[], &definition)
|
4
|
+
@description = description
|
5
|
+
@contexts, @setups, @assertions = [], setups, []
|
6
|
+
self.instance_eval(&definition)
|
12
7
|
end
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
@parent.bootstrap(a_situation).each do |setup_block|
|
17
|
-
run_setup(a_situation, &setup_block)
|
18
|
-
end if @parent
|
19
|
-
@setups
|
20
|
-
end
|
21
|
-
|
22
|
-
def report
|
23
|
-
assertions.each { |assertion| @reporter.process_assertion(assertion) }
|
8
|
+
|
9
|
+
def setup(&definition)
|
10
|
+
@setups << Setup.new(&definition)
|
24
11
|
end
|
25
12
|
|
26
|
-
def
|
13
|
+
def asserts(what, &definition) new_assertion("asserts", what, &definition); end
|
14
|
+
def should(what, &definition) new_assertion("should", what, &definition); end
|
27
15
|
|
28
|
-
|
16
|
+
def asserts_topic; asserts("topic") { topic }; end
|
29
17
|
|
30
|
-
def
|
31
|
-
|
32
|
-
|
18
|
+
def context(description, &definition)
|
19
|
+
# not liking the dup
|
20
|
+
@contexts << Context.new("#{@description} #{description}", @setups.dup, &definition)
|
33
21
|
end
|
34
|
-
|
35
|
-
def
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
22
|
+
|
23
|
+
def run(reporter)
|
24
|
+
runnables = @setups + @assertions
|
25
|
+
reporter.describe_context(@description) unless @assertions.empty?
|
26
|
+
situation = Situation.new
|
27
|
+
runnables.each do |runnable|
|
28
|
+
reporter.report(runnable.to_s, runnable.run(situation))
|
29
|
+
end
|
30
|
+
@contexts.each { |ctx| ctx.run(reporter) }
|
31
|
+
reporter
|
42
32
|
end
|
43
|
-
|
44
|
-
def
|
45
|
-
|
33
|
+
private
|
34
|
+
def new_assertion(scope, what, &definition)
|
35
|
+
(@assertions << Assertion.new("#{scope} #{what}", &definition)).last
|
46
36
|
end
|
47
37
|
end # Context
|
48
38
|
end # Riot
|