baretest 0.2.4 → 0.4.0.pre1

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.
Files changed (85) hide show
  1. data/LICENSE.txt +6 -6
  2. data/MANIFEST.txt +40 -18
  3. data/README.rdoc +8 -1
  4. data/bin/baretest +126 -118
  5. data/doc/baretest.rdoc +1 -1
  6. data/doc/mocking_stubbing_test_doubles.rdoc +31 -3
  7. data/doc/news/news-0.3.0.rdoc +7 -0
  8. data/doc/quickref.rdoc +74 -28
  9. data/doc/whats_going_on.rdoc +5 -0
  10. data/doc/writing_tests.rdoc +25 -13
  11. data/examples/components/rack-test.rb +17 -0
  12. data/examples/{tests/irb_mode → irb_mode}/failures.rb +0 -0
  13. data/examples/rake/test.rake +40 -0
  14. data/examples/tests/01_basics_I.rb +34 -0
  15. data/examples/tests/02_basics_II_helpers.rb +25 -0
  16. data/examples/tests/03_basics_III_setup_and_teardown.rb +53 -0
  17. data/examples/tests/04_advanced_I_dependencies.rb +31 -0
  18. data/examples/tests/05_advanced_II_tags.rb +12 -0
  19. data/examples/tests/06_advanced_III_requires.rb +21 -0
  20. data/examples/tests/07_advanced_IV_components.rb +48 -0
  21. data/examples/tests/08_expert_I_setup_variants.rb +46 -0
  22. data/lib/baretest.rb +142 -21
  23. data/lib/baretest/assertion.rb +83 -92
  24. data/lib/baretest/assertion/context.rb +9 -0
  25. data/lib/baretest/assertion/support.rb +88 -61
  26. data/lib/baretest/commandline.rb +268 -0
  27. data/lib/baretest/formatter.rb +58 -0
  28. data/lib/baretest/invalidselectors.rb +24 -0
  29. data/lib/baretest/irb_mode.rb +100 -58
  30. data/lib/baretest/persistence.rb +94 -0
  31. data/lib/baretest/run.rb +138 -37
  32. data/lib/baretest/run/cli.rb +97 -43
  33. data/lib/baretest/run/minimal.rb +2 -1
  34. data/lib/baretest/run/none.rb +21 -0
  35. data/lib/baretest/run/xml.rb +21 -19
  36. data/lib/baretest/setup.rb +2 -0
  37. data/lib/baretest/status.rb +93 -0
  38. data/lib/baretest/suite.rb +185 -59
  39. data/lib/baretest/uid.rb +51 -0
  40. data/lib/baretest/use/mocha.rb +24 -0
  41. data/lib/baretest/use/rack_test.rb +9 -0
  42. data/lib/baretest/use/rr.rb +17 -0
  43. data/lib/baretest/version.rb +18 -4
  44. data/lib/command.rb +36 -0
  45. data/lib/command/argument.rb +11 -0
  46. data/lib/command/decoratinghash.rb +31 -0
  47. data/lib/command/definition.rb +294 -0
  48. data/lib/command/directorynotfounderror.rb +11 -0
  49. data/lib/command/env.rb +11 -0
  50. data/lib/command/filenotfounderror.rb +11 -0
  51. data/lib/command/kernel.rb +14 -0
  52. data/lib/command/nodirectoryerror.rb +11 -0
  53. data/lib/command/nofileerror.rb +11 -0
  54. data/lib/command/option.rb +16 -0
  55. data/lib/command/parser.rb +145 -0
  56. data/lib/command/result.rb +11 -0
  57. data/lib/command/types.rb +33 -0
  58. data/lib/command/version.rb +28 -0
  59. data/test/setup.rb +3 -0
  60. data/test/suite/lib/baretest.rb +0 -178
  61. data/test/suite/lib/baretest/assertion.rb +133 -112
  62. data/test/suite/lib/baretest/assertion/context.rb +40 -0
  63. data/test/suite/lib/baretest/assertion/failure.rb +19 -0
  64. data/test/suite/lib/baretest/assertion/skip.rb +19 -0
  65. data/test/suite/lib/baretest/assertion/support.rb +366 -84
  66. data/test/suite/lib/baretest/run.rb +114 -15
  67. data/test/suite/lib/baretest/suite.rb +70 -29
  68. metadata +46 -24
  69. data/examples/test.rake +0 -65
  70. data/examples/tests/mock_developer/test/helper/mocks.rb +0 -0
  71. data/examples/tests/mock_developer/test/setup.rb +0 -57
  72. data/examples/tests/mock_developer/test/suite/mock_demo.rb +0 -19
  73. data/examples/tests/overview/test.rb +0 -89
  74. data/examples/tests/variations/variations_01.rb +0 -14
  75. data/examples/tests/variations/variations_02.rb +0 -19
  76. data/examples/tests/variations/variations_03.rb +0 -19
  77. data/lib/baretest/mocha.rb +0 -18
  78. data/lib/baretest/rr.rb +0 -16
  79. data/lib/baretest/run/errors.rb +0 -49
  80. data/lib/baretest/skipped.rb +0 -15
  81. data/lib/baretest/skipped/assertion.rb +0 -20
  82. data/lib/baretest/skipped/suite.rb +0 -49
  83. data/test/external/bootstraptest.rb +0 -5
  84. data/test/external/bootstrapwrap.rb +0 -2
  85. data/test/helper/mocks.rb +0 -0
