baretest 0.1.0 → 0.2.3
Sign up to get free protection for your applications and to get access to all the features.
- 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
|