activegroonga 0.0.7 → 1.0.0

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 (122) hide show
  1. data/README.ja.rdoc +4 -1
  2. data/README.rdoc +4 -1
  3. data/Rakefile +18 -4
  4. data/lib/active_groonga.rb +25 -52
  5. data/lib/active_groonga/base.rb +164 -1480
  6. data/lib/active_groonga/callbacks.rb +26 -7
  7. data/lib/active_groonga/database.rb +55 -0
  8. data/lib/active_groonga/{dirty.rb → error.rb} +20 -10
  9. data/lib/active_groonga/locale/en.yml +5 -0
  10. data/lib/active_groonga/migration.rb +44 -113
  11. data/lib/active_groonga/migrator.rb +172 -0
  12. data/lib/active_groonga/persistence.rb +172 -0
  13. data/lib/active_groonga/railtie.rb +66 -0
  14. data/lib/active_groonga/railties/configurable.rb +47 -0
  15. data/lib/active_groonga/railties/groonga.rake +167 -0
  16. data/lib/active_groonga/result_set.rb +89 -0
  17. data/lib/active_groonga/schema.rb +54 -188
  18. data/lib/active_groonga/validations.rb +54 -5
  19. data/lib/active_groonga/vector.rb +64 -0
  20. data/lib/active_groonga/version.rb +3 -3
  21. data/lib/{active_groonga/aggregations.rb → rails/generators/active_groonga.rb} +17 -10
  22. data/lib/rails/generators/active_groonga/migration/column.rb +101 -0
  23. data/lib/rails/generators/active_groonga/migration/migration_generator.rb +53 -0
  24. data/lib/rails/generators/active_groonga/migration/templates/migration.rb +29 -0
  25. data/lib/rails/generators/active_groonga/model/model_generator.rb +60 -0
  26. data/lib/rails/generators/active_groonga/model/templates/migration.rb +16 -0
  27. data/lib/rails/generators/active_groonga/model/templates/model.rb +2 -0
  28. data/lib/rails/generators/active_groonga/model/templates/module.rb +5 -0
  29. data/test-unit-notify/COPYING +502 -0
  30. data/test-unit-notify/Rakefile +47 -0
  31. data/test-unit-notify/lib/test/unit/notify.rb +127 -0
  32. data/test-unit/COPYING +56 -0
  33. data/test-unit/GPL +340 -0
  34. data/test-unit/PSFL +271 -0
  35. data/test-unit/Rakefile +18 -5
  36. data/test-unit/html/bar.svg +153 -0
  37. data/test-unit/html/developer.svg +469 -0
  38. data/test-unit/html/favicon.ico +0 -0
  39. data/test-unit/html/favicon.svg +82 -0
  40. data/test-unit/html/heading-mark.svg +393 -0
  41. data/test-unit/html/index.html +235 -13
  42. data/test-unit/html/index.html.ja +258 -15
  43. data/test-unit/html/install.svg +636 -0
  44. data/test-unit/html/logo.svg +483 -0
  45. data/test-unit/html/test-unit.css +339 -0
  46. data/test-unit/html/tutorial.svg +559 -0
  47. data/test-unit/lib/test/unit.rb +29 -43
  48. data/test-unit/lib/test/unit/assertionfailederror.rb +11 -0
  49. data/test-unit/lib/test/unit/assertions.rb +202 -20
  50. data/test-unit/lib/test/unit/autorunner.rb +51 -20
  51. data/test-unit/lib/test/unit/collector.rb +1 -8
  52. data/test-unit/lib/test/unit/collector/dir.rb +1 -1
  53. data/test-unit/lib/test/unit/collector/load.rb +16 -9
  54. data/test-unit/lib/test/unit/color-scheme.rb +19 -3
  55. data/test-unit/lib/test/unit/diff.rb +240 -38
  56. data/test-unit/lib/test/unit/error.rb +4 -0
  57. data/test-unit/lib/test/unit/failure.rb +31 -5
  58. data/test-unit/lib/test/unit/notification.rb +8 -4
  59. data/test-unit/lib/test/unit/omission.rb +51 -3
  60. data/test-unit/lib/test/unit/pending.rb +4 -0
  61. data/test-unit/lib/test/unit/priority.rb +2 -3
  62. data/test-unit/lib/test/unit/testcase.rb +65 -7
  63. data/test-unit/lib/test/unit/testresult.rb +34 -2
  64. data/test-unit/lib/test/unit/ui/console/testrunner.rb +197 -45
  65. data/test-unit/lib/test/unit/ui/emacs/testrunner.rb +14 -0
  66. data/test-unit/lib/test/unit/ui/tap/testrunner.rb +2 -12
  67. data/test-unit/lib/test/unit/ui/testrunner.rb +33 -0
  68. data/test-unit/lib/test/unit/util/backtracefilter.rb +1 -0
  69. data/test-unit/lib/test/unit/util/output.rb +31 -0
  70. data/test-unit/lib/test/unit/version.rb +1 -1
  71. data/test-unit/sample/{tc_adder.rb → test_adder.rb} +3 -1
  72. data/test-unit/sample/{tc_subtracter.rb → test_subtracter.rb} +3 -1
  73. data/test-unit/sample/test_user.rb +1 -0
  74. data/test-unit/test/collector/test-descendant.rb +2 -4
  75. data/test-unit/test/collector/test-load.rb +121 -8
  76. data/test-unit/test/collector/test_objectspace.rb +7 -5
  77. data/test-unit/test/run-test.rb +2 -0
  78. data/test-unit/test/test-color-scheme.rb +11 -2
  79. data/test-unit/test/test-diff.rb +48 -7
  80. data/test-unit/test/test-omission.rb +1 -1
  81. data/test-unit/test/test-testcase.rb +57 -20
  82. data/test-unit/test/test_assertions.rb +128 -13
  83. data/test-unit/test/ui/test_tap.rb +33 -0
  84. data/test-unit/test/util/test-output.rb +11 -0
  85. data/test/active-groonga-test-utils.rb +50 -36
  86. data/test/fixtures/site.rb +2 -0
  87. data/test/run-test.rb +36 -9
  88. data/test/test-associations.rb +5 -2
  89. data/test/test-base.rb +39 -31
  90. data/test/test-callbacks.rb +13 -3
  91. data/test/test-persistence.rb +53 -0
  92. data/{lib/active_groonga/observer.rb → test/test-result-set.rb} +14 -12
  93. data/test/test-schema.rb +85 -22
  94. data/{lib/active_groonga/rails_support.rb → test/test-validations.rb} +15 -13
  95. metadata +85 -52
  96. data/lib/active_groonga/associations.rb +0 -93
  97. data/lib/active_groonga/associations/belongs_to_association.rb +0 -25
  98. data/lib/active_groonga/attribute_methods.rb +0 -36
  99. data/lib/active_groonga/column.rb +0 -137
  100. data/lib/active_groonga/dynamic_record_expression_builder.rb +0 -40
  101. data/lib/active_groonga/reflection.rb +0 -30
  102. data/lib/active_groonga/schema_dumper.rb +0 -163
  103. data/lib/active_groonga/tasks.rb +0 -16
  104. data/lib/active_groonga/tasks/groonga.rake +0 -164
  105. data/lib/active_groonga/timestamp.rb +0 -30
  106. data/rails/README +0 -28
  107. data/rails/init.rb +0 -70
  108. data/rails_generators/index_table_groonga/USAGE +0 -23
  109. data/rails_generators/index_table_groonga/index_table_groonga_generator.rb +0 -44
  110. data/rails_generators/index_table_groonga/templates/migration.rb +0 -12
  111. data/rails_generators/migration_groonga/USAGE +0 -29
  112. data/rails_generators/migration_groonga/migration_groonga_generator.rb +0 -19
  113. data/rails_generators/migration_groonga/templates/migration.rb +0 -11
  114. data/rails_generators/model_groonga/USAGE +0 -28
  115. data/rails_generators/model_groonga/model_groonga_generator.rb +0 -45
  116. data/rails_generators/model_groonga/templates/fixtures.yml +0 -17
  117. data/rails_generators/model_groonga/templates/migration.rb +0 -16
  118. data/rails_generators/model_groonga/templates/model.rb +0 -2
  119. data/rails_generators/model_groonga/templates/unit_test.rb +0 -8
  120. data/test-unit/html/classic.html +0 -15
  121. data/test-unit/sample/ts_examples.rb +0 -7
  122. data/test/test-schema-dumper.rb +0 -48