data/lib/baretest/run.rb CHANGED
@@ -6,15 +6,24 @@
6
6
 
7
7
 
8
8
 
9
+ require 'baretest/persistence'
10
+
11
+
12
+
9
13
  module BareTest
10
14
 
11
- # Run is the environment in which the suites and asserts are executed.
15
+ # Run is the environment in which the suites and assertions are executed.
12
16
  # Prior to the execution, the Run instance extends itself with the
13
- # formatter given.
17
+ # formatter that should be used and other runner related toolsets.
14
18
  # Your formatter can override:
15
- # :run_all:: Invoked once, before the first run_suite is ran. No arguments.
16
- # :run_suite:: Invoked per suite. Takes the suite to run as argument.
17
- # :run_test:: Invoked per assertion. Takes the assertion to execute as argument.
19
+ # :run_all:: Invoked once, before the first run_suite is ran. No
20
+ # arguments.
21
+ # :run_suite:: Invoked per suite. Takes the suite to run as argument.
22
+ # :run_test_variants:: Invoked per assertion. Takes the assertion to execute
23
+ # as argument.
24
+ # :run_test:: Invoked per setup variation of each assertion. Takes
25
+ # the assertion to execute and the setup blocks to use
26
+ # as arguments.
18
27
  #
19
28
  # Don't forget to call super within your overrides, or the tests won't be
20
29
  # executed.
@@ -26,13 +35,10 @@ module BareTest
26
35
  attr_reader :inits
27
36
 
28
37
  # Some statistics, standard count keys are:
29
- # * :test - the number of tests executed until now
30
- # * :suite - the number of suites executed until now
31
- # * :success - the number of tests with status :success
32
- # * :failure - the number of tests with status :failure
33
- # * :pending - the number of tests with status :pending
34
- # * :skipped - the number of tests with status :skipped
35
- # * :error - the number of tests with status :error
38
+ # :test:: the number of tests executed until now
39
+ # :suite:: the number of suites executed until now
40
+ # <status>:: the number of tests with that status (see
41
+ # BareTest::StatusOrder for a list of states)
36
42
  attr_reader :count
37
43
 
38
44
  # Run the passed suite.
@@ -53,19 +59,42 @@ module BareTest
53
59
  # * :format (extends with the formatter module)
54
60
  # * :interactive (extends with IRBMode)
55
61
  def initialize(suite, opts=nil)
56
- @suite = suite
57
- @inits = []
58
- @options = opts || {}
59
- @count = @options[:count] || Hash.new(0)
62
+ @suite = suite
63
+ @inits = []
64
+ @options = opts || {}
65
+ @count = @options[:count] || Hash.new(0)
66
+ @provided = [] # Array's set operations are the fastest
67
+ @include_tags = @options[:include_tags] # nil is ok here
68
+ @exclude_tags = @options[:exclude_tags] # nil is ok here
69
+ include_states = @options[:include_states] # nil is ok here
70
+ exclude_states = @options[:exclude_states] # nil is ok here
71
+ @states = [nil, :success, :failure, :skipped, :pending, :error]
72
+ @skipped = {}
73
+ @last_run_states = {}
74
+
75
+ @persistence = @options[:persistence]
76
+
77
+ if (include_states || exclude_states) && !((include_states && include_states.empty?) && (exclude_states && exclude_states.empty?)) then
78
+ [include_states, exclude_states].compact.each do |states|
79
+ states << nil if states.include?(:new)
80
+ states << :pending if states.include?(:skipped)
81
+ states.concat([:error, :skipped, :pending]) if states.include?(:failure)
82
+ states.delete(:new)
83
+ end
84
+ @states = (include_states || @states) - (exclude_states || [])
85
+ end
60
86
 
