unparser 0.4.3 → 0.4.8

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,189 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe Unparser::Diff do
4
+ let(:object) { described_class }
5
+
6
+ describe '.build' do
7
+
8
+ subject { object.build(old_string, new_string) }
9
+
10
+ let(:old_string) { "foo\nbar" }
11
+ let(:new_string) { "bar\nbaz" }
12
+
13
+ it { should eql(described_class.new(%w[foo bar], %w[bar baz])) }
14
+
15
+ end
16
+
17
+ describe '#colorized_diff' do
18
+ let(:object) { described_class.new(old, new) }
19
+
20
+ subject { object.colorized_diff }
21
+
22
+ context 'when there is a diff at begin of hunk' do
23
+ let(:old) { %w[foo bar] }
24
+ let(:new) { %w[baz bar] }
25
+
26
+ let(:expectation) do
27
+ [
28
+ "@@ -1,3 +1,3 @@\n",
29
+ Unparser::Color::RED.format("-foo\n"),
30
+ Unparser::Color::GREEN.format("+baz\n"),
31
+ " bar\n"
32
+ ].join
33
+ end
34
+
35
+ it { should eql(expectation) }
36
+
37
+ it_should_behave_like 'an idempotent method'
38
+ end
39
+
40
+ context 'when there is no diff' do
41
+ let(:old) { '' }
42
+ let(:new) { '' }
43
+
44
+ it { should be(nil) }
45
+
46
+ it_should_behave_like 'an idempotent method'
47
+ end
48
+ end
49
+
50
+ describe '#diff' do
51
+ let(:object) { described_class.new(old, new) }
52
+
53
+ subject { object.diff }
54
+
55
+ context 'when there is a diff at begin and end' do
56
+ let(:old) { %w[foo bar foo] }
57
+ let(:new) { %w[baz bar baz] }
58
+
59
+ let(:expectation) do
60
+ <<~STR
61
+ @@ -1,4 +1,4 @@
62
+ -foo
63
+ +baz
64
+ bar
65
+ -foo
66
+ +baz
67
+ STR
68
+ end
69
+
70
+ it { should eql(expectation) }
71
+
72
+ it_should_behave_like 'an idempotent method'
73
+ end
74
+
75
+ context 'when there is a diff at begin of hunk' do
76
+ let(:old) { %w[foo bar] }
77
+ let(:new) { %w[baz bar] }
78
+
79
+ let(:expectation) do
80
+ <<~STR
81
+ @@ -1,3 +1,3 @@
82
+ -foo
83
+ +baz
84
+ bar
85
+ STR
86
+ end
87
+
88
+ it { should eql(expectation) }
89
+
90
+ it_should_behave_like 'an idempotent method'
91
+ end
92
+
93
+ context 'when there is a diff NOT at begin of hunk' do
94
+ let(:old) { %w[foo bar] }
95
+ let(:new) { %w[foo baz bar] }
96
+
97
+ let(:expectation) do
98
+ <<~STR
99
+ @@ -1,3 +1,4 @@
100
+ foo
101
+ +baz
102
+ bar
103
+ STR
104
+ end
105
+
106
+ it { should eql(expectation) }
107
+
108
+ it_should_behave_like 'an idempotent method'
109
+ end
110
+
111
+ context 'when the diff has a long context at begin' do
112
+ let(:old) { %w[foo bar baz boz a b c] }
113
+ let(:new) { %w[foo bar baz boz a b c other] }
114
+
115
+ let(:expectation) do
116
+ <<~STR
117
+ @@ -1,8 +1,9 @@
118
+ foo
119
+ bar
120
+ baz
121
+ boz
122
+ a
123
+ b
124
+ c
125
+ +other
126
+ STR
127
+ end
128
+
129
+ it { should eql(expectation) }
130
+
131
+ it_should_behave_like 'an idempotent method'
132
+ end
133
+
134
+ context 'when the diff has a long context at end, deleting' do
135
+ let(:old) { %w[other foo bar baz boz a b c] }
136
+ let(:new) { %w[foo bar baz boz a b c] }
137
+
138
+ let(:expectation) do
139
+ <<~STR
140
+ @@ -1,9 +1,8 @@
141
+ -other
142
+ foo
143
+ bar
144
+ baz
145
+ boz
146
+ a
147
+ b
148
+ c
149
+ STR
150
+ end
151
+
152
+ it { should eql(expectation) }
153
+
154
+ it_should_behave_like 'an idempotent method'
155
+ end
156
+
157
+ context 'when the diff has a long context at end, inserting' do
158
+ let(:old) { %w[foo bar baz boz a b c] }
159
+ let(:new) { %w[other foo bar baz boz a b c] }
160
+
161
+ let(:expectation) do
162
+ <<~STR
163
+ @@ -1,8 +1,9 @@
164
+ +other
165
+ foo
166
+ bar
167
+ baz
168
+ boz
169
+ a
170
+ b
171
+ c
172
+ STR
173
+ end
174
+
175
+ it { should eql(expectation) }
176
+
177
+ it_should_behave_like 'an idempotent method'
178
+ end
179
+
180
+ context 'when there is no diff' do
181
+ let(:old) { '' }
182
+ let(:new) { '' }
183
+
184
+ it { should be(nil) }
185
+
186
+ it_should_behave_like 'an idempotent method'
187
+ end
188
+ end
189
+ end
@@ -0,0 +1,327 @@
1
+ require 'spec_helper'
2
+
3
+ describe Unparser::Validation do
4
+ let(:object) do
5
+ described_class.new(
6
+ identification: identification,
7
+ generated_node: generated_node,
8
+ generated_source: generated_source,
9
+ original_node: original_node,
10
+ original_source: original_source
11
+ )
12
+ end
13
+
14
+ def right(value)
15
+ MPrelude::Either::Right.new(value)
16
+ end
17
+
18
+ def left(value)
19
+ MPrelude::Either::Left.new(value)
20
+ end
21
+
22
+ let(:generated_node) { right(s(:send, s(:int, 1), :foo)) }
23
+ let(:generated_source) { right('1.foo') }
24
+ let(:identification) { 'example-identification' }
25
+ let(:original_node) { right(s(:send, s(:int, 1), :foo)) }
26
+ let(:original_source) { right('1.foo') }
27
+
28
+ let(:exception) do
29
+ left(
30
+ instance_double(
31
+ RuntimeError,
32
+ message: 'foo',
33
+ backtrace: Array.new(21, &'line-%02d'.method(:%))
34
+ )
35
+ )
36
+ end
37
+
38
+ let(:exception_report) do
39
+ <<~'REPORT'.strip
40
+ #<InstanceDouble(RuntimeError) (anonymous)>
41
+ line-00
42
+ line-01
43
+ line-02
44
+ line-03
45
+ line-04
46
+ line-05
47
+ line-06
48
+ line-07
49
+ line-08
50
+ line-09
51
+ line-10
52
+ line-11
53
+ line-12
54
+ line-13
55
+ line-14
56
+ line-15
57
+ line-16
58
+ line-17
59
+ line-18
60
+ line-19
61
+ REPORT
62
+ end
63
+
64
+ def report
65
+ object.report
66
+ end
67
+
68
+ shared_examples 'not successful' do
69
+ it 'is not successful' do
70
+ expect(object.success?).to be(false)
71
+ end
72
+ end
73
+
74
+ context 'on success' do
75
+ it 'is successful' do
76
+ expect(object.success?).to be(true)
77
+ end
78
+
79
+ it 'returns expected report' do
80
+ expect(report).to eql(<<~'REPORT'.strip)
81
+ example-identification
82
+ Original-Source:
83
+ 1.foo
84
+ Generated-Source:
85
+ 1.foo
86
+ Original-Node:
87
+ (send
88
+ (int 1) :foo)
89
+ Generated-Node:
90
+ (send
91
+ (int 1) :foo)
92
+ REPORT
93
+ end
94
+ end
95
+
96
+ context 'on failing to generate original source with exception' do
97
+ let(:original_source) { exception }
98
+
99
+ include_examples 'not successful'
100
+
101
+ it 'returns expected report' do
102
+ expect(report).to eql(<<~REPORT.strip)
103
+ example-identification
104
+ Original-Source:
105
+ #{exception_report}
106
+ Generated-Source:
107
+ 1.foo
108
+ Original-Node:
109
+ (send
110
+ (int 1) :foo)
111
+ Generated-Node:
112
+ (send
113
+ (int 1) :foo)
114
+ REPORT
115
+ end
116
+ end
117
+
118
+ context 'on failing to parse generated source due precondition error' do
119
+ let(:generated_node) { left(nil) }
120
+
121
+ include_examples 'not successful'
122
+
123
+ it 'returns expected report' do
124
+ expect(report).to eql(<<~REPORT.strip)
125
+ example-identification
126
+ Original-Source:
127
+ 1.foo
128
+ Generated-Source:
129
+ 1.foo
130
+ Original-Node:
131
+ (send
132
+ (int 1) :foo)
133
+ Generated-Node:
134
+ undefined
135
+ REPORT
136
+ end
137
+ end
138
+
139
+ context 'on failing to parse original source' do
140
+ let(:original_node) { exception }
141
+
142
+ include_examples 'not successful'
143
+
144
+ it 'returns expected report' do
145
+ expect(report).to eql(<<~REPORT.strip)
146
+ example-identification
147
+ Original-Source:
148
+ 1.foo
149
+ Generated-Source:
150
+ 1.foo
151
+ Original-Node:
152
+ #{exception_report}
153
+ Generated-Node:
154
+ (send
155
+ (int 1) :foo)
156
+ REPORT
157
+ end
158
+ end
159
+
160
+ context 'on failing to generate generated source' do
161
+ let(:generated_source) { exception }
162
+
163
+ include_examples 'not successful'
164
+
165
+ it 'returns expected report' do
166
+ expect(report).to eql(<<~REPORT.strip)
167
+ example-identification
168
+ Original-Source:
169
+ 1.foo
170
+ Generated-Source:
171
+ #{exception_report}
172
+ Original-Node:
173
+ (send
174
+ (int 1) :foo)
175
+ Generated-Node:
176
+ (send
177
+ (int 1) :foo)
178
+ REPORT
179
+ end
180
+ end
181
+
182
+ context 'on failing to parse generated source' do
183
+ let(:generated_node) { exception }
184
+
185
+ include_examples 'not successful'
186
+
187
+ it 'returns expected report' do
188
+ expect(report).to eql(<<~REPORT.strip)
189
+ example-identification
190
+ Original-Source:
191
+ 1.foo
192
+ Generated-Source:
193
+ 1.foo
194
+ Original-Node:
195
+ (send
196
+ (int 1) :foo)
197
+ Generated-Node:
198
+ #{exception_report}
199
+ REPORT
200
+ end
201
+ end
202
+
203
+ context 'on generating different node' do
204
+ let(:generated_node) { right(s(:send, s(:int, 1), :bar)) }
205
+
206
+ include_examples 'not successful'
207
+
208
+ it 'returns expected report' do
209
+ diff = [
210
+ Unparser::Color::NONE.format(" (send\n"),
211
+ Unparser::Color::RED.format("- (int 1) :foo)\n"),
212
+ Unparser::Color::GREEN.format("+ (int 1) :bar)\n")
213
+ ]
214
+
215
+ expect(report).to eql(<<~'REPORT' + diff.join)
216
+ example-identification
217
+ Original-Source:
218
+ 1.foo
219
+ Generated-Source:
220
+ 1.foo
221
+ Original-Node:
222
+ (send
223
+ (int 1) :foo)
224
+ Generated-Node:
225
+ (send
226
+ (int 1) :bar)
227
+ Node-Diff:
228
+ @@ -1,3 +1,3 @@
229
+ REPORT
230
+ end
231
+ end
232
+
233
+ describe '.from_path' do
234
+ def apply
235
+ described_class.from_path(path)
236
+ end
237
+
238
+ let(:path) { instance_double(Pathname, read: source, to_s: '/some/file') }
239
+ let(:source) { 'true' }
240
+
241
+ it 'returns expected validator' do
242
+ expect(apply).to eql(
243
+ described_class.new(
244
+ generated_node: right(s(:true)),
245
+ generated_source: right(source),
246
+ identification: '/some/file',
247
+ original_node: right(s(:true)),
248
+ original_source: right(source)
249
+ )
250
+ )
251
+ end
252
+ end
253
+
254
+ describe '.from_string' do
255
+ def apply
256
+ described_class.from_string(source)
257
+ end
258
+
259
+ let(:attributes) do
260
+ {
261
+ generated_node: right(s(:true)),
262
+ generated_source: right(source),
263
+ identification: '(string)',
264
+ original_node: right(s(:true)),
265
+ original_source: right(source)
266
+ }
267
+ end
268
+
269
+ context 'on valid original source' do
270
+ let(:source) { 'true' }
271
+
272
+ it 'returns expected validator' do
273
+ expect(apply).to eql(described_class.new(attributes))
274
+ end
275
+
276
+ context 'with unparsing error' do
277
+ let(:exception) { RuntimeError.new('example-error') }
278
+
279
+ before do
280
+ allow(Unparser).to receive(:unparse).and_raise(exception)
281
+ end
282
+
283
+ it 'returns expected validator' do
284
+ validator = apply
285
+
286
+ expect(validator.generated_node).to eql(left(nil))
287
+ expect(validator.generated_source.from_left.class).to be(RuntimeError)
288
+ expect(validator.original_source).to eql(right(source))
289
+ expect(validator.original_node).to eql(right(s(:true)))
290
+ end
291
+ end
292
+ end
293
+
294
+ # These are actually specifying the wrong behavior as the normalization is a conceptual mistake
295
+ # But for now we specify them to get this PR through.
296
+ #
297
+ # Removal in followup.
298
+ context 'on denormalized valid original source' do
299
+ let(:source) { '(true)' }
300
+
301
+ it 'returns expected validator' do
302
+ expect(apply).to eql(described_class.new(attributes.merge(generated_source: right('true'))))
303
+ end
304
+ end
305
+
306
+ context 'on very denormalized valid original source' do
307
+ let(:source) { '((true))' }
308
+
309
+ it 'returns expected validator' do
310
+ expect(apply).to eql(described_class.new(attributes.merge(generated_source: right('true'))))
311
+ end
312
+ end
313
+
314
+ context 'on invalid original source' do
315
+ let(:source) { '(' }
316
+
317
+ it 'returns expected validator' do
318
+ validator = apply
319
+
320
+ expect(validator.generated_node).to eql(left(nil))
321
+ expect(validator.generated_source).to eql(left(nil))
322
+ expect(validator.original_source).to eql(right(source))
323
+ expect(validator.original_node.from_left.class).to be(Parser::SyntaxError)
324
+ end
325
+ end
326
+ end
327
+ end