test-unit 3.1.4 → 3.6.2

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 (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