test-unit 2.0.3 → 2.0.4

Sign up to get free protection for your applications and to get access to all the features.
@@ -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)
@@ -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
@@ -0,0 +1,8 @@
1
+ module Test
2
+ module Unit
3
+ AutoRunner.register_runner(:tap) do |auto_runner|
4
+ require 'test/unit/ui/tap/testrunner'
5
+ Test::Unit::UI::Tap::TestRunner
6
+ end
7
+ end
8
+ end
@@ -1,7 +1,9 @@
1
1
  #--
2
2
  #
3
3
  # Author:: Nathaniel Talbott.
4
- # Copyright:: Copyright (c) 2000-2003 Nathaniel Talbott. All rights reserved.
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
- nl
104
- output(@result, result_color)
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
- output_single(name + ": ", nil, VERBOSE)
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