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,3 +1,33 @@
1
+ === 2.0.1 / 2008-11-09
2
+
3
+ * 19 major enhancements
4
+
5
+ * support ruby 1.9.1.
6
+ * add run_test method to be extensible.
7
+ * improve priority-mode auto off.
8
+ * improve startup/shutdown RDoc. [Daniel Berger]
9
+ * add assert_compare. [#20851] [Designing Patterns]
10
+ * add assert_fail_assertion. [#20851] [Designing Patterns]
11
+ * add assert_raise_message. [#20851] [Designing Patterns]
12
+ * support folded diff.
13
+ * add assert_raise_kind_of. [Daniel Berger]
14
+ * ingore inherited test for nested test case.
15
+ * add assert_const_defined.
16
+ * add assert_not_const_defined.
17
+ * support assert_raise with an exception object.
18
+ * support assert_raise with no arguments that asserts any
19
+ exception is raised. [#22602] [Daniel Berger]
20
+ * support folded dot progress.
21
+ * add --progress-row-max option.
22
+ * support color scheme customize.
23
+ * support configuration file. (YAML)
24
+ * recognize test-XXX.rb files as test files not only test_XXX.rb
25
+
26
+ * Thanks
27
+
28
+ * Daniel Berger
29
+ * Designing Patterns
30
+
1
31
  === 2.0.0 / 2008-06-18
2
32
 
3
33
  * 15 major enhancements
@@ -2,7 +2,12 @@ History.txt
2
2
  Manifest.txt
3
3
  README.txt
4
4
  Rakefile
5
+ TODO
5
6
  bin/testrb
7
+ html/classic.html
8
+ html/index.html
9
+ html/index.html.ja
10
+ html/test-unit-classic.png
6
11
  lib/test/unit.rb
7
12
  lib/test/unit/assertionfailederror.rb
8
13
  lib/test/unit/assertions.rb
@@ -13,6 +18,7 @@ lib/test/unit/collector/descendant.rb
13
18
  lib/test/unit/collector/dir.rb
14
19
  lib/test/unit/collector/load.rb
15
20
  lib/test/unit/collector/objectspace.rb
21
+ lib/test/unit/color-scheme.rb
16
22
  lib/test/unit/color.rb
17
23
  lib/test/unit/diff.rb
18
24
  lib/test/unit/error.rb
@@ -42,28 +48,30 @@ sample/adder.rb
42
48
  sample/subtracter.rb
43
49
  sample/tc_adder.rb
44
50
  sample/tc_subtracter.rb
51
+ sample/test_user.rb
45
52
  sample/ts_examples.rb
46
- test/collector/test_descendant.rb
53
+ test/collector/test-descendant.rb
54
+ test/collector/test-load.rb
47
55
  test/collector/test_dir.rb
48
- test/collector/test_load.rb
49
56
  test/collector/test_objectspace.rb
50
57
  test/run-test.rb
58
+ test/test-attribute.rb
59
+ test/test-color-scheme.rb
60
+ test/test-color.rb
61
+ test/test-diff.rb
62
+ test/test-emacs-runner.rb
63
+ test/test-fixture.rb
64
+ test/test-notification.rb
65
+ test/test-omission.rb
66
+ test/test-pending.rb
67
+ test/test-priority.rb
51
68
  test/test_assertions.rb
52
- test/test_attribute.rb
53
- test/test_color.rb
54
- test/test_diff.rb
55
- test/test_emacs_runner.rb
56
69
  test/test_error.rb
57
70
  test/test_failure.rb
58
- test/test_fixture.rb
59
- test/test_notification.rb
60
- test/test_omission.rb
61
- test/test_pending.rb
62
- test/test_priority.rb
63
71
  test/test_testcase.rb
64
72
  test/test_testresult.rb
65
73
  test/test_testsuite.rb
66
- test/testunit_test_util.rb
74
+ test/testunit-test-util.rb
67
75
  test/ui/test_testrunmediator.rb
68
76
  test/util/test_backtracefilter.rb
69
77
  test/util/test_observable.rb
data/README.txt CHANGED
@@ -1,13 +1,17 @@
1
- = Test::Unit (Classic)
1
+ = Test::Unit 2.x
2
2
 
3
3
  * http://rubyforge.org/projects/test-unit/
4
4
 
5
- == DESCRIPTION:
5
+ == DESCRIPTION
6
6
 
7
- Test::Unit (Classic) - Nathaniel Talbott's originial test-unit,
8
- externalized from the ruby project as a gem (for tool developers).
7
+ Test::Unit 2.x - Improved version of Test::Unit bundled in
8
+ Ruby 1.8.x.
9
9
 
10
- == FEATURES/PROBLEMS:
10
+ Ruby 1.9.x bundles miniunit not Test::Unit. Test::Unit
11
+ bundled in Ruby 1.8.x had not been improved but unbundled
12
+ Test::Unit (Test::Unit 2.x) will be improved actively.
13
+
14
+ == FEATURES
11
15
 
12
16
  * Test::Unit 1.2.3 is the original Test::Unit, taken
13
17
  straight from the ruby distribution. It is being
@@ -15,18 +19,30 @@ externalized from the ruby project as a gem (for tool developers).
15
19
  stand-alone package. (The test framework in ruby is going
16
20
  to radically change very soon).
17
21
 
18
- * DO NOT INSTALL THIS GEM unless you're active state or some other
19
- development tool provider! You don't need it.
22
+ * Test::Unit 2.x will be improved actively and may break
23
+ compatiblity with Test::Unit 1.2.3. (We will not hope it
24
+ if it isn't needed.)
25
+
26
+ * Some features exist as separated gems like GUI test
27
+ runner. (Tk, GTK+ and Fox) test-unit-full gem package
28
+ provides for installing all Test::Unit related gems
29
+ easily.
30
+
31
+ == INSTALL
20
32
 
21
- * Test::Unit 2.0.0 or later are extended versions of the
22
- original Test::Unit (== Tset::Unit 1.2.3).
33
+ % sudo gem install test-unit
23
34
 
24
- == INSTALL:
35
+ If you want to use full Test::Unit features:
25
36
 
26
- * sudo gem install test-unit
37
+ % sudo gem install test-unit-full
27
38
 
28
- == LICENSE:
39
+ == LICENSE
29
40
 
30
41
  (The Ruby License)
31
42
 
32
43
  This software is distributed under the same terms as ruby.
44
+
45
+ == Thanks
46
+
47
+ * Daniel Berger: suggestions.
48
+ * Designing Patterns: Suggestions.
data/Rakefile CHANGED
@@ -15,12 +15,17 @@ Hoe.new('test-unit', version) do |p|
15
15
  end
16
16
 
17
17
  task :check_manifest => :clean_test_result
18
+ task :check_manifest => :clean_coverage
18
19
 
19
20
  task :clean_test_result do
20
21
  test_results = Dir.glob("**/.test-result")
21
22
  sh("rm", "-rf", *test_results) unless test_results.empty?
22
23
  end
23
24
 
25
+ task :clean_coverage do
26
+ sh("rm", "-rf", "coverage")
27
+ end
28
+
24
29
  task :tag do
25
30
  message = "Released Test::Unit #{version}!"
26
31
  base = "svn+ssh://#{ENV['USER']}@rubyforge.org/var/svn/test-unit/"
data/TODO ADDED
@@ -0,0 +1 @@
1
+ * mock.
@@ -0,0 +1,15 @@
1
+ <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
2
+ <html>
3
+ <head>
4
+ <title>Test::Unit (Classic)</title>
5
+ </head>
6
+ <body bgcolor="red">
7
+ <p style="text-align: center">
8
+ <img height="161" width="308" src="test-unit-classic.png">
9
+ <br>
10
+ <br>
11
+ <br>
12
+ Read the <a href="classic/test-unit/">rdoc</a>
13
+ </p>
14
+ </body>
15
+ </html>
@@ -0,0 +1,25 @@
1
+ <?xml version="1.0" encoding="utf-8" ?>
2
+ <!DOCTYPE html
3
+ PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
4
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
5
+ <html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">
6
+ <head>
7
+ <meta http-equiv="Content-type" content="text/html; charset=utf-8" />
8
+ <title>Test::Unit - a Unit Testing Framework for Ruby</title>
9
+ </head>
10
+ <body>
11
+ <h1>Test::Unit - a Unit Testing Framework for Ruby</h1>
12
+ <p>[<a href="index.html.ja">Japanese</a>]</p>
13
+ <ul>
14
+ <li><a href="http://rubyforge.org/projects/test-unit/">Project Page</a></li>
15
+ <li>
16
+ <a href="test-unit/">RDoc</a>
17
+ <!--(<a href="ja/test-unit/">ja</a>)-->
18
+ </li>
19
+ <li>
20
+ <a href="classic.html">Classic</a>
21
+ <!--(<a href="ja/classic.html">ja</a>)-->
22
+ </li>
23
+ </ul>
24
+ </body>
25
+ </html>
@@ -0,0 +1,27 @@
1
+ <?xml version="1.0" encoding="utf-8" ?>
2
+ <!DOCTYPE html
3
+ PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
4
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
5
+ <html xmlns="http://www.w3.org/1999/xhtml" lang="ja" xml:lang="ja">
6
+ <head>
7
+ <meta http-equiv="Content-type" content="text/html; charset=utf-8" />
8
+ <title>Test::Unit - Ruby用単体テストフレームワーク</title>
9
+ </head>
10
+ <body>
11
+ <h1>Test::Unit - Ruby用単体テストフレームワーク</h1>
12
+ <p>[<a href="./">English</a>]</p>
13
+ <ul>
14
+ <li>
15
+ <a href="http://rubyforge.org/projects/test-unit/">プロジェクトページ</a>
16
+ </li>
17
+ <li>
18
+ <!--<a href="ja/test-unit/">RDoc</a>-->
19
+ RDoc(<a href="test-unit/">en</a>)
20
+ </li>
21
+ <li>
22
+ <!--<a href="classic.html.html">Classic</a>-->
23
+ Classic(<a href="classic.html">en</a>)
24
+ </li>
25
+ </ul>
26
+ </body>
27
+ </html>
@@ -253,6 +253,68 @@ module Test # :nodoc:
253
253
  # the dynamic suite using the console TestRunner.
254
254
  #
255
255
  #
256
+ # == Configuration file
257
+ #
258
+ # Test::Unit reads 'test-unit.yml' in the current working
259
+ # directory as Test::Unit's configuration file. It can
260
+ # contain the following configurations:
261
+ #
262
+ # * color scheme definitions
263
+ # * test runner to be used
264
+ # * test runner options
265
+ # * test collector to be used
266
+ #
267
+ # Except color scheme definitions, all of them are
268
+ # specified by command line option.
269
+ #
270
+ # Here are sample color scheme definitions:
271
+ #
272
+ # color_schemes:
273
+ # inverted:
274
+ # success:
275
+ # name: red
276
+ # bold: true
277
+ # failure:
278
+ # name: green
279
+ # bold: true
280
+ # other_scheme:
281
+ # ...
282
+ #
283
+ # Here are the syntax of color scheme definitions:
284
+ #
285
+ # color_schemes:
286
+ # SCHEME_NAME:
287
+ # EVENT_NAME:
288
+ # name: COLOR_NAME
289
+ # intensity: BOOLEAN
290
+ # bold: BOOLEAN
291
+ # italic: BOOLEAN
292
+ # underline: BOOLEAN
293
+ # ...
294
+ # ...
295
+ #
296
+ # SCHEME_NAME:: the name of the color scheme
297
+ # EVENT_NAME:: one of [success, failure, pending,
298
+ # omission, notification, error]
299
+ # COLOR_NAME:: one of [black, red, green, yellow, blue,
300
+ # magenta, cyan, white]
301
+ # BOOLEAN:: true or false
302
+ #
303
+ # You can use the above 'inverted' color scheme with the
304
+ # following configuration:
305
+ #
306
+ # runner: console
307
+ # console_options:
308
+ # color_scheme: inverted
309
+ # color_schemes:
310
+ # inverted:
311
+ # success:
312
+ # name: red
313
+ # bold: true
314
+ # failure:
315
+ # name: green
316
+ # bold: true
317
+ #
256
318
  # == Questions?
257
319
  #
258
320
  # I'd really like to get feedback from all levels of Ruby
@@ -77,21 +77,7 @@ module Test
77
77
 
78
78
  public
79
79
  def assert_equal(expected, actual, message=nil)
80
- diff = AssertionMessage.delayed_literal do
81
- if !expected.is_a?(String) or !actual.is_a?(String)
82
- expected = AssertionMessage.convert(expected)
83
- actual = AssertionMessage.convert(actual)
84
- end
85
- diff = Diff.readable(expected, actual)
86
- if /^[-+]/ !~ diff
87
- diff = ""
88
- elsif /^[ ?]/ =~ diff or /(?:.*\n){2,}/ =~ diff
89
- diff = "\n\ndiff:\n#{diff}"
90
- else
91
- diff = ""
92
- end
93
- diff
94
- end
80
+ diff = AssertionMessage.delayed_diff(expected, actual)
95
81
  full_message = build_message(message, <<EOT, expected, actual, diff)
96
82
  <?> expected but was
97
83
  <?>.?
@@ -99,53 +85,36 @@ EOT
99
85
  assert_block(full_message) { expected == actual }
100
86
  end
101
87
 
102
- private
103
- def _check_exception_class(args) # :nodoc:
104
- args.partition do |klass|
105
- next if klass.instance_of?(Module)
106
- assert(Exception >= klass, "Should expect a class of exception, #{klass}")
107
- true
108
- end
109
- end
110
-
111
- private
112
- def _expected_exception?(actual_exception, exceptions, modules) # :nodoc:
113
- exceptions.include?(actual_exception.class) or
114
- modules.any? {|mod| actual_exception.is_a?(mod)}
115
- end
116
-
117
88
  ##
118
- # Passes if the block raises one of the given exceptions.
89
+ # Passes if the block raises one of the expected
90
+ # exceptions. When an expected exception is an Exception
91
+ # object, passes if expected_exception == actual_exception.
119
92
  #
120
93
  # Example:
121
- # assert_raise RuntimeError, LoadError do
94
+ # assert_raise(RuntimeError, LoadError) do
122
95
  # raise 'Boom!!!'
123
- # end
124
-
96
+ # end # -> pass
97
+ #
98
+ # assert_raise do
99
+ # raise Exception, 'Any exception should be raised!!!'
100
+ # end # -> pass
101
+ #
102
+ # assert_raise(RuntimeError.new("XXX")) {raise "XXX"} # -> pass
103
+ # assert_raise(MyError.new("XXX")) {raise "XXX"} # -> fail
104
+ # assert_raise(RuntimeError.new("ZZZ")) {raise "XXX"} # -> fail
125
105
  public
126
- def assert_raise(*args)
127
- _wrap_assertion do
128
- if Module === args.last
129
- message = ""
130
- else
131
- message = args.pop
132
- end
133
- exceptions, modules = _check_exception_class(args)
134
- expected = args.size == 1 ? args.first : args
135
- actual_exception = nil
136
- full_message = build_message(message, "<?> exception expected but none was thrown.", expected)
106
+ def assert_raise(*args, &block)
107
+ assert_expected_exception = Proc.new do |*_args|
108
+ message, assert_exception_helper, actual_exception = _args
109
+ expected = assert_exception_helper.expected_exceptions
110
+ full_message = build_message(message,
111
+ "<?> exception expected but was\n?",
112
+ expected, actual_exception)
137
113
  assert_block(full_message) do
138
- begin
139
- yield
140
- rescue Exception => actual_exception
141
- break
142
- end
143
- false
114
+ expected == [] or assert_exception_helper.expected?(actual_exception)
144
115
  end
145
- full_message = build_message(message, "<?> exception expected but was\n?", expected, actual_exception)
146
- assert_block(full_message) {_expected_exception?(actual_exception, exceptions, modules)}
147
- actual_exception
148
116
  end
117
+ _assert_raise(assert_expected_exception, *args, &block)
149
118
  end
150
119
 
151
120
  ##
@@ -158,6 +127,30 @@ EOT
158
127
  assert_raise(*args, &block)
159
128
  end
160
129
 
130
+ ##
131
+ # Passes if the block raises one of the given
132
+ # exceptions or sub exceptions of the given exceptions.
133
+ #
134
+ # Example:
135
+ # assert_raise_kind_of(SystemCallError) do
136
+ # raise Errno::EACCES
137
+ # end
138
+ def assert_raise_kind_of(*args, &block)
139
+ assert_expected_exception = Proc.new do |*_args|
140
+ message, assert_exception_helper, actual_exception = _args
141
+ expected = assert_exception_helper.expected_exceptions
142
+ full_message = build_message(message,
143
+ "<?> family exception expected " +
144
+ "but was\n?",
145
+ expected, actual_exception)
146
+ assert_block(full_message) do
147
+ assert_exception_helper.expected?(actual_exception, :kind_of?)
148
+ end
149
+ end
150
+ _assert_raise(assert_expected_exception, *args, &block)
151
+ end
152
+
153
+
161
154
  ##
162
155
  # Passes if +object+ .instance_of? +klass+
163
156
  #
@@ -301,18 +294,20 @@ EOT
301
294
  public
302
295
  def assert_nothing_raised(*args)
303
296
  _wrap_assertion do
304
- if Module === args.last
305
- message = ""
306
- else
297
+ if args.last.is_a?(String)
307
298
  message = args.pop
299
+ else
300
+ message = ""
308
301
  end
309
- exceptions, modules = _check_exception_class(args)
302
+
303
+ assert_exception_helper = AssertExceptionHelper.new(self, args)
310
304
  begin
311
305
  yield
312
306
  rescue Exception => e
313
307
  if ((args.empty? && !e.instance_of?(AssertionFailedError)) ||
314
- _expected_exception?(e, exceptions, modules))
315
- assert_block(build_message(message, "Exception raised:\n?", e)){false}
308
+ assert_exception_helper.expected?(e))
309
+ failure_message = build_message(message, "Exception raised:\n?", e)
310
+ assert_block(failure_message) {false}
316
311
  else
317
312
  raise
318
313
  end
@@ -398,12 +393,12 @@ EOT
398
393
  # Passes if the block throws +expected_object+
399
394
  #
400
395
  # Example:
401
- # assert_throws :done do
402
- # throw :done
396
+ # assert_throw(:done) do
397
+ # throw(:done)
403
398
  # end
404
399
 
405
400
  public
406
- def assert_throws(expected_object, message="", &proc)
401
+ def assert_throw(expected_object, message="", &proc)
407
402
  _wrap_assertion do
408
403
  begin
409
404
  catch([]) {}
@@ -411,7 +406,7 @@ EOT
411
406
  assert_instance_of(Symbol, expected_object,
412
407
  "assert_throws expects the symbol that should be thrown for its first argument")
413
408
  end
414
- assert_block("Should have passed a block to assert_throws.") do
409
+ assert_block("Should have passed a block to assert_throw.") do
415
410
  block_given?
416
411
  end
417
412
  caught = true
@@ -437,6 +432,14 @@ EOT
437
432
  end
438
433
  end
439
434
 
435
+ ##
436
+ # Alias of assert_throw.
437
+ #
438
+ # Will be deprecated in 1.9, and removed in 2.0.
439
+ def assert_throws(*args, &block)
440
+ assert_throw(*args, &block)
441
+ end
442
+
440
443
  ##
441
444
  # Passes if block does not throw anything.
442
445
  #
@@ -559,6 +562,136 @@ EOT
559
562
  end
560
563
  end
561
564
 
565
+ ##
566
+ # Passes if expression "+expected+ +operator+
567
+ # +actual+" is true.
568
+ #
569
+ # Example:
570
+ # assert_compare(1, "<", 10) # -> pass
571
+ # assert_compare(1, ">=", 10) # -> fail
572
+ def assert_compare(expected, operator, actual, message=nil)
573
+ _wrap_assertion do
574
+ assert_send([["<", "<=", ">", ">="], :include?, operator.to_s])
575
+ case operator.to_s
576
+ when "<"
577
+ operator_description = "less than"
578
+ when "<="
579
+ operator_description = "less than or equal to"
580
+ when ">"
581
+ operator_description = "greater than"
582
+ when ">="
583
+ operator_description = "greater than or equal to"
584
+ end
585
+ template = <<-EOT
586
+ <?> #{operator} <?> should be true
587
+ <?> expected #{operator_description}
588
+ <?>.
589
+ EOT
590
+ full_message = build_message(message, template,
591
+ expected, actual,
592
+ expected, actual)
593
+ assert_block(full_message) do
594
+ expected.send(operator, actual)
595
+ end
596
+ end
597
+ end
598
+
599
+ ##
600
+ # Passes if assertion is failed in block.
601
+ #
602
+ # Example:
603
+ # assert_fail_assertion {assert_equal("A", "B")} # -> pass
604
+ # assert_fail_assertion {assert_equal("A", "A")} # -> fail
605
+ def assert_fail_assertion(message=nil)
606
+ _wrap_assertion do
607
+ full_message = build_message(message,
608
+ "Failed assertion was expected.")
609
+ assert_block(full_message) do
610
+ begin
611
+ yield
612
+ false
613
+ rescue AssertionFailedError
614
+ true
615
+ end
616
+ end
617
+ end
618
+ end
619
+
620
+ ##
621
+ # Passes if an exception is raised in block and its
622
+ # message is +expected+.
623
+ #
624
+ # Example:
625
+ # assert_raise_message("exception") {raise "exception"} # -> pass
626
+ # assert_raise_message(/exc/i) {raise "exception"} # -> pass
627
+ # assert_raise_message("exception") {raise "EXCEPTION"} # -> fail
628
+ # assert_raise_message("exception") {} # -> fail
629
+ def assert_raise_message(expected, message=nil)
630
+ _wrap_assertion do
631
+ full_message = build_message(message,
632
+ "<?> exception message expected " +
633
+ "but none was thrown.",
634
+ expected)
635
+ exception = nil
636
+ assert_block(full_message) do
637
+ begin
638
+ yield
639
+ false
640
+ rescue Exception => exception
641
+ true
642
+ end
643
+ end
644
+
645
+ actual = exception.message
646
+ diff = AssertionMessage.delayed_diff(expected, actual)
647
+ full_message =
648
+ build_message(message,
649
+ "<?> exception message expected but was\n" +
650
+ "<?>.?", expected, actual, diff)
651
+ assert_block(full_message) do
652
+ if expected.is_a?(Regexp)
653
+ expected =~ actual
654
+ else
655
+ expected == actual
656
+ end
657
+ end
658
+ end
659
+ end
660
+
661
+ ##
662
+ # Passes if +object+.const_defined?(+constant_name+)
663
+ #
664
+ # Example:
665
+ # assert_const_defined(Test, :Unit) # -> pass
666
+ # assert_const_defined(Object, :Nonexistent) # -> fail
667
+ def assert_const_defined(object, constant_name, message=nil)
668
+ _wrap_assertion do
669
+ full_message = build_message(message,
670
+ "<?>.const_defined\\?(<?>) expected.",
671
+ object, constant_name)
672
+ assert_block(full_message) do
673
+ object.const_defined?(constant_name)
674
+ end
675
+ end
676
+ end
677
+
678
+ ##
679
+ # Passes if !+object+.const_defined?(+constant_name+)
680
+ #
681
+ # Example:
682
+ # assert_not_const_defined(Object, :Nonexistent) # -> pass
683
+ # assert_not_const_defined(Test, :Unit) # -> fail
684
+ def assert_not_const_defined(object, constant_name, message=nil)
685
+ _wrap_assertion do
686
+ full_message = build_message(message,
687
+ "!<?>.const_defined\\?(<?>) expected.",
688
+ object, constant_name)
689
+ assert_block(full_message) do
690
+ !object.const_defined?(constant_name)
691
+ end
692
+ end
693
+ end
694
+
562
695
  ##
563
696
  # Builds a failure message. +head+ is added before the +template+ and
564
697
  # +arguments+ replaces the '?'s positionally in the template.
@@ -601,8 +734,37 @@ EOT
601
734
  def self.use_pp=(value)
602
735
  AssertionMessage.use_pp = value
603
736
  end
604
-
737
+
605
738
  # :stopdoc:
739
+ private
740
+ def _assert_raise(assert_expected_exception, *args, &block)
741
+ _wrap_assertion do
742
+ if args.last.is_a?(String)
743
+ message = args.pop
744
+ else
745
+ message = ""
746
+ end
747
+
748
+ assert_exception_helper = AssertExceptionHelper.new(self, args)
749
+ expected = assert_exception_helper.expected_exceptions
750
+ actual_exception = nil
751
+ full_message = build_message(message,
752
+ "<?> exception expected " +
753
+ "but none was thrown.",
754
+ expected)
755
+ assert_block(full_message) do
756
+ begin
757
+ yield
758
+ false
759
+ rescue Exception => actual_exception
760
+ true
761
+ end
762
+ end
763
+ assert_expected_exception.call(message, assert_exception_helper,
764
+ actual_exception)
765
+ actual_exception
766
+ end
767
+ end
606
768
 
607
769
  class AssertionMessage
608
770
  @use_pp = true
@@ -617,6 +779,31 @@ EOT
617
779
  DelayedLiteral.new(block)
618
780
  end
619
781
 
782
+ def delayed_diff(from, to)
783
+ delayed_literal do
784
+ if !from.is_a?(String) or !to.is_a?(String)
785
+ from = convert(from)
786
+ to = convert(to)
787
+ end
788
+
789
+ diff = Diff.readable(from, to)
790
+ if /^[-+]/ !~ diff
791
+ diff = ""
792
+ elsif /^[ ?]/ =~ diff or /(?:.*\n){2,}/ =~ diff
793
+ diff = "\n\ndiff:\n#{diff}"
794
+ else
795
+ diff = ""
796
+ end
797
+
798
+ if Diff.need_fold?(diff)
799
+ folded_diff = Diff.folded_readable(from, to)
800
+ diff << "\n\nfolded diff:\n#{folded_diff}"
801
+ end
802
+
803
+ diff
804
+ end
805
+ end
806
+
620
807
  def convert(object)
621
808
  case object
622
809
  when Exception
@@ -715,8 +902,105 @@ EOM
715
902
  end
716
903
  end
717
904
 
718
- # :startdoc:
905
+ class AssertExceptionHelper
906
+ class WrappedException
907
+ def initialize(exception)
908
+ @exception = exception
909
+ end
910
+
911
+ def inspect
912
+ inspect_method = @exception.method(:inspect)
913
+ if inspect_method.respond_to?(:owner) and
914
+ inspect_method.owner == Exception
915
+ "#{@exception.class.inspect}(#{@exception.message.inspect})"
916
+ else
917
+ @exception.inspect
918
+ end
919
+ end
920
+
921
+ def method_missing(name, *args, &block)
922
+ @exception.send(name, *args, &block)
923
+ end
924
+ end
925
+
926
+ def initialize(test_case, expected_exceptions)
927
+ @test_case = test_case
928
+ @expected_exceptions = expected_exceptions
929
+ @expected_classes, @expected_modules, @expected_objects =
930
+ split_expected_exceptions(expected_exceptions)
931
+ end
932
+
933
+ def expected_exceptions
934
+ exceptions = @expected_exceptions.collect do |exception|
935
+ if exception.is_a?(Exception)
936
+ WrappedException.new(exception)
937
+ else
938
+ exception
939
+ end
940
+ end
941
+ if exceptions.size == 1
942
+ exceptions[0]
943
+ else
944
+ exceptions
945
+ end
946
+ end
947
+
948
+ def expected?(actual_exception, equality=nil)
949
+ equality ||= :instance_of?
950
+ expected_class?(actual_exception, equality) or
951
+ expected_module?(actual_exception) or
952
+ expected_object?(actual_exception)
953
+ end
954
+
955
+ private
956
+ def split_expected_exceptions(expected_exceptions)
957
+ exception_modules = []
958
+ exception_objects = []
959
+ exception_classes = []
960
+ expected_exceptions.each do |exception_type|
961
+ if exception_type.instance_of?(Module)
962
+ exception_modules << exception_type
963
+ elsif exception_type.is_a?(Exception)
964
+ exception_objects << exception_type
965
+ else
966
+ @test_case.send(:assert,
967
+ Exception >= exception_type,
968
+ "Should expect a class of exception, " +
969
+ "#{exception_type}")
970
+ exception_classes << exception_type
971
+ end
972
+ end
973
+ [exception_classes, exception_modules, exception_objects]
974
+ end
975
+
976
+ def expected_class?(actual_exception, equality)
977
+ @expected_classes.any? do |expected_class|
978
+ actual_exception.send(equality, expected_class)
979
+ end
980
+ end
719
981
 
982
+ def expected_module?(actual_exception)
983
+ @expected_modules.any? do |expected_module|
984
+ actual_exception.is_a?(expected_module)
985
+ end
986
+ end
987
+
988
+ def expected_object?(actual_exception)
989
+ @expected_objects.any? do |expected_object|
990
+ equal_method = expected_object.method(:==)
991
+ if equal_method.respond_to?(:owner) and
992
+ (equal_method.owner == Kernel or
993
+ equal_method.owner == Exception)
994
+ expected_object.class == actual_exception.class and
995
+ expected_object.message == actual_exception.message
996
+ else
997
+ expected_object == actual_exception
998
+ end
999
+ end
1000
+ end
1001
+ end
1002
+
1003
+ # :startdoc:
720
1004
  end
721
1005
  end
722
1006
  end