riot 0.12.5 → 0.12.6

Sign up to get free protection for your applications and to get access to all the features.
@@ -51,8 +51,11 @@ module Riot
51
51
  @parent = parent || RootContext.new([],[], "", {})
52
52
  @description = description
53
53
  @contexts, @setups, @assertions, @teardowns = [], [], [], []
54
+ @context_error = nil
54
55
  @options = @parent.option_set.dup
55
56
  prepare_middleware(&definition)
57
+ rescue Exception => e
58
+ @context_error = e
56
59
  end
57
60
 
58
61
  # Create a new test context.
@@ -88,8 +91,12 @@ module Riot
88
91
  # @return [Riot::Reporter] the given reporter
89
92
  def run(reporter)
90
93
  reporter.describe_context(self) unless @assertions.empty?
91
- local_run(reporter, situation_class.new)
92
- run_sub_contexts(reporter)
94
+ if @context_error
95
+ reporter.report("context preparation", [:context_error, @context_error])
96
+ else
97
+ local_run(reporter, situation_class.new)
98
+ run_sub_contexts(reporter)
99
+ end
93
100
  reporter
94
101
  end
95
102
 
@@ -98,7 +105,11 @@ module Riot
98
105
  # @param [Riot::Reporter] reporter the reporter to report results to
99
106
  # @param [Riot::Situation] situation the situation to use for executing the context.
100
107
  def local_run(reporter, situation)
101
- runnables.each { |runnable| reporter.report(runnable.to_s, runnable.run(situation)) }
108
+ runnables.each do |runnable|
109
+ code, response = *runnable.run(situation)
110
+ reporter.report(runnable.to_s, [code, response])
111
+ break if code == :setup_error
112
+ end
102
113
  end
103
114
 
104
115
  # Prints the full description from the context tree, grabbing the description from the parent and
@@ -19,7 +19,7 @@ module Riot
19
19
  # => "hello world whats the news"
20
20
  #
21
21
  # For every method called it is also acceptable to pass any number of arguments. These arguments will be
22
- # added to the final message after having {Kernel#inspect} called on them. Another for instance:
22
+ # added to the final message after having `inspect` called on them. Another for instance:
23
23
  #
24
24
  # message = Riot::Message.new
25
25
  # message.expected([1, 2, 3], "foo").not([3, 2, 1], "bar")
@@ -3,18 +3,18 @@ module Riot
3
3
  # Context middlewares are chainable, context preparers. This to say that a middleware knows about a single
4
4
  # neighbor and that it can prepare context before the context is "run". As a for instance, suppose you
5
5
  # wanted the following to be possible.
6
- #
6
+ #
7
7
  # context Person do
8
8
  # denies(:valid?)
9
9
  # end # Person
10
- #
11
- # Without writing a middleware, the topic in this would actually be nil, but what the context is saying is
12
- # that there should be something in the topic that responds to +:valid?+; an instance of +Person+ in this
10
+ #
11
+ # Without writing a middleware, the topic in this would actually be nil, but what the context is saying is
12
+ # that there should be something in the topic that responds to +:valid?+; an instance of +Person+ in this
13
13
  # case. We can do this with middleware like so:
14
- #
14
+ #
15
15
  # class Modelware < Riot::ContextMiddleware
16
16
  # register
17
- #
17
+ #
18
18
  # def call(context)
19
19
  # if context.description.kind_of?(Model)
20
20
  # context.setup { context.description.new }
@@ -22,37 +22,37 @@ module Riot
22
22
  # middleware.call(context)
23
23
  # end
24
24
  # end # Modelware
25
- #
26
- # That's good stuff. If you're familiar at all with the nature of Rack middleware - how to implement it,
25
+ #
26
+ # That's good stuff. If you're familiar at all with the nature of Rack middleware - how to implement it,
27
27
  # how it's executed, etc. - you'll be familiar with Context middleware as the principles are similar:
28
- #
28
+ #
29
29
  # 1. Define a class that extends {Riot::ContextMiddleware}
