test-unit 3.1.5 → 3.6.1

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 (87) hide show
  1. checksums.yaml +5 -5
  2. data/BSDL +24 -0
  3. data/COPYING +41 -41
  4. data/README.md +24 -17
  5. data/Rakefile +21 -24
  6. data/doc/text/getting-started.md +246 -0
  7. data/doc/text/news.md +797 -56
  8. data/lib/test/unit/assertion-failed-error.rb +35 -0
  9. data/lib/test/unit/assertions.rb +542 -220
  10. data/lib/test/unit/attribute.rb +78 -4
  11. data/lib/test/unit/auto-runner-loader.rb +17 -0
  12. data/lib/test/unit/autorunner.rb +175 -78
  13. data/lib/test/unit/code-snippet-fetcher.rb +7 -7
  14. data/lib/test/unit/collector/descendant.rb +1 -0
  15. data/lib/test/unit/collector/dir.rb +4 -2
  16. data/lib/test/unit/collector/load.rb +25 -15
  17. data/lib/test/unit/collector/objectspace.rb +1 -0
  18. data/lib/test/unit/collector.rb +31 -0
  19. data/lib/test/unit/color-scheme.rb +29 -2
  20. data/lib/test/unit/data-sets.rb +127 -0
  21. data/lib/test/unit/data.rb +121 -12
  22. data/lib/test/unit/diff.rb +10 -11
  23. data/lib/test/unit/fixture.rb +77 -27
  24. data/lib/test/unit/notification.rb +9 -7
  25. data/lib/test/unit/omission.rb +34 -31
  26. data/lib/test/unit/pending.rb +12 -11
  27. data/lib/test/unit/priority.rb +7 -5
  28. data/lib/test/unit/runner/console.rb +20 -1
  29. data/lib/test/unit/test-suite-creator.rb +30 -9
  30. data/lib/test/unit/testcase.rb +349 -196
  31. data/lib/test/unit/testresult.rb +7 -0
  32. data/lib/test/unit/testsuite.rb +1 -1
  33. data/lib/test/unit/ui/console/testrunner.rb +171 -60
  34. data/lib/test/unit/ui/emacs/testrunner.rb +5 -5
  35. data/lib/test/unit/ui/testrunnermediator.rb +9 -7
  36. data/lib/test/unit/util/backtracefilter.rb +17 -5
  37. data/lib/test/unit/util/memory-usage.rb +47 -0
  38. data/lib/test/unit/util/observable.rb +2 -2
  39. data/lib/test/unit/util/output.rb +5 -4
  40. data/lib/test/unit/util/procwrapper.rb +4 -4
  41. data/lib/test/unit/version.rb +1 -1
  42. data/lib/test/unit/warning.rb +3 -0
  43. data/lib/test/unit.rb +177 -161
  44. data/lib/test-unit.rb +2 -17
  45. metadata +20 -94
  46. data/GPL +0 -339
  47. data/LGPL +0 -502
  48. data/test/collector/test-descendant.rb +0 -178
  49. data/test/collector/test-load.rb +0 -442
  50. data/test/collector/test_dir.rb +0 -406
  51. data/test/collector/test_objectspace.rb +0 -100
  52. data/test/fixtures/header-label.csv +0 -3
  53. data/test/fixtures/header-label.tsv +0 -3
  54. data/test/fixtures/header.csv +0 -3
  55. data/test/fixtures/header.tsv +0 -3
  56. data/test/fixtures/no-header.csv +0 -2
  57. data/test/fixtures/no-header.tsv +0 -2
  58. data/test/fixtures/plus.csv +0 -3
  59. data/test/run-test.rb +0 -22
  60. data/test/test-assertions.rb +0 -2157
  61. data/test/test-attribute-matcher.rb +0 -38
  62. data/test/test-attribute.rb +0 -123
  63. data/test/test-code-snippet.rb +0 -37
  64. data/test/test-color-scheme.rb +0 -82
  65. data/test/test-color.rb +0 -47
  66. data/test/test-data.rb +0 -281
  67. data/test/test-diff.rb +0 -518
  68. data/test/test-emacs-runner.rb +0 -60
  69. data/test/test-error.rb +0 -26
  70. data/test/test-failure.rb +0 -33
  71. data/test/test-fault-location-detector.rb +0 -163
  72. data/test/test-fixture.rb +0 -659
  73. data/test/test-notification.rb +0 -33
  74. data/test/test-omission.rb +0 -81
  75. data/test/test-pending.rb +0 -70
  76. data/test/test-priority.rb +0 -173
  77. data/test/test-test-case.rb +0 -1171
  78. data/test/test-test-result.rb +0 -113
  79. data/test/test-test-suite-creator.rb +0 -97
  80. data/test/test-test-suite.rb +0 -150
  81. data/test/testunit-test-util.rb +0 -31
  82. data/test/ui/test_testrunmediator.rb +0 -20
  83. data/test/util/test-method-owner-finder.rb +0 -38
  84. data/test/util/test-output.rb +0 -11
  85. data/test/util/test_backtracefilter.rb +0 -41
  86. data/test/util/test_observable.rb +0 -102
  87. data/test/util/test_procwrapper.rb +0 -36
