test-unit 2.0.0 → 2.0.1

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