baretest 0.1.0 → 0.2.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (69) hide show
  1. data/LICENSE.txt +52 -0
  2. data/MANIFEST.txt +50 -31
  3. data/README.rdoc +260 -0
  4. data/bin/baretest +82 -24
  5. data/doc/baretest.rdoc +98 -0
  6. data/doc/mocking_stubbing_test_doubles.rdoc +5 -0
  7. data/doc/quickref.rdoc +261 -0
  8. data/doc/writing_tests.rdoc +148 -0
  9. data/examples/test.rake +58 -30
  10. data/examples/tests/irb_mode/failures.rb +26 -0
  11. data/examples/tests/mock_developer/test/helper/mocks.rb +0 -0
  12. data/examples/tests/mock_developer/test/setup.rb +57 -0
  13. data/examples/tests/mock_developer/test/suite/mock_demo.rb +19 -0
  14. data/examples/tests/overview/test.rb +89 -0
  15. data/examples/tests/variations/variations_01.rb +14 -0
  16. data/examples/tests/variations/variations_02.rb +19 -0
  17. data/examples/tests/variations/variations_03.rb +19 -0
  18. data/lib/baretest/assertion/context.rb +20 -0
  19. data/lib/baretest/assertion/failure.rb +22 -0
  20. data/lib/baretest/assertion/skip.rb +21 -0
  21. data/lib/{test → baretest}/assertion/support.rb +174 -39
  22. data/lib/baretest/assertion.rb +182 -0
  23. data/lib/baretest/irb_mode.rb +263 -0
  24. data/lib/{test/assertion/failure.rb → baretest/layout.rb} +6 -5
  25. data/lib/baretest/mocha.rb +18 -0
  26. data/lib/baretest/run/cli.rb +104 -0
  27. data/lib/{test → baretest}/run/errors.rb +12 -7
  28. data/lib/{test → baretest}/run/minimal.rb +8 -3
  29. data/lib/baretest/run/profile.rb +151 -0
  30. data/lib/{test → baretest}/run/spec.rb +10 -4
  31. data/lib/baretest/run/tap.rb +44 -0
  32. data/lib/baretest/run/xml.rb +80 -0
  33. data/lib/{test → baretest}/run.rb +31 -18
  34. data/lib/baretest/setup.rb +15 -0
  35. data/lib/baretest/skipped/assertion.rb +20 -0
  36. data/lib/baretest/skipped/suite.rb +49 -0
  37. data/lib/baretest/skipped.rb +15 -0
  38. data/lib/baretest/suite.rb +234 -0
  39. data/lib/baretest/utilities.rb +43 -0
  40. data/lib/{test → baretest}/version.rb +12 -3
  41. data/lib/baretest.rb +112 -0
  42. data/test/external/bootstraptest.rb +1 -1
  43. data/test/setup.rb +1 -1
  44. data/test/{lib/test → suite/lib/baretest}/assertion/support.rb +78 -24
  45. data/test/suite/lib/baretest/assertion.rb +192 -0
  46. data/test/{lib/test → suite/lib/baretest}/irb_mode.rb +0 -0
  47. data/test/{lib/test → suite/lib/baretest}/run/cli.rb +0 -0
  48. data/test/{lib/test → suite/lib/baretest}/run/errors.rb +0 -0
  49. data/test/{lib/test → suite/lib/baretest}/run/interactive.rb +0 -0
  50. data/test/{lib/test → suite/lib/baretest}/run/spec.rb +0 -0
  51. data/test/{lib/test → suite/lib/baretest}/run/tap.rb +0 -0
  52. data/test/{lib/test → suite/lib/baretest}/run/xml.rb +0 -0
  53. data/test/{lib/test → suite/lib/baretest}/run.rb +63 -61
  54. data/test/{lib/test → suite/lib/baretest}/suite.rb +77 -54
  55. data/test/{lib/test.rb → suite/lib/baretest.rb} +37 -37
  56. metadata +61 -40
  57. data/README.markdown +0 -229
  58. data/examples/test.rb +0 -93
  59. data/lib/test/assertion.rb +0 -117
  60. data/lib/test/debug.rb +0 -34
  61. data/lib/test/irb_mode.rb +0 -104
  62. data/lib/test/run/cli.rb +0 -79
  63. data/lib/test/run/interactive.rb +0 -60
  64. data/lib/test/run/tap.rb +0 -32
  65. data/lib/test/run/xml.rb +0 -56
  66. data/lib/test/suite.rb +0 -95
  67. data/lib/test.rb +0 -118
  68. data/test/lib/test/assertion.rb +0 -142
  69. data/test/lib/test/debug.rb +0 -63
