test-unit 3.1.4 → 3.6.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (88) 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 +824 -54
  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 +200 -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/fault-location-detector.rb +1 -1
  24. data/lib/test/unit/fixture.rb +77 -27
  25. data/lib/test/unit/notification.rb +9 -7
  26. data/lib/test/unit/omission.rb +34 -31
  27. data/lib/test/unit/pending.rb +12 -11
  28. data/lib/test/unit/priority.rb +7 -5
  29. data/lib/test/unit/runner/console.rb +20 -1
  30. data/lib/test/unit/test-suite-creator.rb +30 -9
  31. data/lib/test/unit/testcase.rb +349 -196
  32. data/lib/test/unit/testresult.rb +7 -0
  33. data/lib/test/unit/testsuite.rb +1 -1
  34. data/lib/test/unit/ui/console/testrunner.rb +171 -60
  35. data/lib/test/unit/ui/emacs/testrunner.rb +5 -5
  36. data/lib/test/unit/ui/testrunnermediator.rb +9 -7
  37. data/lib/test/unit/util/backtracefilter.rb +17 -5
  38. data/lib/test/unit/util/memory-usage.rb +47 -0
  39. data/lib/test/unit/util/observable.rb +2 -2
  40. data/lib/test/unit/util/output.rb +5 -4
  41. data/lib/test/unit/util/procwrapper.rb +4 -4
  42. data/lib/test/unit/version.rb +1 -1
  43. data/lib/test/unit/warning.rb +3 -0
  44. data/lib/test/unit.rb +177 -161
  45. data/lib/test-unit.rb +10 -23
  46. metadata +21 -95
  47. data/GPL +0 -339
  48. data/LGPL +0 -502
  49. data/test/collector/test-descendant.rb +0 -178
  50. data/test/collector/test-load.rb +0 -442
  51. data/test/collector/test_dir.rb +0 -406
  52. data/test/collector/test_objectspace.rb +0 -100
  53. data/test/fixtures/header-label.csv +0 -3
  54. data/test/fixtures/header-label.tsv +0 -3
  55. data/test/fixtures/header.csv +0 -3
  56. data/test/fixtures/header.tsv +0 -3
  57. data/test/fixtures/no-header.csv +0 -2
  58. data/test/fixtures/no-header.tsv +0 -2
  59. data/test/fixtures/plus.csv +0 -3
  60. data/test/run-test.rb +0 -22
  61. data/test/test-assertions.rb +0 -2157
  62. data/test/test-attribute-matcher.rb +0 -38
  63. data/test/test-attribute.rb +0 -123
  64. data/test/test-code-snippet.rb +0 -37
  65. data/test/test-color-scheme.rb +0 -82
  66. data/test/test-color.rb +0 -47
  67. data/test/test-data.rb +0 -281
  68. data/test/test-diff.rb +0 -518
  69. data/test/test-emacs-runner.rb +0 -60
  70. data/test/test-error.rb +0 -26
  71. data/test/test-failure.rb +0 -33
  72. data/test/test-fault-location-detector.rb +0 -163
  73. data/test/test-fixture.rb +0 -659
  74. data/test/test-notification.rb +0 -33
  75. data/test/test-omission.rb +0 -81
  76. data/test/test-pending.rb +0 -70
  77. data/test/test-priority.rb +0 -173
  78. data/test/test-test-case.rb +0 -1171
  79. data/test/test-test-result.rb +0 -113
  80. data/test/test-test-suite-creator.rb +0 -97
  81. data/test/test-test-suite.rb +0 -150
  82. data/test/testunit-test-util.rb +0 -31
  83. data/test/ui/test_testrunmediator.rb +0 -20
  84. data/test/util/test-method-owner-finder.rb +0 -38
  85. data/test/util/test-output.rb +0 -11
  86. data/test/util/test_backtracefilter.rb +0 -41
  87. data/test/util/test_observable.rb +0 -102
  88. 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,17 @@ 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
148
+ attr_writer :gc_stress
136
149
  attr_writer :runner, :collector
137
150
 
138
151
  def initialize(standalone)
@@ -141,11 +154,15 @@ module Test
141
154
  @collector = default_collector
142
155
  @filters = []
143
156
  @to_run = []
157
+ @default_test_paths = []
144
158
  @color_scheme = ColorScheme.default
145
159
  @runner_options = {}
146
160
  @default_arguments = []
147
161
  @workdir = nil
148
162
  @listeners = []
163
+ @stop_on_failure = false
164
+ @debug_on_failure = false
165
+ @gc_stress = false
149
166
  config_file = "test-unit.yml"
150
167
  if File.exist?(config_file)
151
168
  load_config(config_file)
@@ -155,6 +172,14 @@ module Test
155
172
  yield(self) if block_given?
