test-unit 3.2.9 → 3.5.5

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.
Files changed (80) hide show
  1. checksums.yaml +4 -4
  2. data/BSDL +24 -0
  3. data/COPYING +41 -44
  4. data/README.md +18 -11
  5. data/Rakefile +0 -23
  6. data/doc/text/getting-started.md +2 -2
  7. data/doc/text/news.md +329 -1
  8. data/lib/test/unit/assertion-failed-error.rb +35 -0
  9. data/lib/test/unit/assertions.rb +453 -161
  10. data/lib/test/unit/attribute.rb +3 -1
  11. data/lib/test/unit/autorunner.rb +78 -30
  12. data/lib/test/unit/code-snippet-fetcher.rb +7 -7
  13. data/lib/test/unit/collector/descendant.rb +1 -0
  14. data/lib/test/unit/collector/dir.rb +4 -2
  15. data/lib/test/unit/collector/load.rb +3 -3
  16. data/lib/test/unit/collector/objectspace.rb +1 -0
  17. data/lib/test/unit/collector.rb +31 -0
  18. data/lib/test/unit/color-scheme.rb +20 -2
  19. data/lib/test/unit/data-sets.rb +26 -15
  20. data/lib/test/unit/data.rb +5 -5
  21. data/lib/test/unit/diff.rb +2 -3
  22. data/lib/test/unit/fixture.rb +6 -0
  23. data/lib/test/unit/notification.rb +9 -7
  24. data/lib/test/unit/omission.rb +34 -31
  25. data/lib/test/unit/pending.rb +12 -11
  26. data/lib/test/unit/priority.rb +7 -5
  27. data/lib/test/unit/runner/console.rb +0 -17
  28. data/lib/test/unit/testcase.rb +222 -146
  29. data/lib/test/unit/testsuite.rb +1 -1
  30. data/lib/test/unit/ui/console/testrunner.rb +58 -49
  31. data/lib/test/unit/util/memory-usage.rb +47 -0
  32. data/lib/test/unit/util/observable.rb +2 -2
  33. data/lib/test/unit/util/output.rb +5 -4
  34. data/lib/test/unit/version.rb +1 -1
  35. data/lib/test/unit/warning.rb +3 -0
  36. data/lib/test/unit.rb +177 -161
  37. data/lib/test-unit.rb +2 -17
  38. metadata +14 -91
  39. data/GPL +0 -339
  40. data/LGPL +0 -502
  41. data/test/collector/test-descendant.rb +0 -182
  42. data/test/collector/test-load.rb +0 -442
  43. data/test/collector/test_dir.rb +0 -407
  44. data/test/collector/test_objectspace.rb +0 -102
  45. data/test/fixtures/header-label.csv +0 -3
  46. data/test/fixtures/header-label.tsv +0 -3
  47. data/test/fixtures/header.csv +0 -3
  48. data/test/fixtures/header.tsv +0 -3
  49. data/test/fixtures/no-header.csv +0 -2
  50. data/test/fixtures/no-header.tsv +0 -2
  51. data/test/fixtures/plus.csv +0 -3
  52. data/test/run-test.rb +0 -22
  53. data/test/test-assertions.rb +0 -2180
  54. data/test/test-attribute-matcher.rb +0 -38
  55. data/test/test-attribute.rb +0 -123
  56. data/test/test-code-snippet.rb +0 -37
  57. data/test/test-color-scheme.rb +0 -82
  58. data/test/test-color.rb +0 -47
  59. data/test/test-data.rb +0 -419
  60. data/test/test-diff.rb +0 -518
  61. data/test/test-emacs-runner.rb +0 -60
  62. data/test/test-error.rb +0 -26
  63. data/test/test-failure.rb +0 -33
  64. data/test/test-fault-location-detector.rb +0 -163
  65. data/test/test-fixture.rb +0 -713
  66. data/test/test-notification.rb +0 -33
  67. data/test/test-omission.rb +0 -81
  68. data/test/test-pending.rb +0 -70
  69. data/test/test-priority.rb +0 -173
  70. data/test/test-test-case.rb +0 -1279
  71. data/test/test-test-result.rb +0 -113
  72. data/test/test-test-suite-creator.rb +0 -97
  73. data/test/test-test-suite.rb +0 -151
  74. data/test/testunit-test-util.rb +0 -31
  75. data/test/ui/test_testrunmediator.rb +0 -20
  76. data/test/util/test-method-owner-finder.rb +0 -38
  77. data/test/util/test-output.rb +0 -11
  78. data/test/util/test_backtracefilter.rb +0 -52
  79. data/test/util/test_observable.rb +0 -102
  80. data/test/util/test_procwrapper.rb +0 -36
