baretest 0.1.0 → 0.2.3
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.
- data/LICENSE.txt +52 -0
- data/MANIFEST.txt +50 -31
- data/README.rdoc +260 -0
- data/bin/baretest +82 -24
- data/doc/baretest.rdoc +98 -0
- data/doc/mocking_stubbing_test_doubles.rdoc +5 -0
- data/doc/quickref.rdoc +261 -0
- data/doc/writing_tests.rdoc +148 -0
- data/examples/test.rake +58 -30
- data/examples/tests/irb_mode/failures.rb +26 -0
- data/examples/tests/mock_developer/test/helper/mocks.rb +0 -0
- data/examples/tests/mock_developer/test/setup.rb +57 -0
- data/examples/tests/mock_developer/test/suite/mock_demo.rb +19 -0
- data/examples/tests/overview/test.rb +89 -0
- data/examples/tests/variations/variations_01.rb +14 -0
- data/examples/tests/variations/variations_02.rb +19 -0
- data/examples/tests/variations/variations_03.rb +19 -0
- data/lib/baretest/assertion/context.rb +20 -0
- data/lib/baretest/assertion/failure.rb +22 -0
- data/lib/baretest/assertion/skip.rb +21 -0
- data/lib/{test → baretest}/assertion/support.rb +174 -39
- data/lib/baretest/assertion.rb +182 -0
- data/lib/baretest/irb_mode.rb +263 -0
- data/lib/{test/assertion/failure.rb → baretest/layout.rb} +6 -5
- data/lib/baretest/mocha.rb +18 -0
- data/lib/baretest/run/cli.rb +104 -0
- data/lib/{test → baretest}/run/errors.rb +12 -7
- data/lib/{test → baretest}/run/minimal.rb +8 -3
- data/lib/baretest/run/profile.rb +151 -0
- data/lib/{test → baretest}/run/spec.rb +10 -4
- data/lib/baretest/run/tap.rb +44 -0
- data/lib/baretest/run/xml.rb +80 -0
- data/lib/{test → baretest}/run.rb +31 -18
- data/lib/baretest/setup.rb +15 -0
- data/lib/baretest/skipped/assertion.rb +20 -0
- data/lib/baretest/skipped/suite.rb +49 -0
- data/lib/baretest/skipped.rb +15 -0
- data/lib/baretest/suite.rb +234 -0
- data/lib/baretest/utilities.rb +43 -0
- data/lib/{test → baretest}/version.rb +12 -3
- data/lib/baretest.rb +112 -0
- data/test/external/bootstraptest.rb +1 -1
- data/test/setup.rb +1 -1
- data/test/{lib/test → suite/lib/baretest}/assertion/support.rb +78 -24
- data/test/suite/lib/baretest/assertion.rb +192 -0
- data/test/{lib/test → suite/lib/baretest}/irb_mode.rb +0 -0
- data/test/{lib/test → suite/lib/baretest}/run/cli.rb +0 -0
- data/test/{lib/test → suite/lib/baretest}/run/errors.rb +0 -0
- data/test/{lib/test → suite/lib/baretest}/run/interactive.rb +0 -0
- data/test/{lib/test → suite/lib/baretest}/run/spec.rb +0 -0
- data/test/{lib/test → suite/lib/baretest}/run/tap.rb +0 -0
- data/test/{lib/test → suite/lib/baretest}/run/xml.rb +0 -0
- data/test/{lib/test → suite/lib/baretest}/run.rb +63 -61
- data/test/{lib/test → suite/lib/baretest}/suite.rb +77 -54
- data/test/{lib/test.rb → suite/lib/baretest.rb} +37 -37
- metadata +61 -40
- data/README.markdown +0 -229
- data/examples/test.rb +0 -93
- data/lib/test/assertion.rb +0 -117
- data/lib/test/debug.rb +0 -34
- data/lib/test/irb_mode.rb +0 -104
- data/lib/test/run/cli.rb +0 -79
- data/lib/test/run/interactive.rb +0 -60
- data/lib/test/run/tap.rb +0 -32
- data/lib/test/run/xml.rb +0 -56
- data/lib/test/suite.rb +0 -95
- data/lib/test.rb +0 -118
- data/test/lib/test/assertion.rb +0 -142
- 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
|
@@ -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
|
9
|
+
module BareTest
|
10
10
|
class Run
|
11
|
-
|
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}
|
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
|
-
|
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["
|
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
|
9
|
+
module BareTest
|
10
10
|
class Run
|
11
|
-
|
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["
|
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
|
9
|
+
module BareTest
|
10
10
|
class Run
|
11
|
-
|
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["
|
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
|