@@ -60,6 +60,10 @@ module Test
60
60
  def to_s
61
61
  long_display
62
62
  end
63
+
64
+ def critical?
65
+ true
66
+ end
63
67
  end
64
68
 
65
69
  module ErrorHandler
@@ -11,16 +11,23 @@ module Test
11
11
  # when an assertion fails.
12
12
  class Failure
13
13
  attr_reader :test_name, :location, :message
14
-
14
+ attr_reader :expected, :actual, :user_message
15
+ attr_reader :inspected_expected, :inspected_actual
16
+
15
17
  SINGLE_CHARACTER = 'F'
16
18
  LABEL = "Failure"
17
19
 
18
20
  # Creates a new Failure with the given location and
19
21
  # message.
20
- def initialize(test_name, location, message)
22
+ def initialize(test_name, location, message, options={})
21
23
  @test_name = test_name
22
24
  @location = location
23
25
  @message = message
26
+ @expected = options[:expected]
27
+ @actual = options[:actual]
28
+ @inspected_expected = options[:inspected_expected]
29
+ @inspected_actual = options[:inspected_actual]
30
+ @user_message = options[:user_message]
24
31
  end
25
32
 
26
33
  # Returns a single character representation of a failure.
@@ -51,6 +58,19 @@ module Test
51
58
  def to_s