@@ -199,12 +199,14 @@ module Test
199
199
  ancestor.is_a?(Class) and
200
200
  ancestor < Test::Unit::Attribute
201
201
  end
202
+ return nil if @cached_parent_test_case.nil?
202
203
 
203
204
  @cached_parent_test_case.find_attribute(method_name, name, options)
204
205
  end
205
206
 
206
207
  @@attribute_observers = StringifyKeyHash.new
207
- def register_attribute_observer(attribute_name, observer=Proc.new)
208
+ def register_attribute_observer(attribute_name, observer=nil, &block)
209
+ observer ||= Proc.new(&block)
208
210
  @@attribute_observers[attribute_name] ||= []
209
211
  @@attribute_observers[attribute_name] << observer
210
212
  end
@@ -1,10 +1,10 @@
1
1
  require "English"
2
+ require "optparse"
2
3
 
3
4
  require "test/unit/color-scheme"
4
5
  require "test/unit/priority"
5
6
  require "test/unit/attribute-matcher"
6
7
  require "test/unit/testcase"
7
- require "optparse"
8
8
 
9
9
  module Test
10
10
  module Unit
@@ -15,7 +15,8 @@ module Test
15
15
  PREPARE_HOOKS = []
16
16
 
17
17
  class << self
18
- def register_runner(id, runner_builder=Proc.new)
18
+ def register_runner(id, runner_builder=nil, &block)
19
+ runner_builder ||= Proc.new(&block)
19
20
  RUNNERS[id] = runner_builder
20
21
  RUNNERS[id.to_s] = runner_builder
21
22
  end
@@ -33,7 +34,8 @@ module Test
33
34
  @@default_runner = id
34
35
  end
35
36
 
36
- def register_collector(id, collector_builder=Proc.new)
37
+ def register_collector(id, collector_builder=nil, &block)
38
+ collector_builder ||= Proc.new(&block)
37
39
  COLLECTORS[id] = collector_builder
38
40
  COLLECTORS[id.to_s] = collector_builder
39
41
  end
@@ -46,11 +48,13 @@ module Test
46
48
  ColorScheme[id] = scheme
47
49
  end
48
50
 
49
- def setup_option(option_builder=Proc.new)
51
+ def setup_option(option_builder=nil, &block)
52
+ option_builder ||= Proc.new(&block)
50
53
  ADDITIONAL_OPTIONS << option_builder
51
54
  end
52
55
 
53
- def prepare(hook=Proc.new)
56
+ def prepare(hook=nil, &block)
57
+ hook ||= Proc.new(&block)
54
58
  PREPARE_HOOKS << hook
55
59
  end
56
60
 
@@ -140,6 +144,7 @@ module Test
140
144
  attr_accessor :pattern, :exclude, :base, :workdir
141
145
  attr_accessor :color_scheme, :listeners
142
146
  attr_writer :stop_on_failure
147
+ attr_writer :debug_on_failure
143
148
  attr_writer :runner, :collector
144
149
 
145
150
  def initialize(standalone)
@@ -155,6 +160,7 @@ module Test
155
160
  @workdir = nil
156
161
  @listeners = []
157
162
  @stop_on_failure = false
163
+ @debug_on_failure = false
158
164
  config_file = "test-unit.yml"
159
165
  if File.exist?(config_file)
160
166
  load_config(config_file)
@@ -168,6 +174,10 @@ module Test
168
174
  @stop_on_failure
169
175
  end
170
176
 
177
+ def debug_on_failure?
178
+ @debug_on_failure
179
+ end
180
+
171
181
  def prepare
172
182
  PREPARE_HOOKS.each do |handler|
173
183
  handler.call(self)
@@ -242,54 +252,61 @@ module Test
242
252
 
