test-unit 2.0.0 → 2.0.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 (39) hide show
  1. data/History.txt +30 -0
  2. data/Manifest.txt +20 -12
  3. data/README.txt +28 -12
  4. data/Rakefile +5 -0
  5. data/TODO +1 -0
  6. data/html/classic.html +15 -0
  7. data/html/index.html +25 -0
  8. data/html/index.html.ja +27 -0
  9. data/html/test-unit-classic.png +0 -0
  10. data/lib/test/unit.rb +62 -0
  11. data/lib/test/unit/assertions.rb +350 -66
  12. data/lib/test/unit/autorunner.rb +68 -13
  13. data/lib/test/unit/collector/load.rb +1 -1
  14. data/lib/test/unit/color-scheme.rb +85 -0
  15. data/lib/test/unit/color.rb +40 -5
  16. data/lib/test/unit/diff.rb +14 -0
  17. data/lib/test/unit/fixture.rb +2 -2
  18. data/lib/test/unit/runner/console.rb +8 -2
  19. data/lib/test/unit/testcase.rb +86 -2
  20. data/lib/test/unit/ui/console/testrunner.rb +51 -26
  21. data/lib/test/unit/version.rb +1 -1
  22. data/sample/test_user.rb +22 -0
  23. data/test/collector/{test_descendant.rb → test-descendant.rb} +0 -0
  24. data/test/collector/{test_load.rb → test-load.rb} +1 -1
  25. data/test/{test_attribute.rb → test-attribute.rb} +0 -0
  26. data/test/test-color-scheme.rb +55 -0
  27. data/test/{test_color.rb → test-color.rb} +10 -0
  28. data/test/{test_diff.rb → test-diff.rb} +0 -0
  29. data/test/{test_emacs_runner.rb → test-emacs-runner.rb} +0 -0
  30. data/test/test-fixture.rb +287 -0
  31. data/test/{test_notification.rb → test-notification.rb} +4 -4
  32. data/test/{test_omission.rb → test-omission.rb} +6 -6
  33. data/test/{test_pending.rb → test-pending.rb} +6 -6
  34. data/test/{test_priority.rb → test-priority.rb} +0 -0
  35. data/test/test_assertions.rb +366 -63
  36. data/test/test_testcase.rb +48 -0
  37. data/test/{testunit_test_util.rb → testunit-test-util.rb} +1 -1
  38. metadata +27 -29
  39. data/test/test_fixture.rb +0 -275
@@ -1,4 +1,5 @@
1
1
  require 'test/unit'
2
+ require 'test/unit/color-scheme'
2
3
  require 'optparse'
3
4
 
4
5
  module Test
@@ -11,10 +12,24 @@ module Test
11
12
  class << self
12
13
  def register_runner(id, runner_builder=Proc.new)
13
14
  RUNNERS[id] = runner_builder
15
+ RUNNERS[id.to_s] = runner_builder
16
+ end
17
+
18
+ def runner(id)
19
+ RUNNERS[id.to_s]
14
20
  end
15
21
 
16
22
  def register_collector(id, collector_builder=Proc.new)
17
23
  COLLECTORS[id] = collector_builder
24
+ COLLECTORS[id.to_s] = collector_builder
25
+ end
26
+
27
+ def collector(id)
28
+ COLLECTORS[id.to_s]
29
+ end
30
+
31
+ def register_color_scheme(id, scheme)
32
+ ColorScheme[id] = scheme
18
33
  end
19
34
 
20
35
  def setup_option(option_builder=Proc.new)
@@ -76,6 +91,7 @@ module Test
76
91
 
77
92
  attr_reader :suite, :runner_options
78
93
  attr_accessor :filters, :to_run, :pattern, :exclude, :base, :workdir
94
+ attr_accessor :color_scheme
79
95
  attr_writer :runner, :collector
80
96
 
81
97
  def initialize(standalone)
@@ -85,8 +101,11 @@ module Test
85
101
  @collector = default_collector
86
102
  @filters = []
