test-unit 2.3.0 → 2.3.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 (47) hide show
  1. data/COPYING +9 -1
  2. data/{README.txt → README.textile} +24 -17
  3. data/Rakefile +301 -27
  4. data/lib/test/unit/assertions.rb +49 -23
  5. data/lib/test/unit/attribute.rb +1 -1
  6. data/lib/test/unit/collector/load.rb +3 -3
  7. data/lib/test/unit/runner/console.rb +11 -4
  8. data/lib/test/unit/testcase.rb +1 -1
  9. data/lib/test/unit/ui/console/outputlevel.rb +3 -2
  10. data/lib/test/unit/ui/console/testrunner.rb +101 -22
  11. data/lib/test/unit/version.rb +1 -1
  12. data/test/test-assertions.rb +20 -0
  13. data/test/test-data.rb +1 -1
  14. data/test/test-priority.rb +17 -2
  15. data/test/test-testcase.rb +3 -3
  16. metadata +62 -111
  17. data/History.txt +0 -302
  18. data/Manifest.txt +0 -118
  19. data/html/bar.png +0 -0
  20. data/html/bar.svg +0 -153
  21. data/html/developer.png +0 -0
  22. data/html/developer.svg +0 -469
  23. data/html/famfamfam-logo.png +0 -0
  24. data/html/favicon.ico +0 -0
  25. data/html/favicon.png +0 -0
  26. data/html/favicon.svg +0 -82
  27. data/html/github-logo.png +0 -0
  28. data/html/heading-mark.png +0 -0
  29. data/html/heading-mark.svg +0 -393
  30. data/html/index.html +0 -291
  31. data/html/index.html.ja +0 -306
  32. data/html/install.png +0 -0
  33. data/html/install.svg +0 -636
  34. data/html/jp.png +0 -0
  35. data/html/kinotan-failure.png +0 -0
  36. data/html/kinotan-pass.png +0 -0
  37. data/html/logo.png +0 -0
  38. data/html/logo.svg +0 -483
  39. data/html/reference.png +0 -0
  40. data/html/rubyforge.png +0 -0
  41. data/html/tango-logo.png +0 -0
  42. data/html/test-unit.css +0 -346
  43. data/html/tutorial.png +0 -0
  44. data/html/tutorial.svg +0 -559
  45. data/html/us.png +0 -0
  46. data/images/color-diff.png +0 -0
  47. data/test/fixtures/plus.csv +0 -3
@@ -116,7 +116,7 @@ EOT
116
116
  failure.inspected_expected = AssertionMessage.convert(expected)
117
117
  failure.inspected_actual = AssertionMessage.convert(actual)
118
118
  failure.user_message = message
119
- raise
119
+ raise failure # For JRuby. :<
120
120
  end
121
121
  end
122
122
 
@@ -1019,7 +1019,7 @@ EOT
1019
1019
  expected, actual,
1020
1020
  expected, actual)
1021
1021
  assert_block(full_message) do
1022
- expected.send(operator, actual)
1022
+ expected.__send__(operator, actual)
1023
1023
  end
1024
1024
  end
1025
1025
  end
@@ -1129,7 +1129,7 @@ EOT
1129
1129
  def assert_predicate(object, predicate, message=nil)
1130
1130
  _wrap_assertion do
1131
1131
  assert_respond_to(object, predicate, message)
