test-unit 2.0.3 → 2.0.4
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/History.txt +22 -0
- data/Manifest.txt +5 -3
- data/README.txt +2 -1
- data/images/color-diff.png +0 -0
- data/lib/test/unit.rb +20 -40
- data/lib/test/unit/assertionfailederror.rb +11 -0
- data/lib/test/unit/assertions.rb +30 -9
- data/lib/test/unit/autorunner.rb +32 -6
- data/lib/test/unit/collector/load.rb +3 -1
- data/lib/test/unit/color-scheme.rb +17 -1
- data/lib/test/unit/diff.rb +221 -37
- data/lib/test/unit/error.rb +7 -5
- data/lib/test/unit/failure.rb +27 -5
- data/lib/test/unit/runner/tap.rb +8 -0
- data/lib/test/unit/ui/console/testrunner.rb +251 -10
- data/lib/test/unit/ui/emacs/testrunner.rb +14 -0
- data/lib/test/unit/ui/tap/testrunner.rb +92 -0
- data/lib/test/unit/ui/testrunner.rb +8 -0
- data/lib/test/unit/version.rb +1 -1
- data/sample/{tc_adder.rb → test_adder.rb} +3 -1
- data/sample/{tc_subtracter.rb → test_subtracter.rb} +3 -1
- data/sample/test_user.rb +1 -0
- data/test/collector/test-load.rb +1 -5
- data/test/run-test.rb +2 -0
- data/test/test-color-scheme.rb +11 -0
- data/test/test-diff.rb +33 -7
- data/test/test_assertions.rb +8 -10
- metadata +15 -13
- data/sample/ts_examples.rb +0 -7
data/lib/test/unit/error.rb
CHANGED
@@ -69,18 +69,20 @@ module Test
|
|
69
69
|
end
|
70
70
|
end
|
71
71
|
|
72
|
+
NOT_PASS_THROUGH_EXCEPTIONS = []
|
72
73
|
PASS_THROUGH_EXCEPTIONS = [NoMemoryError, SignalException, Interrupt,
|
73
74
|
SystemExit]
|
74
75
|
private
|
75
76
|
def handle_all_exception(exception)
|
76
77
|
case exception
|
78
|
+
when *NOT_PASS_THROUGH_EXCEPTIONS
|
77
79
|
when *PASS_THROUGH_EXCEPTIONS
|
78
|
-
false
|
79
|
-
else
|
80
|
-
problem_occurred
|
81
|
-
add_error(exception)
|
82
|
-
true
|
80
|
+
return false
|
83
81
|
end
|
82
|
+
|
83
|
+
problem_occurred
|
84
|
+
add_error(exception)
|
85
|
+
true
|
84
86
|
end
|
85
87
|
|
86
88
|
def add_error(exception)
|
data/lib/test/unit/failure.rb
CHANGED
@@ -11,16 +11,23 @@ module Test
|
|
11
11
|
# when an assertion fails.
|
12
12
|
class Failure
|
13
13
|
attr_reader :test_name, :location, :message
|
14
|
-
|
14
|
+
attr_reader :expected, :actual, :user_message
|
15
|
+
attr_reader :inspected_expected, :inspected_actual
|
16
|
+
|
15
17
|
SINGLE_CHARACTER = 'F'
|
16
18
|
LABEL = "Failure"
|
17
19
|
|
18
20
|
# Creates a new Failure with the given location and
|
19
21
|
# message.
|
20
|
-
def initialize(test_name, location, message)
|
22
|
+
def initialize(test_name, location, message, options={})
|
21
23
|
@test_name = test_name
|
22
24
|
@location = location
|
23
25
|
@message = message
|
26
|
+
@expected = options[:expected]
|
27
|
+
@actual = options[:actual]
|
28
|
+
@inspected_expected = options[:inspected_expected]
|
29
|
+
@inspected_actual = options[:inspected_actual]
|
30
|
+
@user_message = options[:user_message]
|
24
31
|
end
|
25
32
|
|
26
33
|
# Returns a single character representation of a failure.
|
@@ -51,6 +58,15 @@ module Test
|
|
51
58
|
def to_s
|
52
59
|
long_display
|
53
60
|
end
|
61
|
+
|
62
|
+
def diff
|
63
|
+
@diff ||= compute_diff
|
64
|
+
end
|
65
|
+
|
66
|
+
private
|
67
|
+
def compute_diff
|
68
|
+
Assertions::AssertionMessage.delayed_diff(@expected, @actual).inspect
|
69
|
+
end
|
54
70
|
end
|
55
71
|
|
56
72
|
module FailureHandler
|
@@ -64,12 +80,18 @@ module Test
|
|
64
80
|
def handle_assertion_failed_error(exception)
|
65
81
|
return false unless exception.is_a?(AssertionFailedError)
|
66
82
|
problem_occurred
|
67
|
-
add_failure(exception.message, exception.backtrace
|
83
|
+
add_failure(exception.message, exception.backtrace,
|
84
|
+
:expected => exception.expected,
|
85
|
+
:actual => exception.actual,
|
86
|
+
:inspected_expected => exception.inspected_expected,
|
87
|
+
:inspected_actual => exception.inspected_actual,
|
88
|
+
:user_message => exception.user_message)
|
68
89
|
true
|
69
90
|
end
|
70
91
|
|
71
|
-
def add_failure(message, backtrace)
|
72
|
-
failure = Failure.new(name, filter_backtrace(backtrace), message
|
92
|
+
def add_failure(message, backtrace, options={})
|
93
|
+
failure = Failure.new(name, filter_backtrace(backtrace), message,
|
94
|
+
options)
|
73
95
|
current_result.add_failure(failure)
|
74
96
|
end
|
75
97
|
end
|
@@ -1,7 +1,9 @@
|
|
1
1
|
#--
|
2
2
|
#
|
3
3
|
# Author:: Nathaniel Talbott.
|
4
|
-
# Copyright::
|
4
|
+
# Copyright::
|
5
|
+
# * Copyright (c) 2000-2003 Nathaniel Talbott. All rights reserved.
|
6
|
+
# * Copyright (c) 2008-2009 Kouhei Sutou <kou@clear-code.com>
|
5
7
|
# License:: Ruby license.
|
6
8
|
|
7
9
|
require 'test/unit/color-scheme'
|
@@ -36,6 +38,9 @@ module Test
|
|
36
38
|
@progress_row_max = @options[:progress_row_max]
|
37
39
|
@progress_row_max ||= guess_progress_row_max
|
38
40
|
@already_outputted = false
|
41
|
+
@n_successes = 0
|
42
|
+
@indent = 0
|
43
|
+
@top_level = true
|
39
44
|
@faults = []
|
40
45
|
end
|
41
46
|
|
@@ -68,6 +73,8 @@ module Test
|
|
68
73
|
@mediator.add_listener(TestRunnerMediator::FINISHED, &method(:finished))
|
69
74
|
@mediator.add_listener(TestCase::STARTED, &method(:test_started))
|
70
75
|
@mediator.add_listener(TestCase::FINISHED, &method(:test_finished))
|
76
|
+
@mediator.add_listener(TestSuite::STARTED, &method(:test_suite_started))
|
77
|
+
@mediator.add_listener(TestSuite::FINISHED, &method(:test_suite_finished))
|
71
78
|
end
|
72
79
|
|
73
80
|
def start_mediator
|
@@ -91,35 +98,140 @@ module Test
|
|
91
98
|
|
92
99
|
def finished(elapsed_time)
|
93
100
|
nl if output?(NORMAL) and !output?(VERBOSE)
|
94
|
-
nl
|
95
|
-
output("Finished in #{elapsed_time} seconds.")
|
96
101
|
@faults.each_with_index do |fault, index|
|
97
102
|
nl
|
98
103
|
output_single("%3d) " % (index + 1))
|
104
|
+
output_fault(fault)
|
105
|
+
end
|
106
|
+
nl
|
107
|
+
output("Finished in #{elapsed_time} seconds.")
|
108
|
+
nl
|
109
|
+
output(@result, result_color)
|
110
|
+
n_tests = @result.run_count
|
111
|
+
if n_tests.zero?
|
112
|
+
pass_percentage = 0
|
113
|
+
else
|
114
|
+
pass_percentage = 100.0 * (@n_successes / n_tests.to_f)
|
115
|
+
end
|
116
|
+
output("%g%% passed" % pass_percentage, result_color)
|
117
|
+
end
|
118
|
+
|
119
|
+
def output_fault(fault)
|
120
|
+
if @use_color and fault.is_a?(Failure) and
|
121
|
+
fault.inspected_expected and fault.inspected_actual
|
122
|
+
output_single(fault.label, fault_color(fault))
|
123
|
+
output(":")
|
124
|
+
output_fault_backtrace(fault)
|
125
|
+
output_fault_message(fault)
|
126
|
+
else
|
99
127
|
label, detail = format_fault(fault).split(/\r?\n/, 2)
|
100
128
|
output(label, fault_color(fault))
|
101
129
|
output(detail)
|
102
130
|
end
|
103
|
-
|
104
|
-
|
131
|
+
end
|
132
|
+
|
133
|
+
def output_fault_backtrace(fault)
|
134
|
+
backtrace = fault.location
|
135
|
+
if backtrace.size == 1
|
136
|
+
output(fault.test_name +
|
137
|
+
backtrace[0].sub(/\A(.+:\d+).*/, ' [\\1]') +
|
138
|
+
":")
|
139
|
+
else
|
140
|
+
output(fault.test_name)
|
141
|
+
backtrace.each_with_index do |entry, i|
|
142
|
+
if i.zero?
|
143
|
+
prefix = "["
|
144
|
+
postfix = ""
|
145
|
+
elsif i == backtrace.size - 1
|
146
|
+
prefix = " "
|
147
|
+
postfix = "]:"
|
148
|
+
else
|
149
|
+
prefix = " "
|
150
|
+
postfix = ""
|
151
|
+
end
|
152
|
+
output(" #{prefix}#{entry}#{postfix}")
|
153
|
+
end
|
154
|
+
end
|
155
|
+
end
|
156
|
+
|
157
|
+
def output_fault_message(fault)
|
158
|
+
output(fault.user_message) if fault.user_message
|
159
|
+
output_single("<")
|
160
|
+
output_single(fault.inspected_expected, color("success"))
|
161
|
+
output("> expected but was")
|
162
|
+
output_single("<")
|
163
|
+
output_single(fault.inspected_actual, color("failure"))
|
164
|
+
output(">")
|
165
|
+
from, to = prepare_for_diff(fault.expected, fault.actual)
|
166
|
+
if from and to
|
167
|
+
differ = ColorizedReadableDiffer.new(from.split(/\r?\n/),
|
168
|
+
to.split(/\r?\n/),
|
169
|
+
self)
|
170
|
+
if differ.need_diff?
|
171
|
+
output("")
|
172
|
+
output("diff:")
|
173
|
+
differ.diff
|
174
|
+
end
|
175
|
+
end
|
105
176
|
end
|
106
177
|
|
107
178
|
def format_fault(fault)
|
108
179
|
fault.long_display
|
109
180
|
end
|
110
|
-
|
181
|
+
|
111
182
|
def test_started(name)
|
112
|
-
|
183
|
+
return unless output?(VERBOSE)
|
184
|
+
|
185
|
+
name = name.sub(/\(.+?\)\z/, '')
|
186
|
+
right_space = 8 * 2
|
187
|
+
left_space = @progress_row_max - right_space
|
188
|
+
left_space = left_space - indent.size - name.size
|
189
|
+
tab_stop = "\t" * ((left_space - 1) / 8)
|
190
|
+
output_single("#{indent}#{name}:#{tab_stop}", nil, VERBOSE)
|
191
|
+
@test_start = Time.now
|
113
192
|
end
|
114
|
-
|
193
|
+
|
115
194
|
def test_finished(name)
|
116
195
|
unless @already_outputted
|
196
|
+
@n_successes += 1
|
117
197
|
output_progress(".", color("success"))
|
118
198
|
end
|
119
|
-
nl(VERBOSE)
|
120
199
|
@already_outputted = false
|
200
|
+
|
201
|
+
return unless output?(VERBOSE)
|
202
|
+
|
203
|
+
output(": (%f)" % (Time.now - @test_start), nil, VERBOSE)
|
121
204
|
end
|
122
|
-
|
205
|
+
|
206
|
+
def test_suite_started(name)
|
207
|
+
if @top_level
|
208
|
+
@top_level = false
|
209
|
+
return
|
210
|
+
end
|
211
|
+
|
212
|
+
output_single(indent, nil, VERBOSE)
|
213
|
+
if /\A[A-Z]/ =~ name
|
214
|
+
_color = color("case")
|
215
|
+
else
|
216
|
+
_color = color("suite")
|
217
|
+
end
|
218
|
+
output_single(name, _color, VERBOSE)
|
219
|
+
output(": ", nil, VERBOSE)
|
220
|
+
@indent += 2
|
221
|
+
end
|
222
|
+
|
223
|
+
def test_suite_finished(name)
|
224
|
+
@indent -= 2
|
225
|
+
end
|
226
|
+
|
227
|
+
def indent
|
228
|
+
if output?(VERBOSE)
|
229
|
+
" " * @indent
|
230
|
+
else
|
231
|
+
""
|
232
|
+
end
|
233
|
+
end
|
234
|
+
|
123
235
|
def nl(level=NORMAL)
|
124
236
|
output("", nil, level)
|
125
237
|
end
|
@@ -213,6 +325,135 @@ module Test
|
|
213
325
|
0
|
214
326
|
end
|
215
327
|
end
|
328
|
+
|
329
|
+
class ColorizedReadableDiffer < Diff::ReadableDiffer
|
330
|
+
def initialize(from, to, runner)
|
331
|
+
@runner = runner
|
332
|
+
super(from, to)
|
333
|
+
end
|
334
|
+
|
335
|
+
def need_diff?(options={})
|
336
|
+
operations.each do |tag,|
|
337
|
+
return true if [:replace, :equal].include?(tag)
|
338
|
+
end
|
339
|
+
false
|
340
|
+
end
|
341
|
+
|
342
|
+
private
|
343
|
+
def output_single(something, color=nil)
|
344
|
+
@runner.send(:output_single, something, color)
|
345
|
+
end
|
346
|
+
|
347
|
+
def output(something, color=nil)
|
348
|
+
@runner.send(:output, something, color)
|
349
|
+
end
|
350
|
+
|
351
|
+
def color(name)
|
352
|
+
@runner.send(:color, name)
|
353
|
+
end
|
354
|
+
|
355
|
+
def cut_off_ratio
|
356
|
+
0
|
357
|
+
end
|
358
|
+
|
359
|
+
def default_ratio
|
360
|
+
0
|
361
|
+
end
|
362
|
+
|
363
|
+
def tag(mark, color_name, contents)
|
364
|
+
_color = color(color_name)
|
365
|
+
contents.each do |content|
|
366
|
+
output_single(mark, _color)
|
367
|
+
output_single(" ")
|
368
|
+
output(content)
|
369
|
+
end
|
370
|
+
end
|
371
|
+
|
372
|
+
def tag_deleted(contents)
|
373
|
+
tag("-", "diff-deleted-tag", contents)
|
374
|
+
end
|
375
|
+
|
376
|
+
def tag_inserted(contents)
|
377
|
+
tag("+", "diff-inserted-tag", contents)
|
378
|
+
end
|
379
|
+
|
380
|
+
def tag_equal(contents)
|
381
|
+
tag(" ", "normal", contents)
|
382
|
+
end
|
383
|
+
|
384
|
+
def tag_difference(contents)
|
385
|
+
tag("?", "diff-difference-tag", contents)
|
386
|
+
end
|
387
|
+
|
388
|
+
def diff_line(from_line, to_line)
|
389
|
+
to_operations = []
|
390
|
+
from_line, to_line, _operations = line_operations(from_line, to_line)
|
391
|
+
|
392
|
+
no_replace = true
|
393
|
+
_operations.each do |tag,|
|
394
|
+
if tag == :replace
|
395
|
+
no_replace = false
|
396
|
+
break
|
397
|
+
end
|
398
|
+
end
|
399
|
+
|
400
|
+
output_single("?", color("diff-difference-tag"))
|
401
|
+
output_single(" ")
|
402
|
+
_operations.each do |tag, from_start, from_end, to_start, to_end|
|
403
|
+
from_width = compute_width(from_line, from_start, from_end)
|
404
|
+
to_width = compute_width(to_line, to_start, to_end)
|
405
|
+
case tag
|
406
|
+
when :replace
|
407
|
+
output_single(from_line[from_start...from_end],
|
408
|
+
color("diff-deleted"))
|
409
|
+
if (from_width < to_width)
|
410
|
+
output_single(" " * (to_width - from_width))
|
411
|
+
end
|
412
|
+
to_operations << Proc.new do
|
413
|
+
output_single(to_line[to_start...to_end],
|
414
|
+
color("diff-inserted"))
|
415
|
+
if (to_width < from_width)
|
416
|
+
output_single(" " * (from_width - to_width))
|
417
|
+
end
|
418
|
+
end
|
419
|
+
when :delete
|
420
|
+
output_single(from_line[from_start...from_end],
|
421
|
+
color("diff-deleted"))
|
422
|
+
unless no_replace
|
423
|
+
to_operations << Proc.new {output_single(" " * from_width)}
|
424
|
+
end
|
425
|
+
when :insert
|
426
|
+
if no_replace
|
427
|
+
output_single(to_line[to_start...to_end],
|
428
|
+
color("diff-inserted"))
|
429
|
+
else
|
430
|
+
output_single(" " * to_width)
|
431
|
+
to_operations << Proc.new do
|
432
|
+
output_single(to_line[to_start...to_end],
|
433
|
+
color("diff-inserted"))
|
434
|
+
end
|
435
|
+
end
|
436
|
+
when :equal
|
437
|
+
output_single(from_line[from_start...from_end])
|
438
|
+
unless no_replace
|
439
|
+
to_operations << Proc.new {output_single(" " * to_width)}
|
440
|
+
end
|
441
|
+
else
|
442
|
+
raise "unknown tag: #{tag}"
|
443
|
+
end
|
444
|
+
end
|
445
|
+
output("")
|
446
|
+
|
447
|
+
unless to_operations.empty?
|
448
|
+
output_single("?", color("diff-difference-tag"))
|
449
|
+
output_single(" ")
|
450
|
+
to_operations.each do |operation|
|
451
|
+
operation.call
|
452
|
+
end
|
453
|
+
output("")
|
454
|
+
end
|
455
|
+
end
|
456
|
+
end
|
216
457
|
end
|
217
458
|
end
|
218
459
|
end
|
@@ -22,6 +22,20 @@ module Test
|
|
22
22
|
end
|
23
23
|
end
|
24
24
|
|
25
|
+
def output_fault_backtrace(fault)
|
26
|
+
backtrace = fault.location
|
27
|
+
if backtrace.size == 1
|
28
|
+
output(fault.test_name +
|
29
|
+
backtrace[0].sub(/\A(.+:\d+).*/, ' [\\1]') +
|
30
|
+
":")
|
31
|
+
else
|
32
|
+
output(fault.test_name)
|
33
|
+
backtrace.each do |entry|
|
34
|
+
output(entry)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
25
39
|
def format_fault_failure(failure)
|
26
40
|
if failure.location.size == 1
|
27
41
|
location = failure.location[0]
|
@@ -0,0 +1,92 @@
|
|
1
|
+
#--
|
2
|
+
#
|
3
|
+
# Author:: Kouhei Sutou.
|
4
|
+
# Copyright:: Copyright (c) 2009 Kouhei Sutou <kou@clear-code.com>.
|
5
|
+
# License:: Ruby license.
|
6
|
+
|
7
|
+
require 'test/unit/ui/testrunner'
|
8
|
+
require 'test/unit/ui/testrunnermediator'
|
9
|
+
|
10
|
+
module Test
|
11
|
+
module Unit
|
12
|
+
module UI
|
13
|
+
module Tap
|
14
|
+
|
15
|
+
# Runs a Test::Unit::TestSuite and outputs result
|
16
|
+
# as TAP format.
|
17
|
+
class TestRunner < UI::TestRunner
|
18
|
+
def initialize(suite, options={})
|
19
|
+
super
|
20
|
+
@output = @options[:output] || STDOUT
|
21
|
+
@n_tests = 0
|
22
|
+
@already_outputted = false
|
23
|
+
end
|
24
|
+
|
25
|
+
# Begins the test run.
|
26
|
+
def start
|
27
|
+
setup_mediator
|
28
|
+
result = start_mediator
|
29
|
+
def result.passed?
|
30
|
+
true # for prove commend :<
|
31
|
+
end
|
32
|
+
result
|
33
|
+
end
|
34
|
+
|
35
|
+
private
|
36
|
+
def setup_mediator
|
37
|
+
@mediator = TestRunnerMediator.new(@suite)
|
38
|
+
attach_to_mediator
|
39
|
+
end
|
40
|
+
|
41
|
+
def attach_to_mediator
|
42
|
+
@mediator.add_listener(TestResult::FAULT, &method(:add_fault))
|
43
|
+
@mediator.add_listener(TestRunnerMediator::STARTED, &method(:started))
|
44
|
+
@mediator.add_listener(TestRunnerMediator::FINISHED, &method(:finished))
|
45
|
+
@mediator.add_listener(TestCase::STARTED, &method(:test_started))
|
46
|
+
@mediator.add_listener(TestCase::FINISHED, &method(:test_finished))
|
47
|
+
end
|
48
|
+
|
49
|
+
def start_mediator
|
50
|
+
@mediator.run_suite
|
51
|
+
end
|
52
|
+
|
53
|
+
def add_fault(fault)
|
54
|
+
puts("not ok #{@n_tests} - #{fault.short_display}")
|
55
|
+
fault.long_display.each_line do |line|
|
56
|
+
puts("# #{line}")
|
57
|
+
end
|
58
|
+
@already_outputted = true
|
59
|
+
end
|
60
|
+
|
61
|
+
def started(result)
|
62
|
+
@result = result
|
63
|
+
puts("1..#{@suite.size}")
|
64
|
+
end
|
65
|
+
|
66
|
+
def finished(elapsed_time)
|
67
|
+
puts("# Finished in #{elapsed_time} seconds.")
|
68
|
+
@result.to_s.each_line do |line|
|
69
|
+
puts("# #{line}")
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
def test_started(name)
|
74
|
+
@n_tests += 1
|
75
|
+
end
|
76
|
+
|
77
|
+
def test_finished(name)
|
78
|
+
unless @already_outputted
|
79
|
+
puts("ok #{@n_tests} - #{name}")
|
80
|
+
end
|
81
|
+
@already_outputted = false
|
82
|
+
end
|
83
|
+
|
84
|
+
def puts(*args)
|
85
|
+
@output.puts(*args)
|
86
|
+
@output.flush
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|