@@ -43,12 +43,80 @@ module Test
43
43
  kept_attributes = StringifyKeyHash.new
44
44
  @current_attributes.each do |attribute_name, attribute|
45
45
  attributes[attribute_name] = attribute[:value]
46
- kept_attributes[attribute_name] = attribute if attribute[:keep]
46
+ if attribute[:keep]
47
+ keep_hook = attribute[:keep_hook]
48
+ attribute = keep_hook.call(attribute) if keep_hook
49
+ kept_attributes[attribute_name] = attribute
50
+ end
47
51
  end
48
52
  set_attributes(name, attributes)
49
53
  @current_attributes = kept_attributes
50
54
  end
51
55
 
56
+ # Set an attribute to test methods.
57
+ #
58
+ # @overload attribute(name, value)
59
+ # @example
60
+ # attribute :speed, :slow
61
+ # def test_my_slow_method
62
+ # self[:speed] # => :slow
63
+ # end
64
+ #
65
+ # @param [Object] name the attribute name
66
+ # @param [Object] value the attribute value
67
+ # @return [void]
68
+ #
69
+ # @overload attribute(name, value, *method_names)
70
+ # @example
71
+ # def test_my_slow_method1
72
+ # self[:speed] # => :slow
73
+ # end
74
+ #
75
+ # attribute :speed, :slow, :test_my_slow_method1, :test_my_slow_method2
76
+ #
77
+ # def test_my_slow_method2
78
+ # self[:speed] # => :slow
79
+ # end
80
+ #
81
+ # @param [Object] name the attribute name
82
+ # @param [Object] value the attribute value
83
+ # @param [Array<Symbol, String>] method_names the test method names set the attribute
84
+ # @return [void]
85
+ #
86
+ # @overload attribute(name, value, options)
87
+ # @example
88
+ # attribute :speed, :slow, keep: true
89
+ # def test_my_slow_method1
90
+ # self[:speed] # => :slow
91
+ # end
92
+ #
93
+ # def test_my_slow_method2
94
+ # self[:speed] # => :slow
95
+ # end
96
+ #
97
+ # @param [Object] name the attribute name
98
+ # @param [Object] value the attribute value
99
+ # @option options [Boolean] :keep whether or not to set attribute to following test methods
100
+ # @return [void]
101
+ #
102
+ # @overload attribute(name, value, options, *method_names)
103
+ # @example
104
+ # def test_my_slow_method1
105
+ # self[:speed] # => :slow
106
+ # end
107
+ #
108
+ # # There are no valid options for now.
109
+ # attribute :speed, :slow, {}, :test_my_slow_method1
110
+ #
111
+ # def test_my_slow_method2
112
+ # self[:speed] # => nil
113
+ # end
114
+ #
115
+ # @param [Object] name the attribute name
116
+ # @param [Object] value the attribute value
117
+ # @param [Hash] options ignored
118
+ # @param [Array<Symbol, String>] method_names the test method names set the attribute
119
+ # @return [void]
52
120
  def attribute(name, value, options={}, *method_names)
