rspec-expectations 3.0.0.beta1 → 3.0.0.beta2
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.
- data.tar.gz.sig +2 -2
- data/.yardopts +1 -0
- data/Changelog.md +138 -0
- data/README.md +75 -8
- data/features/README.md +2 -2
- data/features/built_in_matchers/README.md +12 -9
- data/features/built_in_matchers/comparisons.feature +2 -2
- data/features/built_in_matchers/contain_exactly.feature +46 -0
- data/features/built_in_matchers/expect_change.feature +2 -2
- data/features/built_in_matchers/include.feature +0 -48
- data/features/built_in_matchers/output.feature +70 -0
- data/features/composing_matchers.feature +250 -0
- data/features/compound_expectations.feature +45 -0
- data/features/custom_matchers/access_running_example.feature +1 -1
- data/features/custom_matchers/define_matcher.feature +6 -6
- data/features/custom_matchers/define_matcher_outside_rspec.feature +4 -8
- data/features/test_frameworks/{test_unit.feature → minitest.feature} +11 -11
- data/lib/rspec/expectations.rb +31 -42
- data/lib/rspec/expectations/diff_presenter.rb +141 -0
- data/lib/rspec/expectations/differ.rb +22 -132
- data/lib/rspec/expectations/encoded_string.rb +56 -0
- data/lib/rspec/expectations/expectation_target.rb +0 -30
- data/lib/rspec/expectations/fail_with.rb +2 -2
- data/lib/rspec/expectations/handler.rb +128 -31
- data/lib/rspec/expectations/minitest_integration.rb +16 -0
- data/lib/rspec/expectations/syntax.rb +4 -58
- data/lib/rspec/expectations/version.rb +1 -1
- data/lib/rspec/matchers.rb +298 -60
- data/lib/rspec/matchers/aliased_matcher.rb +35 -0
- data/lib/rspec/matchers/built_in.rb +37 -33
- data/lib/rspec/matchers/built_in/base_matcher.rb +25 -15
- data/lib/rspec/matchers/built_in/be.rb +23 -31
- data/lib/rspec/matchers/built_in/be_between.rb +55 -0
- data/lib/rspec/matchers/built_in/be_within.rb +15 -11
- data/lib/rspec/matchers/built_in/change.rb +198 -81
- data/lib/rspec/matchers/built_in/compound.rb +106 -0
- data/lib/rspec/matchers/built_in/contain_exactly.rb +245 -0
- data/lib/rspec/matchers/built_in/eq.rb +43 -4
- data/lib/rspec/matchers/built_in/eql.rb +2 -2
- data/lib/rspec/matchers/built_in/equal.rb +35 -18
- data/lib/rspec/matchers/built_in/has.rb +16 -15
- data/lib/rspec/matchers/built_in/include.rb +45 -23
- data/lib/rspec/matchers/built_in/match.rb +6 -3
- data/lib/rspec/matchers/built_in/operators.rb +103 -0
- data/lib/rspec/matchers/built_in/output.rb +108 -0
- data/lib/rspec/matchers/built_in/raise_error.rb +9 -15
- data/lib/rspec/matchers/built_in/respond_to.rb +5 -4
- data/lib/rspec/matchers/built_in/satisfy.rb +4 -3
- data/lib/rspec/matchers/built_in/start_and_end_with.rb +37 -16
- data/lib/rspec/matchers/built_in/throw_symbol.rb +6 -5
- data/lib/rspec/matchers/built_in/yield.rb +31 -29
- data/lib/rspec/matchers/composable.rb +138 -0
- data/lib/rspec/matchers/dsl.rb +330 -0
- data/lib/rspec/matchers/generated_descriptions.rb +6 -6
- data/lib/rspec/matchers/matcher_delegator.rb +33 -0
- data/lib/rspec/matchers/pretty.rb +13 -2
- data/spec/rspec/expectations/{differ_spec.rb → diff_presenter_spec.rb} +56 -36
- data/spec/rspec/expectations/encoded_string_spec.rb +74 -0
- data/spec/rspec/expectations/extensions/kernel_spec.rb +11 -11
- data/spec/rspec/expectations/fail_with_spec.rb +8 -8
- data/spec/rspec/expectations/handler_spec.rb +27 -49
- data/spec/rspec/expectations/minitest_integration_spec.rb +27 -0
- data/spec/rspec/expectations/syntax_spec.rb +17 -67
- data/spec/rspec/expectations_spec.rb +7 -52
- data/spec/rspec/matchers/aliased_matcher_spec.rb +48 -0
- data/spec/rspec/matchers/aliases_spec.rb +449 -0
- data/spec/rspec/matchers/{base_matcher_spec.rb → built_in/base_matcher_spec.rb} +24 -3
- data/spec/rspec/matchers/built_in/be_between_spec.rb +159 -0
- data/spec/rspec/matchers/{be_instance_of_spec.rb → built_in/be_instance_of_spec.rb} +0 -0
- data/spec/rspec/matchers/{be_kind_of_spec.rb → built_in/be_kind_of_spec.rb} +0 -0
- data/spec/rspec/matchers/{be_spec.rb → built_in/be_spec.rb} +76 -32
- data/spec/rspec/matchers/{be_within_spec.rb → built_in/be_within_spec.rb} +6 -2
- data/spec/rspec/matchers/{change_spec.rb → built_in/change_spec.rb} +310 -69
- data/spec/rspec/matchers/built_in/compound_spec.rb +292 -0
- data/spec/rspec/matchers/built_in/contain_exactly_spec.rb +441 -0
- data/spec/rspec/matchers/{cover_spec.rb → built_in/cover_spec.rb} +0 -0
- data/spec/rspec/matchers/built_in/eq_spec.rb +156 -0
- data/spec/rspec/matchers/{eql_spec.rb → built_in/eql_spec.rb} +2 -2
- data/spec/rspec/matchers/built_in/equal_spec.rb +106 -0
- data/spec/rspec/matchers/{exist_spec.rb → built_in/exist_spec.rb} +1 -1
- data/spec/rspec/matchers/{has_spec.rb → built_in/has_spec.rb} +39 -0
- data/spec/rspec/matchers/{include_spec.rb → built_in/include_spec.rb} +118 -109
- data/spec/rspec/matchers/{match_spec.rb → built_in/match_spec.rb} +30 -2
- data/spec/rspec/matchers/{operator_matcher_spec.rb → built_in/operators_spec.rb} +26 -26
- data/spec/rspec/matchers/built_in/output_spec.rb +165 -0
- data/spec/rspec/matchers/{raise_error_spec.rb → built_in/raise_error_spec.rb} +81 -11
- data/spec/rspec/matchers/{respond_to_spec.rb → built_in/respond_to_spec.rb} +0 -0
- data/spec/rspec/matchers/{satisfy_spec.rb → built_in/satisfy_spec.rb} +0 -0
- data/spec/rspec/matchers/{start_with_end_with_spec.rb → built_in/start_and_end_with_spec.rb} +82 -15
- data/spec/rspec/matchers/{throw_symbol_spec.rb → built_in/throw_symbol_spec.rb} +29 -10
- data/spec/rspec/matchers/{yield_spec.rb → built_in/yield_spec.rb} +90 -0
- data/spec/rspec/matchers/configuration_spec.rb +7 -39
- data/spec/rspec/matchers/description_generation_spec.rb +22 -6
- data/spec/rspec/matchers/dsl_spec.rb +838 -0
- data/spec/rspec/matchers/legacy_spec.rb +101 -0
- data/spec/rspec/matchers_spec.rb +74 -0
- data/spec/spec_helper.rb +35 -21
- data/spec/support/shared_examples.rb +26 -4
- metadata +172 -116
- metadata.gz.sig +3 -4
- checksums.yaml +0 -15
- checksums.yaml.gz.sig +0 -0
- data/features/built_in_matchers/match_array.feature +0 -37
- data/lib/rspec/expectations/errors.rb +0 -9
- data/lib/rspec/expectations/extensions.rb +0 -1
- data/lib/rspec/expectations/extensions/object.rb +0 -29
- data/lib/rspec/matchers/built_in/match_array.rb +0 -51
- data/lib/rspec/matchers/compatibility.rb +0 -14
- data/lib/rspec/matchers/matcher.rb +0 -301
- data/lib/rspec/matchers/method_missing.rb +0 -12
- data/lib/rspec/matchers/operator_matcher.rb +0 -99
- data/lib/rspec/matchers/test_unit_integration.rb +0 -11
- data/spec/rspec/matchers/eq_spec.rb +0 -60
- data/spec/rspec/matchers/equal_spec.rb +0 -78
- data/spec/rspec/matchers/include_matcher_integration_spec.rb +0 -30
- data/spec/rspec/matchers/match_array_spec.rb +0 -194
- data/spec/rspec/matchers/matcher_spec.rb +0 -706
- data/spec/rspec/matchers/matchers_spec.rb +0 -36
- data/spec/rspec/matchers/method_missing_spec.rb +0 -28
- data/spec/support/classes.rb +0 -56
- data/spec/support/in_sub_process.rb +0 -37
- data/spec/support/ruby_version.rb +0 -10
@@ -1,18 +1,18 @@
|
|
1
|
-
Feature:
|
1
|
+
Feature: Minitest integration
|
2
2
|
|
3
|
-
|
4
|
-
RSpec. If you like
|
5
|
-
|
3
|
+
rspec-expectations is a stand-alone gem that can be used without the rest of
|
4
|
+
RSpec. If you like minitest as your test runner, but prefer RSpec's
|
5
|
+
approach to expressing expectations, you can have both.
|
6
6
|
|
7
|
-
|
7
|
+
To integrate rspec-expectations with minitest, require `rspec/expectations/minitest_integration`.
|
8
8
|
|
9
|
-
Scenario: use rspec/expectations with
|
9
|
+
Scenario: use rspec/expectations with minitest
|
10
10
|
Given a file named "rspec_expectations_test.rb" with:
|
11
11
|
"""ruby
|
12
|
-
require '
|
13
|
-
require 'rspec/expectations'
|
12
|
+
require 'minitest/autorun'
|
13
|
+
require 'rspec/expectations/minitest_integration'
|
14
14
|
|
15
|
-
class RSpecExpectationsTest < Test
|
15
|
+
class RSpecExpectationsTest < Minitest::Test
|
16
16
|
RSpec::Matchers.define :be_an_integer do
|
17
17
|
match { |actual| Integer === actual }
|
18
18
|
end
|
@@ -30,7 +30,7 @@ Feature: Test::Unit integration
|
|
30
30
|
end
|
31
31
|
|
32
32
|
def test_failing_expectation
|
33
|
-
expect([1,2]).to be_empty
|
33
|
+
expect([1, 2]).to be_empty
|
34
34
|
end
|
35
35
|
|
36
36
|
def test_custom_matcher_with_deprecation_warning
|
@@ -39,6 +39,6 @@ Feature: Test::Unit integration
|
|
39
39
|
end
|
40
40
|
"""
|
41
41
|
When I run `ruby rspec_expectations_test.rb`
|
42
|
-
Then the output should contain "3
|
42
|
+
Then the output should contain "3 runs, 3 assertions, 1 failures, 0 errors"
|
43
43
|
And the output should contain "expected empty? to return true, got false"
|
44
44
|
And the output should contain "be_an_int is deprecated"
|
data/lib/rspec/expectations.rb
CHANGED
@@ -1,42 +1,49 @@
|
|
1
1
|
require 'rspec/support/caller_filter'
|
2
2
|
require 'rspec/support/warnings'
|
3
3
|
|
4
|
-
require 'rspec/expectations/extensions'
|
5
4
|
require 'rspec/matchers'
|
6
5
|
require 'rspec/expectations/expectation_target'
|
7
6
|
require 'rspec/matchers/configuration'
|
8
7
|
require 'rspec/expectations/fail_with'
|
9
|
-
require 'rspec/expectations/errors'
|
10
8
|
require 'rspec/expectations/handler'
|
11
9
|
require 'rspec/expectations/version'
|
12
|
-
require 'rspec/expectations/
|
10
|
+
require 'rspec/expectations/diff_presenter'
|
13
11
|
|
14
12
|
module RSpec
|
15
|
-
# RSpec::Expectations
|
13
|
+
# RSpec::Expectations provides a simple, readable API to express
|
14
|
+
# the expected outcomes in a code example. To express an expected
|
15
|
+
# outcome, wrap an object or block in `expect`, call `to` or `to_not`
|
16
|
+
# (aliased as `not_to`) and pass it a matcher object:
|
16
17
|
#
|
17
|
-
#
|
18
|
-
#
|
18
|
+
# expect(order.total).to eq(Money.new(5.55, :USD))
|
19
|
+
# expect(list).to include(user)
|
20
|
+
# expect(message).not_to match(/foo/)
|
21
|
+
# expect { do_something }.to raise_error
|
19
22
|
#
|
20
|
-
#
|
21
|
-
#
|
22
|
-
#
|
23
|
+
# The last form (the block form) is needed to match against ruby constructs
|
24
|
+
# that are not objects, but can only be observed when executing a block
|
25
|
+
# of code. This includes raising errors, throwing symbols, yielding,
|
26
|
+
# and changing values.
|
27
|
+
#
|
28
|
+
# When `expect(...).to` is invoked with a matcher, it turns around
|
29
|
+
# and calls `matcher.matches?(<object wrapped by expect>)`. For example,
|
23
30
|
# in the expression:
|
24
31
|
#
|
25
|
-
# order.total.
|
32
|
+
# expect(order.total).to eq(Money.new(5.55, :USD))
|
26
33
|
#
|
27
|
-
#
|
28
|
-
#
|
29
|
-
# `
|
30
|
-
# `eq.
|
34
|
+
# ...`eq(Money.new(5.55, :USD))` returns a matcher object, and it results
|
35
|
+
# in the equivalent of `eq.matches?(order.total)`. If `matches?` returns
|
36
|
+
# `true`, the expectation is met and execution continues. If `false`, then
|
37
|
+
# the spec fails with the message returned by `eq.failure_message`.
|
31
38
|
#
|
32
39
|
# Given the expression:
|
33
40
|
#
|
34
|
-
# order.entries.
|
41
|
+
# expect(order.entries).not_to include(entry)
|
35
42
|
#
|
36
|
-
# the `
|
43
|
+
# ...the `not_to` method (also available as `to_not`) invokes the equivalent of
|
37
44
|
# `include.matches?(order.entries)`, but it interprets `false` as success, and
|
38
45
|
# `true` as a failure, using the message generated by
|
39
|
-
# `eq.
|
46
|
+
# `eq.failure_message_when_negated`.
|
40
47
|
#
|
41
48
|
# rspec-expectations ships with a standard set of useful matchers, and writing
|
42
49
|
# your own matchers is quite simple.
|
@@ -45,31 +52,13 @@ module RSpec
|
|
45
52
|
# built-in matchers that ship with rspec-expectations, and how to write your
|
46
53
|
# own custom matchers.
|
47
54
|
module Expectations
|
48
|
-
|
49
|
-
# @api private
|
50
|
-
KERNEL_METHOD_METHOD = ::Kernel.instance_method(:method)
|
51
|
-
|
52
|
-
# @api private
|
55
|
+
# Exception raised when an expectation fails.
|
53
56
|
#
|
54
|
-
#
|
55
|
-
#
|
56
|
-
#
|
57
|
-
#
|
58
|
-
|
59
|
-
# - Objects that redefine #method (e.g. an HTTPRequest struct)
|
60
|
-
# - BasicObject subclasses that mixin a Kernel dup (e.g. SimpleDelegator)
|
61
|
-
if RUBY_VERSION.to_i >= 2
|
62
|
-
def self.method_handle_for(object, method_name)
|
63
|
-
KERNEL_METHOD_METHOD.bind(object).call(method_name)
|
64
|
-
end
|
65
|
-
else
|
66
|
-
def self.method_handle_for(object, method_name)
|
67
|
-
if ::Kernel === object
|
68
|
-
KERNEL_METHOD_METHOD.bind(object).call(method_name)
|
69
|
-
else
|
70
|
-
object.method(method_name)
|
71
|
-
end
|
72
|
-
end
|
73
|
-
end
|
57
|
+
# @note We subclass Exception so that in a stub implementation if
|
58
|
+
# the user sets an expectation, it can't be caught in their
|
59
|
+
# code by a bare `rescue`.
|
60
|
+
# @api public
|
61
|
+
ExpectationNotMetError = Class.new(::Exception)
|
74
62
|
end
|
75
63
|
end
|
64
|
+
|
@@ -0,0 +1,141 @@
|
|
1
|
+
require 'diff/lcs'
|
2
|
+
require "rspec/expectations/encoded_string"
|
3
|
+
require "rspec/expectations/differ"
|
4
|
+
require 'diff/lcs/hunk'
|
5
|
+
require 'pp'
|
6
|
+
|
7
|
+
module RSpec
|
8
|
+
module Expectations
|
9
|
+
class DiffPresenter
|
10
|
+
def diff_as_string(actual, expected)
|
11
|
+
@encoding = pick_encoding actual, expected
|
12
|
+
|
13
|
+
@actual = EncodedString.new(actual, @encoding)
|
14
|
+
@expected = EncodedString.new(expected, @encoding)
|
15
|
+
|
16
|
+
output = EncodedString.new("\n", @encoding)
|
17
|
+
|
18
|
+
hunks.each_cons(2) do |prev_hunk, current_hunk|
|
19
|
+
begin
|
20
|
+
if current_hunk.overlaps?(prev_hunk)
|
21
|
+
add_old_hunk_to_hunk(current_hunk, prev_hunk)
|
22
|
+
else
|
23
|
+
add_to_output(output, prev_hunk.diff(format).to_s)
|
24
|
+
end
|
25
|
+
ensure
|
26
|
+
add_to_output(output, "\n")
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
if hunks.last
|
31
|
+
finalize_output(output, hunks.last.diff(format).to_s)
|
32
|
+
end
|
33
|
+
|
34
|
+
color_diff output
|
35
|
+
rescue Encoding::CompatibilityError
|
36
|
+
handle_encoding_errors
|
37
|
+
end
|
38
|
+
|
39
|
+
def diff_as_object(actual, expected)
|
40
|
+
actual_as_string = object_to_string(actual)
|
41
|
+
expected_as_string = object_to_string(expected)
|
42
|
+
diff_as_string(actual_as_string, expected_as_string)
|
43
|
+
end
|
44
|
+
|
45
|
+
private
|
46
|
+
|
47
|
+
def hunks
|
48
|
+
@hunks ||= Differ.new(@actual, @expected).hunks
|
49
|
+
end
|
50
|
+
|
51
|
+
def finalize_output(output, final_line)
|
52
|
+
add_to_output(output, final_line)
|
53
|
+
add_to_output(output, "\n")
|
54
|
+
end
|
55
|
+
|
56
|
+
def add_to_output(output, string)
|
57
|
+
output << string
|
58
|
+
end
|
59
|
+
|
60
|
+
def add_old_hunk_to_hunk(hunk, oldhunk)
|
61
|
+
hunk.merge(oldhunk)
|
62
|
+
end
|
63
|
+
|
64
|
+
def format
|
65
|
+
:unified
|
66
|
+
end
|
67
|
+
|
68
|
+
def color(text, color_code)
|
69
|
+
"\e[#{color_code}m#{text}\e[0m"
|
70
|
+
end
|
71
|
+
|
72
|
+
def red(text)
|
73
|
+
color(text, 31)
|
74
|
+
end
|
75
|
+
|
76
|
+
def green(text)
|
77
|
+
color(text, 32)
|
78
|
+
end
|
79
|
+
|
80
|
+
def blue(text)
|
81
|
+
color(text, 34)
|
82
|
+
end
|
83
|
+
|
84
|
+
def normal(text)
|
85
|
+
color(text, 0)
|
86
|
+
end
|
87
|
+
|
88
|
+
def color_diff(diff)
|
89
|
+
return diff unless RSpec::Matchers.configuration.color?
|
90
|
+
|
91
|
+
diff.lines.map { |line|
|
92
|
+
case line[0].chr
|
93
|
+
when "+"
|
94
|
+
green line
|
95
|
+
when "-"
|
96
|
+
red line
|
97
|
+
when "@"
|
98
|
+
line[1].chr == "@" ? blue(line) : normal(line)
|
99
|
+
else
|
100
|
+
normal(line)
|
101
|
+
end
|
102
|
+
}.join
|
103
|
+
end
|
104
|
+
|
105
|
+
def object_to_string(object)
|
106
|
+
object = Matchers::Composable.surface_descriptions_in(object)
|
107
|
+
case object
|
108
|
+
when Hash
|
109
|
+
object.keys.sort_by { |k| k.to_s }.map do |key|
|
110
|
+
pp_key = PP.singleline_pp(key, "")
|
111
|
+
pp_value = PP.singleline_pp(object[key], "")
|
112
|
+
|
113
|
+
"#{pp_key} => #{pp_value},"
|
114
|
+
end.join("\n")
|
115
|
+
when String
|
116
|
+
object =~ /\n/ ? object : object.inspect
|
117
|
+
else
|
118
|
+
PP.pp(object,"")
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
if String.method_defined?(:encoding)
|
123
|
+
def pick_encoding(source_a, source_b)
|
124
|
+
Encoding.compatible?(source_a, source_b) || Encoding.default_external
|
125
|
+
end
|
126
|
+
else
|
127
|
+
def pick_encoding(source_a, source_b)
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
def handle_encoding_errors
|
132
|
+
if @actual.source_encoding != @expected.source_encoding
|
133
|
+
"Could not produce a diff because the encoding of the actual string (#{@actual.source_encoding}) "+
|
134
|
+
"differs from the encoding of the expected string (#{@expected.source_encoding})"
|
135
|
+
else
|
136
|
+
"Could not produce a diff because of the encoding of the string (#{@expected.source_encoding})"
|
137
|
+
end
|
138
|
+
end
|
139
|
+
end
|
140
|
+
end
|
141
|
+
end
|
@@ -1,154 +1,44 @@
|
|
1
|
-
require 'diff/lcs'
|
2
|
-
require 'diff/lcs/hunk'
|
3
|
-
require 'pp'
|
4
|
-
|
5
1
|
module RSpec
|
6
2
|
module Expectations
|
7
3
|
class Differ
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
encoding = pick_encoding input_data_new, input_data_old
|
12
|
-
output = matching_encoding("", encoding)
|
13
|
-
data_old = input_data_old.split(matching_encoding("\n", encoding)).map! { |e| e.chomp }
|
14
|
-
data_new = input_data_new.split(matching_encoding("\n", encoding)).map! { |e| e.chomp }
|
15
|
-
diffs = Diff::LCS.diff(data_old, data_new)
|
16
|
-
return output if diffs.empty?
|
17
|
-
oldhunk = hunk = nil
|
18
|
-
file_length_difference = 0
|
19
|
-
diffs.each do |piece|
|
20
|
-
begin
|
21
|
-
hunk = Diff::LCS::Hunk.new(
|
22
|
-
data_old, data_new, piece, context_lines, file_length_difference
|
23
|
-
)
|
24
|
-
file_length_difference = hunk.file_length_difference
|
25
|
-
next unless oldhunk
|
26
|
-
# Hunks may overlap, which is why we need to be careful when our
|
27
|
-
# diff includes lines of context. Otherwise, we might print
|
28
|
-
# redundant lines.
|
29
|
-
if (context_lines > 0) and hunk.overlaps?(oldhunk)
|
30
|
-
if hunk.respond_to?(:merge)
|
31
|
-
# diff-lcs 1.2.x
|
32
|
-
hunk.merge(oldhunk)
|
33
|
-
else
|
34
|
-
# diff-lcs 1.1.3
|
35
|
-
hunk.unshift(oldhunk)
|
36
|
-
end
|
37
|
-
else
|
38
|
-
output << matching_encoding(oldhunk.diff(format).to_s, encoding)
|
39
|
-
end
|
40
|
-
ensure
|
41
|
-
oldhunk = hunk
|
42
|
-
output << matching_encoding("\n", encoding)
|
43
|
-
end
|
44
|
-
end
|
45
|
-
#Handle the last remaining hunk
|
46
|
-
output << matching_encoding(oldhunk.diff(format).to_s, encoding)
|
47
|
-
output << matching_encoding("\n", encoding)
|
48
|
-
color_diff output
|
49
|
-
rescue Encoding::CompatibilityError
|
50
|
-
if input_data_new.encoding != input_data_old.encoding
|
51
|
-
"Could not produce a diff because the encoding of the actual string (#{input_data_old.encoding}) "+
|
52
|
-
"differs from the encoding of the expected string (#{input_data_new.encoding})"
|
53
|
-
else
|
54
|
-
"Could not produce a diff because of the encoding of the string (#{input_data_old.encoding})"
|
55
|
-
end
|
4
|
+
def initialize(actual, expected)
|
5
|
+
@actual = actual
|
6
|
+
@expected = expected
|
56
7
|
end
|
57
8
|
|
58
|
-
def
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
color_diff diff
|
9
|
+
def hunks
|
10
|
+
@file_length_difference = 0
|
11
|
+
@hunks ||= diffs.map do |piece|
|
12
|
+
build_hunk(piece)
|
63
13
|
end
|
64
14
|
end
|
65
15
|
|
66
|
-
|
67
|
-
|
68
|
-
def format
|
69
|
-
:unified
|
70
|
-
end
|
71
|
-
|
72
|
-
def context_lines
|
73
|
-
3
|
74
|
-
end
|
75
|
-
|
76
|
-
def color(text, color_code)
|
77
|
-
"\e[#{color_code}m#{text}\e[0m"
|
78
|
-
end
|
79
|
-
|
80
|
-
def red(text)
|
81
|
-
color(text, 31)
|
82
|
-
end
|
16
|
+
private
|
83
17
|
|
84
|
-
def
|
85
|
-
|
18
|
+
def diffs
|
19
|
+
Diff::LCS.diff(expected_lines, actual_lines)
|
86
20
|
end
|
87
21
|
|
88
|
-
def
|
89
|
-
|
22
|
+
def expected_lines
|
23
|
+
@expected.split("\n").map! { |e| e.chomp }
|
90
24
|
end
|
91
25
|
|
92
|
-
def
|
93
|
-
|
94
|
-
|
95
|
-
diff.lines.map { |line|
|
96
|
-
case line[0].chr
|
97
|
-
when "+"
|
98
|
-
green line
|
99
|
-
when "-"
|
100
|
-
red line
|
101
|
-
when "@"
|
102
|
-
line[1].chr == "@" ? blue(line) : line
|
103
|
-
else
|
104
|
-
line
|
105
|
-
end
|
106
|
-
}.join
|
26
|
+
def actual_lines
|
27
|
+
@actual.split("\n").map! { |e| e.chomp }
|
107
28
|
end
|
108
29
|
|
109
|
-
def
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
pp_value = PP.singleline_pp(object[key], "")
|
115
|
-
|
116
|
-
# on 1.9.3 PP seems to minimise to US-ASCII, ensure we're matching source encoding
|
117
|
-
#
|
118
|
-
# note, PP is used to ensure the ordering of the internal values of key/value e.g.
|
119
|
-
# <# a: b: c:> not <# c: a: b:>
|
120
|
-
encoding = pick_encoding pp_key, pp_value
|
121
|
-
matching_encoding("#{pp_key} => #{pp_value}", encoding)
|
122
|
-
end.join(",\n")
|
123
|
-
when String
|
124
|
-
object =~ /\n/ ? object : object.inspect
|
125
|
-
else
|
126
|
-
PP.pp(object,"")
|
30
|
+
def build_hunk(piece)
|
31
|
+
Diff::LCS::Hunk.new(
|
32
|
+
expected_lines, actual_lines, piece, context_lines, @file_length_difference
|
33
|
+
).tap do |h|
|
34
|
+
@file_length_difference = h.file_length_difference
|
127
35
|
end
|
128
36
|
end
|
129
37
|
|
130
|
-
|
131
|
-
|
132
|
-
if String.method_defined?(:encoding)
|
133
|
-
def pick_encoding(source_a, source_b)
|
134
|
-
Encoding.compatible?(source_a, source_b) || Encoding.default_external
|
135
|
-
end
|
136
|
-
|
137
|
-
def matching_encoding(string, encoding)
|
138
|
-
string.encode encoding
|
139
|
-
rescue Encoding::UndefinedConversionError
|
140
|
-
string.encode(encoding, :undef => :replace)
|
141
|
-
end
|
142
|
-
else
|
143
|
-
def pick_encoding(source_a, source_b)
|
144
|
-
end
|
145
|
-
|
146
|
-
def matching_encoding(string, encoding)
|
147
|
-
string
|
148
|
-
end
|
38
|
+
def context_lines
|
39
|
+
3
|
149
40
|
end
|
150
|
-
end
|
151
41
|
|
42
|
+
end
|
152
43
|
end
|
153
44
|
end
|
154
|
-
|