243
253
  o.on("-n", "--name=NAME", String,
244
254
  "Runs tests matching NAME.",
245
- "Use '/PATTERN/' for NAME to use regular expression.") do |name|
246
- name = (%r{\A/(.*)/\Z} =~ name ? Regexp.new($1) : name)
255
+ "Use '/PATTERN/' for NAME to use regular expression.",
256
+ "Regular expression accepts options.",
257
+ "Example: '/taRget/i' matches 'target' and 'TARGET'") do |name|
258
+ name = prepare_name(name)
247
259
  @filters << lambda do |test|
248
- return true if name === test.method_name
249
- return true if name === test.local_name
250
- false
260
+ match_test_name(test, name)
251
261
  end
252
262
  end
253
263
 
254
264
  o.on("--ignore-name=NAME", String,
255
265
  "Ignores tests matching NAME.",
256
- "Use '/PATTERN/' for NAME to use regular expression.") do |n|
257
- n = (%r{\A/(.*)/\Z} =~ n ? Regexp.new($1) : n)
258
- case n
259
- when Regexp
260
- @filters << proc {|t| n =~ t.method_name ? false : true}
261
- else
262
- @filters << proc {|t| n != t.method_name}
266
+ "Use '/PATTERN/' for NAME to use regular expression.",
267
+ "Regular expression accepts options.",
268
+ "Example: '/taRget/i' matches 'target' and 'TARGET'") do |name|
269
+ name = prepare_name(name)
270
+ @filters << lambda do |test|
271
+ not match_test_name(test, name)
263
272
  end
264
273
  end
265
274
 
266
275
  o.on("-t", "--testcase=TESTCASE", String,
267
276
  "Runs tests in TestCases matching TESTCASE.",
268
- "Use '/PATTERN/' for TESTCASE to use regular expression.") do |n|
269
- n = (%r{\A/(.*)/\Z} =~ n ? Regexp.new($1) : n)
277
+ "Use '/PATTERN/' for TESTCASE to use regular expression.",
278
+ "Regular expression accepts options.",
279
+ "Example: '/taRget/i' matches 'target' and 'TARGET'") do |name|
280
+ name = prepare_name(name)
270
281
  @filters << lambda do |test|
271
- match_test_case_name(test, n)
282
+ match_test_case_name(test, name)
272
283
  end
273
284
  end
274
285
 
275
286
  o.on("--ignore-testcase=TESTCASE", String,
276
287
  "Ignores tests in TestCases matching TESTCASE.",
277
- "Use '/PATTERN/' for TESTCASE to use regular expression.") do |n|
278
- n = (%r{\A/(.*)/\Z} =~ n ? Regexp.new($1) : n)
288
+ "Use '/PATTERN/' for TESTCASE to use regular expression.",
289
+ "Regular expression accepts options.",
290
+ "Example: '/taRget/i' matches 'target' and 'TARGET'") do |name|
291
+ name = prepare_name(name)
279
292
  @filters << lambda do |test|
280
- not match_test_case_name(test, n)
293
+ not match_test_case_name(test, name)
281
294
  end
282
295
  end
283
296
 
284
297
  o.on("--location=LOCATION", String,
285
298
  "Runs tests that defined in LOCATION.",
286
- "LOCATION is one of PATH:LINE, PATH or LINE") do |location|
287
- if /\A\d+\z/ =~ location
299
+ "LOCATION is one of PATH:LINE, PATH or LINE.") do |location|
300
+ case location
301
+ when /\A(\d+)\z/
288
302
  path = nil
289
- line = location.to_i
303
+ line = $1.to_i
304
+ when /:(\d+)\z/
305
+ path = $PREMATCH
306
+ line = $1.to_i
290
307
  else
291
- path, line, = location.split(/:(\d+)/, 2)
292
- line = line.to_i unless line.nil?
308
+ path = location
309
+ line = nil
293
310
  end
294
311
  add_location_filter(path, line)
295
312
  end
@@ -345,7 +362,7 @@ module Test
345
362
  end
346
363
 
347
364
  o.on("--config=FILE",
348
- "Use YAML fomat FILE content as configuration file.") do |file|
365
+ "Use YAML format FILE content as configuration file.") do |file|
349
366
  load_config(file)
350
367
  end
351
368
 