53
121
  unless options.is_a?(Hash)
54
122
  method_names << options
@@ -111,7 +179,10 @@ module Test
111
179
  attributes || StringifyKeyHash.new
112
180
  end
113
181
 
114
- def find_attribute(method_name, name)
182
+ def find_attribute(method_name, name, options={})
183
+ recursive_p = options[:recursive]
184
+ recursive_p = true if recursive_p.nil?
185
+
115
186
  @attributes_table ||= StringifyKeyHash.new
116
187
  if @attributes_table.key?(method_name)
117
188
  attributes = @attributes_table[method_name]
@@ -120,6 +191,7 @@ module Test
120
191
  end
121
192
  end
122
193
 
194
+ return nil unless recursive_p
123
195
  return nil if self == TestCase
124
196
 
125
197
  @cached_parent_test_case ||= ancestors.find do |ancestor|
@@ -127,12 +199,14 @@ module Test
127
199
  ancestor.is_a?(Class) and
128
200
  ancestor < Test::Unit::Attribute
129
201
  end
202
+ return nil if @cached_parent_test_case.nil?
130
203
 
131
- @cached_parent_test_case.find_attribute(method_name, name)
204
+ @cached_parent_test_case.find_attribute(method_name, name, options)
132
205
  end
133
206
 
134
207
  @@attribute_observers = StringifyKeyHash.new
135
- def register_attribute_observer(attribute_name, observer=Proc.new)
208
+ def register_attribute_observer(attribute_name, observer=nil, &block)
209
+ observer ||= Proc.new(&block)
136
210
  @@attribute_observers[attribute_name] ||= []
137
211
  @@attribute_observers[attribute_name] << observer
138
212
  end
@@ -0,0 +1,17 @@
1
+ require "test/unit/test-suite-creator"
2
+
3
+ module Test
4
+ module Unit
5
+ module AutoRunnerLoader
6
+ @loaded = false
7
+ class << self
8
+ def check(test_case, method_name)
9
+ return if @loaded
10
+ return unless TestSuiteCreator.test_method?(test_case, method_name)
11
+ require "test/unit"
12
+ @loaded = true
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
@@ -1,7 +1,10 @@
1
- require 'test/unit/color-scheme'
2
- require 'test/unit/priority'
3
- require 'test/unit/attribute-matcher'
4
- require 'optparse'
1
+ require "English"
2
+ require "optparse"
3
+
4
+ require "test/unit/color-scheme"
5
+ require "test/unit/priority"
6
+ require "test/unit/attribute-matcher"
7
+ require "test/unit/testcase"
5
8
 
6
9
  module Test
7
10
  module Unit
@@ -12,7 +15,8 @@ module Test
12
15
  PREPARE_HOOKS = []
13
16
 
14
17
  class << self
15
- def register_runner(id, runner_builder=Proc.new)
18
+ def register_runner(id, runner_builder=nil, &block)
19
+ runner_builder ||= Proc.new(&block)
16
20
  RUNNERS[id] = runner_builder
17
21
  RUNNERS[id.to_s] = runner_builder
18
22
  end
@@ -30,7 +34,8 @@ module Test
30
34
  @@default_runner = id
31
35
  end
32
36
 
33
- def register_collector(id, collector_builder=Proc.new)
37
+ def register_collector(id, collector_builder=nil, &block)
38
+ collector_builder ||= Proc.new(&block)
34
39
  COLLECTORS[id] = collector_builder
35
40
  COLLECTORS[id.to_s] = collector_builder
36
41
  end
@@ -43,11 +48,13 @@ module Test
43
48
  ColorScheme[id] = scheme
44
49
  end
45
50
 
46
- def setup_option(option_builder=Proc.new)
51
+ def setup_option(option_builder=nil, &block)
52
+ option_builder ||= Proc.new(&block)
47
53
  ADDITIONAL_OPTIONS << option_builder
48
54
  end
49
55
 
50
- def prepare(hook=Proc.new)
56
+ def prepare(hook=nil, &block)
57
+ hook ||= Proc.new(&block)
51
58
  PREPARE_HOOKS << hook
52
59
  end
53
60
 