87
103
  @to_run = []
104
+ @color_scheme = ColorScheme.default
88
105
  @runner_options = {}
89
106
  @workdir = nil
107
+ default_config_file = "test-unit.yml"
108
+ load_config(default_config_file) if File.exist?(default_config_file)
90
109
  yield(self) if block_given?
91
110
  end
92
111
 
@@ -96,8 +115,7 @@ module Test
96
115
  rescue OptionParser::ParseError => e
97
116
  puts e
98
117
  puts options
99
- $! = nil
100
- abort
118
+ exit(false)
101
119
  else
102
120
  @filters << proc{false} unless(@filters.empty?)
103
121
  end
@@ -116,7 +134,7 @@ module Test
116
134
  @runner = r
117
135
  end
118
136
 
119
- if(@standalone)
137
+ if (@standalone)
120
138
  o.on('-b', '--basedir=DIR', "Base directory of test suites.") do |b|
121
139
  @base = b
122
140
  end
@@ -169,7 +187,11 @@ module Test
169
187
  end
170
188
 
171
189
  priority_filter = Proc.new do |test|
172
- Priority::Checker.new(test).need_to_run? or nil
190
+ if @filters.size > 2
191
+ nil
192
+ else
193
+ Priority::Checker.new(test).need_to_run? or nil
194
+ end
173
195
  end
174
196
  o.on("--[no-]priority-mode",
175
197
  "Runs some tests based on their priority.") do |priority_mode|
@@ -185,6 +207,18 @@ module Test
185
207
  $LOAD_PATH.concat(dirs.split(File::PATH_SEPARATOR))
186
208
  end
187
209
 
210
+ color_schemes = ColorScheme.all
211
+ o.on("--color-scheme=SCHEME", color_schemes,
212
+ "Use SCHEME as color scheme.",
213
+ "(#{keyword_display(color_schemes)})") do |scheme|
214
+ @color_scheme = scheme
215
+ end
216
+
217
+ o.on("--config=FILE",
218
+ "Use YAML fomat FILE content as configuration file.") do |file|
219
+ load_config(file)
220
+ end
221
+
188
222
  ADDITIONAL_OPTIONS.each do |option_builder|
189
223
  option_builder.call(self, o)
190
224
  end
@@ -201,13 +235,13 @@ module Test
201
235
 
202
236
  o.on_tail('--console', 'Console runner (use --runner).') do
203
237
  warn("Deprecated option (--console).")
204
- @runner = RUNNERS[:console]
238
+ @runner = self.class.runner(:console)
205
239
  end
206
240
 
207
241
  if RUNNERS[:fox]
208
242
  o.on_tail('--fox', 'Fox runner (use --runner).') do
209
243
  warn("Deprecated option (--fox).")
210
- @runner = RUNNERS[:fox]
244
+ @runner = self.class.runner(:fox)
211
245
  end
212
246
  end
213
247
 
@@ -215,10 +249,12 @@ module Test
215
249
  end
216
250
  end
217
251
 
218
- def keyword_display(array)
219
- list = array.collect {|e, *| e.to_s}
220
- Array === array or list.sort!
221
- list.collect {|e| e.sub(/^(.)([A-Za-z]+)(?=\w*$)/, '\\1[\\2]')}.join(", ")
252
+ def keyword_display(keywords)
253
+ keywords.collect do |keyword, _|
254
+ keyword.to_s
255
+ end.uniq.sort.collect do |keyword|
256
+ keyword.sub(/^(.)([A-Za-z]+)(?=\w*$)/, '\\1[\\2]')
257
+ end.join(", ")
222
258
  end
223
259
 
224
260
  def run
@@ -226,21 +262,40 @@ module Test
226
262
  return false if suite.nil?
227
263
  runner = @runner[self]
228
264
  return false if runner.nil?
265
+ @runner_options[:color_scheme] ||= @color_scheme
229
266
  Dir.chdir(@workdir) if @workdir
230
267
  runner.run(suite, @runner_options).passed?
231
268
  end