@@ -0,0 +1,263 @@
1
+ #--
2
+ # Copyright 2009 by Stefan Rusterholz.
3
+ # All rights reserved.
4
+ # See LICENSE.txt for permissions.
5
+ #++
6
+
7
+
8
+
9
+ require 'stringio' # for silencing HAX
10
+
11
+
12
+
13
+ module Kernel
14
+ alias lv! local_variables
15
+ private :lv!
16
+ end
17
+
18
+ module BareTest
19
+
20
+ # For internal use only.
21
+ #
22
+ # This module extends BareTest::Run if --interactive/-i is used
23
+ #
24
+ # See BareTest::IRBMode::AssertionContext for some methods IRBMode adds to Assertion for
25
+ # use within the irb session.
26
+ module IRBMode # :nodoc:
27
+ @irb_setup = false
28
+
29
+ def self.irb_setup! # :nodoc:
30
+ @irb_setup = true
31
+ end
32
+
33
+ def self.irb_setup? # :nodoc:
34
+ @irb_setup
35
+ end
36
+
37
+ # The class used to recreate the failed/errored assertion's context.
38
+ # Adds several methods over plain Assertion.
39
+ module IRBContext
40
+
41
+ attr_accessor :__original__
42
+
43
+ # Prints a list of available helper methods
44
+ def help
45
+ puts "Available methods:",
46
+ "s! - the original assertions' status",
47
+ "e! - prints the error message and full backtrace",
48
+ "em! - prints the error message",
49
+ "bt! - prints the full backtrace",
50
+ "iv! - lists all available instance variables",
51
+ "cv! - lists all available class variables",
52
+ "gv! - lists all available global variables",
53
+ "file - the file this assertion was defined in",
54
+ "line - the line number in the file where this assertion's definition starts",
55
+ "nesting - a >-separated list of suite descriptions this assertion is nested in",
56
+ "description - this assertion's description",
57
+ "code - the code of this assertion",
58
+ #"restart! - Restart this irb session, resetting everything",
59
+ "irb_help - irb's original help",
60
+ "help - this text you're reading right now"
61
+ end
62
+
63
+ def to_s # :nodoc:
64
+ "Context"
65
+ end
66
+
67
+ # Returns the original assertion's status
68
+ def s!
69
+ p @__original__.status
70
+ end
71
+
72
+ # Prints the original assertion's error message and backtrace
73
+ def e!
74
+ em!
75
+ bt!(caller.size+3)
76
+ end
77
+
78
+ # Prints the original assertion's error message
79
+ def em!
80
+ if @__original__.exception then
81
+ puts @__original__.exception.message
82
+ elsif @__original__.reason
83
+ puts @__original__.reason
84
+ else
85
+ puts "No exception occurred, therefore no error message is available"
86
+ end
87
+ end
88
+
89
+ # Prints the original assertion's backtrace
90
+ def bt!(size=nil)
91
+ if @__assertion__.exception then
92
+ size ||= caller.size+3
93
+ puts @__assertion__.exception.backtrace[0..-size]
94
+ else
95
+ puts "No exception occurred, therefore no backtrace is available"
96
+ end
97
+ end
98
+
99
+ # Returns an array of all instance variable names
100
+ def iv!
101
+ puts *instance_variables.sort
102
+ end
103
+
104
+ # Returns an array of all class variable names
105
+ def cv!
106
+ puts *self.class.class_variables.sort
107
+ end
108
+
109
+ # Returns an array of all global variable names
110
+ def gv!
111
+ puts *global_variables.sort
112
+ end
113
+
114
+ # Prints a string of the original assertion's nesting within suites
115
+ def description
116
+ puts @__assertion__.description
117
+ end
118
+
119
+ # Prints a string of the original assertion's nesting within suites
120
+ def nesting
121
+ puts @__assertion__.suite.ancestors[0..-2].reverse.map { |s| s.description }.join(' > ')
122
+ end
123
+
124
+ # Prints the code of the assertion
125
+ # Be aware that this relies on your code being properly indented.
126
+ def code!
127
+ if code = @__assertion__.code then
128
+ puts(insert_line_numbers(code, @__assertion__.line-1))
129
+ else
130
+ puts "Code could not be extracted"
131
+ end
132
+ end
133
+
134
+ def insert_line_numbers(code, start_line=1)
135
+ digits = Math.log10(start_line+code.count("\n")).floor+1
136
+ current_line = start_line-1
137
+ code.gsub(/^/) { sprintf ' %0*d ', digits, current_line+=1 }
138
+ end
139
+ end
140
+
141
+ # Install the init handler
142
+ def self.extended(by) # :nodoc:
143
+ by.init do
144
+ require 'irb'
145
+ require 'pp'
146
+ require 'yaml'
147
+ IRB.setup(nil) unless ::BareTest::IRBMode.irb_setup? # must only be called once
148
+ ::BareTest::IRBMode.irb_setup!
149
+ end
150
+ end
151
+
152
+ # Formatter callback.
153
+ # Invoked once for every assertion.
154
+ # Gets the assertion to run as single argument.
155
+ def run_test(assertion, setup)
156
+ rv = super
157
+ # drop into irb if assertion failed
158
+ case rv.status
159
+ when :failure
160
+ start_irb_failure_mode(assertion)
161
+ irb_mode_for_assertion(assertion)
162
+ stop_irb_mode(assertion)
163
+ when :error
164
+ start_irb_error_mode(assertion)
165
+ irb_mode_for_assertion(assertion)
166
+ stop_irb_mode(assertion)
167
+ end
168
+
169
+ rv
170
+ end
171
+
172
+ # Invoked when we have to drop into irb mode due to a failure
173
+ def start_irb_failure_mode(assertion) # :nodoc:
174
+ ancestry = assertion.suite.ancestors.reverse.map { |suite| suite.description }
175
+
176
+ puts
177
+ puts "#{assertion.status.to_s.capitalize} in: #{ancestry[1..-1].join(' > ')}"
178
+ puts "Description: #{assertion.description}"
179
+ if file = assertion.file then
180
+ code = irb_code_reindented(file, assertion.line-1,20)
181
+ match = code.match(/\n^ [^ ]/)
182
+ code[-(match.post_match.size-3)..-1] = ""
183
+ assertion.code = code
184
+ puts "Code (#{file}):", insert_line_numbers(code, assertion.line-1)
185
+ end
186
+ end
187
+
188
+ # Invoked when we have to drop into irb mode due to an error
189
+ def start_irb_error_mode(assertion) # :nodoc:
190
+ ancestry = assertion.suite.ancestors.reverse.map { |suite| suite.description }
191
+
192
+ puts
193
+ puts "#{assertion.status.to_s.capitalize} in: #{ancestry[1..-1].join(' > ')}"
194
+ puts "Description: #{assertion.description}"
195
+ puts "Exception: #{assertion.exception} in file #{assertion.exception.backtrace.first}"
196
+ if assertion.file && match = assertion.exception.backtrace.first.match(/^([^:]+):(\d+)(?:$|:in .*)/) then
197
+ file, line = match.captures
198
+ file = File.expand_path(file)
199
+ if assertion.file == file then
200
+ code = irb_code_reindented(file, (assertion.line-1)..(line.to_i))
201
+ assertion.code = code
202
+ puts "Code (#{file}):", insert_line_numbers(code, assertion.line-1)
203
+ end
204
+ end
205
+ end
206
+
207
+ # Nicely reformats the assertion's code
208
+ def irb_code_reindented(file, *slice) # :nodoc:
209
+ lines = File.readlines(file)
210
+ string = lines[*slice].join("").sub(/[\r\n]*\z/, '')
211
+ string.gsub!(/^\t+/) { |m| " "*m.size }
212
+ indent = string[/^ +/]
213
+ string.gsub!(/^#{indent}/, ' ')
214
+
215
+ string
216
+ end
217
+
218
+ def insert_line_numbers(code, start_line=1)
219
+ digits = Math.log10(start_line+code.count("\n")).floor+1
220
+ current_line = start_line-1
221
+ code.gsub(/^/) { sprintf ' %0*d ', digits, current_line+=1 }
222
+ end
223
+
224
+ # This method is highlevel hax, try to add necessary API to Test::Assertion
225
+ # Drop into an irb shell in the context of the assertion passed as an argument.
226
+ # Uses Assertion#clean_copy(AssertionContext) to create the context.
227
+ # Adds the code into irb's history.
228
+ def irb_mode_for_assertion(original_assertion) # :nodoc:
229
+ assertion = original_assertion.clone
230
+ assertion.reset
231
+ irb_context = assertion.context
232
+ irb_context.extend IRBContext
233
+ irb_context.__original__ = original_assertion
234
+ assertion.setup
235
+
236
+ $stdout = StringIO.new # HAX - silencing 'irb: warn: can't alias help from irb_help.' - find a better way
237
+ irb = IRB::Irb.new(IRB::WorkSpace.new(irb_context))
238
+ $stdout = STDOUT # /HAX
239
+ # HAX - cargo cult, taken from irb.rb, not yet really understood.
240
+ IRB.conf[:IRB_RC].call(irb.context) if IRB.conf[:IRB_RC] # loads the irbrc?
241
+ IRB.conf[:MAIN_CONTEXT] = irb.context # why would the main context be set here?
242
+ # /HAX
243
+
244
+ trap("SIGINT") do irb.signal_handle end
245
+
246
+ if code = original_assertion.code then
247
+ #irb_context.code = code
248
+ Readline::HISTORY.push(*code.split("\n")[1..-2])
249
+ end
250
+
251
+ catch(:IRB_EXIT) do irb.eval_input end
252
+
253
+ assertion.teardown
254
+ end
255
+
256
+ # Invoked when we leave the irb session
257
+ def stop_irb_mode(assertion) # :nodoc:
258
+ puts
259
+ super
260
+ rescue NoMethodError # HAX, not happy about that. necessary due to order of extend
261
+ end
262
+ end
263
+ end
@@ -6,9 +6,10 @@
6
6
 
7
7
 
8
8
 
9
- module Test
10
- class Assertion
11
- class Failure < StandardError
12
- end
13
- end
9
+ module BareTest
10
+ # :stopdoc:
11
+ Layout = Struct.new(
12
+ :foo
13
+ )
14
+ # :startdoc:
14
15
  end
@@ -0,0 +1,18 @@
1
+ # Created by dominikh
2
+
3
+ # This file provides integration with the "mocha" mocking framework.
4
+
5
+ require 'mocha'
6
+
7
+ BareTest.extend Mocha::API
8
+
9
+ BareTest.toplevel_suite.teardown do
10
+ begin
11
+ BareTest.mocha_verify
12
+ rescue Mocha::ExpectationError => e
13
+ @reason = e.message
14
+ @status = :failure
15
+ ensure
16
+ BareTest.mocha_teardown
17
+ end
18
+ end
@@ -0,0 +1,104 @@
1
+ #--
2
+ # Copyright 2009 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
+ # CLI runner is invoked with `-f cli` or `--format cli`.
13
+ # It is intended for use with an interactive shell, to provide a comfortable, human
14
+ # readable output.
15
+ # It prints colored output (requires ANSI colors compatible terminal).
16
+ #
17
+ module CLI # :nodoc:
18
+ 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...
24
+ }
25
+
26
+ FooterFormats = {
27
+ :incomplete => "\e[43m%9s\e[0m\n",
28
+ :success => "\e[42m%9s\e[0m\n",
29
+ :failure => "\e[41m%9s\e[0m\n",
30
+ :error => "\e[37;40;1m%9s\e[0m\n" # ]]]]]]]] - bbedit hates open brackets...
31
+ }
32
+
33
+ def run_all(*args)
34
+ @depth = 0
35
+ 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)
41
+ print "Final status: "
42
+ printf FooterFormats[status], status_label(status)
43
+ end
44
+
45
+ def run_suite(suite)
46
+ return super unless suite.description
47
+ skipped = suite.skipped.size
48
+ case size = suite.assertions.size
49
+ 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
55
+ 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
61
+ 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
67
+ end
68
+ @depth += 1
69
+ super(suite) # run the suite
70
+ @depth -= 1
71
+ end
72
+
73
+ def run_test(assertion, setup)
74
+ rv = super # run the assertion
75
+ indent = ' '+' '*@depth
76
+ message = []
77
+ deeper = []
78
+
79
+ printf(Formats[rv.status], status_label(rv.status), ' '*@depth, rv.interpolated_description)
80
+ 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)
83
+ elsif rv.status == :failure
84
+ message = (rv.reason || "no failure reason given").split("\n")
85
+ deeper = ["#{rv.file}:#{rv.line}"]
86
+ end
87
+ message.each do |line| print(indent, line, "\n") end
88
+ deeper.each do |line| print(indent, ' ', line, "\n") end
89
+
90
+ rv
91
+ end
92
+
93
+ def word_wrap(string, cols)
94
+ str.scan(/[^ ]+ /)
95
+ end
96
+
97
+ def status_label(status)
98
+ status.to_s.capitalize.center(9)
99
+ end
100
+ end
101
+ end
102
+
103
+ @format["baretest/run/cli"] = Run::CLI # register the extender
104
+ end
@@ -6,9 +6,14 @@
6
6
 
