riot 0.10.9 → 0.10.10
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +46 -0
- data/README.markdown +53 -16
- data/Rakefile +8 -0
- data/VERSION +1 -1
- data/lib/riot.rb +1 -1
- data/lib/riot/assertion.rb +18 -31
- data/lib/riot/assertion_macro.rb +35 -0
- data/lib/riot/assertion_macros/any.rb +12 -0
- data/lib/riot/assertion_macros/assigns.rb +27 -0
- data/lib/riot/assertion_macros/empty.rb +13 -0
- data/lib/riot/assertion_macros/equals.rb +18 -0
- data/lib/riot/assertion_macros/exists.rb +15 -0
- data/lib/riot/assertion_macros/includes.rb +17 -0
- data/lib/riot/assertion_macros/kind_of.rb +16 -0
- data/lib/riot/assertion_macros/matches.rb +17 -0
- data/lib/riot/assertion_macros/nil.rb +12 -0
- data/lib/riot/assertion_macros/raises.rb +31 -0
- data/lib/riot/assertion_macros/respond_to.rb +16 -0
- data/lib/riot/assertion_macros/same_elements.rb +14 -0
- data/lib/riot/assertion_macros/size.rb +15 -0
- data/lib/riot/context.rb +9 -17
- data/lib/riot/reporter.rb +25 -21
- data/riot.gemspec +17 -3
- data/test/assertion_macros/any_test.rb +2 -2
- data/test/assertion_macros/equals_test.rb +4 -4
- data/test/assertion_macros/exists_test.rb +2 -2
- data/test/assertion_macros/includes_test.rb +1 -1
- data/test/assertion_macros/kind_of_test.rb +1 -1
- data/test/assertion_macros/matching_test.rb +1 -1
- data/test/assertion_macros/nil_test.rb +1 -1
- data/test/assertion_macros/raises_test.rb +3 -3
- data/test/assertion_macros/respond_to_test.rb +1 -1
- data/test/assertion_macros/size_test.rb +17 -6
- data/test/assertion_test.rb +11 -6
- data/test/context_test.rb +2 -54
- data/test/report_test.rb +7 -2
- data/test/teststrap.rb +12 -3
- metadata +17 -3
- data/lib/riot/assertion_macros.rb +0 -136
data/CHANGELOG
ADDED
@@ -0,0 +1,46 @@
|
|
1
|
+
*0.10.10*
|
2
|
+
|
3
|
+
* Passing assertion macros can now return a custom message [dasch, jaknowlden]
|
4
|
+
|
5
|
+
def evaluate(actual, *expectings)
|
6
|
+
1 == 1 ? pass("1 does equal 1") : fail("1 does not equal 1 in this universe")
|
7
|
+
end
|
8
|
+
|
9
|
+
* Removing Context#extend_assertions and related code [jaknowlden]
|
10
|
+
|
11
|
+
* Allow the use of symbolic descriptions as shorthands for sending the message to the topic [dasch]
|
12
|
+
|
13
|
+
setup { "foo" }
|
14
|
+
asserts(:upcase).equals("FOO")
|
15
|
+
|
16
|
+
* Added AssertionMacro and #register for macros [jaknowlden, splattael]
|
17
|
+
|
18
|
+
module My
|
19
|
+
class CustomThingAssertion < Riot::AssertionMacro
|
20
|
+
register :custom_thing
|
21
|
+
expects_exception!
|
22
|
+
|
23
|
+
def evaluate(actual, *expectings)
|
24
|
+
# ...
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
Riot::Assertion.register_macro :custom_thing, CustomThingAssertion
|
29
|
+
end
|
30
|
+
|
31
|
+
* Replace IOReporter#say with #puts. Also add #print. [splattael]
|
32
|
+
|
33
|
+
class SomeNewReporter < IOReporter
|
34
|
+
def pass
|
35
|
+
puts "I PASSED"
|
36
|
+
end
|
37
|
+
|
38
|
+
def fail
|
39
|
+
print "F"
|
40
|
+
end
|
41
|
+
# ...
|
42
|
+
end
|
43
|
+
|
44
|
+
*0.10.9 and before*
|
45
|
+
|
46
|
+
See [commit log](http://github.com/thumblemonks/riot/commits/master)
|
data/README.markdown
CHANGED
@@ -44,7 +44,7 @@ Then, simply install the Riot gem like so:
|
|
44
44
|
<a name="speed"></a>
|
45
45
|
#### Note on speed
|
46
46
|
|
47
|
-
I have done a really simple benchmarking (10,000 runs), but right now, Riot is running about **
|
47
|
+
I have done a really simple benchmarking (10,000 runs), but right now, Riot is running about **3 times** faster than Test::Unit and thusly Shoulda:
|
48
48
|
|
49
49
|
Rehearsal ----------------------------------------------
|
50
50
|
Riot 0.360000 0.000000 0.360000 ( 0.364236)
|
@@ -112,8 +112,9 @@ The other important thing to note in the examples above is the use of the `topic
|
|
112
112
|
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.
|
113
113
|
|
114
114
|
<a name="examples-shortcut"></a>
|
115
|
-
#### Example:
|
115
|
+
#### Example: Shortcuts
|
116
116
|
|
117
|
+
##### Asserting the topic itself
|
117
118
|
Over the course of developing Riot it became somewhat obvious to some of us that we were creating assertions that returned the `topic` just so we could assert things about the topic itself. For instance, were doing this:
|
118
119
|
|
119
120
|
context "a billionaire" do
|
@@ -129,16 +130,31 @@ This is awfully redundant - not to mention, contrived. So, we wrote a shortcut t
|
|
129
130
|
asserts_topic.kind_of(Billionaire)
|
130
131
|
end
|
131
132
|
|
132
|
-
If you'd like to add a description to your assertion about the topic,
|
133
|
-
but still would like to avoid the redundancy of an assertion simply
|
134
|
-
returning the topic from it's block, you can omit the block all
|
135
|
-
together as follows:
|
133
|
+
If you'd like to add a description to your assertion about the topic, but still would like to avoid the redundancy of an assertion simply returning the topic from it's block, you can omit the block all together as follows:
|
136
134
|
|
137
135
|
context "a trazillionaire" do
|
138
136
|
setup { MoneyMaker.build(:trazillionaire) }
|
139
137
|
asserts("is a trazillionaire").kind_of(Trazillionaire)
|
140
138
|
end
|
141
139
|
|
140
|
+
##### Asserting methods on topic
|
141
|
+
|
142
|
+
A very common assertion pattern with Riot is calling a method on the topic and asserting it's output. For instance, the following is not an uncommon thing to see in an `ActiveRecord` test:
|
143
|
+
|
144
|
+
context "A new post" do
|
145
|
+
setup { Post.new(:name => "Howdy ya'll") }
|
146
|
+
asserts("name") { topic.name }.equals("Howdy ya'll")
|
147
|
+
end
|
148
|
+
|
149
|
+
Since Riot is all about reducing redundancy and increasing semantics, it makes a ton of sense to be able to do this instead:
|
150
|
+
|
151
|
+
context "A new post" do
|
152
|
+
setup { Post.new(:name => "Howdy ya'll") }
|
153
|
+
asserts(:name).equals("Howdy ya'll")
|
154
|
+
end
|
155
|
+
|
156
|
+
And now you can! Isn't that just so much easier to read?
|
157
|
+
|
142
158
|
<a name="examples-equality"></a>
|
143
159
|
#### Example: Equality
|
144
160
|
|
@@ -410,7 +426,10 @@ And then define a context (or many) for testing your Sinatra app. For instance:
|
|
410
426
|
end
|
411
427
|
end
|
412
428
|
|
413
|
-
Make sure to check out the Riot + Sinatra testing macros in Chicago.
|
429
|
+
Make sure to check out the Riot + Sinatra testing macros in Chicago. If you do happen to use Chicago, the above `test_helper.rb` setup can be compressed to the following while allowing the same test to work:
|
430
|
+
|
431
|
+
require 'riot'
|
432
|
+
require 'chicago/riot'
|
414
433
|
|
415
434
|
<a name="rails"></a>
|
416
435
|
### With Rails
|
@@ -449,19 +468,23 @@ And then in your actual test, you might do the following:
|
|
449
468
|
<a name="assertion-macros"></a>
|
450
469
|
#### Assertion macros
|
451
470
|
|
452
|
-
If you want to add special macros to an Assertion,
|
471
|
+
If you want to add special macros to an Assertion, the process is really very easy. You simple need to define a class that extends `AssertionMacro` (or at least quacks like it), be sure to implement the `evaluate` instance method, and then register the macro.
|
453
472
|
|
454
|
-
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:
|
473
|
+
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:
|
455
474
|
|
456
|
-
module
|
457
|
-
class
|
475
|
+
module Foo
|
476
|
+
class KindOfMacro < Riot::AssertionMacro
|
477
|
+
register :kind_of
|
458
478
|
|
459
|
-
|
460
|
-
actual.kind_of?(expected)
|
479
|
+
def evaluate(actual, expected)
|
480
|
+
if actual.kind_of?(expected)
|
481
|
+
pass("is a kind of #{expected.inspect}")
|
482
|
+
else
|
483
|
+
fail("expected kind of #{expected}, not #{actual.inspect}")
|
484
|
+
end
|
461
485
|
end
|
462
|
-
|
463
|
-
|
464
|
-
end # Riot
|
486
|
+
end # KindOfMacro
|
487
|
+
end # Foo
|
465
488
|
|
466
489
|
And in your context, you would use it like so:
|
467
490
|
|
@@ -469,4 +492,18 @@ And in your context, you would use it like so:
|
|
469
492
|
asserts("a hash is defined") { {:foo => 'bar'} }.kind_of(Hash)
|
470
493
|
end
|
471
494
|
|
495
|
+
If your assertion macro expects to be called only when an exception occurs, there's support for that, too. Check this:
|
496
|
+
|
497
|
+
module Foo
|
498
|
+
class RaisesMacro < Riot::AssertionMacro
|
499
|
+
register :raises
|
500
|
+
expects_exception! # THE IMPORTANT LINE
|
501
|
+
|
502
|
+
def evaluate(actual, expected)
|
503
|
+
# ... pass/fail code
|
504
|
+
end
|
505
|
+
end # RaisesMacro
|
506
|
+
end # Foo
|
507
|
+
|
508
|
+
|
472
509
|
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/Rakefile
CHANGED
@@ -11,6 +11,14 @@ Rake::TestTask.new(:test) do |test|
|
|
11
11
|
test.verbose = false
|
12
12
|
end
|
13
13
|
|
14
|
+
desc "Run all of them fancy benchmarks, Howard!"
|
15
|
+
task :benchmarks do
|
16
|
+
Dir["test/benchmark/*.rb"].each do |file|
|
17
|
+
puts ">> Running #{file}"
|
18
|
+
puts %x[ruby #{file}]
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
14
22
|
desc "Run Flog against library (except tests)"
|
15
23
|
task :flog do
|
16
24
|
puts %x[find ./lib -name *.rb | xargs flog]
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.10.
|
1
|
+
0.10.10
|
data/lib/riot.rb
CHANGED
data/lib/riot/assertion.rb
CHANGED
@@ -1,45 +1,32 @@
|
|
1
1
|
module Riot
|
2
2
|
class Assertion < RunnableBlock
|
3
|
-
|
4
|
-
def initialize(description, &definition)
|
5
|
-
super
|
6
|
-
@expectings, @expect_exception, @expectation_block = [], false, nil
|
7
|
-
@assertion_block = lambda do |actual|
|
8
|
-
actual ? self.class.pass : self.class.fail("Expected non-false but got #{actual.inspect} instead")
|
9
|
-
end
|
10
|
-
end
|
11
|
-
|
12
3
|
class << self
|
13
|
-
def
|
14
|
-
def fail(message) [:fail, message]; end
|
15
|
-
def error(e) [:error, e]; end
|
16
|
-
def assertions; @assertions ||= {}; end
|
4
|
+
def macros; @macros ||= {}; end
|
17
5
|
|
18
|
-
|
19
|
-
|
20
|
-
def assertion(name, expect_exception=false, &assertion_block)
|
21
|
-
assertions[name] = [expect_exception, assertion_block]
|
22
|
-
class_eval <<-EOC
|
23
|
-
def #{name}(*expectings, &expectation_block)
|
24
|
-
@expectings, @expectation_block = expectings, expectation_block
|
25
|
-
@expect_exception, @assertion_block = self.class.assertions[#{name.inspect}]
|
26
|
-
self
|
27
|
-
end
|
28
|
-
EOC
|
6
|
+
def register_macro(name, assertion_macro, expect_exception=false)
|
7
|
+
macros[name.to_s] = assertion_macro.new
|
29
8
|
end
|
30
9
|
end
|
31
10
|
|
32
|
-
def
|
33
|
-
|
34
|
-
|
11
|
+
def initialize(description, &definition)
|
12
|
+
super
|
13
|
+
@expectings, @expectation_block = [], false, nil
|
14
|
+
@macro = AssertionMacro.default
|
35
15
|
end
|
36
16
|
|
37
|
-
|
38
|
-
|
17
|
+
def run(situation)
|
18
|
+
@expectings << situation.evaluate(&@expectation_block) if @expectation_block
|
39
19
|
actual = situation.evaluate(&definition)
|
40
|
-
|
20
|
+
@macro.evaluate((@macro.expects_exception? ? nil : actual), *@expectings)
|
41
21
|
rescue Exception => e
|
42
|
-
|
22
|
+
@macro.expects_exception? ? @macro.evaluate(e, *@expectings) : @macro.error(e)
|
23
|
+
end
|
24
|
+
private
|
25
|
+
def enhance_with_macro(name, *expectings, &expectation_block)
|
26
|
+
@macro, @expectings, @expectation_block = self.class.macros[name.to_s], expectings, expectation_block
|
27
|
+
raise(NoMethodError, name) unless @macro
|
28
|
+
self
|
43
29
|
end
|
30
|
+
alias :method_missing :enhance_with_macro
|
44
31
|
end # Assertion
|
45
32
|
end # Riot
|
@@ -0,0 +1,35 @@
|
|
1
|
+
module Riot
|
2
|
+
class AssertionMacro
|
3
|
+
class << self
|
4
|
+
attr_reader :expects_exception
|
5
|
+
|
6
|
+
def default; @default_macro ||= new; end
|
7
|
+
def expects_exception!; @expects_exception = true; end
|
8
|
+
def register(name); Assertion.register_macro name, self; end
|
9
|
+
end
|
10
|
+
|
11
|
+
def pass(message=nil) [:pass, message]; end
|
12
|
+
def fail(message) [:fail, message]; end
|
13
|
+
def error(e) [:error, e]; end
|
14
|
+
|
15
|
+
def expects_exception?; self.class.expects_exception; end
|
16
|
+
|
17
|
+
def evaluate(actual)
|
18
|
+
actual ? pass : fail("Expected non-false but got #{actual.inspect} instead")
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
require 'riot/assertion_macros/any'
|
24
|
+
require 'riot/assertion_macros/assigns'
|
25
|
+
require 'riot/assertion_macros/empty'
|
26
|
+
require 'riot/assertion_macros/equals'
|
27
|
+
require 'riot/assertion_macros/exists'
|
28
|
+
require 'riot/assertion_macros/includes'
|
29
|
+
require 'riot/assertion_macros/kind_of'
|
30
|
+
require 'riot/assertion_macros/matches'
|
31
|
+
require 'riot/assertion_macros/nil'
|
32
|
+
require 'riot/assertion_macros/raises'
|
33
|
+
require 'riot/assertion_macros/respond_to'
|
34
|
+
require 'riot/assertion_macros/same_elements'
|
35
|
+
require 'riot/assertion_macros/size'
|
@@ -0,0 +1,12 @@
|
|
1
|
+
module Riot
|
2
|
+
# Asserts the result has items
|
3
|
+
# asserts("an array") { [1] }.any
|
4
|
+
# asserts("a hash") { {:name => 'washington'} }.any
|
5
|
+
class AnyMacro < AssertionMacro
|
6
|
+
register :any
|
7
|
+
|
8
|
+
def evaluate(actual)
|
9
|
+
actual.any? ? pass("is not empty") : fail("expected #{actual.inspect} to have items")
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module Riot
|
2
|
+
# Asserts that an instance variable is defined for the result of the assertion. Value of instance
|
3
|
+
# variable is expected to not be nil
|
4
|
+
# setup { User.new(:email => "foo@bar.baz") }
|
5
|
+
# topic.assigns(:email)
|
6
|
+
#
|
7
|
+
# If a value is provided in addition to the variable name, the actual value of the instance variable
|
8
|
+
# must equal the expected value
|
9
|
+
# setup { User.new(:email => "foo@bar.baz") }
|
10
|
+
# topic.assigns(:email, "foo@bar.baz")
|
11
|
+
class AssignsMacro < AssertionMacro
|
12
|
+
register :assigns
|
13
|
+
|
14
|
+
def evaluate(actual, *expectings)
|
15
|
+
variable, expected_value = expectings
|
16
|
+
variable_name = "@#{variable}"
|
17
|
+
actual_value = actual.instance_variable_defined?(variable_name) ? actual.instance_variable_get(variable_name) : nil
|
18
|
+
if actual_value.nil?
|
19
|
+
fail("expected @#{variable} to be assigned a value")
|
20
|
+
elsif !expected_value.nil? && expected_value != actual_value
|
21
|
+
fail(%Q[expected @#{variable} to be equal to #{expected_value.inspect}, not #{actual_value.inspect}])
|
22
|
+
else
|
23
|
+
pass
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
module Riot
|
2
|
+
# Asserts the result is empty
|
3
|
+
# asserts("a string") { "" }.empty
|
4
|
+
# asserts("an array") { [] }.empty
|
5
|
+
# asserts("a hash") { Hash.new }.empty
|
6
|
+
class EmptyMacro < AssertionMacro
|
7
|
+
register :empty
|
8
|
+
|
9
|
+
def evaluate(actual)
|
10
|
+
actual.length == 0 ? pass : fail("expected #{actual.inspect} to be empty")
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module Riot
|
2
|
+
# Asserts that the result of the test equals the expected value. Using the +===+ operator to assert
|
3
|
+
# equality.
|
4
|
+
# asserts("test") { "foo" }.equals("foo")
|
5
|
+
# should("test") { "foo" }.equals("foo")
|
6
|
+
# asserts("test") { "foo" }.equals { "foo" }
|
7
|
+
class EqualsMacro < AssertionMacro
|
8
|
+
register :equals
|
9
|
+
|
10
|
+
def evaluate(actual, expected)
|
11
|
+
if expected === actual
|
12
|
+
pass("is equal to #{expected.inspect}")
|
13
|
+
else
|
14
|
+
fail("expected #{expected.inspect}, not #{actual.inspect}")
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module Riot
|
2
|
+
# Asserts that the result of the test is a non-nil value. This is useful in the case where you don't want
|
3
|
+
# to translate the result of the test into a boolean value
|
4
|
+
# asserts("test") { "foo" }.exists
|
5
|
+
# should("test") { 123 }.exists
|
6
|
+
# asserts("test") { "" }.exists
|
7
|
+
# asserts("test") { nil }.exists # This would fail
|
8
|
+
class ExistsMacro < AssertionMacro
|
9
|
+
register :exists
|
10
|
+
|
11
|
+
def evaluate(actual)
|
12
|
+
!actual.nil? ? pass("is not nil") : fail("expected a non-nil value")
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module Riot
|
2
|
+
# Asserts the result contains the expected element
|
3
|
+
# asserts("a string") { "world" }.includes('o')
|
4
|
+
# asserts("an array") { [1,2,3] }.includes(2)
|
5
|
+
# asserts("a range") { (1..15) }.includes(10)
|
6
|
+
class IncludesMacro < AssertionMacro
|
7
|
+
register :includes
|
8
|
+
|
9
|
+
def evaluate(actual, expected)
|
10
|
+
if actual.include?(expected)
|
11
|
+
pass("includes #{expected.inspect}")
|
12
|
+
else
|
13
|
+
fail("expected #{actual.inspect} to include #{expected.inspect}")
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module Riot
|
2
|
+
# Asserts that the result of the test is an object that is a kind of the expected type
|
3
|
+
# asserts("test") { "foo" }.kind_of(String)
|
4
|
+
# should("test") { "foo" }.kind_of(String)
|
5
|
+
class KindOfMacro < AssertionMacro
|
6
|
+
register :kind_of
|
7
|
+
|
8
|
+
def evaluate(actual, expected)
|
9
|
+
if actual.kind_of?(expected)
|
10
|
+
pass("is a kind of #{expected.inspect}")
|
11
|
+
else
|
12
|
+
fail("expected kind of #{expected}, not #{actual.class.inspect}")
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module Riot
|
2
|
+
# Asserts that the result of the test equals matches against the proved expression
|
3
|
+
# asserts("test") { "12345" }.matches(/\d+/)
|
4
|
+
# should("test") { "12345" }.matches(/\d+/)
|
5
|
+
class MatchesMacro < AssertionMacro
|
6
|
+
register :matches
|
7
|
+
|
8
|
+
def evaluate(actual, expected)
|
9
|
+
expected = %r[#{Regexp.escape(expected)}] if expected.kind_of?(String)
|
10
|
+
if actual =~ expected
|
11
|
+
pass("matches #{expected.inspect}")
|
12
|
+
else
|
13
|
+
fail("expected #{expected.inspect} to match #{actual.inspect}")
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
module Riot
|
2
|
+
# Asserts that the result of the test is nil
|
3
|
+
# asserts("test") { nil }.nil
|
4
|
+
# should("test") { nil }.nil
|
5
|
+
class NilMacro < AssertionMacro
|
6
|
+
register :nil
|
7
|
+
|
8
|
+
def evaluate(actual)
|
9
|
+
actual.nil? ? pass("is nil") : fail("expected nil, not #{actual.inspect}")
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|