61
87
  (BareTest.extender+Array(@options[:extender])).each do |extender|
62
88
  extend(extender)
63
89
  end
64
90
 
65
91
  # Extend with the output formatter
66
- if format = @options[:format] then
67
- require "baretest/run/#{format}" if String === format
68
- extend(String === format ? BareTest.format["baretest/run/#{format}"] : format)
92
+ format = @options[:format]
93
+ if format.is_a?(String) then
94
+ require "baretest/run/#{format}"
95
+ extend(BareTest.format["baretest/run/#{format}"])
96
+ elsif format.is_a?(Module) then
97
+ extend(format)
69
98
  end
70
99
 
71
100
  # Extend with irb dropout code
@@ -93,7 +122,10 @@ module BareTest
93
122
  # Invoked once at the beginning.
94
123
  # Gets the toplevel suite as single argument.
95
124
  def run_all
125
+ @last_run_states = @persistence ? @persistence.read('final_states', {}) : {}
126
+ @skipped = {}
96
127
  run_suite(@suite)
128
+ @persistence.store('final_states', @last_run_states) if @persistence
97
129
  end
98
130
 
99
131
  # Formatter callback.
@@ -101,35 +133,97 @@ module BareTest
101
133
  # Gets the suite to run as single argument.
102
134
  # Runs all assertions and nested suites.
103
135
  def run_suite(suite)
104
- suite.assertions.each do |test|
105
- run_test_variants(test)
136
+ missing_tags = @include_tags && @include_tags - suite.tags
137
+ superfluous_tags = @exclude_tags && suite.tags & @exclude_tags
138
+ ignored = (missing_tags && !missing_tags.empty?) || (superfluous_tags && !superfluous_tags.empty?)
139
+
140
+ unless ignored then
141
+ unmet_dependencies = (suite.depends_on-@provided)
142
+ manually_skipped = suite.skipped?
143
+ recursively_skipped = !unmet_dependencies.empty? || manually_skipped
144
+ skipped = @skipped[suite] || recursively_skipped
145
+
146
+ if recursively_skipped then
147
+ skip_recursively(suite, "Skipped")
148
+ elsif skipped then
149
+ skip_suite(suite, "Skipped")
150
+ end
106
151
  end
107
- suite.suites.each do |(description, suite)|
108
- run_suite(suite)
152
+
153
+ if ignored then
154
+ states = []
155
+ else
156
+ states = suite.assertions.map do |test|
157
+ run_test_variants(test)
158
+ end
109
159
  end
160
+ states.concat(suite.suites.map { |(description, subsuite)|
161
+ run_suite(subsuite)
162
+ })
110
163
  @count[:suite] += 1
164
+
165
+ # || in case the suite contains no tests or suites
166
+ final_status = BareTest.most_important_status(states) || :pending
167
+
168
+ @provided |= suite.provides if final_status == :success
169
+
170
+ Status.new(suite, final_status)
111
171
  end
112
172
 
113
173
  # Invoked once for every assertion.
114
174
  # Iterates over all variants of an assertion and invokes run_test
115
175
  # for each.
116
- def run_test_variants(test)
117
- test.suite.each_component_variant do |setups|
118
- run_test(test, setups)
176
+ def run_test_variants(assertion)
177
+ ignored = !@states.include?(@last_run_states[assertion.id])
178
+ skipped = @skipped[assertion] || assertion.skipped?
179
+
180
+ if ignored then
181
+ overall_status = nil
182
+ elsif skipped then
183
+ Array.new(assertion.suite.component_variant_count) { run_test(assertion, []) }
184
+ @last_run_states[assertion.id] = :manually_skipped
185
+ overall_status = :manually_skipped
186
+ else
187
+ states = []
188
+ assertion.suite.each_component_variant do |setups|
189
+ rv = run_test(assertion, setups)
190
+ states << rv.status
191
+ end
192
+ overall_status = BareTest.most_important_status(states)
119
193
  end