@@ -370,6 +387,12 @@ module Test
370
387
  @stop_on_failure = boolean
371
388
  end
372
389
 
390
+ o.on("--[no-]debug-on-failure",
391
+ "Run debugger if available on failure",
392
+ "(#{AssertionFailedError.debug_on_failure?})") do |boolean|
393
+ AssertionFailedError.debug_on_failure = boolean
394
+ end
395
+
373
396
  ADDITIONAL_OPTIONS.each do |option_builder|
374
397
  option_builder.call(self, o)
375
398
  end
@@ -452,7 +475,7 @@ module Test
452
475
  if key == :arguments
453
476
  @default_arguments.concat(value.split)
454
477
  else
455
- runner_options[key.to_sym] = value
478
+ runner_options[key] = value
456
479
  end
457
480
  end
458
481
  @runner_options = @runner_options.merge(runner_options)
@@ -492,6 +515,31 @@ module Test
492
515
  end
493
516
  end
494
517
 
518
+ def prepare_name(name)
519
+ case name
520
+ when /\A\/(.*)\/([imx]*)\z/
521
+ pattern = $1
522
+ options_raw = $2
523
+ options = 0
524
+ options |= Regexp::IGNORECASE if options_raw.include?("i")
525
+ options |= Regexp::MULTILINE if options_raw.include?("m")
526
+ options |= Regexp::EXTENDED if options_raw.include?("x")
527
+ Regexp.new(pattern, options)
528
+ else
529
+ name
530
+ end
531
+ end
532
+
533
+ def match_test_name(test, pattern)
534
+ return true if pattern === test.method_name
535
+ return true if pattern === test.local_name
536
+ if pattern.is_a?(String)
537
+ return true if pattern === "#{test.class}##{test.method_name}"
538
+ return true if pattern === "#{test.class}##{test.local_name}"
539
+ end
540
+ false
541
+ end
542
+
495
543
  def match_test_case_name(test, pattern)
496
544
  test.class.ancestors.each do |test_class|
497
545
  break if test_class == TestCase
@@ -26,16 +26,16 @@ module Test
26
26
  def read_source(path)
27
27
  return nil unless File.exist?(path)
28
28
  lines = []
29
- File.open(path) do |file|
29
+ File.open(path, "rb") do |file|
30
30
  first_line = file.gets
31
31
  break if first_line.nil?
32
- encoding = detect_encoding(first_line)
33
- if encoding
34
- first_line.force_encoding(encoding)
35
- file.set_encoding(encoding, encoding)
36
- end
32
+ encoding = detect_encoding(first_line) || Encoding::UTF_8
33
+ first_line.force_encoding(encoding)
37
34
  lines << first_line
38
- lines.concat(file.readlines)
35
+ file.each_line do |line|
36
+ line.force_encoding(encoding)
37
+ lines << line
38
+ end
39
39
  end
40
40
  lines
41
41
  end
@@ -11,6 +11,7 @@ module Test
11
11
  def collect(name=NAME)
12
12
  suite = TestSuite.new(name)
13
13
  add_test_cases(suite, TestCase::DESCENDANTS)
14
+ adjust_ractor_tests(suite)
14
15
  suite
15
16
  end
16
17
  end
@@ -25,9 +25,9 @@ module Test
25
25
  basedir = @base
26
26
  $:.push(basedir) if basedir
27
27
  if(from.empty?)
28
- recursive_collect('.', find_test_cases)
28
+ suite = recursive_collect('.', find_test_cases)
29
29
  elsif(from.size == 1)
30
- recursive_collect(from.first, find_test_cases)
30
+ suite = recursive_collect(from.first, find_test_cases)
31
31
  else
32
32
  suites = []
33
33
  from.each do |f|
@@ -38,6 +38,8 @@ module Test
38
38
  sort(suites).each{|s| suite << s}
39
39
  suite
40
40
  end
41
+ adjust_ractor_tests(suite)
42
+ suite
41
43
  ensure
42
44
  $:.delete_at($:.rindex(basedir)) if basedir
43
45
  end
@@ -60,6 +60,8 @@ module Test
60
60
  test_suite = test_suites.first
61
61
  end
62
62
 
63
+ adjust_ractor_tests(test_suite)
64
+
63
65
  test_suite