232
269
 
270
+ def load_config(file)
271
+ require 'yaml'
272
+ config = YAML.load(File.read(file))
273
+ runner_name = config["runner"]
274
+ @runner = self.class.runner(runner_name) || @runner
275
+ @collector = self.class.collector(config["collector"]) || @collector
276
+ (config["color_schemes"] || {}).each do |name, options|
277
+ ColorScheme[name] = options
278
+ end
279
+ runner_options = {}
280
+ (config["#{runner_name}_options"] || {}).each do |key, value|
281
+ key = key.to_sym
282
+ value = ColorScheme[value] if key == :color_scheme
283
+ runner_options[key.to_sym] = value
284
+ end
285
+ @runner_options = @runner_options.merge(runner_options)
286
+ end
287
+
233
288
  private
234
289
  def default_runner
235
290
  if ENV["EMACS"] == "t"
236
- RUNNERS[:emacs]
291
+ self.class.runner(:emacs)
237
292
  else
238
- RUNNERS[:console]
293
+ self.class.runner(:console)
239
294
  end
240
295
  end
241
296
 
242
297
  def default_collector
243
- COLLECTORS[@standalone ? :load : :descendant]
298
+ self.class.collector(@standalone ? :load : :descendant)
244
299
  end
245
300
  end
246
301
  end
@@ -15,7 +15,7 @@ module Test
15
15
  super