52
59
  long_display
53
60
  end
61
+
62
+ def critical?
63
+ true
64
+ end
65
+
66
+ def diff
67
+ @diff ||= compute_diff
68
+ end
69
+
70
+ private
71
+ def compute_diff
72
+ Assertions::AssertionMessage.delayed_diff(@expected, @actual).inspect
73
+ end
54
74
  end
55
75
 
56
76
  module FailureHandler
@@ -64,12 +84,18 @@ module Test
64
84
  def handle_assertion_failed_error(exception)
65
85
  return false unless exception.is_a?(AssertionFailedError)
66
86
  problem_occurred
67
- add_failure(exception.message, exception.backtrace)
87
+ add_failure(exception.message, exception.backtrace,
88
+ :expected => exception.expected,
89
+ :actual => exception.actual,
90
+ :inspected_expected => exception.inspected_expected,
91
+ :inspected_actual => exception.inspected_actual,
92
+ :user_message => exception.user_message)
68
93
  true
69
94
  end
70
95
 
71
- def add_failure(message, backtrace)
72
- failure = Failure.new(name, filter_backtrace(backtrace), message)
96
+ def add_failure(message, backtrace, options={})
97
+ failure = Failure.new(name, filter_backtrace(backtrace), message,
98
+ options)
73
99
  current_result.add_failure(failure)
74
100
  end
75
101
  end
@@ -41,6 +41,10 @@ module Test
41
41
  def to_s
42
42
  long_display
43
43
  end
44
+
45
+ def critical?
46
+ false
47
+ end
44
48
  end
45
49
 
46
50
  class NotifiedError < StandardError
@@ -79,16 +83,16 @@ module Test
79
83
  module NotificationHandler
80
84
  class << self
81
85
  def included(base)
82
- base.exception_handler(:handle_Notified_error)
86
+ base.exception_handler(:handle_notified_error)
83
87
  end
84
88
  end
85
89
 
86
90
  private
87
- def handle_Notified_error(exception)
91
+ def handle_notified_error(exception)
88
92
  return false unless exception.is_a?(NotifiedError)
89
93
  notification = Notification.new(name,
90
- filter_backtrace(exception.backtrace),
91
- exception.message)
94
+ filter_backtrace(exception.backtrace),
95
+ exception.message)
92
96
  add_notification(notification)
93
97
  true
94
98
  end
