riot 0.10.4 → 0.10.5

Sign up to get free protection for your applications and to get access to all the features.
@@ -93,6 +93,7 @@ For instance, given a test file named `foo_test.rb`, you might have the followin
93
93
  context "a new user" do
94
94
  setup { User.new }
95
95
  asserts("that it is not yet created") { topic.new_record? }
96
+ teardown { #cleanup here }
96
97
  end
97
98
 
98
99
  Notice that you do not define a class anywhere. That would be the entire contents of that test file. If you wanted to use a `should` instead, you could say this:
@@ -348,7 +349,13 @@ I should say that I love Shoulda in theory and in practice. It changed the way I
348
349
 
349
350
  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.
350
351
 
351
- 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.
352
+ For instance, I believe that no assertion should mangle the context of
353
+ the test data it is running in. Following this allows me to require
354
+ setup be run only once for a collection of related assertions. Even in
355
+ a nested context where setups are inherited, the setup's are called
356
+ only once per the specific context. Furthermore, teardowns are also
357
+ called only once per the specific context, after all the setups and
358
+ assertions have run.
352
359
 
353
360
  Following all of this allows me to have very fast tests (so far).
354
361
 
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.10.4
1
+ 0.10.5
@@ -108,6 +108,22 @@ module Riot
108
108
  actual.length == 0 ? pass : fail("expected #{actual.inspect} to be empty")
109
109
  end
110
110
 
111
+ # Asserts the result has items
112
+ # asserts("an array") { [1] }.any
113
+ # asserts("a hash") { {:name => 'washington'} }.any
114
+ assertion(:any) do |actual|
115
+ actual.any? ? pass : fail("expected #{actual.inspect} to have items")
116
+ end
117
+
118
+ # Asserts that result's size is as expected. Expected size can be specified as
119
+ # a number or a range.
120
+ # asserts("a string") { 'washington' }.size(9..12)
121
+ # asserts("an array") { [1, 2, 3] }.size(3)
122
+ # asserts("a hash") { {:name => 'washington'} }.size(1)
123
+ assertion(:size) do |actual, expected|
124
+ expected === actual.size ? pass : fail("size of #{actual.inspect} expected to be #{expected} but is #{actual.size}")
125
+ end
126
+
111
127
  # Asserts the result contains the expected element
112
128
  # asserts("a string") { "world" }.includes('o')
113
129
  # asserts("an array") { [1,2,3] }.includes(2)
@@ -1,24 +1,22 @@
1
1
  module Riot
2
- RootContext = Struct.new(:setups)
2
+ RootContext = Struct.new(:setups, :teardowns)
3
3
  class Context
4
- def initialize(description, parent=RootContext.new([]), &definition)
4
+ attr_reader :description
5
+ def initialize(description, parent=RootContext.new([],[]), &definition)
5
6
  @parent = parent
6
7
  @description = description
7
- @contexts, @setups, @assertions = [], [], []
8
+ @contexts, @setups, @assertions, @teardowns = [], [], [], []
8
9
  self.instance_eval(&definition)
9
10
  end
10
-
11
- def setup(&definition)
12
- @setups << Setup.new(&definition)
13
- end
14
11
 
15
- def setups
16
- @parent.setups + @setups
17
- end
12
+ def setups; @parent.setups + @setups; end
13
+ def teardowns; @parent.teardowns + @teardowns; end
14
+
15
+ def setup(&definition) (@setups << Setup.new(&definition)).last; end
16
+ def teardown(&definition) (@teardowns << Setup.new(&definition)).last; end
18
17
 
19
18
  def asserts(what, &definition) new_assertion("asserts", what, &definition); end
20
19
  def should(what, &definition) new_assertion("should", what, &definition); end
21
-
22
20
  def asserts_topic; asserts("topic") { topic }; end
23
21
 
24
22
  def context(description, &definition)
@@ -26,16 +24,20 @@ module Riot
26
24
  end
27
25
 
28
26
  def run(reporter)
29
- runnables = setups + @assertions
30
- reporter.describe_context(@description) unless @assertions.empty?
31
- situation = Situation.new
32
- runnables.each do |runnable|
33
- reporter.report(runnable.to_s, runnable.run(situation))
34
- end
35
- @contexts.each { |ctx| ctx.run(reporter) }
27
+ reporter.describe_context(self) unless @assertions.empty?
28
+ local_run(reporter, Situation.new)
29
+ run_sub_contexts(reporter)
36
30
  reporter
37
31
  end
38
32
  private
33
+ def local_run(reporter, situation)
34
+ (setups + @assertions + teardowns).each do |runnable|
35
+ reporter.report(runnable.to_s, runnable.run(situation))
36
+ end
37
+ end
38
+
39
+ def run_sub_contexts(reporter) @contexts.each { |ctx| ctx.run(reporter) }; end
40
+
39
41
  def new_assertion(scope, what, &definition)
40
42
  (@assertions << Assertion.new("#{scope} #{what}", &definition)).last
41
43
  end
@@ -1,8 +1,9 @@
1
1
  module Riot
2
2
  class Reporter
3
- attr_accessor :passes, :failures, :errors
3
+ attr_accessor :passes, :failures, :errors, :current_context
4
4
  def initialize
5
5
  @passes = @failures = @errors = 0
6
+ @current_context = ""
6
7
  end
7
8
 
8
9
  def summarize(&block)
@@ -12,7 +13,7 @@ module Riot
12
13
  results(Time.now - started)
13
14
  end
14
15
 
15
- def describe_context(msg); end
16
+ def describe_context(context); @current_context = context; end
16
17
 
17
18
  def report(description, response)
18
19
  code, result = *response
@@ -36,9 +37,9 @@ module Riot
36
37
 
37
38
  class IOReporter < Reporter
38
39
  attr_reader :writer
39
- def initialize(writer=nil)
40
+ def initialize(writer=STDOUT)
40
41
  super()
41
- @writer = writer || STDOUT
42
+ @writer = writer
42
43
  end
43
44
  def say(message) writer.puts(message); end
44
45
 
@@ -47,6 +48,14 @@ module Riot
47
48
  say "\n%d passes, %d failures, %d errors in %s seconds" % values
48
49
  end
49
50
 
51
+ def format_error(e)
52
+ format = " #{e.class.name} occured"
53
+ format += "\n#{e.to_s}\n"
54
+ e.backtrace.each { |line| format += "\n at #{line}" }
55
+
56
+ format
57
+ end
58
+
50
59
  begin
51
60
  raise LoadError if ENV["TM_MODE"]
52
61
  require 'rubygems'
@@ -60,7 +69,10 @@ module Riot
60
69
  end
61
70
 
62
71
  class StoryReporter < IOReporter
63
- def describe_context(description) say description; end
72
+ def describe_context(context)
73
+ super
74
+ say context.description
75
+ end
64
76
  def pass(description) say " + " + green(description); end
65
77
  def fail(description, message) say " - " + yellow("#{description}: #{message}"); end
66
78
  def error(description, e) say " ! " + red("#{description}: #{e.message}"); end
@@ -69,16 +81,32 @@ module Riot
69
81
  class VerboseStoryReporter < StoryReporter
70
82
  def error(description, e)
71
83
  super(description, e)
72
- say red(" #{e.class.name} occured")
73
- e.backtrace.each { |line| say red(" at #{line}") }
84
+ say red(format_error(e))
74
85
  end
75
86
  end
76
87
 
77
88
  class DotMatrixReporter < IOReporter
78
89
  def pass(description); writer.write green("."); end
79
- def fail(description, message); writer.write yellow("F"); end
80
- def error(description, e); writer.write red("E"); end
81
- # TODO: Print the failures and errors at the end. Sorry :|
90
+
91
+ def initialize(writer=STDOUT)
92
+ super
93
+ @details = []
94
+ end
95
+ def fail(description, message)
96
+ writer.write yellow("F")
97
+ @details << "FAILURE - #{current_context.description} #{description} => #{message}"
98
+ end
99
+
100
+ def error(description, e)
101
+ writer.write red("E")
102
+ @details << "ERROR - #{current_context.description} #{description} => #{format_error(e)}"
103
+ end
104
+
105
+ def results(time_taken)
106
+ say "\n"
107
+ @details.each { |detail| say detail }
108
+ super
109
+ end
82
110
  end
83
111
 
84
112
  class SilentReporter < Reporter
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{riot}
8
- s.version = "0.10.4"
8
+ s.version = "0.10.5"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["Justin 'Gus' Knowlden"]
12
- s.date = %q{2009-12-03}
12
+ s.date = %q{2009-12-14}
13
13
  s.description = %q{An extremely fast, expressive, and context-driven unit-testing framework. A replacement for all other testing frameworks. Protest the slow test.}
14
14
  s.email = %q{gus@gusg.us}
15
15
  s.extra_rdoc_files = [
@@ -30,6 +30,7 @@ Gem::Specification.new do |s|
30
30
  "lib/riot/runnable.rb",
31
31
  "lib/riot/situation.rb",
32
32
  "riot.gemspec",
33
+ "test/assertion_macros/any_test.rb",
33
34
  "test/assertion_macros/assigns_test.rb",
34
35
  "test/assertion_macros/empty_test.rb",
35
36
  "test/assertion_macros/equals_test.rb",
@@ -41,6 +42,7 @@ Gem::Specification.new do |s|
41
42
  "test/assertion_macros/raises_test.rb",
42
43
  "test/assertion_macros/respond_to_test.rb",
43
44
  "test/assertion_macros/same_elements_test.rb",
45
+ "test/assertion_macros/size_test.rb",
44
46
  "test/assertion_test.rb",
45
47
  "test/benchmark/colorize.rb",
46
48
  "test/benchmark/riot_vs_minitest.rb",
@@ -50,6 +52,7 @@ Gem::Specification.new do |s|
50
52
  "test/report_test.rb",
51
53
  "test/setup_test.rb",
52
54
  "test/situation_test.rb",
55
+ "test/teardown_test.rb",
53
56
  "test/teststrap.rb"
54
57
  ]
55
58
  s.homepage = %q{http://github.com/thumblemonks/riot}
@@ -58,7 +61,8 @@ Gem::Specification.new do |s|
58
61
  s.rubygems_version = %q{1.3.5}
59
62
  s.summary = %q{An extremely fast, expressive, and context-driven unit-testing framework. Protest the slow test.}
60
63
  s.test_files = [
61
- "test/assertion_macros/assigns_test.rb",
64
+ "test/assertion_macros/any_test.rb",
65
+ "test/assertion_macros/assigns_test.rb",
62
66
  "test/assertion_macros/empty_test.rb",
63
67
  "test/assertion_macros/equals_test.rb",
64
68
  "test/assertion_macros/exists_test.rb",
@@ -69,6 +73,7 @@ Gem::Specification.new do |s|
69
73
  "test/assertion_macros/raises_test.rb",
70
74
  "test/assertion_macros/respond_to_test.rb",
71
75
  "test/assertion_macros/same_elements_test.rb",
76
+ "test/assertion_macros/size_test.rb",
72
77
  "test/assertion_test.rb",
73
78
  "test/benchmark/colorize.rb",
74
79
  "test/benchmark/riot_vs_minitest.rb",
@@ -78,6 +83,7 @@ Gem::Specification.new do |s|
78
83
  "test/report_test.rb",
79
84
  "test/setup_test.rb",
80
85
  "test/situation_test.rb",
86
+ "test/teardown_test.rb",
81
87
  "test/teststrap.rb"
82
88
  ]
83
89
 
@@ -0,0 +1,19 @@
1
+ require 'teststrap'
2
+
3
+ context "An any assertion macro" do
4
+ setup do
5
+ def assert_any(string)
6
+ Riot::Assertion.new("test") { string }.any
7
+ end
8
+ end
9
+
10
+ assertion_test_passes("when an array has items") { assert_any([1]) }
11
+ assertion_test_fails("when an array is empty", "expected [] to have items") do
12
+ assert_any([])
13
+ end
14
+
15
+ assertion_test_passes("when a hash has items") { assert_any({:name => 'washington'}) }
16
+ assertion_test_fails("when a hash is empty", "expected {} to have items") do
17
+ assert_any({})
18
+ end
19
+ end
@@ -0,0 +1,36 @@
1
+ require 'teststrap'
2
+
3
+ context "A size assertion macro" do
4
+ setup do
5
+ def assert_size(sizable, expected_size)
6
+ Riot::Assertion.new("test") { sizable }.size(expected_size)
7
+ end
8
+ end
9
+
10
+ assertion_test_passes("when string's size is as expected") { assert_size("washington", 10) }
11
+ assertion_test_passes("when string's size is in given range") { assert_size("washington", 9..12) }
12
+ assertion_test_fails("when string's size is not as expected", "size of \"washington\" expected to be 11 but is 10") do
13
+ assert_size("washington", 11)
14
+ end
15
+ assertion_test_fails("when string's size is out of range", "size of \"washington\" expected to be 11..13 but is 10") do
16
+ assert_size("washington", 11..13)
17
+ end
18
+
19
+ assertion_test_passes("when an array's size is as expected") { assert_size([1, 2, 3], 3) }
20
+ assertion_test_passes("when an array's size is in given range") { assert_size([1, 2, 3], 3..4) }
21
+ assertion_test_fails("when an array's size is not as expected", "size of [1, 2, 3] expected to be 2 but is 3") do
22
+ assert_size([1, 2, 3], 2)
23
+ end
24
+ assertion_test_fails("when an array's size is out of range", "size of [1, 2, 3] expected to be 4..6 but is 3") do
25
+ assert_size([1, 2, 3], 4..6)
26
+ end
27
+
28
+ assertion_test_passes("when a hash size is as expected") { assert_size({:name => 'washington'}, 1) }
29
+ assertion_test_passes("when a hash size is in range") { assert_size({:name => 'washington'}, 1...3) }
30
+ assertion_test_fails("when a hash size is not as expected", "size of {} expected to be 2 but is 0") do
31
+ assert_size({}, 2)
32
+ end
33
+ assertion_test_fails("when a hash size is out of range", "size of {} expected to be 2...4 but is 0") do
34
+ assert_size({}, 2...4)
35
+ end
36
+ end
@@ -51,22 +51,21 @@ end # A reporter
51
51
 
52
52
  require 'stringio'
53
53
  context "StoryReporter" do
54
- setup {
54
+ setup do
55
55
  @out = StringIO.new
56
56
  Riot::StoryReporter.new(@out)
57
- }
57
+ emd
58
58
 
59
59
  context 'reporting on an empty context' do
60
60
  setup do
61
61
  context = Riot::Context.new('empty context') do
62
- context "a nested empty context" do
63
- end
62
+ context("a nested empty context") {}
64
63
  end
65
64
  context.run(topic)
66
65
  end
67
66
  should("not output context name") { @out.string }.empty
68
67
  end
69
-
68
+
70
69
  context "reporting on a non-empty context" do
71
70
  setup do
72
71
  context = Riot::Context.new('supercontext') do
@@ -74,9 +73,55 @@ context "StoryReporter" do
74
73
  end
75
74
  context.run(topic)
76
75
  end
77
-
76
+
78
77
  should('output context name') { @out.string }.matches(/supercontext/)
79
78
  should('output name of passed assertion') { @out.string }.matches(/truth/)
80
79
  end
80
+ end
81
81
 
82
+ context "DotMatrixReporter" do
83
+ setup do
84
+ @out = StringIO.new
85
+ Riot::DotMatrixReporter.new(@out)
86
+ end
87
+
88
+ context "with a passing test" do
89
+ setup do
90
+ context = Riot::Context.new('whatever') do
91
+ asserts('true') { true }
92
+ end
93
+ context.run(topic)
94
+ @out.string
95
+ end
96
+ asserts('puts a dot').matches('.')
97
+ end
98
+
99
+ context 'with a failing test' do
100
+ setup do
101
+ Riot::Context.new('whatever') do
102
+ asserts('nope!') { false }
103
+ end.run(topic)
104
+ topic.results(100)
105
+ @out.string
106
+ end
107
+
108
+ asserts('puts an F').matches('F')
109
+ asserts("puts the full context + assertion name").matches('whatever asserts nope!')
110
+ asserts("puts the failure reason").matches(/Expected .* but got false instead/)
111
+ end
112
+
113
+ context 'with an error test' do
114
+ setup do
115
+ Riot::Context.new('whatever') do
116
+ asserts('bang') { raise "BOOM" }
117
+ end.run(topic)
118
+ topic.results(100)
119
+ @out.string
120
+ end
121
+
122
+ asserts('puts an E').matches('E')
123
+ asserts('puts the full context + assertion name').matches('whatever asserts bang')
124
+ asserts('puts the exception message').matches('BOOM')
125
+ asserts('puts the exception backtrace').matches(__FILE__)
126
+ end
82
127
  end
@@ -0,0 +1,42 @@
1
+ require 'teststrap'
2
+
3
+ global_thang = Struct.new(:count).new(0)
4
+
5
+ context "A context with a teardown" do
6
+ setup do
7
+ @a_context = Riot::Context.new("me") do
8
+ setup { global_thang.count += 1 }
9
+ asserts("teardown run") { global_thang.count }.equals(1)
10
+ teardown { global_thang.count += 1 }
11
+ end
12
+ @a_context.run(MockReporter.new)
13
+ end
14
+
15
+ asserts("test passed") { topic.passes }.equals(1)
16
+ asserts("teardown run") { global_thang.count }.equals(2)
17
+
18
+ context "that has a nested context with teardowns" do
19
+ setup do
20
+ @a_context.context "nested" do
21
+ setup { global_thang.count = 0 }
22
+ asserts("no teardowns run") { global_thang.count }.equals(0)
23
+ teardown { global_thang.count += 2 }
24
+ end
25
+ @a_context.run(MockReporter.new)
26
+ end
27
+ asserts("tests passed") { topic.passes }.equals(1)
28
+ asserts("teardowns ran in local and parent context") { global_thang.count }.equals(3)
29
+ end # that has a nested context with teardowns
30
+
31
+ context "that has multiple teardowns in nested context" do
32
+ setup do
33
+ @a_context.context "nested" do
34
+ setup { global_thang.count = 0 }
35
+ teardown { global_thang.count += 2 }
36
+ teardown { global_thang.count += 2 }
37
+ end
38
+ @a_context.run(MockReporter.new)
39
+ end
40
+ asserts("teardowns ran in local and parent context") { global_thang.count }.equals(5)
41
+ end # that has multiple teardowns in nested context
42
+ end # A context with a teardown
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: riot
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.10.4
4
+ version: 0.10.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Justin 'Gus' Knowlden
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2009-12-03 00:00:00 -06:00
12
+ date: 2009-12-14 00:00:00 -06:00
13
13
  default_executable:
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
@@ -45,6 +45,7 @@ files:
45
45
  - lib/riot/runnable.rb
46
46
  - lib/riot/situation.rb
47
47
  - riot.gemspec
48
+ - test/assertion_macros/any_test.rb
48
49
  - test/assertion_macros/assigns_test.rb
49
50
  - test/assertion_macros/empty_test.rb
50
51
  - test/assertion_macros/equals_test.rb
@@ -56,6 +57,7 @@ files:
56
57
  - test/assertion_macros/raises_test.rb
57
58
  - test/assertion_macros/respond_to_test.rb
58
59
  - test/assertion_macros/same_elements_test.rb
60
+ - test/assertion_macros/size_test.rb
59
61
  - test/assertion_test.rb
60
62
  - test/benchmark/colorize.rb
61
63
  - test/benchmark/riot_vs_minitest.rb
@@ -65,6 +67,7 @@ files:
65
67
  - test/report_test.rb
66
68
  - test/setup_test.rb
67
69
  - test/situation_test.rb
70
+ - test/teardown_test.rb
68
71
  - test/teststrap.rb
69
72
  has_rdoc: true
70
73
  homepage: http://github.com/thumblemonks/riot
@@ -95,6 +98,7 @@ signing_key:
95
98
  specification_version: 3
96
99
  summary: An extremely fast, expressive, and context-driven unit-testing framework. Protest the slow test.
97
100
  test_files:
101
+ - test/assertion_macros/any_test.rb
98
102
  - test/assertion_macros/assigns_test.rb
99
103
  - test/assertion_macros/empty_test.rb
100
104
  - test/assertion_macros/equals_test.rb
@@ -106,6 +110,7 @@ test_files:
106
110
  - test/assertion_macros/raises_test.rb
107
111
  - test/assertion_macros/respond_to_test.rb
108
112
  - test/assertion_macros/same_elements_test.rb
113
+ - test/assertion_macros/size_test.rb
109
114
  - test/assertion_test.rb
110
115
  - test/benchmark/colorize.rb
111
116
  - test/benchmark/riot_vs_minitest.rb
@@ -115,4 +120,5 @@ test_files:
115
120
  - test/report_test.rb
116
121
  - test/setup_test.rb
117
122
  - test/situation_test.rb
123
+ - test/teardown_test.rb
118
124
  - test/teststrap.rb