7
7
 
8
8
 
9
- module Test
9
+ module BareTest
10
10
  class Run
11
- module Errors
11
+
12
+ # Errors runner is invoked with `-f errors` or `--format errors`.
13
+ # This runner is specifically built to provide the most possible information about
14
+ # errors in the suite.
15
+ #
16
+ module Errors # :nodoc:
12
17
  def run_all
13
18
  @depth = 0
14
19
  puts "Running all tests, reporting errors"
@@ -19,24 +24,24 @@ module Test
19
24
 
20
25
  def run_suite(suite)
21
26
  return super unless suite.description
22
- puts "#{' '*@depth+suite.description} (#{suite.tests.size} tests)"
27
+ puts "#{' '*@depth+suite.description} (#{suite.assertions.size} tests, #{suite.skipped.size} skipped)"
23
28
  @depth += 1
24
29
  super # run the suite
25
30
  @depth -= 1
26
31
  end
27
32
 
28
- def run_test(assertion)
33
+ def run_test(assertion, setup)
29
34
  rv = super # run the assertion
30
35
  puts(' '*@depth+rv.description)
31
36
  if rv.exception then
32
37
  size = caller.size+5
33
- puts((['-'*80, rv.exception]+rv.exception.backtrace[0..-size]+['-'*80, '']).map { |l|
34
- (' '*(@depth+1))+l
38
+ puts((['-'*80, rv.exception.message]+rv.exception.backtrace[0..-size]+['-'*80, '']).map { |l|
39
+ (' '*(@depth+1))+l
35
40
  })
36
41
  end
37
42
  end
38
43
  end
39
44
  end
40
45
 
41
- @format["test/run/errors"] = Run::Errors # register the extender
46
+ @format["baretest/run/errors"] = Run::Errors # register the extender
42
47
  end
@@ -6,9 +6,14 @@
6
6
 
7
7
 
8
8
 
9
- module Test
9
+ module BareTest
10
10
  class Run
11
- module Minimal
11
+
12
+ # Minimal runner is invoked with `-f minimal` or `--format minimal`.
13
+ # This runner is mainly written as an example. It will provide the final
14
+ # statistics (number of tests, successes, etc.).
15
+ #
16
+ module Minimal # :nodoc:
12
17
  def run_all(*args)
13
18
  start = Time.now
14
19
  super # run all suites
@@ -27,5 +32,5 @@ module Test
27
32
  end
28
33
  end
29
34
 
30
- @format["test/run/minimal"] = Run::Minimal # register the extender
35
+ @format["baretest/run/minimal"] = Run::Minimal # register the extender
31
36
  end
@@ -0,0 +1,151 @@
1
+ # encoding: utf-8
2
+ #--
3
+ # Copyright 2009 by Stefan Rusterholz.
4
+ # All rights reserved.
5
+ # See LICENSE.txt for permissions.
6
+ #++
7
+
8
+
9
+
10
+ module BareTest
11
+ class Run
12
+
13
+ # CLI runner is invoked with `-f cli` or `--format cli`.
14
+ # It is intended for use with an interactive shell, to provide a comfortable, human
15
+ # readable output.
16
+ # It prints colored output (requires ANSI colors compatible terminal).
17
+ #
18
+ module Profile # :nodoc:
19
+ Formats = {
20
+ :pending => "\e[43m%9s\e[0m %s%s (%s)\n",
21
+ :skipped => "\e[43m%9s\e[0m %s%s (%s)\n",
22
+ :success => "\e[42m%9s\e[0m %s%s (%s)\n",
23
+ :failure => "\e[41m%9s\e[0m %s%s (%s)\n",
24
+ :error => "\e[37;40;1m%9s\e[0m %s%s (%s)\n" # ]]]]]]]] - bbedit hates open brackets...
25
+ }
26
+
27
+ FooterFormats = {
28
+ :incomplete => "\e[43m%9s\e[0m\n",
29
+ :success => "\e[42m%9s\e[0m\n",
30
+ :failure => "\e[41m%9s\e[0m\n",
31
+ :error => "\e[37;40;1m%9s\e[0m\n" # ]]]]]]]] - bbedit hates open brackets...
32
+ }
33
+
34
+ def run_all(*args)
35
+ @depth = 0
36
+ puts "Running all tests#{' verbosly' if $VERBOSE}"
37
+ start = Time.now
38
+ super # run all suites
39
+ status = global_status
40
+ printf "\n%2$d tests run in %1$.1fs\n%3$d successful, %4$d pending, %5$d failures, %6$d errors\n",
41
+ Time.now-start, *@count.values_at(:test, :success, :pending, :failure, :error)
42
+ print "Final status: "
43
+ printf FooterFormats[status], status_label(status)
44
+ end
45
+
46
+ def run_suite(suite)
47
+ return super unless suite.description
48
+ skipped = suite.skipped.size
49
+ case size = suite.assertions.size
50
+ when 0
51
+ if skipped.zero? then
52
+ puts "\n \e[1m#{' '*@depth+suite.description}\e[0m"
53
+ else
54
+ puts "\n \e[1m#{' '*@depth+suite.description}\e[0m (#{skipped} skipped)"
55
+ end
56
+ when 1
57
+ if skipped.zero? then
58
+ puts "\n \e[1m#{' '*@depth+suite.description}\e[0m (1 test)"
59
+ else
60
+ puts "\n \e[1m#{' '*@depth+suite.description}\e[0m (1 test/#{skipped} skipped)"
61
+ end
62
+ else
63
+ if skipped.zero? then
64
+ puts "\n \e[1m#{' '*@depth+suite.description}\e[0m (#{size} tests)"
65
+ else
66
+ puts "\n \e[1m#{' '*@depth+suite.description}\e[0m (#{size} tests/#{skipped} skipped)"
67
+ end
68
+ end
69
+ @depth += 1
70
+ super(suite) # run the suite
71
+ @depth -= 1
72
+ end
73
+
74
+ def run_test(assertion, setup)
75
+ start = Time.now
76
+ rv = super # run the assertion
77
+ times = [Time.now-start]
78
+
79
+ if times.first < 1e-3 then
80
+ iters = 19
81
+ elsif times.first < 1
82
+ iters = 2
83
+ else
84
+ iters = 0
85
+ end
86
+
87
+ iters.times do
88
+ assertion.reset
89
+ start = Time.now
90
+ assertion.execute
91
+ times << (Time.now-start)
92
+ end
93
+
94
+ time = times.inject{ |a,b| a+b }/iters
95
+
96
+ indent = ' '+' '*@depth
97
+ message = []
98
+ deeper = []
99
+
100
+ printf(
101
+ Formats[rv.status],
102
+ status_label(rv.status),
103
+ ' '*@depth,
104
+ rv.description,
105
+ humanized_duration(time)
106
+ )
107
+ if rv.status == :error then
108
+ message = (rv.exception.message || "no error message given").split("\n")
109
+ deeper = $VERBOSE ? rv.exception.backtrace : rv.exception.backtrace.first(1)
110
+ elsif rv.status == :failure
111
+ message = (rv.reason || "no failure reason given").split("\n")
112
+ deeper = ["#{rv.file}:#{rv.line}"]
113
+ end
114
+ message.each do |line| print(indent, line, "\n") end
115
+ deeper.each do |line| print(indent, ' ', line, "\n") end
116
+
117
+ rv
118
+ end
119
+
120
+ def word_wrap(string, cols)
121
+ str.scan(/[^ ]+ /)
122
+ end
123
+
124
+ def status_label(status)
125
+ status.to_s.capitalize.center(9)
126
+ end
127
+
128
+ def humanized_duration(duration)
129
+ case
130
+ when duration < 1e-3
131
+ "%dµs" % (duration*1e6)
132
+ when duration < 1
133
+ "%.1fms" % (duration*1e3)
134
+ when duration < 60
135
+ "%.1fs" % duration
136
+ else
137
+ minutes, seconds = *duration.divmod(60)
138
+ hours, minutes = *minutes.divmod(60)
139
+ # lets assume unit tests don't take more than a day :)
140
+ if hours > 0 then
141
+ "#{hours}h #{minutes}m #{seconds}s"
142
+ else
143
+ "#{minutes}m #{seconds}s"
144
+ end
145
+ end
146
+ end
147
+ end
148
+ end
149
+
150
+ @format["baretest/run/profile"] = Run::Profile # register the extender
151
+ end
@@ -6,9 +6,15 @@
6
6
 
7
7
 
8
8
 
9
- module Test
9
+ module BareTest
10
10
  class Run
11
- module Spec
11
+
12
+ # Spec runner is invoked with `-f spec` or `--format spec`.
13
+ # This runner will not actually run the tests. It only extracts the descriptions and
14
+ # prints them. Handy if you just want an overview over what a library is supposed to do
15
+ # and be capable of.
16
+ #
17
+ module Spec # :nodoc:
12
18
  def run_all
13
19
  @depth = 0
14
20
  super
@@ -22,11 +28,11 @@ module Test
22
28
  @depth -= 1
23
29
  end
24
30
 
25
- def run_test(assertion)
31
+ def run_test(assertion, setup)
26
32
  puts(' '*@depth+assertion.description)
27
33
  end
28
34
  end
29
35
  end
30
36
 
31
- @format["test/run/spec"] = Run::Spec
37
+ @format["baretest/run/spec"] = Run::Spec
32
38
  end
@@ -0,0 +1,44 @@
1
+ #--
2
+ # Copyright 2009 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
+ # TAP runner is invoked with `-f tap` or `--format tap`.
13
+ # TAP (Test Anything Protocol) output is intended as a universal, machine readable
14
+ # output format of test frameworks. The are various tools that can further process
15
+ # that information and leverage it in various ways of automation.
16
+ # This runner currently implements the TA Protocol in version 13.
17
+ #
18
+ module TAP # :nodoc:
19
+ def run_all
20
+ puts "TAP version 13"
21
+ count = proc { |acc,csuite|
22
+ acc+
23
+ csuite.assertions.size+
24
+ csuite.skipped.size+
25
+ csuite.suites.map { |d,suite| suite }.inject(0, &count)
26
+ }
27
+ puts "1..#{count[0, suite]}"
28
+ @current = 0
29
+ super
30
+ end
31
+
32
+ def run_test(assertion, setup)
33
+ rv = super
34
+ printf "%sok %d - %s%s\n",
35
+ rv.status == :success ? '' : 'not ',
36
+ @current+=1,
37
+ rv.description,
38
+ rv.status == :success ? '' : " # #{rv.status}"
39
+ end
40
+ end
41
+ end
42
+
43
+ @format["baretest/run/tap"] = Run::TAP
44
+ end