@@ -41,6 +41,10 @@ module Test
41
41
  def to_s
42
42
  long_display
43
43
  end
44
+
45
+ def critical?
46
+ true
47
+ end
44
48
  end
45
49
 
46
50
  class OmittedError < StandardError
@@ -56,7 +60,7 @@ module Test
56
60
  end
57
61
  end
58
62
 
59
- # Omit the test of part of the test.
63
+ # Omit the test or part of the test.
60
64
  #
61
65
  # Example:
62
66
  # def test_omission
@@ -80,12 +84,56 @@ module Test
80
84
  end
81
85
  end
82
86
 
87
+ # Omit the test or part of the test if _condition_ is
88
+ # true.
89
+ #
90
+ # Example:
91
+ # def test_omission
92
+ # omit_if("".empty?)
93
+ # # Not reached here
94
+ # end
95
+ #
96
+ # def test_omission_with_here
97
+ # omit_if(true) do
98
+ # # Not ran here
99
+ # end
100
+ # omit_if(false) do
101
+ # # Reached here
102
+ # end
103
+ # # Reached here too
104
+ # end
83
105
  def omit_if(condition, *args, &block)
84
- omit(*args, &block) if condition
106
+ if condition
107
+ omit(*args, &block)
108
+ else
109
+ block.call if block
110
+ end
85
111
  end
86
112
 
113
+ # Omit the test or part of the test if _condition_ is
114
+ # not true.
115
+ #
116
+ # Example:
117
+ # def test_omission
118
+ # omit_unless("string".empty?)
119
+ # # Not reached here
120
+ # end
121
+ #
122
+ # def test_omission_with_here
123
+ # omit_unless(true) do
124
+ # # Reached here
125
+ # end
126
+ # omit_unless(false) do
127
+ # # Not ran here
128
+ # end
129
+ # # Reached here too
130
+ # end
87
131
  def omit_unless(condition, *args, &block)
88
- omit(*args, &block) unless condition
132
+ if condition
133
+ block.call if block
134
+ else
135
+ omit(*args, &block)
136
+ end
89
137
  end
90
138
 
91
139
  private
@@ -41,6 +41,10 @@ module Test
41
41
  def to_s
42
42
  long_display
43
43
  end
44
+
45
+ def critical?
46
+ true
47
+ end
44
48
  end
45
49
 
46
50
  class PendedError < StandardError
@@ -1,6 +1,3 @@
1
- require "fileutils"
2
- require "tmpdir"
3
-
4
1
  module Test
5
2
  module Unit
6
3
  module Priority
@@ -20,6 +17,8 @@ module Test
20
17
  end
21
18
 
22
19
  def enable
20
+ require "fileutils"
21
+ require "tmpdir"
23
22
  @@enabled = true
24
23
  end
25
24
 
@@ -19,6 +19,7 @@ require 'test/unit/priority'
19
19
  require 'test/unit/testsuite'
20
20
  require 'test/unit/assertionfailederror'
21
21
  require 'test/unit/util/backtracefilter'
22
+ require 'test/unit/util/output'
22
23
  require 'test/unit/util/method-owner-finder'
23
24
 
24
25
  module Test
@@ -82,6 +83,7 @@ module Test
82
83
  include Priority
83
84
  include Assertions
84
85
  include Util::BacktraceFilter
86
+ include Util::Output
85
87
 
86
88
  STARTED = name + "::STARTED" # :nodoc:
87
89
  FINISHED = name + "::FINISHED" # :nodoc:
@@ -94,10 +96,15 @@ module Test
94
96
  DESCENDANTS << sub_class
95
97
  end
96
98
 
97
- @@added_methods = []
99
+ @@added_methods = {}
98
100
  def method_added(name) # :nodoc:
99
101
  super
100
- @@added_methods << name.to_s
102
+ added_methods = (@@added_methods[self] ||= [])
103
+ stringified_name = name.to_s
104
+ if added_methods.include?(stringified_name)
105
+ attribute(:redefined, true, {}, stringified_name)
106
+ end
107
+ added_methods << stringified_name
101
108
  end