1132
- actual = object.send(predicate)
1132
+ actual = object.__send__(predicate)
1133
1133
  full_message = build_message(message,
1134
1134
  "<?>.? is true value expected but was\n" +
1135
1135
  "<?>",
@@ -1151,7 +1151,7 @@ EOT
1151
1151
  def assert_not_predicate(object, predicate, message=nil)
1152
1152
  _wrap_assertion do
1153
1153
  assert_respond_to(object, predicate, message)
1154
- actual = object.send(predicate)
1154
+ actual = object.__send__(predicate)
1155
1155
  full_message = build_message(message,
1156
1156
  "<?>.? is false value expected but was\n" +
1157
1157
  "<?>",
@@ -1525,8 +1525,20 @@ EOM
1525
1525
  end
1526
1526
 
1527
1527
  class Inspector
1528
- def initialize(object)
1528
+ include Comparable
1529
+
1530
+ class << self
1531
+ def cached_new(object, inspected_objects)
1532
+ inspected_objects[object.object_id] ||=
1533
+ new(object, inspected_objects)
1534
+ end
1535
+ end
1536
+
1537
+ attr_reader :object
1538
+ def initialize(object, inspected_objects={})
1539
+ @inspected_objects = inspected_objects
1529
1540
  @object = object
1541
+ @inspected_objects[@object.object_id] = self
1530
1542
  @inspect_target = inspect_target
1531
1543
  end
1532
1544
 
@@ -1543,12 +1555,20 @@ EOM
1543
1555
  @inspect_target.pretty_print_cycle(q)
1544
1556
  end
1545
1557
 
1558
+ def <=>(other)
1559
+ if other.is_a?(self.class)
1560
+ @object <=> other.object
1561
+ else
1562
+ @object <=> other
1563
+ end
1564
+ end
1565
+
1546
1566
  private
1547
1567
  def inspect_target
1548
1568
  if HashInspector.target?(@object)
1549
- HashInspector.new(@object)
1569
+ HashInspector.new(@object, @inspected_objects)
1550
1570
  elsif ArrayInspector.target?(@object)
1551
- ArrayInspector.new(@object)
1571
+ ArrayInspector.new(@object, @inspected_objects)
1552
1572
  else
1553
1573
  @object
1554
1574
  end
@@ -1562,8 +1582,14 @@ EOM
1562
1582
  end
1563
1583
  end
1564
1584
 
1565
- def initialize(hash)
1566
- @hash = hash
1585
+ def initialize(hash, inspected_objects)
1586
+ @inspected_objects = inspected_objects
1587
+ @hash = {}
1588
+ hash.each do |key, value|
1589
+ key = Inspector.cached_new(key, @inspected_objects)
1590
+ value = Inspector.cached_new(value, @inspected_objects)
1591
+ @hash[key] = value
1592
+ end
1567
1593
  end
1568
1594
 
1569
1595
  def inspect
@@ -1596,8 +1622,7 @@ EOM
1596
1622
  rescue ArgumentError
1597
1623
  end
1598
1624
  keys.each do |key|
1599
- yield(Inspector.new(key),
1600
- Inspector.new(@hash[key]))
1625
+ yield(key, @hash[key])
1601
1626
  end
1602
1627
  end
1603
1628
  end
@@ -1609,8 +1634,11 @@ EOM
1609
1634
  end
1610
1635
  end
1611
1636
 
1612
- def initialize(array)
1613
- @array = array
1637
+ def initialize(array, inspected_objects)
1638
+ @inspected_objects = inspected_objects
1639
+ @array = array.collect do |element|
1640
+ Inspector.cached_new(element, @inspected_objects)
1641
+ end
1614
1642
  end
1615
1643
 
1616
1644
  def inspect
@@ -1629,10 +1657,8 @@ EOM
1629
1657
  @array.pretty_print_cycle(q)
1630
1658
  end
1631
1659
 
1632
- def each
1633
- @array.each do |element|
1634
- yield(Inspector.new(element))
1635
- end
1660
+ def each(&block)
1661
+ @array.each(&block)
1636
1662
  end
1637
1663
  end
1638
1664
 
@@ -1743,7 +1769,7 @@ EOM
1743
1769
  end
1744
1770
 
1745
1771
  def method_missing(name, *args, &block)
1746
- @exception.send(name, *args, &block)
1772
+ @exception.__send__(name, *args, &block)
1747
1773
  end
1748
1774
 
1749
1775
  private
@@ -1799,10 +1825,10 @@ EOM
1799
1825
  elsif exception_type.is_a?(Exception)
1800
1826
  exception_objects << exception_type
1801
1827
  else
1802
- @test_case.send(:assert,
1803
- Exception >= exception_type,
1804
- "Should expect a class of exception, " +
1805
- "#{exception_type}")
1828
+ @test_case.__send__(:assert,
1829
+ Exception >= exception_type,
1830
+ "Should expect a class of exception, " +
1831
+ "#{exception_type}")
1806
1832
  exception_classes << exception_type
1807
1833
  end
1808
1834
  end
@@ -1811,7 +1837,7 @@ EOM
1811
1837
 
1812
1838
  def expected_class?(actual_exception, equality)
1813
1839
  @expected_classes.any? do |expected_class|
1814
- actual_exception.send(equality, expected_class)
1840
+ actual_exception.__send__(equality, expected_class)
1815
1841
  end
1816
1842
  end
1817
1843
 
@@ -36,7 +36,7 @@ module Test
36
36
  return unless defined?(@current_attributes)
37
37
 
38
38
  attributes = {}
39
- kept_attributes = {}
39
+ kept_attributes = StringifyKeyHash.new
40
40
  @current_attributes.each do |attribute_name, attribute|
41
41
  attributes[attribute_name] = attribute[:value]
42
42
  kept_attributes[attribute_name] = attribute if attribute[:keep]
@@ -102,7 +102,7 @@ module Test
102
102
  return if @program_file == expanded_path.to_s
103
103
  add_load_path(expanded_path.dirname) do
104
104
  begin
105
- require(path.to_s)
105
+ require(path.basename.to_s)
106
106
  rescue LoadError
107
107
  @require_failed_infos << {:path => expanded_path, :exception => $!}
108
108
  end
@@ -121,10 +121,10 @@ module Test
121
121
  end
122
122
 
123
123
  def add_load_path(path)
124
- $LOAD_PATH.push(path.to_s) if path
124
+ $LOAD_PATH.unshift(path.to_s) if path
125
125
  yield
126
126
  ensure
127
- $LOAD_PATH.delete_at($LOAD_PATH.rindex(path.to_s)) if path
127
+ $LOAD_PATH.delete_at($LOAD_PATH.index(path.to_s)) if path
128
128
  end
129
129
 
130
130
  def excluded_directory?(base)
@@ -9,10 +9,11 @@ module Test
9
9
  require 'test/unit/ui/console/outputlevel'
10
10
 
11
11
  output_levels = [
12
- [:silent, UI::Console::OutputLevel::SILENT],
13
- [:progress, UI::Console::OutputLevel::PROGRESS_ONLY],
14
- [:normal, UI::Console::OutputLevel::NORMAL],
15
- [:verbose, UI::Console::OutputLevel::VERBOSE],
12
+ ["silent", UI::Console::OutputLevel::SILENT],
13
+ ["progress", UI::Console::OutputLevel::PROGRESS_ONLY],
14
+ ["important-only", UI::Console::OutputLevel::IMPORTANT_FAULTS_ONLY],
15
+ ["normal", UI::Console::OutputLevel::NORMAL],
16
+ ["verbose", UI::Console::OutputLevel::VERBOSE],
16
17
  ]
17
18
  opts.on('-v', '--verbose=[LEVEL]', output_levels,
18
19
  "Set the output level (default is verbose).",
@@ -47,6 +48,12 @@ module Test
47
48
  "(default is auto)") do |max|
48
49
  auto_runner.runner_options[:progress_row_max] = max
49
50
  end
51
+
52
+ opts.on("--[no-]show-detail-immediately",
53
+ "Shows not passed test details immediately.",
54
+ "(default is no)") do |boolean|
55
+ auto_runner.runner_options[:show_detail_immediately] = boolean
56
+ end
50
57
  end
51
58
  end
52
59
  end
@@ -257,7 +257,7 @@ module Test
257
257
  message = "wrong number of arguments (#{n_arguments} for 1)"
258
258
  raise ArgumentError, message
259
259
  end
260
- method_name = test_description
260
+ method_name = "test: #{test_description}"
261
261
  define_method(method_name, &block)
262
262
  description(test_description, method_name)
263
263
  attribute(:test, true, {}, method_name)
@@ -5,8 +5,9 @@ module Test
5
5
  module OutputLevel
6
6
  SILENT = 0
7
7
  PROGRESS_ONLY = 1
8
- NORMAL = 2
9
- VERBOSE = 3
8
+ IMPORTANT_FAULTS_ONLY = 2
9
+ NORMAL = 3
10
+ VERBOSE = 4
10
11
  end
11
12
  end
12
13
  end
@@ -3,7 +3,7 @@
3
3
  # Author:: Nathaniel Talbott.
4
4
  # Copyright::
5
5
  # * Copyright (c) 2000-2003 Nathaniel Talbott. All rights reserved.
6
- # * Copyright (c) 2008-2009 Kouhei Sutou <kou@clear-code.com>
6
+ # * Copyright (c) 2008-2011 Kouhei Sutou <kou@clear-code.com>
7
7
  # License:: Ruby license.
8
8
 
9
9
  require 'test/unit/color-scheme'
@@ -37,13 +37,22 @@ module Test
37
37
  @progress_row = 0
38
38
  @progress_row_max = @options[:progress_row_max]
39
39
  @progress_row_max ||= guess_progress_row_max
40
+ @show_detail_immediately = @options[:show_detail_immediately]
40
41
  @already_outputted = false
41
42
  @indent = 0
42
43
  @top_level = true
44
+ @current_output_level = NORMAL
43
45
  @faults = []
44
46
  end
45
47
 
46
48
  private
49
+ def change_output_level(level)
50
+ old_output_level = @current_output_level
51
+ @current_output_level = level
52
+ yield
53
+ @current_output_level = old_output_level
54
+ end
55
+
47
56
  def setup_mediator
48
57
  super
49
58
  output_setup_end
@@ -75,6 +84,7 @@ module Test
75
84
  def add_fault(fault)
76
85
  @faults << fault
77
86
  output_progress(fault.single_character_display, fault_color(fault))
87
+ output_progress_in_detail(fault) if @show_detail_immediately
78
88
  @already_outputted = true if fault.critical?
79
89
  end
80
90
 
@@ -89,24 +99,66 @@ module Test
89
99
 
90
100
  def finished(elapsed_time)
91
101
  nl if output?(NORMAL) and !output?(VERBOSE)
92
- @faults.each_with_index do |fault, index|
102
+ output_faults unless @show_detail_immediately
103
+ nl(IMPORTANT_FAULTS_ONLY)
104
+ change_output_level(IMPORTANT_FAULTS_ONLY) do
105
+ output_statistics(elapsed_time)
106
+ end
107
+ end
108
+
109
+ def output_faults
110
+ categorized_faults = categorize_faults
111
+ change_output_level(IMPORTANT_FAULTS_ONLY) do
112
+ output_faults_in_detail(categorized_faults[:need_detail_faults])
113
+ end
114
+ output_faults_in_short("Omissions", Omission,
115
+ categorized_faults[:omissions])
116
+ output_faults_in_short("Notifications", Notification,
117
+ categorized_faults[:notifications])
118
+ end
119
+
120
+ def max_digit(max_number)
121
+ (Math.log10(max_number) + 1).truncate
122
+ end
123
+
124
+ def output_faults_in_detail(faults)
125
+ return if faults.nil?
126
+ digit = max_digit(faults.size)
127
+ faults.each_with_index do |fault, index|
93
128
  nl
94
- output_single("%3d) " % (index + 1))
129
+ output_single("%#{digit}d) " % (index + 1))
95
130
  output_fault(fault)
96
131
  end
132
+ end
133
+
134
+ def output_faults_in_short(label, fault_class, faults)
135
+ return if faults.nil?
136
+ digit = max_digit(faults.size)
97
137
  nl
98
- output("Finished in #{elapsed_time} seconds.")
99
- nl
100
- output(@result, result_color)
101
- output("%g%% passed" % @result.pass_percentage, result_color)
102
- unless elapsed_time.zero?
103
- nl
104
- throuputs =
105
- [
106
- "%.2f tests/s" % [@result.run_count / elapsed_time],
107
- "%.2f assertions/s" % [@result.assertion_count / elapsed_time],
108
- ]
109
- output(throuputs.join(", "))
138
+ output_single(label, fault_class_color(fault_class))
139
+ output(":")
140
+ faults.each_with_index do |fault, index|
141
+ output_single("%#{digit}d) " % (index + 1))
142
+ output_single(fault.message, fault_color(fault))
143
+ output(" [#{fault.test_name}]")
144
+ output(fault.location.first)
145
+ end
146
+ end
147
+
148
+ def categorize_faults
149
+ @faults.group_by do |fault|
150
+ categorize_fault(fault)
151
+ end
152
+ end
153
+
154
+ def categorize_fault(fault)
155
+ case fault
156
+ when Omission
157
+ :omissions
158
+ when Notification
159
+ :notifications
160
+ else
161
+ :need_detail_faults
110
162
  end
111
163
  end
112
164
 
@@ -198,6 +250,23 @@ module Test
198
250
  fault.long_display
199
251
  end
200
252
 
253
+ def output_statistics(elapsed_time)
254
+ output("Finished in #{elapsed_time} seconds.")
255
+ nl
256
+ output(@result, result_color)
257
+ output("%g%% passed" % @result.pass_percentage, result_color)
258
+ unless elapsed_time.zero?
259
+ nl
260
+ test_throughput = @result.run_count / elapsed_time
261
+ assertion_throughput = @result.assertion_count / elapsed_time
262
+ throughput = [
263
+ "%.2f tests/s" % test_throughput,
264
+ "%.2f assertions/s" % assertion_throughput,
265
+ ]
266
+ output(throughput.join(", "))
267
+ end
268
+ end
269
+
201
270
  def test_started(test)
202
271
  return unless output?(VERBOSE)
203
272
 
@@ -250,17 +319,17 @@ module Test
250
319
  end
251
320
  end
252
321
 
253
- def nl(level=NORMAL)
322
+ def nl(level=nil)
254
323
  output("", nil, level)
255
324
  end
256
-
257
- def output(something, color=nil, level=NORMAL)
325
+
326
+ def output(something, color=nil, level=nil)
258
327
  return unless output?(level)
259
328
  output_single(something, color, level)
260
329
  @output.puts
261
330
  end
262
-
263
- def output_single(something, color=nil, level=NORMAL)
331
+
332
+ def output_single(something, color=nil, level=nil)
264
333
  return false unless output?(level)
265
334
  if @use_color and color
266
335
  something = "%s%s%s" % [color.escape_sequence,
@@ -283,8 +352,14 @@ module Test
283
352
  end
284
353
  end
285
354
 
355
+ def output_progress_in_detail(fault)
356
+ return if @output_level == SILENT
357
+ return unless categorize_fault(fault) == :need_detail_faults
358
+ output_fault(fault)
359
+ end
360
+
286
361
  def output?(level)
287
- level <= @output_level
362
+ (level || @current_output_level) <= @output_level
288
363
  end
289
364
 
290
365
  def color(name)
@@ -295,7 +370,11 @@ module Test
295
370
  end
296
371
 
297
372
  def fault_color(fault)
298
- color(fault.class.name.split(/::/).last.downcase)
373
+ fault_class_color(fault.class)
374
+ end
375
+
376
+ def fault_class_color(fault_class)
377
+ color(fault_class.name.split(/::/).last.downcase)
299
378
  end
300
379
 
301
380
  def result_color
@@ -2,6 +2,6 @@
2
2
  # HACK: quick and dirty to get integrated into the new project - ryan
3
3
  module Test
4
4
  module Unit
5
- VERSION = '2.3.0'
5
+ VERSION = '2.3.1'
6
6
  end
7
7
  end