156
173
  end
157
174
 
175
+ def stop_on_failure?
176
+ @stop_on_failure
177
+ end
178
+
179
+ def debug_on_failure?
180
+ @debug_on_failure
181
+ end
182
+
158
183
  def prepare
159
184
  PREPARE_HOOKS.each do |handler|
160
185
  handler.call(self)
@@ -164,7 +189,7 @@ module Test
164
189
  def process_args(args=ARGV)
165
190
  begin
166
191
  args.unshift(*@default_arguments)
167
- options.order!(args) {|arg| @to_run << arg}
192
+ options.order!(args) {|arg| add_test_path(arg)}
168
193
  rescue OptionParser::ParseError => e
169
194
  puts e
170
195
  puts options
@@ -176,110 +201,119 @@ module Test
176
201
  def options
177
202
  @options ||= OptionParser.new do |o|
178
203
  o.banner = "Test::Unit automatic runner."
179
- o.banner << "\nUsage: #{$0} [options] [-- untouched arguments]"
204
+ o.banner += "\nUsage: #{$0} [options] [-- untouched arguments]"
180
205
 
181
- o.on('-r', '--runner=RUNNER', RUNNERS,
206
+ o.on("-r", "--runner=RUNNER", RUNNERS,
182
207
  "Use the given RUNNER.",
183
208
  "(" + keyword_display(RUNNERS) + ")") do |r|
184
209
  @runner = r
185
210
  end
186
211
 
187
- o.on('--collector=COLLECTOR', COLLECTORS,
212
+ o.on("--collector=COLLECTOR", COLLECTORS,
188
213
  "Use the given COLLECTOR.",
189
214
  "(" + keyword_display(COLLECTORS) + ")") do |collector|
190
215
  @collector = collector
191
216
  end
192
217
 
193
218
  if (@standalone)
194
- o.on('-b', '--basedir=DIR', "Base directory of test suites.") do |b|
219
+ o.on("-b", "--basedir=DIR", "Base directory of test suites.") do |b|
195
220
  @base = b
196
221
  end
197
222
 
198
- o.on('-w', '--workdir=DIR', "Working directory to run tests.") do |w|
223
+ o.on("-w", "--workdir=DIR", "Working directory to run tests.") do |w|
199
224
  @workdir = w
200
225
  end
201
226
 
202
- o.on('-a', '--add=TORUN', Array,
227
+ o.on("--default-test-path=PATH",
228
+ "Add PATH to the default test paths.",
229
+ "The PATH is used when user doesn't specify any test path.",
230
+ "You can specify this option multiple times.") do |path|
231
+ @default_test_paths << path
232
+ end
233
+
234
+ o.on("-a", "--add=TORUN", Array,
203
235
  "Add TORUN to the list of things to run;",
204
- "can be a file or a directory.") do |a|
205
- @to_run.concat(a)
236
+ "can be a file or a directory.") do |paths|
237
+ paths.each do |path|
238
+ add_test_path(path)
239
+ end
206
240
  end
207
241
 
208
242
  @pattern = []
209
- o.on('-p', '--pattern=PATTERN', Regexp,
243
+ o.on("-p", "--pattern=PATTERN", Regexp,
210
244
  "Match files to collect against PATTERN.") do |e|
211
245
  @pattern << e
212
246
  end
213
247
 
214
248
  @exclude = []
215
- o.on('-x', '--exclude=PATTERN', Regexp,
249
+ o.on("-x", "--exclude=PATTERN", Regexp,
216
250
  "Ignore files to collect against PATTERN.") do |e|
217
251
  @exclude << e
218
252
  end
219
253
  end
220
254
 
221
- o.on('-n', '--name=NAME', String,
255
+ o.on("-n", "--name=NAME", String,
222
256
  "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)
257
+ "Use '/PATTERN/' for NAME to use regular expression.",
258
+ "Regular expression accepts options.",
259
+ "Example: '/taRget/i' matches 'target' and 'TARGET'") do |name|
260
+ name = prepare_name(name)
225
261
  @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
262
+ match_test_name(test, name)
232
263
  end
233
264
  end
234
265
 
235
- o.on('--ignore-name=NAME', String,
266
+ o.on("--ignore-name=NAME", String,
236
267
  "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}
268
+ "Use '/PATTERN/' for NAME to use regular expression.",
269
+ "Regular expression accepts options.",
270
+ "Example: '/taRget/i' matches 'target' and 'TARGET'") do |name|
271
+ name = prepare_name(name)
272
+ @filters << lambda do |test|
273
+ not match_test_name(test, name)
244
274
  end
245
275
  end
246
276
 
247
- o.on('-t', '--testcase=TESTCASE', String,
277
+ o.on("-t", "--testcase=TESTCASE", String,
248
278
  "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)
279
+ "Use '/PATTERN/' for TESTCASE to use regular expression.",
280
+ "Regular expression accepts options.",
281
+ "Example: '/taRget/i' matches 'target' and 'TARGET'") do |name|
282
+ name = prepare_name(name)
251
283
  @filters << lambda do |test|
252
- match_test_case_name(test, n)
284
+ match_test_case_name(test, name)
253
285
  end
254
286
  end
255
287
 
256
- o.on('--ignore-testcase=TESTCASE', String,
288
+ o.on("--ignore-testcase=TESTCASE", String,
257
289
  "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)
290
+ "Use '/PATTERN/' for TESTCASE to use regular expression.",
291
+ "Regular expression accepts options.",
292
+ "Example: '/taRget/i' matches 'target' and 'TARGET'") do |name|
293
+ name = prepare_name(name)
260
294
  @filters << lambda do |test|
261
- not match_test_case_name(test, n)
295
+ not match_test_case_name(test, name)
262
296
  end
263
297
  end
264
298
 
265
- o.on('--location=LOCATION', String,
299
+ o.on("--location=LOCATION", String,
266
300
  "Runs tests that defined in LOCATION.",
267
- "LOCATION is one of PATH:LINE, PATH or LINE") do |location|
268
- if /\A\d+\z/ =~ location
301
+ "LOCATION is one of PATH:LINE, PATH or LINE.") do |location|
302
+ case location
303
+ when /\A(\d+)\z/
269
304
  path = nil
270
- line = location.to_i
305
+ line = $1.to_i
306
+ when /:(\d+)\z/
307
+ path = $PREMATCH
308
+ line = $1.to_i
271
309
  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)
310
+ path = location
311
+ line = nil
279
312
  end
313
+ add_location_filter(path, line)
280
314
  end
281
315
 
282
- o.on('--attribute=EXPRESSION', String,
316
+ o.on("--attribute=EXPRESSION", String,
283
317
  "Runs tests that matches EXPRESSION.",
284
318
  "EXPRESSION is evaluated as Ruby's expression.",
285
319
  "Test attribute name can be used with no receiver in EXPRESSION.",
@@ -317,7 +351,7 @@ module Test
317
351
  Priority.default = priority
318
352
  end
319
353
 
320
- o.on('-I', "--load-path=DIR[#{File::PATH_SEPARATOR}DIR...]",
354
+ o.on("-I", "--load-path=DIR[#{File::PATH_SEPARATOR}DIR...]",
321
355
  "Appends directory list to $LOAD_PATH.") do |dirs|
322
356
  $LOAD_PATH.concat(dirs.split(File::PATH_SEPARATOR))
323
357
  end
@@ -330,7 +364,7 @@ module Test
330
364
  end
331
365
 
332
366
  o.on("--config=FILE",
333
- "Use YAML fomat FILE content as configuration file.") do |file|
367
+ "Use YAML format FILE content as configuration file.") do |file|
334
368
  load_config(file)
335
369
  end
336
370
 
@@ -349,27 +383,45 @@ module Test
349
383
  assertion_message_class.max_diff_target_string_size = size
350
384
  end
351
385
 
386
+ o.on("--[no-]stop-on-failure",
387
+ "Stops immediately on the first non success test",
388
+ "(#{@stop_on_failure})") do |boolean|
389
+ @stop_on_failure = boolean
390
+ end
391
+
392
+ o.on("--[no-]debug-on-failure",
393
+ "Run debugger if available on failure",
394
+ "(#{AssertionFailedError.debug_on_failure?})") do |boolean|
395
+ AssertionFailedError.debug_on_failure = boolean
396
+ end
397
+
398
+ o.on("--[no-]gc-stress",
399
+ "Enable GC.stress only while each test is running",
400
+ "(#{@gc_stress})") do |boolean|
401
+ @gc_stress = boolean
402
+ end
403
+
352
404
  ADDITIONAL_OPTIONS.each do |option_builder|
353
405
  option_builder.call(self, o)
354
406
  end
355
407
 
356
- o.on('--',
408
+ o.on("--",
357
409
  "Stop processing options so that the",
358
410
  "remaining options will be passed to the",
359
411
  "test."){o.terminate}
360
412
 
361
- o.on('-h', '--help', 'Display this help.'){puts o; exit}
413
+ o.on("-h", "--help", "Display this help."){puts o; exit}
362
414
 
363
415
  o.on_tail
364
- o.on_tail('Deprecated options:')
416
+ o.on_tail("Deprecated options:")
365
417
 
366
- o.on_tail('--console', 'Console runner (use --runner).') do
418
+ o.on_tail("--console", "Console runner (use --runner).") do
367
419
  warn("Deprecated option (--console).")
368
420
  @runner = self.class.runner(:console)
369
421
  end
370
422
 
371
423
  if RUNNERS[:fox]
372
- o.on_tail('--fox', 'Fox runner (use --runner).') do
424
+ o.on_tail("--fox", "Fox runner (use --runner).") do
373
425
  warn("Deprecated option (--fox).")
374
426
  @runner = self.class.runner(:fox)
375
427
  end
@@ -393,7 +445,7 @@ module Test
393
445
  n = 1
394
446
  end
395
447
  i += 1
396
- keyword.sub(/^(.{#{n}})([A-Za-z]+)(?=\w*$)/, '\\1[\\2]')
448
+ keyword.sub(/^(.{#{n}})([A-Za-z-]+)(?=\w*$)/, '\\1[\\2]')
397
449
  end.join(", ")
398
450
  end
399
451
 
@@ -407,13 +459,19 @@ module Test
407
459
  @runner_options[:color_scheme] ||= @color_scheme
408
460
  @runner_options[:listeners] ||= []
409
461
  @runner_options[:listeners].concat(@listeners)
462
+ if @stop_on_failure
463
+ @runner_options[:listeners] << StopOnFailureListener.new
464
+ end
465
+ if @gc_stress
466
+ @runner_options[:listeners] << GCStressListener.new
467
+ end
410
468
  change_work_directory do
411
469
  runner.run(suite, @runner_options).passed?
412
470
  end
413
471
  end
414
472
 
415
473
  def load_config(file)
416
- require 'yaml'
474
+ require "yaml"
417
475
  config = YAML.load(File.read(file))
418
476
  runner_name = config["runner"]
419
477
  @runner = self.class.runner(runner_name) || @runner
@@ -428,7 +486,7 @@ module Test
428
486
  if key == :arguments
429
487
  @default_arguments.concat(value.split)
430
488
  else
431
- runner_options[key.to_sym] = value
489
+ runner_options[key] = value
432
490
  end
433
491
  end
434
492
  @runner_options = @runner_options.merge(runner_options)
@@ -468,6 +526,31 @@ module Test
468
526
  end
469
527
  end
470
528
 
529
+ def prepare_name(name)
530
+ case name
531
+ when /\A\/(.*)\/([imx]*)\z/
532
+ pattern = $1
533
+ options_raw = $2
534
+ options = 0
535
+ options |= Regexp::IGNORECASE if options_raw.include?("i")
536
+ options |= Regexp::MULTILINE if options_raw.include?("m")
537
+ options |= Regexp::EXTENDED if options_raw.include?("x")
538
+ Regexp.new(pattern, options)
539
+ else
540
+ name
541
+ end
542
+ end
543
+
544
+ def match_test_name(test, pattern)
545
+ return true if pattern === test.method_name
546
+ return true if pattern === test.local_name
547
+ if pattern.is_a?(String)
548
+ return true if pattern === "#{test.class}##{test.method_name}"
549
+ return true if pattern === "#{test.class}##{test.local_name}"
550
+ end
551
+ false
552
+ end
553
+
471
554
  def match_test_case_name(test, pattern)
472
555
  test.class.ancestors.each do |test_class|
473
556
  break if test_class == TestCase
@@ -475,10 +558,49 @@ module Test
475
558
  end
476
559
  false
477
560
  end
561
+
562
+ def add_test_path(path)
563
+ if /:(\d+)\z/ =~ path
564
+ line = $1.to_i
565
+ path = $PREMATCH
566
+ add_location_filter(path, line)
567
+ end
568
+ @to_run << path
569
+ end
570
+
571
+ def add_location_filter(path, line)
572
+ @filters << lambda do |test|
573
+ test.class.test_defined?(:path => path,
574
+ :line => line,
575
+ :method_name => test.method_name)
576
+ end
577
+ end
578
+
579
+ class StopOnFailureListener
580
+ def attach_to_mediator(mediator)
581
+ mediator.add_listener(TestResult::FINISHED) do |result|
582
+ result.stop unless result.passed?
583
+ end
584
+ end
585
+ end
586
+
587
+ class GCStressListener
588
+ def attach_to_mediator(mediator)
589
+ mediator.add_listener(TestCase::STARTED) do |test|
590
+ GC.start
591
+ GC.stress = true
592
+ end
593
+
594
+ mediator.add_listener(TestCase::FINISHED) do |test|
595
+ GC.start
596
+ GC.stress = false
597
+ end
598
+ end
599
+ end
478
600
  end
479
601
  end
480
602
  end
481
603
 
482
- require 'test/unit/runner/console'
483
- require 'test/unit/runner/emacs'
484
- require 'test/unit/runner/xml'
604
+ require "test/unit/runner/console"
605
+ require "test/unit/runner/emacs"
606
+ 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