102
109
 
103
110
  # Rolls up all of the test* methods in the fixture into
@@ -191,12 +198,12 @@ module Test
191
198
  def shutdown
192
199
  end
193
200
 
194
- @@test_order = AVAILABLE_ORDERS.first
201
+ @@test_orders = {}
195
202
 
196
203
  # Returns the current test order. This returns
197
204
  # +:alphabetic+ by default.
198
205
  def test_order
199
- @@test_order
206
+ @@test_orders[self] || AVAILABLE_ORDERS.first
200
207
  end
201
208
 
202
209
  # Sets the current test order.
@@ -209,7 +216,40 @@ module Test
209
216
  # [:defined]
210
217
  # Tests are sorted in defined order.
211
218
  def test_order=(order)
212
- @@test_order = order
219
+ @@test_orders[self] = order
220
+ end
221
+
222
+ # Defines a test in declarative syntax.
223
+ #
224
+ # The following two test definitions are the same:
225
+ #
226
+ # description "register user"
227
+ # def test_register_user
228
+ # ...
229
+ # end
230
+ #
231
+ # test "register user" do
232
+ # ...
233
+ # end
234
+ def test(test_description, &block)
235
+ normalized_description = test_description.gsub(/[^a-zA-Z\d_]+/, '_')
236
+ method_name = "test_#{normalized_description}".to_sym
237
+ define_method(method_name, &block)
238
+ description(test_description, method_name)
239
+ end
240
+
241
+ # Describes a test.
242
+ #
243
+ # The following example associates "register a
244
+ # normal user" description with "test_register"
245
+ # test.
246
+ #
247
+ # description "register a normal user"
248
+ # def test_register
249
+ # ...
250
+ # end
251
+ def description(value, target=nil)
252
+ attribute(:description, value, {}, target || [])
213
253
  end
214
254
 
215
255
  # :stopdoc:
@@ -233,9 +273,10 @@ module Test
233
273
  end
234
274
 
235
275
  def sort_test_names_in_defined_order(test_names)
276
+ added_methods = @@added_methods[self]
236
277
  test_names.sort do |test1, test2|
237
- test1_defined_order = @@added_methods.index(test1)
238
- test2_defined_order = @@added_methods.index(test2)
278
+ test1_defined_order = added_methods.index(test1)
279
+ test2_defined_order = added_methods.index(test2)
239
280
  if test1_defined_order and test2_defined_order
240
281
  test1_defined_order <=> test2_defined_order
241
282
  elsif test1_defined_order
@@ -374,6 +415,15 @@ module Test
374
415
  "#{@method_name}(#{self.class.name})"
375
416
  end
376
417
 
418
+ # Returns a description for the test. A description
419
+ # will be associated by Test::Unit::TestCase.test or
420
+ # Test::Unit::TestCase.description.
421
+ #
422
+ # Returns a name for the test for no description test.
423
+ def description
424
+ self[:description] || name
425
+ end
426
+
377
427
  # Overridden to return #name.
378
428
  def to_s
379
429
  name
@@ -396,7 +446,11 @@ module Test
396
446
  end
397
447
 
398
448
  def run_test
449
+ if self.class.get_attribute(@method_name, :redefined)
450
+ notify("#{self.class}\##{@method_name} was redefined")
451
+ end
399
452
  __send__(@method_name)
453
+ add_pass
400
454
  end
401
455
 
402
456
  def handle_exception(exception)
@@ -420,6 +474,10 @@ module Test
420
474
  def add_assertion
421
475
  current_result.add_assertion
422
476
  end
477
+
478
+ def add_pass
479
+ current_result.add_pass
480
+ end
423
481
  end
424
482
  end
425
483
  end
@@ -34,11 +34,11 @@ module Test
34
34
  CHANGED = "CHANGED"
35
35
  FAULT = "FAULT"
36
36
 
37
- attr_reader :run_count, :assertion_count, :faults
37
+ attr_reader :run_count, :pass_count, :assertion_count, :faults
38
38
 
39
39
  # Constructs a new, empty TestResult.
40
40
  def initialize