30
30
  # 2. Call +register+
31
31
  # 3. Implement a +call+ method that accepts the Context that is about to be executed
32
32
  # 4. Do stuff, but make sure to pass the call along with +middleware.call(context)+
33
- #
33
+ #
34
34
  # Steps 1, 2, and 3 should be pretty straight-forward. Currently, +context+ is the only argument to +call+.
35
35
  # When your middleware is initialized it is given the next registered middleware in the chain (which is
36
36
  # where the `middleware` method gets its value from).
37
- #
37
+ #
38
38
  # So, "Do stuff" from step 4 is the where we start breaking things down. What can you actually do? Well,
39
39
  # you can do anything to the context that you could do if you were writing a Riot test; and I do mean
40
40
  # anything.
41
- #
41
+ #
42
42
  # * Add setup blocks (as many as you like)
43
43
  # * Add teardown blocks (as many as you like)
44
44
  # * Add hookup blocks (as many as you like)
45
45
  # * Add helpers (as many as you like)
46
46
  # * Add assertions
47
- #
47
+ #
48
48
  # The context in question will not run before all middleware have been applied to the context; this is
49
- # different behavior than that of Rack middleware. {Riot::ContextMiddleware} is only about preparing a
50
- # context, not about executing it. Thus, where in your method you actually pass the call off to the next
51
- # middleware in the chain has impact on how the context is set up. Basically, whatever you do before
52
- # calling `middleware.call(context)` is done before any other middleware gets setup and before the innards
53
- # of the context itself are applied. Whatever you do after that call is done after all that, but still
49
+ # different behavior than that of Rack middleware. {Riot::ContextMiddleware} is only about preparing a
50
+ # context, not about executing it. Thus, where in your method you actually pass the call off to the next
51
+ # middleware in the chain has impact on how the context is set up. Basically, whatever you do before
52
+ # calling `middleware.call(context)` is done before any other middleware gets setup and before the innards
53
+ # of the context itself are applied. Whatever you do after that call is done after all that, but still
54
54
  # before the actual setups, hookups, assertions, and teardowns are run.
55
- #
55
+ #
56
56
  # Do not expect the same instance of middleware to exist from one {Riot::Context} instance to the next. It
57
57
  # is highly likely that each {Riot::Context} will instantiate their own middleware instances.
58
58
  class ContextMiddleware
@@ -82,7 +82,7 @@ module Riot
82
82
  end
83
83
 
84
84
  # The magic happens here. Because you have access to the Context, you can add your own setups, hookups,
85
- # etc. +call+ will be called before any tests are run, but after the Context is configured. Though
85
+ # etc. +call+ will be called before any tests are run, but after the Context is configured. Though
86
86
  # something will likely be returned, do not put any faith in what that will be.
87
87
  #
88
88
  # @param [Riot::Context] context the Context instance that will be prepared by registered middleware
@@ -2,7 +2,7 @@ module Riot
2
2
 
3
3
  # A Reporter decides how to output the result of a test. When a context is set to be executed, the
4
4
  # {Riot::Reporter#describe_context} method is called with the context that will be running; this remains
5
- # so until the next context is executed. After each {Riot#Assertion#evaluate assertion is evaluated},
5
+ # so until the next context is executed. After each {Riot::AssertionMacro#evaluate assertion is evaluated},
6
6
  # {Riot::Reporter#report} is called with the description of the assertion and the resulting response.
7
7
  #
8
8
  # The general idea is that a sub-class of Reporter should be defined that knows specifically how to
@@ -22,9 +22,10 @@ module Riot
22
22
  attr_accessor :current_context
23
23
 
24
24
  # Creates a new Reporter instance and initializes counts to zero
25
- def initialize
25
+ def initialize(*args)
26
+ @options = args.extract_options!
26
27
  @passes = @failures = @errors = 0
27
- @current_context = ""
28
+ @current_context = Riot::RootContext.new
28
29
  end
29
30
 
