activegroonga 0.0.7 → 1.0.0

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