unparser 0.4.3 → 0.4.8

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.
@@ -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