30
31
  def new(*args, &block); self; end
@@ -69,7 +70,7 @@ module Riot
69
70
  @failures += 1
70
71
  message, line, file = *response[1..-1]
71
72
  fail(description, message, line, file)
72
- when :error then
73
+ when :error, :setup_error, :context_error then
73
74
  @errors += 1
74
75
  error(description, result)
75
76
  end
@@ -13,8 +13,8 @@ module Riot
13
13
  # @param [IO] writer the writer to use for results
14
14
  # @param [Hash] options options for reporter
15
15
  def initialize(*args)
16
- super()
17
- @options = (args.last.kind_of?(Hash) ? args.pop : {})
16
+ super
17
+ @options = args.extract_options!
18
18
  @writer = (args.shift || STDOUT)
19
19
  end
20
20
 
@@ -45,17 +45,14 @@ module Riot
45
45
  line ? "(on line #{line} in #{file})" : ""
46
46
  end
47
47
 
48
- # Generates a message for assertions that error out. However, in the additional stacktrace, any mentions
48
+ # Generates a message for assertions that error out. However, in the additional stacktrace, any mentions
49
49
  # of Riot and Rake framework methods calls are removed. Makes for a more readable error response.
50
50
  #
51
51
  # @param [Exception] e the exception to generate the backtrace from
52
52
  # @return [String] the error response message
53
53
  def format_error(e)
54
- format = []
55
- format << " #{e.class.name} occurred"
56
- format << "#{e.to_s}"
54
+ format = [" #{e.class.name} occurred", "#{e.to_s}"]
57
55
  filter_backtrace(e.backtrace) { |line| format << " at #{line}" }
58
-
59
56
  format.join("\n")
60
57
  end
61
58
 
@@ -64,13 +61,8 @@ module Riot
64
61
  # @param [Array] backtrace an exception's backtrace
65
62
  # @param [lambda] &line_handler called each time a good line is found
66
63
  def filter_backtrace(backtrace, &line_handler)
67
- cleansed, bad = [], true
68
-
69
- # goal is to filter all the riot stuff/rake before the first non riot thing
70
64
  backtrace.reverse_each do |bt|
71
- # make sure we are still in the bad part
72
- bad = (bt =~ /\/lib\/riot/ || bt =~ /rake_test_loader/) if bad
73
- yield bt unless bad
65
+ yield bt unless (bt =~ /(\/lib\/riot|rake_test_loader)/)
74
66
  end
75
67
  end
76
68
 
@@ -78,7 +70,7 @@ module Riot
78
70
  def red(str); with_color(31, str); end
79
71
  def yellow(str); with_color(33, str); end
80
72
  def green(str); with_color(32, str); end
81
-
73
+
82
74
  def plain?
83
75
  (@options[:plain] || @options["plain"])
84
76
  end
@@ -30,7 +30,6 @@ module Riot
30
30
  def simple_error(e)
31
31
  format = []
32
32
  filter_backtrace(e.backtrace) { |line| format << "at #{line}" }
33
-
34
33
  format.join("\n")
35
34
  end
36
35
  end
@@ -10,6 +10,11 @@ module Riot
10
10
  # setup, yeardown, helper, hookup, or assertion.
11
11
  class Situation < Riot::Situation
12
12
  include ::RR::Adapters::RRMethods
13
+
14
+ def initialize
15
+ self.reset
16
+ super
17
+ end
13
18
  end # Situation
14
19
 
15
20
  # Binds the {Riot::Assertion} to RR so that successes and failures found by RR are inherently handled
@@ -48,6 +48,8 @@ module Riot
48
48
  def run(situation)
49
49
  situation.setup(&definition)
50
50
  [:setup]
51
+ rescue Exception => e
52
+ [:setup_error, e]
51
53
  end
52
54
  end # Setup
53
55
 
@@ -52,7 +52,7 @@ module Riot
52
52
  end
53
53
 
54
54
  # Anonymously evaluates any block given to it against the current instance of +self+. This is how