16
16
  @system_excludes = [/~\z/, /\A\.\#/]
17
17
  @system_directory_excludes = [/\A(?:CVS|\.svn)\z/]
18
- @patterns = [/\Atest_.+\.rb\z/m]
18
+ @patterns = [/\Atest[_\-].+\.rb\z/m]
19
19
  @excludes = []
20
20
  @base = nil
21
21
  end
@@ -0,0 +1,85 @@
1
+ require 'test/unit/color'
2
+
3
+ module Test
4
+ module Unit
5
+ class ColorScheme
6
+ include Enumerable
7
+
8
+ class << self
9
+ @@default = nil
10
+ def default
11
+ @@default ||= new("success" => Color.new("green", :bold => true),
12
+ "failure" => Color.new("red", :bold => true),
13
+ "pending" => Color.new("magenta", :bold => true),
14
+ "omission" => Color.new("blue", :bold => true),
15
+ "notification" => Color.new("cyan", :bold => true),
16
+ "error" => Color.new("yellow", :bold => true))
17
+ end
18
+
19
+ @@schemes = {}
20
+ def all
21
+ @@schemes.merge("default" => default)
22
+ end
23
+
24
+ def [](id)
25
+ @@schemes[id.to_s]
26
+ end
27
+
28
+ def []=(id, scheme_or_spec)
29
+ if scheme_or_spec.is_a?(self)
30
+ scheme = scheme_or_spec
31
+ else
32
+ scheme = new(scheme_or_spec)
33
+ end
34
+ @@schemes[id.to_s] = scheme
35
+ end
36
+ end
37
+
38
+ def initialize(scheme_spec)
39
+ @scheme = {}
40
+ scheme_spec.each do |key, color_spec|
41
+ self[key] = color_spec
42
+ end
43
+ end
44
+
45
+ def [](name)
46
+ @scheme[name.to_s]
47
+ end
48
+
49
+ def []=(name, color_spec)
50
+ @scheme[name.to_s] = make_color(color_spec)
51
+ end
52
+
53
+ def each(&block)
54
+ @scheme.each(&block)
55
+ end
56
+
57
+ def to_hash
58
+ hash = {}
59
+ @scheme.each do |key, color|
60
+ hash[key] = color
61
+ end
62
+ hash
63
+ end
64
+
65
+ private
66
+ def make_color(color_spec)
67
+ if color_spec.is_a?(Color)
68
+ color_spec
69
+ else
70
+ color_name = nil
71
+ normalized_color_spec = {}
72
+ color_spec.each do |key, value|
73
+ key = key.to_sym
74
+ if key == :name
75
+ color_name = value
76
+ else
77
+ normalized_color_spec[key] = value
78
+ end
79
+ end
80
+ Color.new(color_name, normalized_color_spec)
81
+ end
82
+ end
83
+ end
84
+ end
85
+ end
@@ -3,6 +3,8 @@ module Test
3
3
  class Color
4
4
  NAMES = ["black", "red", "green", "yellow",
5
5
  "blue", "magenta", "cyan", "white"]
6
+
7
+ attr_reader :name
6
8
  def initialize(name, options={})
7
9
  @name = name
8
10
  @foreground = options[:foreground]
@@ -13,19 +15,47 @@ module Test
13
15
  @underline = options[:underline]
14
16
  end
15
17
 
18
+ def foreground?
19
+ @foreground
20
+ end
21
+
22
+ def intensity?
23
+ @intensity
24
+ end
25
+
26
+ def bold?
27
+ @bold
28
+ end
29
+
30
+ def italic?
31
+ @italic
32
+ end
33
+
34
+ def underline?
35
+ @underline
36
+ end
37
+
38
+ def ==(other)
39
+ self.class === other and
40
+ [name, foreground?, intensity?,
41
+ bold?, italic?, underline?] ==
42
+ [other.name, other.foreground?, other.intensity?,
43
+ other.bold?, other.italic?, other.underline?]
44
+ end
45
+
16
46
  def sequence
17
47
  sequence = []
18
48
  if @name == "none"
19
49
  elsif @name == "reset"
20
50
  sequence << "0"
21
51
  else
22
- foreground_parameter = @foreground ? 3 : 4
23
- foreground_parameter += 6 if @intensity
52
+ foreground_parameter = foreground? ? 3 : 4
53
+ foreground_parameter += 6 if intensity?
24
54
  sequence << "#{foreground_parameter}#{NAMES.index(@name)}"
25
55
  end
26
- sequence << "1" if @bold
27
- sequence << "3" if @italic
28
- sequence << "4" if @underline
56
+ sequence << "1" if bold?
57
+ sequence << "3" if italic?
58
+ sequence << "4" if underline?
29
59
  sequence
30
60
  end
31
61
 
@@ -39,6 +69,7 @@ module Test
39
69
  end
40
70
 
41
71
  class MixColor
72
+ attr_reader :colors
42
73
  def initialize(colors)
43
74
  @colors = colors
44
75
  end
@@ -56,6 +87,10 @@ module Test
56
87
  def +(other)
57
88
  self.class.new([self, other])
58
89
  end
90
+
91
+ def ==(other)
92
+ self.class === other and colors == other.colors
93
+ end
59
94
  end
60
95
  end
61
96
  end
@@ -507,6 +507,20 @@ module Test
507
507
  end
508
508
 
509
509
  module_function
510
+ def need_fold?(diff)
511
+ /^[-+].{79}/ =~ diff
512
+ end
513
+
514
+ def fold(string)
515
+ string.split(/\r?\n/).collect do |line|
516
+ line.gsub(/(.{78})/, "\\1\n")
517
+ end.join("\n")
518
+ end
519
+
520
+ def folded_readable(from, to, options={})
521
+ readable(fold(from), fold(to), options)
522
+ end
523
+
510
524
  def readable(from, to, options={})
511
525
  diff(ReadableDiffer, from, to, options)
512
526
  end
@@ -153,10 +153,10 @@ module Test
153
153
  unregistered_methods =
154
154
  instance_variable_get(unregistered_methods_variable)
155
155
  end
156
- result + methods - unregistered_methods
156
+ (result | methods) - unregistered_methods
157
157
  end
158
158
  else
159
- []
159
+ result
160
160
  end
161
161
  end
162
162
  end
@@ -31,8 +31,8 @@ module Test
31
31
  ["true", true],
32
32
  ]
33
33
  opts.on("--[no-]use-color=[auto]", use_color_options,
34
- "Use color output",
35
- "(default is auto") do |use_color|
34
+ "Uses color output",
35
+ "(default is auto)") do |use_color|
36
36
  case use_color
