test-unit 2.3.0 → 2.3.1

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