55
- # {Riot::Assertion assertion} and {Riot::AssertionMAcro assertion macro} blocks are evaluated,
55
+ # {Riot::Assertion assertion} and {Riot::AssertionMacro assertion macro} blocks are evaluated,
56
56
  # for instance.
57
57
  #
58
58
  # @param [lambda] &block the block to evaluate against +self+
@@ -1,4 +1,4 @@
1
1
  module Riot
2
- VERSION = "0.12.5"
2
+ VERSION = "0.12.6"
3
3
  end
4
4
 
@@ -23,7 +23,7 @@ context "A raises_kind_of assertion macro" do
23
23
 
24
24
  assertion_test_fails("when nothing was raised",
25
25
  "expected to raise kind of Whoops, but raised nothing") do
26
- assertion = Riot::Assertion.new("foo") { "barf" }.raises_kind_of(Whoops)
26
+ Riot::Assertion.new("foo") { "barf" }.raises_kind_of(Whoops)
27
27
  end
28
28
 
29
29
  assertion_test_passes("when provided message equals expected message",
@@ -13,7 +13,7 @@ context "A raises assertion macro" do
13
13
  end
14
14
 
15
15
  assertion_test_fails("when nothing was raised", "expected to raise Whoops, but raised nothing") do
16
- assertion = Riot::Assertion.new("foo") { "barf" }.raises(Whoops)
16
+ Riot::Assertion.new("foo") { "barf" }.raises(Whoops)
17
17
  end
18
18
 
19
19
  assertion_test_passes("when provided message equals expected message", %Q{raises Whoops with message "Mom"}) do
@@ -100,4 +100,24 @@ context "ContextMiddleware" do
100
100
 
101
101
  asserts("tests passed") { topic.passes }.equals(1)
102
102
  end # has access to options after context setup
103
+
104
+ context "that errors while preparing" do
105
+ hookup do
106
+ Class.new(Riot::ContextMiddleware) do
107
+ register
108
+ def call(context)
109
+ raise Exception.new("Banana pants")
110
+ end
111
+ end
112
+ end
113
+
114
+ setup do
115
+ Riot::Context.new("Foo") { asserts_topic.nil }.run(MockReporter.new)
116
+ end
117
+
118
+ asserts("tests passed") { topic.passes }.equals(0)
119
+ asserts("tests failed") { topic.failures }.equals(0)
120
+ asserts("tests errored") { topic.errors }.equals(1)
121
+ end # that is not meant to be used
122
+
103
123
  end # ContextMiddleware
@@ -39,6 +39,11 @@ context "A reporter" do
39
39
  topic.errors
40
40
  end.equals(1)
41
41
 
42
+ asserts("error count increase when :setup_error sent to #report") do
43
+ topic.report("", [:setup_error, ""])
44
+ topic.errors
45
+ end.equals(2)
46
+
42
47
  asserts("description sent to #error") do
43
48
  topic.report("break it down", [:error, "error time"])
44
49
  end.equals("errored(break it down, error time)")
@@ -46,6 +51,7 @@ context "A reporter" do
46
51
  context "instance" do
47
52
  setup { Riot::Reporter.new }
48
53
  should("return self invoking new") { topic.new }.equals { topic }
54
+ should("accept an options hash") { topic.new({}) }.equals { topic }
49
55
  end
50
56
 
51
57
  context "with no errors or failures" do
@@ -44,7 +44,13 @@ context "DotMatrixReporter" do
44
44
  asserts_topic('puts the full context + assertion name').matches('whatever asserts bang')
45
45
  asserts_topic('puts the exception message').matches('BOOM')
46
46
  # <file path>:<one or more number><two newlines><anything till end of line><newline> is the last thing in the stack trace
47
- asserts_topic('puts the filtered exception backtrace').matches(/#{__FILE__}:\d+:[^\n]*\n\n.*$\n\z/)
47
+ asserts_topic('puts the filtered exception backtrace').matches do
48
+ if RUBY_VERSION =~ /^1.8.\d+/
49
+ /#{__FILE__}:\d+\n\n.*$\n\z/
50
+ else
51
+ /#{__FILE__}:\d+:[^\n]*\n\n.*$\n\z/
52
+ end
53
+ end
48
54
  end
49
55
  end
50
56
 
@@ -20,20 +20,18 @@ context "StoryReporter" do
20
20
 
21
21
  context 'reporting on an empty context' do
22
22
  setup do
23
- context = Riot::Context.new('empty context') do
23
+ context = Riot::Context.new('empty context') {
24
24
  context("a nested empty context") {}
25
- end
26
- context.run(topic)
25
+ }.run(topic)
27
26
  end
28
27
  should("not output context name") { @out.string }.empty
29
28
  end
30
29
 
31
30
  context "reporting on a non-empty context" do
32
31
  setup do
33
- context = Riot::Context.new('supercontext') do
32
+ Riot::Context.new('supercontext') {
34
33
  asserts("truth") { true }
35
- end
36
- context.run(topic)
34
+ }.run(topic)
37
35
  end
38
36
 
39
37
  should('output context name') { @out.string }.matches(/supercontext/)
@@ -0,0 +1,47 @@
1
+ require 'teststrap'
2
+
3
+ context "Executing setup with an error" do
4
+ setup do
5
+ Riot::Setup.new { raise "Error in setup" }.run(Riot::Situation.new)
6
+ end
7
+
8
+ asserts("result") { topic[0] }.equals(:setup_error)
9
+ asserts("result object") { topic[1] }.kind_of(Exception)
10
+ asserts("error message") { topic[1].message }.equals("Error in setup")
11
+
12
+ end # Executing setup with an error
13
+
14
+ context "Executing a context" do
15
+ context "that errors during setup" do
16
+ setup do
17
+ Riot::Context.new("A") {
18
+ setup { raise "Whoopsie!" } # error
19
+ asserts("foo") { true } # success
20
+ asserts("bar") { false } # failure
21
+ }.run(Riot::SilentReporter.new)
22
+ end
23
+
24
+ asserts(:errors).equals(1)
25
+ asserts(:failures).equals(0)
26
+ asserts(:passes).equals(0)
27
+ end # that errors during setup
28
+
29
+ context "that errors in a parent setup" do
30
+ setup do
31
+ Riot::Context.new("A") {
32
+ setup { raise "Whoopsie!" } # error
33
+
34
+ context "B" do
35
+ asserts("foo") { true } # success
36
+ asserts("bar") { false } # failure
37
+ end
38
+ }.run(Riot::SilentReporter.new)
39
+ end
40
+
41
+ asserts(:errors).equals(2) # Same setup fails twice
42
+ asserts(:failures).equals(0)
43
+ asserts(:passes).equals(0)
44
+ end # that errors in a parent setup
45
+
46
+ end # Executing a cotext
47
+
@@ -1,7 +1,9 @@
1
1
  $:.unshift(File.dirname(__FILE__) + "/../lib/")
2
+ require 'rubygems'
3
+ require 'bundler/setup'
4
+
2
5
  require 'riot'
3
6
  Riot.verbose
4
-
5
7
  Riot.pretty_dots if ENV["TM_MODE"]
6
8
 
7
9
  module Riot
metadata CHANGED
@@ -1,39 +1,41 @@
1
- --- !ruby/object:Gem::Specification
1
+ --- !ruby/object:Gem::Specification
2
2
  name: riot
3
- version: !ruby/object:Gem::Version
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.12.6
4
5
  prerelease:
5
- version: 0.12.5
6
6
  platform: ruby
7
- authors:
7
+ authors:
8
8
  - Justin 'Gus' Knowlden
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
-
13
- date: 2011-09-13 00:00:00 -05:00
14
- default_executable:
15
- dependencies:
16
- - !ruby/object:Gem::Dependency
12
+ date: 2013-07-10 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
17
15
  name: rr
18
- prerelease: false
19
- requirement: &id001 !ruby/object:Gem::Requirement
16
+ requirement: !ruby/object:Gem::Requirement
20
17
  none: false
21
- requirements:
22
- - - ">="
23
- - !ruby/object:Gem::Version
24
- version: "0"
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
25
22
  type: :runtime
26
- version_requirements: *id001
27
- description: An extremely fast, expressive, and context-driven unit-testing framework. A replacement for all other testing frameworks. Protest the slow test.
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ! '>='
28
+ - !ruby/object:Gem::Version
29
+ version: '0'
30
+ description: An extremely fast, expressive, and context-driven unit-testing framework.
31
+ A replacement for all other testing frameworks. Protest the slow test.
28
32
  email: gus@gusg.us
29
33
  executables: []
30
-
31
34
  extensions: []
32
-
33
35
  extra_rdoc_files: []
34
-
35
- files:
36
+ files:
36
37
  - .gitignore
38
+ - .travis.yml
37
39
  - .yardopts
38
40
  - CHANGELOG
39
41
  - Gemfile
@@ -112,6 +114,7 @@ files:
112
114
  - test/core/reports/story_reporter_test.rb
113
115
  - test/core/runnable/assertion_macro_test.rb
114
116
  - test/core/runnable/assertion_test.rb
117
+ - test/core/runnable/erroring_gracefully_test.rb
115
118
  - test/core/runnable/message_test.rb
116
119
  - test/core/runnable/negative_assertion_test.rb
117
120
  - test/core/runnable/setup_test.rb
@@ -119,35 +122,32 @@ files:
119
122
  - test/core/runnable/teardown_test.rb
120
123
  - test/extensions/rrriot_test.rb
121
124
  - test/teststrap.rb
122
- has_rdoc: true
123
125
  homepage: http://github.com/thumblemonks/riot
124
126
  licenses: []
125
-
126
127
  post_install_message:
127
128
  rdoc_options: []
128
-
129
- require_paths:
129
+ require_paths:
130
130
  - lib
131
- required_ruby_version: !ruby/object:Gem::Requirement
131
+ required_ruby_version: !ruby/object:Gem::Requirement
132
132
  none: false
133
- requirements:
134
- - - ">="
135
- - !ruby/object:Gem::Version
136
- version: "0"
137
- required_rubygems_version: !ruby/object:Gem::Requirement
133
+ requirements:
134
+ - - ! '>='
135
+ - !ruby/object:Gem::Version
136
+ version: '0'
137
+ required_rubygems_version: !ruby/object:Gem::Requirement
138
138
  none: false
139
- requirements:
140
- - - ">="
141
- - !ruby/object:Gem::Version
142
- version: "0"
139
+ requirements:
140
+ - - ! '>='
141
+ - !ruby/object:Gem::Version
142
+ version: '0'
143
143
  requirements: []
144
-
145
144
  rubyforge_project:
146
- rubygems_version: 1.6.2
145
+ rubygems_version: 1.8.25
147
146
  signing_key:
148
147
  specification_version: 3
149
- summary: An extremely fast, expressive, and context-driven unit-testing framework. Protest the slow test.
150
- test_files:
148
+ summary: An extremely fast, expressive, and context-driven unit-testing framework.
149
+ Protest the slow test.
150
+ test_files:
151
151
  - test/benchmark/message_concatenation.rb
152
152
  - test/benchmark/riot_vs_minitest.rb
153
153
  - test/benchmark/same_elements_vs_set.rb
@@ -186,6 +186,7 @@ test_files:
186
186
  - test/core/reports/story_reporter_test.rb
187
187
  - test/core/runnable/assertion_macro_test.rb
188
188
  - test/core/runnable/assertion_test.rb
189
+ - test/core/runnable/erroring_gracefully_test.rb
189
190
  - test/core/runnable/message_test.rb
190
191
  - test/core/runnable/negative_assertion_test.rb
191
192
  - test/core/runnable/setup_test.rb