riot 0.10.4 → 0.10.5

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.
@@ -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