test-unit 3.1.5 → 3.6.1

Sign up to get free protection for your applications and to get access to all the features.
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