test-unit 3.2.0 → 3.3.6
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/COPYING +4 -1
- data/README.md +11 -11
- data/Rakefile +10 -1
- data/doc/text/getting-started.md +246 -0
- data/doc/text/news.md +372 -1
- data/lib/test/unit.rb +171 -157
- data/lib/test/unit/assertions.rb +187 -149
- data/lib/test/unit/attribute.rb +71 -2
- data/lib/test/unit/autorunner.rb +65 -32
- data/lib/test/unit/code-snippet-fetcher.rb +7 -7
- data/lib/test/unit/collector/load.rb +8 -13
- data/lib/test/unit/data-sets.rb +116 -0
- data/lib/test/unit/data.rb +121 -12
- data/lib/test/unit/diff.rb +11 -11
- data/lib/test/unit/fixture.rb +3 -0
- data/lib/test/unit/notification.rb +9 -7
- data/lib/test/unit/omission.rb +34 -31
- data/lib/test/unit/pending.rb +12 -11
- data/lib/test/unit/priority.rb +7 -3
- data/lib/test/unit/runner/console.rb +25 -0
- data/lib/test/unit/test-suite-creator.rb +22 -8
- data/lib/test/unit/testcase.rb +270 -182
- data/lib/test/unit/ui/console/testrunner.rb +90 -35
- data/lib/test/unit/ui/emacs/testrunner.rb +5 -5
- data/lib/test/unit/util/observable.rb +2 -2
- data/lib/test/unit/util/output.rb +5 -4
- data/lib/test/unit/util/procwrapper.rb +4 -4
- data/lib/test/unit/version.rb +1 -1
- data/test/collector/test-descendant.rb +4 -0
- data/test/collector/test-load.rb +35 -2
- data/test/collector/test_dir.rb +5 -4
- data/test/collector/test_objectspace.rb +7 -5
- data/test/test-assertions.rb +128 -101
- data/test/test-code-snippet.rb +42 -0
- data/test/test-data.rb +195 -79
- data/test/test-priority.rb +19 -8
- data/test/test-test-case.rb +111 -3
- data/test/test-test-suite.rb +1 -0
- data/test/testunit-test-util.rb +2 -0
- metadata +38 -37
@@ -3,7 +3,7 @@
|
|
3
3
|
# Author:: Nathaniel Talbott.
|
4
4
|
# Copyright::
|
5
5
|
# * Copyright (c) 2000-2003 Nathaniel Talbott. All rights reserved.
|
6
|
-
# * Copyright (c) 2008-
|
6
|
+
# * Copyright (c) 2008-2017 Kouhei Sutou <kou@clear-code.com>
|
7
7
|
# License:: Ruby license.
|
8
8
|
|
9
9
|
begin
|
@@ -47,6 +47,8 @@ module Test
|
|
47
47
|
@progress_row_max ||= guess_progress_row_max
|
48
48
|
@show_detail_immediately = @options[:show_detail_immediately]
|
49
49
|
@show_detail_immediately = true if @show_detail_immediately.nil?
|
50
|
+
@reverse_output = @options[:reverse_output]
|
51
|
+
@reverse_output = @output.tty? if @reverse_output.nil?
|
50
52
|
@already_outputted = false
|
51
53
|
@indent = 0
|
52
54
|
@top_level = true
|
@@ -110,8 +112,10 @@ module Test
|
|
110
112
|
end
|
111
113
|
|
112
114
|
def finished(elapsed_time)
|
113
|
-
|
114
|
-
|
115
|
+
unless @show_detail_immediately
|
116
|
+
nl if output?(NORMAL) and !output?(VERBOSE)
|
117
|
+
output_faults
|
118
|
+
end
|
115
119
|
nl(PROGRESS_ONLY)
|
116
120
|
change_output_level(IMPORTANT_FAULTS_ONLY) do
|
117
121
|
output_statistics(elapsed_time)
|
@@ -178,22 +182,31 @@ module Test
|
|
178
182
|
|
179
183
|
def output_fault_in_detail(fault)
|
180
184
|
if fault.is_a?(Failure) and
|
181
|
-
fault.inspected_expected and
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
185
|
+
fault.inspected_expected and
|
186
|
+
fault.inspected_actual
|
187
|
+
if @reverse_output
|
188
|
+
output_fault_backtrace(fault)
|
189
|
+
output_failure_message(fault)
|
190
|
+
output_single("#{fault.label}: ")
|
191
|
+
output(fault.test_name, fault_color(fault))
|
192
|
+
else
|
193
|
+
output_single("#{fault.label}: ")
|
194
|
+
output(fault.test_name, fault_color(fault))
|
195
|
+
output_fault_backtrace(fault)
|
196
|
+
output_failure_message(fault)
|
197
|
+
end
|
186
198
|
else
|
187
|
-
if
|
199
|
+
if @reverse_output
|
200
|
+
output_fault_backtrace(fault)
|
188
201
|
output_single("#{fault.label}: ")
|
189
202
|
output_single(fault.test_name, fault_color(fault))
|
190
203
|
output_fault_message(fault)
|
191
204
|
else
|
192
|
-
output_single(fault.label
|
205
|
+
output_single("#{fault.label}: ")
|
206
|
+
output_single(fault.test_name, fault_color(fault))
|
193
207
|
output_fault_message(fault)
|
194
|
-
|
208
|
+
output_fault_backtrace(fault)
|
195
209
|
end
|
196
|
-
output_fault_backtrace(fault)
|
197
210
|
end
|
198
211
|
end
|
199
212
|
|
@@ -212,26 +225,47 @@ module Test
|
|
212
225
|
end
|
213
226
|
|
214
227
|
def output_fault_backtrace(fault)
|
215
|
-
snippet_is_shown = false
|
216
228
|
detector = FaultLocationDetector.new(fault, @code_snippet_fetcher)
|
217
229
|
backtrace = fault.location
|
218
230
|
# workaround for test-spec. :<
|
219
231
|
# see also GitHub:#22
|
220
232
|
backtrace ||= []
|
233
|
+
|
234
|
+
code_snippet_backtrace_index = nil
|
235
|
+
code_snippet_lines = nil
|
221
236
|
backtrace.each_with_index do |entry, i|
|
222
|
-
output(entry)
|
223
|
-
next if snippet_is_shown
|
224
237
|
next unless detector.target?(entry)
|
225
238
|
file, line_number, = detector.split_backtrace_entry(entry)
|
226
|
-
|
227
|
-
|
239
|
+
lines = fetch_code_snippet(file, line_number)
|
240
|
+
unless lines.empty?
|
241
|
+
code_snippet_backtrace_index = i
|
242
|
+
code_snippet_lines = lines
|
243
|
+
break
|
244
|
+
end
|
245
|
+
end
|
246
|
+
|
247
|
+
if @reverse_output
|
248
|
+
backtrace.each_with_index.reverse_each do |entry, i|
|
249
|
+
if i == code_snippet_backtrace_index
|
250
|
+
output_code_snippet(code_snippet_lines, fault_color(fault))
|
251
|
+
end
|
252
|
+
output(entry)
|
253
|
+
end
|
254
|
+
else
|
255
|
+
backtrace.each_with_index do |entry, i|
|
256
|
+
output(entry)
|
257
|
+
if i == code_snippet_backtrace_index
|
258
|
+
output_code_snippet(code_snippet_lines, fault_color(fault))
|
259
|
+
end
|
260
|
+
end
|
228
261
|
end
|
229
262
|
end
|
230
263
|
|
231
|
-
def
|
232
|
-
|
233
|
-
|
264
|
+
def fetch_code_snippet(file, line_number)
|
265
|
+
@code_snippet_fetcher.fetch(file, line_number)
|
266
|
+
end
|
234
267
|
|
268
|
+
def output_code_snippet(lines, target_line_color=nil)
|
235
269
|
max_n = lines.collect {|n, line, attributes| n}.max
|
236
270
|
digits = (Math.log10(max_n) + 1).truncate
|
237
271
|
lines.each do |n, line, attributes|
|
@@ -245,7 +279,6 @@ module Test
|
|
245
279
|
output(" %2s %*d: %s" % [current_line_mark, digits, n, line],
|
246
280
|
line_color)
|
247
281
|
end
|
248
|
-
true
|
249
282
|
end
|
250
283
|
|
251
284
|
def output_failure_message(failure)
|
@@ -303,9 +336,17 @@ module Test
|
|
303
336
|
end
|
304
337
|
|
305
338
|
def output_fault_in_short(fault)
|
306
|
-
|
307
|
-
|
308
|
-
|
339
|
+
if @reverse_output
|
340
|
+
output(fault.location.first)
|
341
|
+
output_single("#{fault.label}: ")
|
342
|
+
output_single(fault.message, fault_color(fault))
|
343
|
+
output(" [#{fault.test_name}]")
|
344
|
+
else
|
345
|
+
output_single("#{fault.label}: ")
|
346
|
+
output_single(fault.message, fault_color(fault))
|
347
|
+
output(" [#{fault.test_name}]")
|
348
|
+
output(fault.location.first)
|
349
|
+
end
|
309
350
|
end
|
310
351
|
|
311
352
|
def format_fault(fault)
|
@@ -330,24 +371,34 @@ module Test
|
|
330
371
|
end
|
331
372
|
|
332
373
|
def output_summary_marker
|
333
|
-
|
334
|
-
|
335
|
-
marker_width = 6
|
374
|
+
if @progress_row_max > 0
|
375
|
+
output("-" * @progress_row_max, summary_marker_color)
|
336
376
|
else
|
337
|
-
|
377
|
+
nl
|
338
378
|
end
|
339
|
-
output("-" * marker_width, summary_marker_color)
|
340
379
|
end
|
341
380
|
|
342
381
|
def test_started(test)
|
343
382
|
return unless output?(VERBOSE)
|
344
383
|
|
345
|
-
|
346
|
-
|
384
|
+
tab_width = 8
|
385
|
+
name = test.local_name
|
386
|
+
separator = ":"
|
387
|
+
left_used = indent.size + name.size + separator.size
|
388
|
+
right_space = tab_width * 2
|
347
389
|
left_space = @progress_row_max - right_space
|
348
|
-
|
349
|
-
|
350
|
-
|
390
|
+
if (left_used % tab_width).zero?
|
391
|
+
left_space -= left_used
|
392
|
+
n_tabs = 0
|
393
|
+
else
|
394
|
+
left_space -= ((left_used / tab_width) + 1) * tab_width
|
395
|
+
n_tabs = 1
|
396
|
+
end
|
397
|
+
n_tabs += [left_space, 0].max / tab_width
|
398
|
+
tab_stop = "\t" * n_tabs
|
399
|
+
output_single("#{indent}#{name}#{separator}#{tab_stop}",
|
400
|
+
nil,
|
401
|
+
VERBOSE)
|
351
402
|
@test_start = Time.now
|
352
403
|
end
|
353
404
|
|
@@ -473,8 +524,12 @@ module Test
|
|
473
524
|
fault_class.name.split(/::/).last.downcase
|
474
525
|
end
|
475
526
|
|
527
|
+
def fault_class_color(fault_class)
|
528
|
+
color(fault_class_color_name(fault_class))
|
529
|
+
end
|
530
|
+
|
476
531
|
def fault_color(fault)
|
477
|
-
|
532
|
+
fault_class_color(fault.class)
|
478
533
|
end
|
479
534
|
|
480
535
|
def fault_marker_color(fault)
|
@@ -30,16 +30,16 @@ module Test
|
|
30
30
|
location_display = "\n" + failure.location.join("\n")
|
31
31
|
end
|
32
32
|
result = "#{failure.label}:\n"
|
33
|
-
result
|
34
|
-
result
|
33
|
+
result += "#{failure.test_name}#{location_display}:\n"
|
34
|
+
result += failure.message
|
35
35
|
result
|
36
36
|
end
|
37
37
|
|
38
38
|
def format_fault_error(error)
|
39
39
|
result = "#{error.label}:\n"
|
40
|
-
result
|
41
|
-
result
|
42
|
-
result
|
40
|
+
result += "#{error.test_name}:\n"
|
41
|
+
result += "#{error.message}\n"
|
42
|
+
result += error.backtrace.join("\n")
|
43
43
|
result
|
44
44
|
end
|
45
45
|
end
|
@@ -26,8 +26,8 @@ module Test
|
|
26
26
|
# returned, making it very easy to use the proc
|
27
27
|
# itself as the listener_key:
|
28
28
|
#
|
29
|
-
#
|
30
|
-
#
|
29
|
+
# listener = add_listener("Channel") { ... }
|
30
|
+
# remove_listener("Channel", listener)
|
31
31
|
def add_listener(channel_name, listener_key=NOTHING, &listener) # :yields: value
|
32
32
|
unless(block_given?)
|
33
33
|
raise ArgumentError.new("No callback was passed as a listener")
|
@@ -7,10 +7,11 @@ module Test
|
|
7
7
|
# error as string.
|
8
8
|
#
|
9
9
|
# Example:
|
10
|
-
#
|
11
|
-
#
|
12
|
-
#
|
13
|
-
#
|
10
|
+
#
|
11
|
+
# capture_output do
|
12
|
+
# puts("stdout")
|
13
|
+
# warn("stderr")
|
14
|
+
# end # -> ["stdout\n", "stderr\n"]
|
14
15
|
def capture_output
|
15
16
|
require 'stringio'
|
16
17
|
|
data/lib/test/unit/version.rb
CHANGED
@@ -31,6 +31,8 @@ class TestUnitCollectorDescendant < Test::Unit::TestCase
|
|
31
31
|
super
|
32
32
|
|
33
33
|
@test_case1 = Class.new(Test::Unit::TestCase) do
|
34
|
+
self.test_order = :alphabetic
|
35
|
+
|
34
36
|
def self.name
|
35
37
|
"test-case1"
|
36
38
|
end
|
@@ -43,6 +45,8 @@ class TestUnitCollectorDescendant < Test::Unit::TestCase
|
|
43
45
|
end
|
44
46
|
|
45
47
|
@test_case2 = Class.new(Test::Unit::TestCase) do
|
48
|
+
self.test_order = :alphabetic
|
49
|
+
|
46
50
|
def self.name
|
47
51
|
"test-case2"
|
48
52
|
end
|
data/test/collector/test-load.rb
CHANGED
@@ -20,7 +20,9 @@ class TestUnitCollectorLoad < Test::Unit::TestCase
|
|
20
20
|
|
21
21
|
setup
|
22
22
|
def setup_top_level_test_cases
|
23
|
-
@
|
23
|
+
@test_case1_base_name = "test_case1.rb"
|
24
|
+
|
25
|
+
@test_case1 = @test_dir + @test_case1_base_name
|
24
26
|
@test_case2 = @test_dir + "test_case2.rb"
|
25
27
|
@no_load_test_case3 = @test_dir + "case3.rb"
|
26
28
|
|
@@ -66,10 +68,25 @@ EOT
|
|
66
68
|
@sub_test_dir = @test_dir + "sub"
|
67
69
|
@sub_test_dir.mkpath
|
68
70
|
|
71
|
+
@sub_test_case1 = @sub_test_dir + @test_case1_base_name
|
69
72
|
@sub_test_case4 = @sub_test_dir + "test_case4.rb"
|
70
73
|
@no_load_sub_test_case5 = @sub_test_dir + "case5.rb"
|
71
74
|
@sub_test_case6 = @sub_test_dir + "test_case6.rb"
|
72
75
|
|
76
|
+
@sub_test_case1.open("w") do |test_case|
|
77
|
+
test_case.puts(<<-TEST_CASE)
|
78
|
+
module #{@temporary_test_cases_module_name}
|
79
|
+
class SubTestCase1 < Test::Unit::TestCase
|
80
|
+
def test1_1
|
81
|
+
end
|
82
|
+
|
83
|
+
def test1_2
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
TEST_CASE
|
88
|
+
end
|
89
|
+
|
73
90
|
@sub_test_case4.open("w") do |test_case|
|
74
91
|
test_case.puts(<<-EOT)
|
75
92
|
module #{@temporary_test_cases_module_name}
|
@@ -271,6 +288,9 @@ EOT
|
|
271
288
|
|
272
289
|
def test_simple_collect
|
273
290
|
assert_collect([:suite, {:name => @sub_test_dir.basename.to_s},
|
291
|
+
[:suite, {:name => _test_case_name("SubTestCase1")},
|
292
|
+
[:test, {:name => "test1_1"}],
|
293
|
+
[:test, {:name => "test1_2"}]],
|
274
294
|
[:suite, {:name => _test_case_name("SubTestCase4")},
|
275
295
|
[:test, {:name => "test4_1"}],
|
276
296
|
[:test, {:name => "test4_2"}]],
|
@@ -302,6 +322,9 @@ EOT
|
|
302
322
|
[:suite, {:name => _test_case_name("TestCase2")},
|
303
323
|
[:test, {:name => "test2"}]],
|
304
324
|
[:suite, {:name => @sub_test_dir.basename.to_s},
|
325
|
+
[:suite, {:name => _test_case_name("SubTestCase1")},
|
326
|
+
[:test, {:name => "test1_1"}],
|
327
|
+
[:test, {:name => "test1_2"}]],
|
305
328
|
[:suite, {:name => _test_case_name("SubTestCase4")},
|
306
329
|
[:test, {:name => "test4_1"}],
|
307
330
|
[:test, {:name => "test4_2"}]],
|
@@ -356,6 +379,9 @@ EOT
|
|
356
379
|
[:suite, {:name => _test_case_name("NoLoadSubTestCase5")},
|
357
380
|
[:test, {:name => "test5_1"}],
|
358
381
|
[:test, {:name => "test5_2"}]],
|
382
|
+
[:suite, {:name => _test_case_name("SubTestCase1")},
|
383
|
+
[:test, {:name => "test1_1"}],
|
384
|
+
[:test, {:name => "test1_2"}]],
|
359
385
|
[:suite, {:name => _test_case_name("SubTestCase4")},
|
360
386
|
[:test, {:name => "test4_1"}],
|
361
387
|
[:test, {:name => "test4_2"}]],
|
@@ -370,7 +396,11 @@ EOT
|
|
370
396
|
assert_collect([:suite, {:name => "."},
|
371
397
|
[:suite, {:name => _test_case_name("TestCase1")},
|
372
398
|
[:test, {:name => "test1_1"}],
|
373
|
-
[:test, {:name => "test1_2"}]]
|
399
|
+
[:test, {:name => "test1_2"}]],
|
400
|
+
[:suite, {:name => @sub_test_dir.basename.to_s},
|
401
|
+
[:suite, {:name => _test_case_name("SubTestCase1")},
|
402
|
+
[:test, {:name => "test1_1"}],
|
403
|
+
[:test, {:name => "test1_2"}]]]]) do |collector|
|
374
404
|
collector.filter = Proc.new do |test|
|
375
405
|
!/\Atest1/.match(test.method_name).nil?
|
376
406
|
end
|
@@ -381,6 +411,9 @@ EOT
|
|
381
411
|
test_dirs = [@sub_test_dir.to_s, @sub2_test_dir.to_s]
|
382
412
|
assert_collect([:suite, {:name => "[#{test_dirs.join(', ')}]"},
|
383
413
|
[:suite, {:name => @sub_test_dir.basename.to_s},
|
414
|
+
[:suite, {:name => _test_case_name("SubTestCase1")},
|
415
|
+
[:test, {:name => "test1_1"}],
|
416
|
+
[:test, {:name => "test1_2"}]],
|
384
417
|
[:suite, {:name => _test_case_name("SubTestCase4")},
|
385
418
|
[:test, {:name => "test4_1"}],
|
386
419
|
[:test, {:name => "test4_2"}]],
|
data/test/collector/test_dir.rb
CHANGED
@@ -15,7 +15,7 @@ module Test
|
|
15
15
|
@contents = {'.' => self, '..' => parent}
|
16
16
|
instance_eval(&block) if(block)
|
17
17
|
end
|
18
|
-
|
18
|
+
|
19
19
|
def file(name, contents)
|
20
20
|
@contents[name] = contents
|
21
21
|
end
|
@@ -74,7 +74,7 @@ module Test
|
|
74
74
|
end
|
75
75
|
|
76
76
|
attr_reader :object_space
|
77
|
-
|
77
|
+
|
78
78
|
def initialize(&block)
|
79
79
|
@root = Directory.new('/', self, &block)
|
80
80
|
@pwd = @root
|
@@ -295,7 +295,7 @@ module Test
|
|
295
295
|
assert_raises(LoadError) do
|
296
296
|
fs.require('bogus')
|
297
297
|
end
|
298
|
-
|
298
|
+
|
299
299
|
assert(fs.require('test_class1.rb'))
|
300
300
|
assert(!fs.require('test_class1.rb'))
|
301
301
|
c = []
|
@@ -345,6 +345,7 @@ module Test
|
|
345
345
|
def create_test(name)
|
346
346
|
t = Class.new(TestCase)
|
347
347
|
t.class_eval <<-EOC
|
348
|
+
self.test_order = :alphabetic
|
348
349
|
def self.name
|
349
350
|
"T\#{#{name}}"
|
350
351
|
end
|
@@ -373,7 +374,7 @@ module Test
|
|
373
374
|
expected = TestSuite.new('test_1.rb')
|
374
375
|
expected << @t1.suite
|
375
376
|
assert_equal(expected, @c.collect('test_1.rb'))
|
376
|
-
|
377
|
+
|
377
378
|
expected = TestSuite.new('t4.rb')
|
378
379
|
expected << @t4.suite
|
379
380
|
assert_equal(expected, @c.collect('t4.rb'))
|
@@ -11,6 +11,7 @@ module Test
|
|
11
11
|
class TC_ObjectSpace < TestCase
|
12
12
|
def setup
|
13
13
|
@tc1 = Class.new(TestCase) do
|
14
|
+
self.test_order = :alphabetic
|
14
15
|
def self.name
|
15
16
|
"tc_1"
|
16
17
|
end
|
@@ -21,6 +22,7 @@ module Test
|
|
21
22
|
end
|
22
23
|
|
23
24
|
@tc2 = Class.new(TestCase) do
|
25
|
+
self.test_order = :alphabetic
|
24
26
|
def self.name
|
25
27
|
"tc_2"
|
26
28
|
end
|
@@ -32,7 +34,7 @@ module Test
|
|
32
34
|
def test_4
|
33
35
|
end
|
34
36
|
end
|
35
|
-
|
37
|
+
|
36
38
|
@object_space = {Class => [@tc1, @tc2, @no_tc], String => ['']}
|
37
39
|
def @object_space.each_object(type)
|
38
40
|
self[type].each{|item| yield(item) }
|
@@ -50,14 +52,14 @@ module Test
|
|
50
52
|
def empty_suite
|
51
53
|
TestSuite.new(ObjectSpace::NAME)
|
52
54
|
end
|
53
|
-
|
55
|
+
|
54
56
|
def test_basic_collection
|
55
57
|
assert_equal(full_suite("name"), @c.collect("name"))
|
56
58
|
|
57
59
|
@c.filter = []
|
58
60
|
assert_equal(full_suite("name"), @c.collect("name"))
|
59
61
|
end
|
60
|
-
|
62
|
+
|
61
63
|
def test_filtered_collection
|
62
64
|
@c.filter = proc{false}
|
63
65
|
assert_equal(empty_suite, @c.collect)
|
@@ -76,10 +78,10 @@ module Test
|
|
76
78
|
|
77
79
|
@c.filter = [proc{nil}, proc{false}]
|
78
80
|
assert_equal(empty_suite, @c.collect)
|
79
|
-
|
81
|
+
|
80
82
|
@c.filter = [proc{nil}, proc{true}]
|
81
83
|
assert_equal(full_suite, @c.collect)
|
82
|
-
|
84
|
+
|
83
85
|
expected = TestSuite.new(ObjectSpace::NAME)
|
84
86
|
expected << (TestSuite.new(@tc1.name) << @tc1.new('test_1'))
|
85
87
|
expected << (TestSuite.new(@tc2.name) << @tc2.new('test_0'))
|