194
+ @last_run_states[assertion.id] = overall_status if overall_status
195
+
196
+ overall_status
120
197
  end
121
198
 
122
199
  # Formatter callback.
123
200
  # Invoked once for every variation of an assertion.
124
201
  # Gets the assertion to run as single argument.
125
202
  def run_test(assertion, setup)
126
- assertion.setups = setup
127
- rv = assertion.execute
128
- @count[:test] += 1
129
- @count[assertion.status] += 1
203
+ rv = assertion.execute(setup.map { |s| s.block }, assertion.suite.ancestry_teardown)
204
+ @count[:test] += 1
205
+ @count[rv.status] += 1
206
+
130
207
  rv
131
208
  end
132
209
 
210
+ # Marks all assertion within this suite as skipped and the suite itself too.
211
+ def skip_suite(suite, reason) # :nodoc:
212
+ suite.skip(reason)
213
+ reason = suite.reason
214
+ suite.assertions.each do |test|
215
+ test.skip(reason)
216
+ end
217
+ end
218
+
219
+ # Marks all tests, suites and their subsuites within this suite as skipped.
220
+ def skip_recursively(suite, reason) # :nodoc:
221
+ skip_suite(suite, reason)
222
+ suite.suites.each do |description, subsuite|
223
+ skip_recursively(subsuite, reason)
224
+ end
225
+ end
226
+
133
227
  # Status over all tests ran up to now
134
228
  # Can be :error, :failure, :incomplete or :success
135
229
  # The algorithm is a simple fall through:
@@ -138,13 +232,20 @@ module BareTest
138
232
  # if not, then if any test was pending or skipped, global_status is :incomplete,
139
233
  # if not, then global_status is success
140
234
  def global_status
141
- case
142
- when @count[:error] > 0 then :error
143
- when @count[:failure] > 0 then :failure
144
- when @count[:pending] > 0 then :incomplete
145
- when @count[:skipped] > 0 then :incomplete
146
- else :success
147
- end
235
+ status_counts = @count.values_at(*BareTest::StatusOrder)
236
+ most_important_status = BareTest::StatusOrder.zip(status_counts) { |status, count|
237
+ break status if count > 0
238
+ } || :success
239
+ end
240
+
241
+ # Get an assertions' interpolated description for a given Array of Setup
242
+ # instances.
243
+ # See Assertion#interpolated_description
244
+ def interpolated_description(assertion, setup)
245
+ setups = setups ? setups.select { |s| s.component } : []
246
+ substitutes = {}
247
+ setups.each do |setup| substitutes[setup.component] = setup.substitute end
248
+ assertion.interpolated_description(substitutes)
148
249
  end
149
250
  end
150
251
  end
@@ -15,14 +15,57 @@ module BareTest
15
15
  # It prints colored output (requires ANSI colors compatible terminal).
16
16
  #
17
17
  module CLI # :nodoc:
18
+ extend Formatter
19
+
20
+ option_defaults :color => true,
21
+ :profile => false
22
+
23
+ text "Options for 'CLI' formatter:\n"
24
+
25
+ option :color, '-c', '--[no-]color', :Boolean, 'Enable/disable output coloring'
26
+ option :profile, '-p', '--[no-]profile', :Boolean, 'Enable/disable profiling assertions'
27
+
28
+ text "\nEnvironment variables for 'CLI' formatter:\n"
29
+
30
+ env_option :color, 'COLOR'
31
+ env_option :profile, 'PROFILE'
32
+
18
33
  Formats = {
19
- :pending => "\e[43m%9s\e[0m %s%s\n",
20
- :skipped => "\e[43m%9s\e[0m %s%s\n",
21
- :success => "\e[42m%9s\e[0m %s%s\n",
22
- :failure => "\e[41m%9s\e[0m %s%s\n",
23
- :error => "\e[37;40;1m%9s\e[0m %s%s\n" # ]]]]]]]] - bbedit hates open brackets...
34
+ :pending => "\e[43m%9s\e[0m %s%s\n",
35
+ :manually_skipped => "\e[43m%9s\e[0m %s%s\n",
36
+ :dependency_missing => "\e[43m%9s\e[0m %s%s\n",
37
+ :library_missing => "\e[43m%9s\e[0m %s%s\n",
38
+ :component_missing => "\e[43m%9s\e[0m %s%s\n",
39
+ :ignored => "\e[43m%9s\e[0m %s%s\n",
40
+ :skipped => "\e[43m%9s\e[0m %s%s\n",
41
+ :success => "\e[42m%9s\e[0m %s%s\n",
42
+ :failure => "\e[41m%9s\e[0m %s%s\n",
43
+ :error => "\e[37;40;1m%9s\e[0m %s%s\n" # ]]]]]]]]]]]]]]]]]]]] - bbedit hates open brackets...
44
+ }
45
+ StatusLabel = {
46
+ :pending => " Pending ",
47
+ :manually_skipped => " Skipped ",
48
+ :dependency_missing => " Skipped ",
49
+ :library_missing => " Skipped ",
50
+ :component_missing => " Skipped ",
51
+ :ignored => " Skipped ",
52
+ :skipped => " Skipped ",
53
+ :success => " Success ",
54
+ :failure => " Failure ",
55
+ :error => " Error ",
56
+ }
57
+ Map = {
58
+ :pending => :incomplete,
59
+ :manually_skipped => :incomplete,
60
+ :dependency_missing => :incomplete,
61
+ :library_missing => :incomplete,
62
+ :component_missing => :incomplete,
63
+ :ignored => :incomplete,
64
+ :skipped => :incomplete,
65
+ :success => :success,
66
+ :failure => :failure,
67
+ :error => :error,
24
68
  }
25
-
26
69
  FooterFormats = {
27
70
  :incomplete => "\e[43m%9s\e[0m\n",
28
71
  :success => "\e[42m%9s\e[0m\n",
@@ -31,61 +74,63 @@ module BareTest
31
74
  }
32
75
 
33
76
  def run_all(*args)
34
- @depth = 0
35
77
  puts "Running all tests#{' verbosly' if $VERBOSE}"
36
- start = Time.now
37
- super # run all suites
38
- status = global_status
39
- printf "\n%2$d tests run in %1$.1fs\n%3$d successful, %4$d pending, %5$d failures, %6$d errors\n",
40
- Time.now-start, *@count.values_at(:test, :success, :pending, :failure, :error)
78
+
79
+ @depth = 0
80
+ @deferred = []
81
+ start = Time.now
82
+ rv = super # run all suites
83
+ duration = Time.now-start
84
+ status = global_status
85
+ test, success, pending, manually_skipped, dependency_missing,
86
+ library_missing, component_missing, ignored, skipped, failure, error =
87
+ *@count.values_at(:test, :success, :pending, :manually_skipped,
88
+ :dependency_missing, :library_missing,
89
+ :component_missing, :ignored, :skipped, :failure,
90
+ :error)
91
+
92
+ printf "\n%2$d tests run in %1$.1fs\n%3$d successful, %4$d pending, %5$d skipped, %6$d failures, %7$d errors\n",
93
+ duration, test, success, pending, (skipped+manually_skipped+
94
+ dependency_missing+library_missing+component_missing), failure, error
41
95
  print "Final status: "
42
- printf FooterFormats[status], status_label(status)
96
+ printf FooterFormats[Map[status]], StatusLabel[status]
97
+
98
+ rv
43
99
  end
44
100
 
45
101
  def run_suite(suite)
46
102
  return super unless suite.description
47
- skipped = suite.skipped.size
48
103
  case size = suite.assertions.size
49
104
  when 0
50
- if skipped.zero? then
51
- puts "\n \e[1m#{' '*@depth+suite.description}\e[0m"
52
- else
53
- puts "\n \e[1m#{' '*@depth+suite.description}\e[0m (#{skipped} skipped)"
54
- end
105
+ defer "\n \e[1m#{' '*@depth+suite.description}\e[0m"
55
106
  when 1