41
- @run_count, @assertion_count = 0, 0
41
+ @run_count, @pass_count, @assertion_count = 0, 0, 0
42
42
  @summary_generators = []
43
43
  @problem_checkers = []
44
44
  @faults = []
@@ -51,6 +51,10 @@ module Test
51
51
  notify_changed
52
52
  end
53
53
 
54
+ def add_pass
55
+ @pass_count += 1
56
+ end
57
+
54
58
  # Records an individual assertion.
55
59
  def add_assertion
56
60
  @assertion_count += 1
@@ -65,6 +69,25 @@ module Test
65
69
  *@summary_generators.collect {|generator| send(generator)}].join(", ")
66
70
  end
67
71
 
72
+ # Returnes a string that shows result status.
73
+ def status
74
+ if passed?
75
+ if pending_count > 0
76
+ "pending"
77
+ elsif omission_count > 0
78
+ "omission"
79
+ elsif notification_count > 0
80
+ "notification"
81
+ else
82
+ "pass"
83
+ end
84
+ elsif error_count > 0
85
+ "error"
86
+ elsif failure_count > 0
87
+ "failure"
88
+ end
89
+ end
90
+
68
91
  def to_s
69
92
  summary
70
93
  end
@@ -75,6 +98,15 @@ module Test
75
98
  @problem_checkers.all? {|checker| not send(checker)}
76
99
  end
77
100
 
101
+ def pass_percentage
102
+ n_tests = @run_count - omission_count
103
+ if n_tests.zero?
104
+ 0
105
+ else
106
+ 100.0 * (@pass_count / n_tests.to_f)
107
+ end
108
+ end
109
+
78
110
  private
79
111
  def notify_changed
80
112
  notify_listeners(CHANGED, self)
@@ -38,22 +38,14 @@ module Test
38
38
  @progress_row_max = @options[:progress_row_max]
39
39
  @progress_row_max ||= guess_progress_row_max
40
40
  @already_outputted = false
41
- @n_successes = 0
42
41
  @indent = 0
43
42
  @top_level = true
44
43
  @faults = []
45
44
  end
46
45
 
47
- # Begins the test run.
48
- def start
49
- setup_mediator
50
- attach_to_mediator
51
- return start_mediator
52
- end
53
-
54
46
  private
55
47
  def setup_mediator
56
- @mediator = create_mediator(@suite)
48
+ super
57
49
  output_setup_end
58
50
  end
59
51
 
@@ -63,10 +55,6 @@ module Test
63
55
  output("Loaded suite #{suite_name}")
64
56
  end
65
57
 
66
- def create_mediator(suite)
67
- return TestRunnerMediator.new(suite)
68
- end
69
-
70
58
  def attach_to_mediator
71
59
  @mediator.add_listener(TestResult::FAULT, &method(:add_fault))
72
60
  @mediator.add_listener(TestRunnerMediator::STARTED, &method(:started))
@@ -77,14 +65,10 @@ module Test
77
65
  @mediator.add_listener(TestSuite::FINISHED, &method(:test_suite_finished))
78
66
  end
79
67
 
80
- def start_mediator
81
- return @mediator.run_suite
82
- end
83
-
84
68
  def add_fault(fault)
85
69
  @faults << fault
86
70
  output_progress(fault.single_character_display, fault_color(fault))
87
- @already_outputted = true
71
+ @already_outputted = true if fault.critical?
88
72
  end
89
73
 
90
74
  def started(result)
@@ -101,21 +85,72 @@ module Test
101
85
  @faults.each_with_index do |fault, index|
102
86
  nl
103
87
  output_single("%3d) " % (index + 1))
104
- label, detail = format_fault(fault).split(/\r?\n/, 2)
105
- output(label, fault_color(fault))
106
- output(detail)
88
+ output_fault(fault)
107
89
  end
108
90
  nl
109
91
  output("Finished in #{elapsed_time} seconds.")
110
92
  nl
111
93
  output(@result, result_color)