@@ -78,14 +85,14 @@ module Test
78
85
  end
79
86
 
80
87
  register_collector(:descendant) do |auto_runner|
81
- require 'test/unit/collector/descendant'
88
+ require "test/unit/collector/descendant"
82
89
  collector = Collector::Descendant.new
83
90
  collector.filter = auto_runner.filters
84
- collector.collect($0.sub(/\.rb\Z/, ''))
91
+ collector.collect($0.sub(/\.rb\Z/, ""))
85
92
  end
86
93
 
87
94
  register_collector(:load) do |auto_runner|
88
- require 'test/unit/collector/load'
95
+ require "test/unit/collector/load"
89
96
  collector = Collector::Load.new
90
97
  unless auto_runner.pattern.empty?
91
98
  collector.patterns.replace(auto_runner.pattern)
@@ -94,13 +101,14 @@ module Test
94
101
  collector.excludes.replace(auto_runner.exclude)
95
102
  end
96
103
  collector.base = auto_runner.base
104
+ collector.default_test_paths = auto_runner.default_test_paths
97
105
  collector.filter = auto_runner.filters
98
106
  collector.collect(*auto_runner.to_run)
99
107
  end
100
108
 
101
109
  # JUST TEST!
102
110
  # register_collector(:xml) do |auto_runner|
103
- # require 'test/unit/collector/xml'
111
+ # require "test/unit/collector/xml"
104
112
  # collector = Collector::XML.new
105
113
  # collector.filter = auto_runner.filters
106
114
  # collector.collect(auto_runner.to_run[0])
@@ -108,15 +116,15 @@ module Test
108
116
 
109
117
  # deprecated
110
118
  register_collector(:object_space) do |auto_runner|
111
- require 'test/unit/collector/objectspace'
119
+ require "test/unit/collector/objectspace"
112
120
  c = Collector::ObjectSpace.new
113
121
  c.filter = auto_runner.filters
114
- c.collect($0.sub(/\.rb\Z/, ''))
122
+ c.collect($0.sub(/\.rb\Z/, ""))
115
123
  end
116
124
 
117
125
  # deprecated
118
126
  register_collector(:dir) do |auto_runner|
119
- require 'test/unit/collector/dir'
127
+ require "test/unit/collector/dir"
120
128
  c = Collector::Dir.new
121
129
  c.filter = auto_runner.filters
122
130
  unless auto_runner.pattern.empty?
@@ -127,12 +135,16 @@ module Test
127
135
  end
128
136
  c.base = auto_runner.base
129
137
  $:.push(auto_runner.base) if auto_runner.base
130
- c.collect(*(auto_runner.to_run.empty? ? ['.'] : auto_runner.to_run))
138
+ c.collect(*(auto_runner.to_run.empty? ? ["."] : auto_runner.to_run))
131
139
  end
132
140
 
133
141
  attr_reader :suite, :runner_options
134
- attr_accessor :filters, :to_run, :pattern, :exclude, :base, :workdir
142
+ attr_accessor :filters, :to_run
143
+ attr_accessor :default_test_paths
144
+ attr_accessor :pattern, :exclude, :base, :workdir
135
145
  attr_accessor :color_scheme, :listeners
146
+ attr_writer :stop_on_failure
147
+ attr_writer :debug_on_failure
136
148
  attr_writer :runner, :collector
137
149
 
138
150
  def initialize(standalone)
@@ -141,11 +153,14 @@ module Test
141
153
  @collector = default_collector
142
154
  @filters = []
143
155
  @to_run = []
156
+ @default_test_paths = []
144
157
  @color_scheme = ColorScheme.default
145
158
  @runner_options = {}
146
159
  @default_arguments = []
147
160
  @workdir = nil
148
161
  @listeners = []
162
+ @stop_on_failure = false
163
+ @debug_on_failure = false
149
164
  config_file = "test-unit.yml"
150
165
  if File.exist?(config_file)
151
166
  load_config(config_file)
@@ -155,6 +170,14 @@ module Test
155
170
  yield(self) if block_given?
156
171
  end
157
172
 