64
66
  end
65
67
  end
@@ -111,7 +113,7 @@ module Test
111
113
  return if @program_file == expanded_path.to_s
112
114
  add_load_path(expanded_path.dirname) do
113
115
  begin
114
- require(path.basename.to_s)
116
+ require(expanded_path.to_s)
115
117
  rescue LoadError
116
118
  @require_failed_infos << {:path => expanded_path, :exception => $!}
117
119
  end
@@ -131,8 +133,6 @@ module Test
131
133
  return yield if path.nil?
132
134
 
133
135
  path = path.to_s
134
- return yield if $LOAD_PATH.index(path)
135
-
136
136
  begin
137
137
  $LOAD_PATH.unshift(path)
138
138
  yield
@@ -26,6 +26,7 @@ module Test
26
26
  end
27
27
  end
28
28
  sort(sub_suites).each{|s| suite << s}
29
+ adjust_ractor_tests(suite)
29
30
  suite
30
31
  end
31
32
  end
@@ -68,6 +68,37 @@ module Test
68
68
  suite << sub_suite
69
69
  end
70
70
  end
71
+
72
+ def adjust_ractor_tests(suite)
73
+ return if suite.nil?
74
+ ractor_suites = extract_ractor_tests(suite)
75
+ ractor_suites.each do |ractor_suite|
76
+ suite << ractor_suite
77
+ end
78
+ end
79
+
80
+ def extract_ractor_tests(suite)
81
+ ractor_suites = []
82
+ ractor_tests = []
83
+ suite.tests.each do |test|
84
+ case test
85
+ when TestSuite
86
+ ractor_suites.concat(extract_ractor_tests(test))
87
+ else
88
+ next unless test[:ractor]
89
+ ractor_tests << test
90
+ end
91
+ end
92
+ unless ractor_tests.empty?
93
+ suite.delete_tests(ractor_tests)
94
+ ractor_suite = TestSuite.new(suite.name, suite.test_case)
95
+ ractor_tests.each do |ractor_test|
96
+ ractor_suite << ractor_test
97
+ end
98
+ ractor_suites << ractor_suite
99
+ end
100
+ ractor_suites
101
+ end
71
102
  end
72
103
  end
73
104
  end
@@ -5,9 +5,25 @@ module Test
5
5
  class ColorScheme
6
6
  include Enumerable
7
7
 
8
+ TERM_256 = /
9
+ [+-]256color|
10
+ \A(?:
11
+ alacritty|
12
+ iTerm\s?\d*\.app|
13
+ kitty|
14
+ mintty|
15
+ ms-terminal|
16
+ nsterm-build\d+|
17
+ nsterm|
18
+ terminator|
19
+ terminology(?:-[0-9.]+)?|
20
+ termite|
21
+ vscode
22
+ )\z/x
23
+
8
24
  class << self
9
25
  def default
10
- if available_colors == 256
26
+ if available_colors >= 256
11
27
  default_for_256_colors
12
28
  else
13
29
  default_for_8_colors
@@ -140,7 +156,9 @@ module Test
140
156
 
141
157
  def guess_available_colors_from_term_env
142
158
  case ENV["TERM"]
143
- when /-256color\z/
159
+ when /[+-]direct/
160
+ 2**24
161
+ when TERM_256
144
162
  256
145
163
  else
146
164
  nil
@@ -22,17 +22,16 @@ module Test
22
22
  add(data_set)
23
23
  end
24
24
 
25
+ def have_keep?
26
+ each_data_set do |_, options|
27
+ return true if options[:keep]
28
+ end
29
+ false
30
+ end
31
+
25
32
  def keep
26
33
  new_data_sets = self.class.new
27
- all_data_sets = Enumerator.new do |yielder|
28
- block = lambda do |(data_set, options)|
29
- yielder << [data_set, options]
30
- end
31
- @procs.each(&block)
32
- @variables.each(&block)
33
- @value_sets.each(&block)
34
- end
35
- all_data_sets.each do |data_set, options|
34
+ each_data_set do |data_set, options|
36
35
  next if options.nil?
37
36
  next unless options[:keep]
38
37
  new_data_sets.add(data_set, options)
@@ -79,18 +78,24 @@ module Test
79
78
  end