112
- n_tests = @result.run_count
113
- if n_tests.zero?
114
- pass_percentage = 0
94
+ output("%g%% passed" % @result.pass_percentage, result_color)
95
+ end
96
+
97
+ def output_fault(fault)
98
+ if @use_color and fault.is_a?(Failure) and
99
+ fault.inspected_expected and fault.inspected_actual
100
+ output_single(fault.label, fault_color(fault))
101
+ output(":")
102
+ output_fault_backtrace(fault)
103
+ output_fault_message(fault)
115
104
  else
116
- pass_percentage = 100.0 * (@n_successes / n_tests.to_f)
105
+ label, detail = format_fault(fault).split(/\r?\n/, 2)
106
+ output(label, fault_color(fault))
107
+ output(detail)
108
+ end
109
+ end
110
+
111
+ def output_fault_backtrace(fault)
112
+ backtrace = fault.location
113
+ if backtrace.size == 1
114
+ output(fault.test_name +
115
+ backtrace[0].sub(/\A(.+:\d+).*/, ' [\\1]') +
116
+ ":")
117
+ else
118
+ output(fault.test_name)
119
+ backtrace.each_with_index do |entry, i|
120
+ if i.zero?
121
+ prefix = "["
122
+ postfix = ""
123
+ elsif i == backtrace.size - 1
124
+ prefix = " "
125
+ postfix = "]:"
126
+ else
127
+ prefix = " "
128
+ postfix = ""
129
+ end
130
+ output(" #{prefix}#{entry}#{postfix}")
131
+ end
132
+ end
133
+ end
134
+
135
+ def output_fault_message(fault)
136
+ output(fault.user_message) if fault.user_message
137
+ output_single("<")
138
+ output_single(fault.inspected_expected, color("pass"))
139
+ output("> expected but was")
140
+ output_single("<")
141
+ output_single(fault.inspected_actual, color("failure"))
142
+ output(">")
143
+ from, to = prepare_for_diff(fault.expected, fault.actual)
144
+ if from and to
145
+ differ = ColorizedReadableDiffer.new(from.split(/\r?\n/),
146
+ to.split(/\r?\n/),
147
+ self)
148
+ if differ.need_diff?
149
+ output("")
150
+ output("diff:")
151
+ differ.diff
152
+ end
117
153
  end
118
- output("%g%% passed" % pass_percentage, result_color)
119
154
  end
120
155
 
121
156
  def format_fault(fault)
@@ -129,15 +164,14 @@ module Test
129
164
  right_space = 8 * 2
130
165
  left_space = @progress_row_max - right_space
131
166
  left_space = left_space - indent.size - name.size
132
- tab_stop = "\t" * ((left_space - 1) / 8)
167
+ tab_stop = "\t" * ([left_space - 1, 0].max / 8)
133
168
  output_single("#{indent}#{name}:#{tab_stop}", nil, VERBOSE)
134
169
  @test_start = Time.now
135
170
  end
136
171
 
137
172
  def test_finished(name)
138
173
  unless @already_outputted
139
- @n_successes += 1
140
- output_progress(".", color("success"))
174
+ output_progress(".", color("pass"))
141
175
  end
142
176
  @already_outputted = false
143
177
 
@@ -213,7 +247,10 @@ module Test
213
247
  end
214
248
 
215
249
  def color(name)
216
- @color_scheme[name] || ColorScheme.default[name]
250
+ _color = @color_scheme[name]
251
+ _color ||= @color_scheme["success"] if name == "pass"
252
+ _color ||= ColorScheme.default[name]
253
+ _color
217
254
  end
218
255
 
219
256
  def fault_color(fault)
@@ -221,21 +258,7 @@ module Test
221
258
  end
222
259
 
223
260
  def result_color
224
- if @result.passed?
225
- if @result.pending_count > 0
226
- color("pending")
227
- elsif @result.omission_count > 0
228
- color("omission")
229
- elsif @result.notification_count > 0
230
- color("notification")
231
- else
232
- color("success")
233
- end
234
- elsif @result.error_count > 0
235
- color("error")
236
- elsif @result.failure_count > 0
237
- color("failure")
238
- end
261
+ color(@result.status)
239
262
  end
240
263
 
