-
Notifications
You must be signed in to change notification settings - Fork 47
/
unix_diff_formatter.rb
159 lines (128 loc) · 4.45 KB
/
unix_diff_formatter.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
require 'pact/shared/jruby_support'
require 'pact/matchers/differ'
require 'pact/matchers/extract_diff_messages'
module Pact
module Matchers
class UnixDiffFormatter
include JRubySupport
MESSAGES_TITLE = "\n\nDescription of differences\n--------------------------------------"
def initialize diff, options = {}
@diff = diff
@colour = options.fetch(:colour, false)
@actual = options.fetch(:actual, {})
@include_explanation = options.fetch(:include_explanation, true)
@differ = Pact::Matchers::Differ.new(@colour)
@messages = Pact::Matchers::ExtractDiffMessages.call(diff).collect{ | message| "* #{message}" }.join("\n")
end
def self.call diff, options = {}
# require stops circular dependency from pact/configuration <-> pact/matchers/unix_diff_formatter
require 'pact/configuration'
default_options = {colour: Pact.configuration.color_enabled}
new(diff, default_options.merge(options)).call
end
def call
to_s
end
def to_s
expected = generate_string(diff, :expected)
actual = generate_string(diff, :actual)
suffix = @include_explanation ? key + "\n" : ''
messages = @include_explanation ? "#{MESSAGES_TITLE}\n#{@messages}\n" : ''
string_diff = @differ.diff_as_string(actual, expected).lstrip
string_diff = remove_first_line(string_diff)
string_diff = remove_comma_from_end_of_arrays(string_diff)
suffix + string_diff + messages
end
private
def handle thing, target
case thing
when Hash then copy_hash(thing, target)
when Array then copy_array(thing, target)
when Difference then copy_diff(thing, target)
when TypeDifference then copy_diff(thing, target)
when RegexpDifference then copy_diff(thing, target)
when NoDiffAtIndex then copy_no_diff(thing, target)
else copy_object(thing, target)
end
end
def generate_string diff, target
comparable = handle(diff, target)
begin
# Can't think of an elegant way to check if we can pretty generate other than to try it and maybe fail
json = fix_blank_lines_in_empty_hashes JSON.pretty_generate(comparable)
json = add_blank_lines_in_empty_hashes json
json = add_blank_lines_in_empty_arrays json
add_comma_to_end_of_arrays json
rescue JSON::GeneratorError
comparable.to_s
end
end
def copy_hash hash, target
hash.keys.each_with_object({}) do | key, new_hash |
value = handle hash[key], target
new_hash[key] = value unless (KeyNotFound === value || UnexpectedKey === value)
end
end
def copy_array array, target
array.each_index.each_with_object([]) do | index, new_array |
value = handle array[index], target
new_array[index] = value unless (UnexpectedIndex === value || IndexNotFound === value)
end
end
def copy_no_diff(thing, target)
NoDifferenceDecorator.new
end
def copy_diff difference, target
if target == :actual
handle difference.actual, target
else
handle difference.expected, target
end
end
def copy_object object, target
if Regexp === object
RegexpDecorator.new(object)
else
object
end
end
def key
"Diff\n--------------------------------------\n" +
"Key: " + @differ.red("-") + @differ.red(" is expected \n") +
@differ.green(" +") + @differ.green(" is actual \n") +
"Matching keys and values are not shown\n"
end
def remove_first_line string_diff
lines = string_diff.split("\n")
if lines[0] =~ /@@/
lines[1..-1].join("\n")
else
string_diff
end
end
def add_comma_to_end_of_arrays string
string.gsub(/(\n\s*\])/, ',\1')
end
def remove_comma_from_end_of_arrays string
string.gsub(/,(\n\s*\])/, '\1')
end
class NoDifferenceDecorator
def to_json options = {}
"... "
end
end
class RegexpDecorator
def initialize regexp
@regexp = regexp
end
def to_json options = {}
@regexp.inspect
end
def as_json
@regexp.inspect
end
end
attr_reader :diff
end
end
end