37
37
  when nil
38
38
  use_color = true
@@ -41,6 +41,12 @@ module Test
41
41
  end
42
42
  auto_runner.runner_options[:use_color] = use_color
43
43
  end
44
+
45
+ opts.on("--progress-row-max=MAX", Integer,
46
+ "Uses MAX as max terminal width for progress mark",
47
+ "(default is auto)") do |max|
48
+ auto_runner.runner_options[:progress_row_max] = max
49
+ end
44
50
  end
45
51
  end
46
52
  end
@@ -109,6 +109,79 @@ module Test
109
109
  end
110
110
  suite
111
111
  end
112
+
113
+ # Called before every test case runs. Can be used
114
+ # to set up fixture information used in test case
115
+ # scope.
116
+ #
117
+ # Here is an example test case:
118
+ # class TestMyClass < Test::Unit::TestCase
119
+ # class << self
120
+ # def startup
121
+ # ...
122
+ # end
123
+ # end
124
+ #
125
+ # def setup
126
+ # ...
127
+ # end
128
+ #
129
+ # def test_my_class1
130
+ # ...
131
+ # end
132
+ #
133
+ # def test_my_class2
134
+ # ...
135
+ # end
136
+ # end
137
+ #
138
+ # Here is a call order:
139
+ # * startup
140
+ # * setup
141
+ # * test_my_class1 (or test_my_class2)
142
+ # * setup
143
+ # * test_my_class2 (or test_my_class1)
144
+ #
145
+ # Note that you should not assume test order. Tests
146
+ # should be worked in any order.
147
+ def startup
148
+ end
149
+
150
+ # Called after every test case runs. Can be used to tear
151
+ # down fixture information used in test case scope.
152
+ #
153
+ # Here is an example test case:
154
+ # class TestMyClass < Test::Unit::TestCase
155
+ # class << self
156
+ # def shutdown
157
+ # ...
158
+ # end
159
+ # end
160
+ #
161
+ # def teardown
162
+ # ...
163
+ # end
164
+ #
165
+ # def test_my_class1
166
+ # ...
167
+ # end
168
+ #
169
+ # def test_my_class2
170
+ # ...
171
+ # end
172
+ # end
173
+ #
174
+ # Here is a call order:
175
+ # * test_my_class1 (or test_my_class2)
176
+ # * teardown
177
+ # * test_my_class2 (or test_my_class1)
178
+ # * teardown
179
+ # * shutdown
180
+ #
181
+ # Note that you should not assume test order. Tests
182
+ # should be worked in any order.
183
+ def shutdown
184
+ end
112
185
  end
113
186
 
114
187
  attr_reader :method_name
@@ -117,7 +190,14 @@ module Test
117
190
  # test represented by test_method_name.
118
191
  def initialize(test_method_name)
119
192
  throw :invalid_test unless respond_to?(test_method_name)
120
- throw :invalid_test if method(test_method_name).arity > 0
193
+ test_method = method(test_method_name)
194
+ throw :invalid_test if test_method.arity > 0
195
+ if test_method.respond_to?(:owner)
196
+ if test_method.owner.class != Module and
197
+ self.class != test_method.owner
198
+ throw :invalid_test
199
+ end
200
+ end
121
201
  @method_name = test_method_name
122
202
  @test_passed = true
123
203
  @interrupted = false
@@ -132,7 +212,7 @@ module Test
132
212
  yield(STARTED, name)
133
213
  begin
134
214
  run_setup
135
- __send__(@method_name)
215
+ run_test
136
216
  rescue Exception
137
217
  @interrupted = true
138
218
  raise unless handle_exception($!)
@@ -251,6 +331,10 @@ module Test
251
331
  @_result
252
332
  end
253
333
 
334
+ def run_test
335
+ __send__(@method_name)
336
+ end
337
+
254
338
  def handle_exception(exception)
255
339
  self.class.exception_handlers.each do |handler|
256
340
  return true if send(handler, exception)