241
264
  def guess_color_availability
@@ -268,6 +291,135 @@ module Test
268
291
  0
269
292
  end
270
293
  end
294
+
295
+ class ColorizedReadableDiffer < Diff::ReadableDiffer
296
+ def initialize(from, to, runner)
297
+ @runner = runner
298
+ super(from, to)
299
+ end
300
+
301
+ def need_diff?(options={})
302
+ operations.each do |tag,|
303
+ return true if [:replace, :equal].include?(tag)
304
+ end
305
+ false
306
+ end
307
+
308
+ private
309
+ def output_single(something, color=nil)
310
+ @runner.send(:output_single, something, color)
311
+ end
312
+
313
+ def output(something, color=nil)
314
+ @runner.send(:output, something, color)
315
+ end
316
+
317
+ def color(name)
318
+ @runner.send(:color, name)
319
+ end
320
+
321
+ def cut_off_ratio
322
+ 0
323
+ end
324
+
325
+ def default_ratio
326
+ 0
327
+ end
328
+
329
+ def tag(mark, color_name, contents)
330
+ _color = color(color_name)
331
+ contents.each do |content|
332
+ output_single(mark, _color)
333
+ output_single(" ")
334
+ output(content)
335
+ end
336
+ end
337
+
338
+ def tag_deleted(contents)
339
+ tag("-", "diff-deleted-tag", contents)
340
+ end
341
+
342
+ def tag_inserted(contents)
343
+ tag("+", "diff-inserted-tag", contents)
344
+ end
345
+
346
+ def tag_equal(contents)
347
+ tag(" ", "normal", contents)
348
+ end
349
+
350
+ def tag_difference(contents)
351
+ tag("?", "diff-difference-tag", contents)
352
+ end
353
+
354
+ def diff_line(from_line, to_line)
355
+ to_operations = []
356
+ from_line, to_line, _operations = line_operations(from_line, to_line)
357
+
358
+ no_replace = true
359
+ _operations.each do |tag,|
360
+ if tag == :replace
361
+ no_replace = false
362
+ break
363
+ end
364
+ end
365
+
366
+ output_single("?", color("diff-difference-tag"))
367
+ output_single(" ")
368
+ _operations.each do |tag, from_start, from_end, to_start, to_end|
369
+ from_width = compute_width(from_line, from_start, from_end)
370
+ to_width = compute_width(to_line, to_start, to_end)
371
+ case tag
372
+ when :replace
373
+ output_single(from_line[from_start...from_end],
374
+ color("diff-deleted"))
375
+ if (from_width < to_width)
376
+ output_single(" " * (to_width - from_width))
377
+ end
378
+ to_operations << Proc.new do
379
+ output_single(to_line[to_start...to_end],
380
+ color("diff-inserted"))
381
+ if (to_width < from_width)
382
+ output_single(" " * (from_width - to_width))
383
+ end
384
+ end
385
+ when :delete
386
+ output_single(from_line[from_start...from_end],
387
+ color("diff-deleted"))
388
+ unless no_replace
389
+ to_operations << Proc.new {output_single(" " * from_width)}
390
+ end
391
+ when :insert
392
+ if no_replace
393
+ output_single(to_line[to_start...to_end],
394
+ color("diff-inserted"))
395
+ else
396
+ output_single(" " * to_width)
397
+ to_operations << Proc.new do
398
+ output_single(to_line[to_start...to_end],
399
+ color("diff-inserted"))
400
+ end
401
+ end
402
+ when :equal
403
+ output_single(from_line[from_start...from_end])
404
+ unless no_replace
405
+ to_operations << Proc.new {output_single(" " * to_width)}
406
+ end
407
+ else
408
+ raise "unknown tag: #{tag}"
409
+ end
410
+ end
411
+ output("")
412
+
413
+ unless to_operations.empty?
414
+ output_single("?", color("diff-difference-tag"))
415
+ output_single(" ")
416
+ to_operations.each do |operation|
417
+ operation.call
418
+ end
419
+ output("")
420
+ end
421
+ end
422
+ end
271
423
  end
272
424
  end
273
425
  end