56
- if skipped.zero? then
57
- puts "\n \e[1m#{' '*@depth+suite.description}\e[0m (1 test)"
58
- else
59
- puts "\n \e[1m#{' '*@depth+suite.description}\e[0m (1 test/#{skipped} skipped)"
60
- end
107
+ defer "\n \e[1m#{' '*@depth+suite.description}\e[0m (1 test)"
61
108
  else
62
- if skipped.zero? then
63
- puts "\n \e[1m#{' '*@depth+suite.description}\e[0m (#{size} tests)"
64
- else
65
- puts "\n \e[1m#{' '*@depth+suite.description}\e[0m (#{size} tests/#{skipped} skipped)"
66
- end
109
+ defer "\n \e[1m#{' '*@depth+suite.description}\e[0m (#{size} tests)"
67
110
  end
68
111
  @depth += 1
69
- super(suite) # run the suite
112
+ rv = super(suite) # run the suite
113
+ pop_deferred
70
114
  @depth -= 1
115
+
116
+ rv
71
117
  end
72
118
 
73
119
  def run_test(assertion, setup)
74
- rv = super # run the assertion
75
- indent = ' '+' '*@depth
76
- message = []
77
- deeper = []
120
+ clear_deferred
121
+ rv = super # run the assertion
122
+ indent = ' '+' '*@depth
123
+ backtrace = []
124
+ reason = rv.reason(:indent => indent)
78
125
 
79
- printf(Formats[rv.status], status_label(rv.status), ' '*@depth, rv.interpolated_description)
126
+ printf(Formats[rv.status], StatusLabel[rv.status], ' '*@depth, interpolated_description(assertion, setup))
80
127
  if rv.status == :error then
81
- message = (rv.exception.message || "no error message given").split("\n")
82
- deeper = $VERBOSE ? rv.exception.backtrace : rv.exception.backtrace.first(1)
128
+ backtrace = $VERBOSE ? rv.exception.backtrace : rv.exception.backtrace.first(1)
83
129
  elsif rv.status == :failure
84
- message = (rv.reason || "no failure reason given").split("\n")
85
- deeper = ["#{rv.file}:#{rv.line}"]
130
+ backtrace = ["#{assertion.file}:#{assertion.line}"]
86
131
  end
87
- message.each do |line| print(indent, line, "\n") end
88
- deeper.each do |line| print(indent, ' ', line, "\n") end
132
+ puts reason if reason
133
+ backtrace.each do |line| print(indent, ' ', line, "\n") end
89
134
 
90
135
  rv
91
136
  end
@@ -94,8 +139,17 @@ module BareTest
94
139
  str.scan(/[^ ]+ /)
95
140
  end
96
141
 
97
- def status_label(status)
98
- status.to_s.capitalize.center(9)
142
+ def defer(output)
143
+ @deferred << output
144
+ end
145
+
146
+ def pop_deferred
147
+ @deferred.pop
148
+ end
149
+
150
+ def clear_deferred
151
+ puts *@deferred unless @deferred.empty?
152
+ @deferred.clear
99
153
  end
100
154
  end
101
155
  end
@@ -18,11 +18,12 @@ module BareTest
18
18
  start = Time.now
19
19
  super # run all suites
20
20
  stop = Time.now
21
- values = @count.values_at(:test, :success, :pending, :failure, :error)
21
+ values = @count.values_at(:test, :success, :pending, :skipped, :failure, :error)
22
22
  values.push(stop-start, global_status)
23
23
  printf "Tests: %d\n" \
24
24
  "Success: %d\n" \
25
25
  "Pending: %d\n" \
26
+ "Skipped: %d\n" \
26
27
  "Failures: %d\n" \
27
28
  "Errors: %d\n" \
28
29
  "Time: %f\n" \
@@ -0,0 +1,21 @@
1
+ #--
2
+ # Copyright 2009-2010 by Stefan Rusterholz.
3
+ # All rights reserved.
4
+ # See LICENSE.txt for permissions.
5
+ #++
6
+
7
+
8
+
9
+ module BareTest
10
+ class Run
11
+
12
+ # None runner is invoked with `-f none` or `--format none`.
13
+ # This runner produces NO output at all. You can use it if you're only
14
+ # interested in baretests exit status.
15
+ #
16
+ module None # :nodoc:
17
+ end
18
+ end
19
+
20
+ @format["baretest/run/none"] = Run::None # register the extender
21
+ end