80
79
 
81
80
  private
81
+ def each_data_set(&block)
82
+ @procs.each(&block)
83
+ @variables.each(&block)
84
+ @value_sets.each(&block)
85
+ end
86
+
82
87
  def each_pattern(variables)
83
88
  grouped_variables = variables.group_by do |_, options|
84
89
  options[:group]
85
90
  end
86
- grouped_variables.each do |group, variables|
87
- each_raw_pattern(variables) do |cell|
91
+ grouped_variables.each do |group, group_variables|
92
+ each_raw_pattern(group_variables) do |cell|
88
93
  label = String.new
89
94
  label << "group: #{group.inspect}" unless group.nil?
90
95
  data = {}
91
- cell.each do |variable, pattern|
96
+ cell.each do |variable, pattern, pattern_label|
92
97
  label << ", " unless label.empty?
93
- label << "#{variable}: #{pattern.inspect}"
98
+ label << "#{variable}: #{pattern_label}"
94
99
  data[variable] = pattern
95
100
  end
96
101
  yield(label, data)
@@ -105,8 +110,14 @@ module Test
105
110
  variable
106
111
  end
107
112
  all_patterns = sorted_variables.collect do |(variable, patterns), _|
108
- patterns.collect do |pattern|
109
- [variable, pattern]
113
+ if patterns.is_a?(Hash)
114
+ patterns.collect do |pattern_label, pattern|
115
+ [variable, pattern, pattern_label]
116
+ end
117
+ else
118
+ patterns.collect do |pattern|
119
+ [variable, pattern, pattern.inspect]
120
+ end
110
121
  end
111
122
  end
112
123
  all_patterns[0].product(*all_patterns[1..-1], &block)
@@ -136,7 +136,7 @@ module Test
136
136
  when 1
137
137
  if block_given?
138
138
  data_set = block
139
- options = arguments[1]
139
+ options = arguments[0]
140
140
  else
141
141
  data_set = arguments[0]
142
142
  end
@@ -170,11 +170,11 @@ module Test
170
170
  options ||= {}
171
171
  data_sets = current_attribute(:data)[:value] || DataSets.new
172
172
  data_sets.add(data_set, options)
173
- if options[:keep]
173
+ if options[:keep] or data_sets.have_keep?
174
174
  keep_hook = lambda do |attr|
175
175
  attr.merge(value: attr[:value].keep)
176
176
  end
177
- options = options.merge(keep_hook: keep_hook)
177
+ options = options.merge(keep: true, keep_hook: keep_hook)
178
178
  end
179
179
  attribute(:data, data_sets, options)
180
180
  end
@@ -187,7 +187,7 @@ module Test
187
187
  #
188
188
  # @param [String] file_name full path to test data file.
189
189
  # File format is automatically detected from filename extension.
190
- # @raise [ArgumentError] if +file_name+ is not supported file format.
190
+ # @raise [ArgumentError] if `file_name` is not supported file format.
191
191
  # @see Loader#load
192
192
  #
193
193
  # @example Load data from CSV file
@@ -211,7 +211,7 @@ module Test
211
211
  #
212
212
  # @param [String] file_name full path to test data file.
213
213
  # File format is automatically detected from filename extension.
214
- # @raise [ArgumentError] if +file_name+ is not supported file format.
214
+ # @raise [ArgumentError] if `file_name` is not supported file format.
215
215
  # @see #load_csv
216
216
  # @see #load_tsv
217
217
  # @api private
@@ -3,9 +3,8 @@
3
3
  # Copyright (c) 2001-2008 Python Software Foundation; All Rights Reserved
4
4
  # Copyright (c) 2008-2011 Kouhei Sutou; All Rights Reserved
5
5
  #
6
- # It is free software, and is distributed under the Ruby license, the
7
- # PSF license and/or LGPLv2.1 or later. See the COPYING file, the PSFL
8
- # file and the LGPL file.
6
+ # It is free software, and is distributed under (the new Ruby license
7
+ # or BSDL) and the PSF license.
9
8
 
10
9
  module Test
11
10
  module Unit
@@ -103,6 +103,7 @@ module Test
103
103
  @test_case = test_case
104
104
  @type = type
105
105
  @default_options = default_options