173
+ def stop_on_failure?
174
+ @stop_on_failure
175
+ end
176
+
177
+ def debug_on_failure?
178
+ @debug_on_failure
179
+ end
180
+
158
181
  def prepare
159
182
  PREPARE_HOOKS.each do |handler|
160
183
  handler.call(self)
@@ -164,7 +187,7 @@ module Test
164
187
  def process_args(args=ARGV)
165
188
  begin
166
189
  args.unshift(*@default_arguments)
167
- options.order!(args) {|arg| @to_run << arg}
190
+ options.order!(args) {|arg| add_test_path(arg)}
168
191
  rescue OptionParser::ParseError => e
169
192
  puts e
170
193
  puts options
@@ -176,110 +199,119 @@ module Test
176
199
  def options
177
200
  @options ||= OptionParser.new do |o|
178
201
  o.banner = "Test::Unit automatic runner."
179
- o.banner << "\nUsage: #{$0} [options] [-- untouched arguments]"
202
+ o.banner += "\nUsage: #{$0} [options] [-- untouched arguments]"
180
203
 
181
- o.on('-r', '--runner=RUNNER', RUNNERS,
204
+ o.on("-r", "--runner=RUNNER", RUNNERS,
182
205
  "Use the given RUNNER.",
183
206
  "(" + keyword_display(RUNNERS) + ")") do |r|
184
207
  @runner = r
185
208
  end
186
209
 
187
- o.on('--collector=COLLECTOR', COLLECTORS,
210
+ o.on("--collector=COLLECTOR", COLLECTORS,
188
211
  "Use the given COLLECTOR.",
189
212
  "(" + keyword_display(COLLECTORS) + ")") do |collector|
190
213
  @collector = collector
191
214
  end
192
215
 
193
216
  if (@standalone)
194
- o.on('-b', '--basedir=DIR', "Base directory of test suites.") do |b|
217
+ o.on("-b", "--basedir=DIR", "Base directory of test suites.") do |b|
195
218
  @base = b
196
219
  end
197
220
 
198
- o.on('-w', '--workdir=DIR', "Working directory to run tests.") do |w|
221
+ o.on("-w", "--workdir=DIR", "Working directory to run tests.") do |w|
199
222
  @workdir = w
200
223
  end
201
224
 
202
- o.on('-a', '--add=TORUN', Array,
225
+ o.on("--default-test-path=PATH",
226
+ "Add PATH to the default test paths.",
227
+ "The PATH is used when user doesn't specify any test path.",
228
+ "You can specify this option multiple times.") do |path|
229
+ @default_test_paths << path
230
+ end
231
+
232
+ o.on("-a", "--add=TORUN", Array,
203
233
  "Add TORUN to the list of things to run;",
204
- "can be a file or a directory.") do |a|
205
- @to_run.concat(a)
234
+ "can be a file or a directory.") do |paths|
235
+ paths.each do |path|
236
+ add_test_path(path)
237
+ end
206
238
  end
207
239
 
208
240
  @pattern = []
209
- o.on('-p', '--pattern=PATTERN', Regexp,
241
+ o.on("-p", "--pattern=PATTERN", Regexp,
210
242
  "Match files to collect against PATTERN.") do |e|
211
243
  @pattern << e
212
244
  end
213
245
 
214
246
  @exclude = []
215
- o.on('-x', '--exclude=PATTERN', Regexp,
247
+ o.on("-x", "--exclude=PATTERN", Regexp,
216
248
  "Ignore files to collect against PATTERN.") do |e|
217
249
  @exclude << e
218
250
  end
219
251
  end
220
252
 
221
- o.on('-n', '--name=NAME', String,
253
+ o.on("-n", "--name=NAME", String,
222
254
  "Runs tests matching NAME.",
223
- "Use '/PATTERN/' for NAME to use regular expression.") do |name|
224
- 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)
225
259
  @filters << lambda do |test|
226
- return true if name === test.method_name
227
- test_name_without_class_name = test.name.gsub(/\(.+?\)\z/, "")
228
- if test_name_without_class_name != test.method_name
229
- return true if name === test_name_without_class_name
230
- end
231
- false
260
+ match_test_name(test, name)
232
261
  end
233
262
  end
234
263
 
235
- o.on('--ignore-name=NAME', String,
264
+ o.on("--ignore-name=NAME", String,
236
265
  "Ignores tests matching NAME.",
237
- "Use '/PATTERN/' for NAME to use regular expression.") do |n|
238
- n = (%r{\A/(.*)/\Z} =~ n ? Regexp.new($1) : n)
239
- case n
240
- when Regexp
241
- @filters << proc {|t| n =~ t.method_name ? false : true}
242
- else
243
- @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)
244
272
  end
245
273
  end
246
274
 
247
- o.on('-t', '--testcase=TESTCASE', String,
275
+ o.on("-t", "--testcase=TESTCASE", String,
248
276
  "Runs tests in TestCases matching TESTCASE.",
249
- "Use '/PATTERN/' for TESTCASE to use regular expression.") do |n|
250
- 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)
251
281
  @filters << lambda do |test|
252
- match_test_case_name(test, n)
282
+ match_test_case_name(test, name)
253
283
  end
254
284
  end
255
285
 
256
- o.on('--ignore-testcase=TESTCASE', String,
286
+ o.on("--ignore-testcase=TESTCASE", String,
257
287
  "Ignores tests in TestCases matching TESTCASE.",
258
- "Use '/PATTERN/' for TESTCASE to use regular expression.") do |n|
259
- 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)
260
292
  @filters << lambda do |test|
261
- not match_test_case_name(test, n)
293
+ not match_test_case_name(test, name)
262
294
  end
263
295
  end
264
296
 
265
- o.on('--location=LOCATION', String,
297
+ o.on("--location=LOCATION", String,
266
298
  "Runs tests that defined in LOCATION.",
267
- "LOCATION is one of PATH:LINE, PATH or LINE") do |location|
268
- 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/
269
302
  path = nil
270
- line = location.to_i
303
+ line = $1.to_i
304
+ when /:(\d+)\z/
305
+ path = $PREMATCH
306
+ line = $1.to_i
271
307
  else
272
- path, line, = location.split(/:(\d+)/, 2)
273
- line = line.to_i unless line.nil?
274
- end
275
- @filters << lambda do |test|
276
- test.class.test_defined?(:path => path,
277
- :line => line,
278
- :method_name => test.method_name)
308
+ path = location
309
+ line = nil
279
310
  end
311
+ add_location_filter(path, line)
280
312
  end
281
313
 
282
- o.on('--attribute=EXPRESSION', String,
314
+ o.on("--attribute=EXPRESSION", String,
283
315
  "Runs tests that matches EXPRESSION.",
284
316
  "EXPRESSION is evaluated as Ruby's expression.",
285
317
  "Test attribute name can be used with no receiver in EXPRESSION.",
@@ -317,7 +349,7 @@ module Test
317
349
  Priority.default = priority
318
350
  end
319
351
 
320
- o.on('-I', "--load-path=DIR[#{File::PATH_SEPARATOR}DIR...]",
352
+ o.on("-I", "--load-path=DIR[#{File::PATH_SEPARATOR}DIR...]",
321
353
  "Appends directory list to $LOAD_PATH.") do |dirs|
322
354
  $LOAD_PATH.concat(dirs.split(File::PATH_SEPARATOR))
323
355
  end
@@ -330,7 +362,7 @@ module Test
330
362
  end
331
363
 
332
364
  o.on("--config=FILE",
333
- "Use YAML fomat FILE content as configuration file.") do |file|
365
+ "Use YAML format FILE content as configuration file.") do |file|
334
366
  load_config(file)
335
367
  end
336
368
 
@@ -349,27 +381,39 @@ module Test
349
381
  assertion_message_class.max_diff_target_string_size = size
350
382
  end
351
383
 
384
+ o.on("--[no-]stop-on-failure",
385
+ "Stops immediately on the first non success test",
386
+ "(#{@stop_on_failure})") do |boolean|
387
+ @stop_on_failure = boolean
388
+ end
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
+
352
396
  ADDITIONAL_OPTIONS.each do |option_builder|
353
397
  option_builder.call(self, o)
354
398
  end
355
399
 
356
- o.on('--',
400
+ o.on("--",
357
401
  "Stop processing options so that the",
358
402
  "remaining options will be passed to the",
359
403
  "test."){o.terminate}
360
404
 
361
- o.on('-h', '--help', 'Display this help.'){puts o; exit}
405
+ o.on("-h", "--help", "Display this help."){puts o; exit}
362
406
 
363
407
  o.on_tail
364
- o.on_tail('Deprecated options:')
408
+ o.on_tail("Deprecated options:")
365
409
 
366
- o.on_tail('--console', 'Console runner (use --runner).') do
410
+ o.on_tail("--console", "Console runner (use --runner).") do
367
411
  warn("Deprecated option (--console).")
368
412
  @runner = self.class.runner(:console)
369
413
  end
370
414
 
371
415
  if RUNNERS[:fox]
372
- o.on_tail('--fox', 'Fox runner (use --runner).') do
416
+ o.on_tail("--fox", "Fox runner (use --runner).") do
373
417
  warn("Deprecated option (--fox).")
374
418
  @runner = self.class.runner(:fox)
375
419
  end
@@ -393,7 +437,7 @@ module Test
393
437
  n = 1
394
438
  end
395
439
  i += 1
396
- keyword.sub(/^(.{#{n}})([A-Za-z]+)(?=\w*$)/, '\\1[\\2]')
440
+ keyword.sub(/^(.{#{n}})([A-Za-z-]+)(?=\w*$)/, '\\1[\\2]')
397
441
  end.join(", ")
398
442
  end
399
443
 
@@ -407,13 +451,16 @@ module Test
407
451
  @runner_options[:color_scheme] ||= @color_scheme
408
452
  @runner_options[:listeners] ||= []
409
453
  @runner_options[:listeners].concat(@listeners)
454
+ if @stop_on_failure
455
+ @runner_options[:listeners] << StopOnFailureListener.new
456
+ end
410
457
  change_work_directory do
411
458
  runner.run(suite, @runner_options).passed?
412
459
  end
413
460
  end
414
461
 
415
462
  def load_config(file)
416
- require 'yaml'
463
+ require "yaml"
417
464
  config = YAML.load(File.read(file))
418
465
  runner_name = config["runner"]
419
466
  @runner = self.class.runner(runner_name) || @runner
@@ -428,7 +475,7 @@ module Test
428
475
  if key == :arguments
429
476
  @default_arguments.concat(value.split)
430
477
  else
431
- runner_options[key.to_sym] = value
478
+ runner_options[key] = value
432
479
  end
433
480
  end
434
481
  @runner_options = @runner_options.merge(runner_options)
@@ -468,6 +515,31 @@ module Test
468
515
  end
469
516
  end
470
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
+
471
543
  def match_test_case_name(test, pattern)
472
544
  test.class.ancestors.each do |test_class|
473
545
  break if test_class == TestCase
@@ -475,10 +547,35 @@ module Test
475
547
  end
476
548
  false
477
549
  end
550
+
551
+ def add_test_path(path)
552
+ if /:(\d+)\z/ =~ path
553
+ line = $1.to_i
554
+ path = $PREMATCH
555
+ add_location_filter(path, line)
556
+ end
557
+ @to_run << path
558
+ end
559
+
560
+ def add_location_filter(path, line)
561
+ @filters << lambda do |test|
562
+ test.class.test_defined?(:path => path,
563
+ :line => line,
564
+ :method_name => test.method_name)
565
+ end
566
+ end
567
+
568
+ class StopOnFailureListener
569
+ def attach_to_mediator(mediator)
570
+ mediator.add_listener(TestResult::FINISHED) do |result|
571
+ result.stop unless result.passed?
572
+ end
573
+ end
574
+ end
478
575
  end
479
576
  end
480
577
  end
481
578
 
482
- require 'test/unit/runner/console'
483
- require 'test/unit/runner/emacs'
484
- require 'test/unit/runner/xml'
579
+ require "test/unit/runner/console"
580
+ require "test/unit/runner/emacs"
581
+ require "test/unit/runner/xml"
@@ -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