106
+ @callbacks = {}
106
107
  @before_prepend_callbacks = []
107
108
  @before_append_callbacks = []
108
109
  @after_prepend_callbacks = []
@@ -130,6 +131,11 @@ module Test
130
131
  @test_case.attribute(:source_location,
131
132
  callback.source_location,
132
133
  method_name)
134
+ # For Ruby 2.6 or earlier. callback may be GC-ed. If
135
+ # callback is GC-ed, callback_method_name may be
136
+ # duplicated because callback_method_name uses callback.object_id.
137
+ # See also: https://github.com/test-unit/test-unit/issues/179
138
+ @callbacks[callback] = true
133
139
  @test_case.__send__(:define_method, method_name, &callback)
134
140
  else
135
141
  method_name = method_name_or_callback
@@ -65,15 +65,17 @@ module Test
65
65
  # Notify some information.
66
66
  #
67
67
  # Example:
68
- # def test_notification
69
- # notify("I'm here!")
70
- # # Reached here
71
- # notify("Special!") if special_case?
72
- # # Reached here too
73
- # end
68
+ #
69
+ # def test_notification
70
+ # notify("I'm here!")
71
+ # # Reached here
72
+ # notify("Special!") if special_case?
73
+ # # Reached here too
74
+ # end
74
75
  #
75
76
  # options:
76
- # :backtrace override backtrace.
77
+ #
78
+ # :backtrace override backtrace.
77
79
  def notify(message, options={}, &block)
78
80
  backtrace = filter_backtrace(options[:backtrace] || caller)
79
81
  notification = Notification.new(name, backtrace, message,
@@ -65,17 +65,18 @@ module Test
65
65
  # Omit the test or part of the test.
66
66
  #
67
67
  # Example:
68
- # def test_omission
69
- # omit
70
- # # Not reached here
71
- # end
72
68
  #
73
- # def test_omission_with_here
74
- # omit do
75
- # # Not ran here
69
+ # def test_omission
70
+ # omit
71
+ # # Not reached here
72
+ # end
73
+ #
74
+ # def test_omission_with_here
75
+ # omit do
76
+ # # Not ran here
77
+ # end
78
+ # # Reached here
76
79
  # end
77
- # # Reached here
78
- # end
79
80
  def omit(message=nil, &block)
80
81
  message ||= "omitted."
81
82
  if block_given?
@@ -91,20 +92,21 @@ module Test
91
92
  # true.
92
93
  #
93
94
  # Example:
94
- # def test_omission
95
- # omit_if("".empty?)
96
- # # Not reached here
97
- # end
98
95
  #
99
- # def test_omission_with_here
100
- # omit_if(true) do
101
- # # Not ran here
96
+ # def test_omission
97
+ # omit_if("".empty?)
98
+ # # Not reached here
102
99
  # end
103
- # omit_if(false) do
104
- # # Reached here
100
+ #
101
+ # def test_omission_with_here
102
+ # omit_if(true) do
103
+ # # Not ran here
104
+ # end
105
+ # omit_if(false) do
106
+ # # Reached here
107
+ # end
108
+ # # Reached here too
105
109
  # end
106
- # # Reached here too
107
- # end
108
110
  def omit_if(condition, *args, &block)
109
111
  if condition
110
112
  omit(*args, &block)
@@ -117,20 +119,21 @@ module Test
117
119
  # not true.
118
120
  #
119
121
  # Example:
120
- # def test_omission
121
- # omit_unless("string".empty?)
122
- # # Not reached here
123
- # end
124
122
  #
125
- # def test_omission_with_here
126
- # omit_unless(true) do
127
- # # Reached here
123
+ # def test_omission
124
+ # omit_unless("string".empty?)
125
+ # # Not reached here
128
126
  # end
129
- # omit_unless(false) do
130
- # # Not ran here
127
+ #
128
+ # def test_omission_with_here
129
+ # omit_unless(true) do
130
+ # # Reached here
131
+ # end
132
+ # omit_unless(false) do
133
+ # # Not ran here
134
+ # end
135
+ # # Reached here too
131
136
  # end
132
- # # Reached here too
133
- # end
134
137
  def omit_unless(condition, *args, &block)
135
138
  if condition
136
139
  block.call if block