zombie-killer 0.2

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,1148 @@
1
+ # Generated from spec/zombie_killer_spec.md -- do not change!
2
+
3
+ require "spec_helper"
4
+
5
+ describe "ZombieKiller:" do
6
+ describe "table of contents:" do
7
+ end
8
+
9
+ describe "concepts:" do
10
+ end
11
+
12
+ describe "literals:" do
13
+ it "translates `Ops.add` of two string literals" do
14
+ original_code = cleanup(<<-EOT)
15
+ Ops.add("Hello", "World")
16
+ EOT
17
+
18
+ translated_code = cleanup(<<-EOT)
19
+ "Hello" + "World"
20
+ EOT
21
+
22
+ expect(ZombieKiller.new.kill(original_code)).to eq(translated_code)
23
+ end
24
+
25
+ it "translates `Ops.add` of two integer literals" do
26
+ original_code = cleanup(<<-EOT)
27
+ Ops.add(40, 2)
28
+ EOT
29
+
30
+ translated_code = cleanup(<<-EOT)
31
+ 40 + 2
32
+ EOT
33
+
34
+ expect(ZombieKiller.new.kill(original_code)).to eq(translated_code)
35
+ end
36
+
37
+ it "translates assignment of `Ops.add` of two string literals" do
38
+ original_code = cleanup(<<-EOT)
39
+ v = Ops.add("Hello", "World")
40
+ EOT
41
+
42
+ translated_code = cleanup(<<-EOT)
43
+ v = "Hello" + "World"
44
+ EOT
45
+
46
+ expect(ZombieKiller.new.kill(original_code)).to eq(translated_code)
47
+ end
48
+
49
+ it "does not translate Ops.add if any argument is ugly" do
50
+ original_code = cleanup(<<-EOT)
51
+ Ops.add("Hello", world)
52
+ EOT
53
+
54
+ translated_code = cleanup(<<-EOT)
55
+ Ops.add("Hello", world)
56
+ EOT
57
+
58
+ expect(ZombieKiller.new.kill(original_code)).to eq(translated_code)
59
+ end
60
+
61
+ it "does not translate Ops.add if any argument is the nil literal" do
62
+ original_code = cleanup(<<-EOT)
63
+ Ops.add("Hello", nil)
64
+ EOT
65
+
66
+ translated_code = cleanup(<<-EOT)
67
+ Ops.add("Hello", nil)
68
+ EOT
69
+
70
+ expect(ZombieKiller.new.kill(original_code)).to eq(translated_code)
71
+ end
72
+ end
73
+
74
+ describe "variables:" do
75
+ it "translates `Ops.add(nice_variable, literal)`" do
76
+ original_code = cleanup(<<-EOT)
77
+ v = "Hello"
78
+ Ops.add(v, "World")
79
+ EOT
80
+
81
+ translated_code = cleanup(<<-EOT)
82
+ v = "Hello"
83
+ v + "World"
84
+ EOT
85
+
86
+ expect(ZombieKiller.new.kill(original_code)).to eq(translated_code)
87
+ end
88
+
89
+ it "doesn't translate `Ops.add(nice_variable, literal)` when the variable got it's niceness via multiple assignemnt" do
90
+ original_code = cleanup(<<-EOT)
91
+ v1, v2 = "Hello", "World"
92
+ Ops.add(v1, v2)
93
+ EOT
94
+
95
+ translated_code = cleanup(<<-EOT)
96
+ v1, v2 = "Hello", "World"
97
+ Ops.add(v1, v2)
98
+ EOT
99
+
100
+ expect(ZombieKiller.new.kill(original_code)).to eq(translated_code)
101
+ end
102
+
103
+ it "translates `Ops.add(nontrivially_nice_variable, literal)`" do
104
+ original_code = cleanup(<<-EOT)
105
+ v = "Hello"
106
+ v2 = v
107
+ v = uglify
108
+ Ops.add(v2, "World")
109
+ EOT
110
+
111
+ translated_code = cleanup(<<-EOT)
112
+ v = "Hello"
113
+ v2 = v
114
+ v = uglify
115
+ v2 + "World"
116
+ EOT
117
+
118
+ expect(ZombieKiller.new.kill(original_code)).to eq(translated_code)
119
+ end
120
+
121
+ it "does not translate `Ops.add(mutated_variable, literal)`" do
122
+ original_code = cleanup(<<-EOT)
123
+ v = "Hello"
124
+ v = f(v)
125
+ Ops.add(v, "World")
126
+ EOT
127
+
128
+ translated_code = cleanup(<<-EOT)
129
+ v = "Hello"
130
+ v = f(v)
131
+ Ops.add(v, "World")
132
+ EOT
133
+
134
+ expect(ZombieKiller.new.kill(original_code)).to eq(translated_code)
135
+ end
136
+
137
+ it "does not confuse variables across `def`s" do
138
+ original_code = cleanup(<<-EOT)
139
+ def a
140
+ v = "literal"
141
+ end
142
+
143
+ def b(v)
144
+ Ops.add(v, "literal")
145
+ end
146
+ EOT
147
+
148
+ translated_code = cleanup(<<-EOT)
149
+ def a
150
+ v = "literal"
151
+ end
152
+
153
+ def b(v)
154
+ Ops.add(v, "literal")
155
+ end
156
+ EOT
157
+
158
+ expect(ZombieKiller.new.kill(original_code)).to eq(translated_code)
159
+ end
160
+
161
+ it "does not confuse variables across `def self.`s" do
162
+ original_code = cleanup(<<-EOT)
163
+ v = 1
164
+
165
+ def self.foo(v)
166
+ Ops.add(v, 1)
167
+ end
168
+ EOT
169
+
170
+ translated_code = cleanup(<<-EOT)
171
+ v = 1
172
+
173
+ def self.foo(v)
174
+ Ops.add(v, 1)
175
+ end
176
+ EOT
177
+
178
+ expect(ZombieKiller.new.kill(original_code)).to eq(translated_code)
179
+ end
180
+
181
+ it "does not confuse variables across `module`s" do
182
+ original_code = cleanup(<<-EOT)
183
+ module A
184
+ v = "literal"
185
+ end
186
+
187
+ module B
188
+ # The assignment is needed to convince Ruby parser that the "v" reference in
189
+ # the "Ops.add" call later refers to a variable, not a method. This means it
190
+ # will be parsed as a "lvar" node (which can possibly be nice), not a "send"
191
+ # node (which can't be nice).
192
+
193
+ v = v
194
+ Ops.add(v, "literal")
195
+ end
196
+ EOT
197
+
198
+ translated_code = cleanup(<<-EOT)
199
+ module A
200
+ v = "literal"
201
+ end
202
+
203
+ module B
204
+ # The assignment is needed to convince Ruby parser that the "v" reference in
205
+ # the "Ops.add" call later refers to a variable, not a method. This means it
206
+ # will be parsed as a "lvar" node (which can possibly be nice), not a "send"
207
+ # node (which can't be nice).
208
+
209
+ v = v
210
+ Ops.add(v, "literal")
211
+ end
212
+ EOT
213
+
214
+ expect(ZombieKiller.new.kill(original_code)).to eq(translated_code)
215
+ end
216
+
217
+ it "does not confuse variables across `class`s" do
218
+ original_code = cleanup(<<-EOT)
219
+ class A
220
+ v = "literal"
221
+ end
222
+
223
+ class B
224
+ # The assignment is needed to convince Ruby parser that the "v" reference in
225
+ # the "Ops.add" call later refers to a variable, not a method. This means it
226
+ # will be parsed as a "lvar" node (which can possibly be nice), not a "send"
227
+ # node (which can't be nice).
228
+
229
+ v = v
230
+ Ops.add(v, "literal")
231
+ end
232
+ EOT
233
+
234
+ translated_code = cleanup(<<-EOT)
235
+ class A
236
+ v = "literal"
237
+ end
238
+
239
+ class B
240
+ # The assignment is needed to convince Ruby parser that the "v" reference in
241
+ # the "Ops.add" call later refers to a variable, not a method. This means it
242
+ # will be parsed as a "lvar" node (which can possibly be nice), not a "send"
243
+ # node (which can't be nice).
244
+
245
+ v = v
246
+ Ops.add(v, "literal")
247
+ end
248
+ EOT
249
+
250
+ expect(ZombieKiller.new.kill(original_code)).to eq(translated_code)
251
+ end
252
+
253
+ it "does not confuse variables across singleton `class`s" do
254
+ original_code = cleanup(<<-EOT)
255
+ class << self
256
+ v = "literal"
257
+ end
258
+
259
+ class << self
260
+ # The assignment is needed to convince Ruby parser that the "v" reference in
261
+ # the "Ops.add" call later refers to a variable, not a method. This means it
262
+ # will be parsed as a "lvar" node (which can possibly be nice), not a "send"
263
+ # node (which can't be nice).
264
+
265
+ v = v
266
+ Ops.add(v, "literal")
267
+ end
268
+ EOT
269
+
270
+ translated_code = cleanup(<<-EOT)
271
+ class << self
272
+ v = "literal"
273
+ end
274
+
275
+ class << self
276
+ # The assignment is needed to convince Ruby parser that the "v" reference in
277
+ # the "Ops.add" call later refers to a variable, not a method. This means it
278
+ # will be parsed as a "lvar" node (which can possibly be nice), not a "send"
279
+ # node (which can't be nice).
280
+
281
+ v = v
282
+ Ops.add(v, "literal")
283
+ end
284
+ EOT
285
+
286
+ expect(ZombieKiller.new.kill(original_code)).to eq(translated_code)
287
+ end
288
+ end
289
+
290
+ describe "assignments:" do
291
+ describe "and-assignment:" do
292
+ it "manages niceness correctly in presence of `&&=`" do
293
+ original_code = cleanup(<<-EOT)
294
+ nice1 = true
295
+ nice2 = true
296
+ ugly1 = nil
297
+ ugly2 = nil
298
+
299
+ nice1 &&= true
300
+ nice2 &&= nil
301
+ ugly1 &&= true
302
+ ugly2 &&= nil
303
+
304
+ Ops.add(nice1, 1)
305
+ Ops.add(nice2, 1)
306
+ Ops.add(ugly1, 1)
307
+ Ops.add(ugly2, 1)
308
+ EOT
309
+
310
+ translated_code = cleanup(<<-EOT)
311
+ nice1 = true
312
+ nice2 = true
313
+ ugly1 = nil
314
+ ugly2 = nil
315
+
316
+ nice1 &&= true
317
+ nice2 &&= nil
318
+ ugly1 &&= true
319
+ ugly2 &&= nil
320
+
321
+ nice1 + 1
322
+ Ops.add(nice2, 1)
323
+ Ops.add(ugly1, 1)
324
+ Ops.add(ugly2, 1)
325
+ EOT
326
+
327
+ expect(ZombieKiller.new.kill(original_code)).to eq(translated_code)
328
+ end
329
+ end
330
+
331
+ describe "or-assignment:" do
332
+ it "manages niceness correctly in presence of `||=`" do
333
+ original_code = cleanup(<<-EOT)
334
+ nice1 = true
335
+ nice2 = true
336
+ ugly1 = nil
337
+ ugly2 = nil
338
+
339
+ nice1 ||= true
340
+ nice2 ||= nil
341
+ ugly1 ||= true
342
+ ugly2 ||= nil
343
+
344
+ Ops.add(nice1, 1)
345
+ Ops.add(nice2, 1)
346
+ Ops.add(ugly1, 1)
347
+ Ops.add(ugly2, 1)
348
+ EOT
349
+
350
+ translated_code = cleanup(<<-EOT)
351
+ nice1 = true
352
+ nice2 = true
353
+ ugly1 = nil
354
+ ugly2 = nil
355
+
356
+ nice1 ||= true
357
+ nice2 ||= nil
358
+ ugly1 ||= true
359
+ ugly2 ||= nil
360
+
361
+ nice1 + 1
362
+ nice2 + 1
363
+ ugly1 + 1
364
+ Ops.add(ugly2, 1)
365
+ EOT
366
+
367
+ expect(ZombieKiller.new.kill(original_code)).to eq(translated_code)
368
+ end
369
+ end
370
+ end
371
+
372
+ describe "calls preserving niceness:" do
373
+ it "A localized string literal is nice" do
374
+ original_code = cleanup(<<-EOT)
375
+ v = _("Hello")
376
+ Ops.add(v, "World")
377
+ EOT
378
+
379
+ translated_code = cleanup(<<-EOT)
380
+ v = _("Hello")
381
+ v + "World"
382
+ EOT
383
+
384
+ expect(ZombieKiller.new.kill(original_code)).to eq(translated_code)
385
+ end
386
+
387
+ describe "calls generating niceness:" do
388
+ end
389
+ end
390
+
391
+ describe "translation below top level:" do
392
+ it "translates a zombie nested in other calls" do
393
+ original_code = cleanup(<<-EOT)
394
+ v = 1
395
+ foo(bar(Ops.add(v, 1), baz))
396
+ EOT
397
+
398
+ translated_code = cleanup(<<-EOT)
399
+ v = 1
400
+ foo(bar(v + 1, baz))
401
+ EOT
402
+
403
+ expect(ZombieKiller.new.kill(original_code)).to eq(translated_code)
404
+ end
405
+ end
406
+
407
+ describe "chained translation:" do
408
+ it "translates a left-associative chain of nice zombies" do
409
+ original_code = cleanup(<<-EOT)
410
+ Ops.add(Ops.add(1, 2), 3)
411
+ EOT
412
+
413
+ translated_code = cleanup(<<-EOT)
414
+ (1 + 2) + 3
415
+ EOT
416
+
417
+ expect(ZombieKiller.new.kill(original_code)).to eq(translated_code)
418
+ end
419
+
420
+ it "translates a right-associative chain of nice zombies" do
421
+ original_code = cleanup(<<-EOT)
422
+ Ops.add(1, Ops.add(2, 3))
423
+ EOT
424
+
425
+ translated_code = cleanup(<<-EOT)
426
+ 1 + (2 + 3)
427
+ EOT
428
+
429
+ expect(ZombieKiller.new.kill(original_code)).to eq(translated_code)
430
+ end
431
+
432
+ describe "in case arguments are translated already:" do
433
+ it "translates `Ops.add` of plus and literal" do
434
+ original_code = cleanup(<<-EOT)
435
+ Ops.add("Hello" + " ", "World")
436
+ EOT
437
+
438
+ translated_code = cleanup(<<-EOT)
439
+ ("Hello" + " ") + "World"
440
+ EOT
441
+
442
+ expect(ZombieKiller.new.kill(original_code)).to eq(translated_code)
443
+ end
444
+
445
+ it "translates `Ops.add` of parenthesized plus and literal" do
446
+ original_code = cleanup(<<-EOT)
447
+ Ops.add(("Hello" + " "), "World")
448
+ EOT
449
+
450
+ translated_code = cleanup(<<-EOT)
451
+ ("Hello" + " ") + "World"
452
+ EOT
453
+
454
+ expect(ZombieKiller.new.kill(original_code)).to eq(translated_code)
455
+ end
456
+
457
+ it "translates `Ops.add` of literal and plus" do
458
+ original_code = cleanup(<<-EOT)
459
+ Ops.add("Hello", " " + "World")
460
+ EOT
461
+
462
+ translated_code = cleanup(<<-EOT)
463
+ "Hello" + (" " + "World")
464
+ EOT
465
+
466
+ expect(ZombieKiller.new.kill(original_code)).to eq(translated_code)
467
+ end
468
+ end
469
+ end
470
+
471
+ describe "if:" do
472
+ it "translates the `then` body of an `if` statement" do
473
+ original_code = cleanup(<<-EOT)
474
+ if cond
475
+ Ops.add(1, 1)
476
+ end
477
+ EOT
478
+
479
+ translated_code = cleanup(<<-EOT)
480
+ if cond
481
+ 1 + 1
482
+ end
483
+ EOT
484
+
485
+ expect(ZombieKiller.new.kill(original_code)).to eq(translated_code)
486
+ end
487
+
488
+ it "translates the `then` body of an `unless` statement" do
489
+ original_code = cleanup(<<-EOT)
490
+ unless cond
491
+ Ops.add(1, 1)
492
+ end
493
+ EOT
494
+
495
+ translated_code = cleanup(<<-EOT)
496
+ unless cond
497
+ 1 + 1
498
+ end
499
+ EOT
500
+
501
+ expect(ZombieKiller.new.kill(original_code)).to eq(translated_code)
502
+ end
503
+
504
+ it "It translates both branches of an `if` statement, independently of each other" do
505
+ original_code = cleanup(<<-EOT)
506
+ v = 1
507
+ if cond
508
+ Ops.add(v, 1)
509
+ v = nil
510
+ else
511
+ Ops.add(1, v)
512
+ v = nil
513
+ end
514
+ EOT
515
+
516
+ translated_code = cleanup(<<-EOT)
517
+ v = 1
518
+ if cond
519
+ v + 1
520
+ v = nil
521
+ else
522
+ 1 + v
523
+ v = nil
524
+ end
525
+ EOT
526
+
527
+ expect(ZombieKiller.new.kill(original_code)).to eq(translated_code)
528
+ end
529
+
530
+ it "The condition also contributes to the data state" do
531
+ original_code = cleanup(<<-EOT)
532
+ if cond(v = 1)
533
+ Ops.add(v, 1)
534
+ end
535
+ EOT
536
+
537
+ translated_code = cleanup(<<-EOT)
538
+ if cond(v = 1)
539
+ v + 1
540
+ end
541
+ EOT
542
+
543
+ expect(ZombieKiller.new.kill(original_code)).to eq(translated_code)
544
+ end
545
+
546
+ describe "a variable is not nice after its niceness was invalidated by an `if`:" do
547
+ it "Plain `if`" do
548
+ original_code = cleanup(<<-EOT)
549
+ v = 1
550
+ if cond
551
+ v = nil
552
+ end
553
+ Ops.add(v, 1)
554
+ EOT
555
+
556
+ translated_code = cleanup(<<-EOT)
557
+ v = 1
558
+ if cond
559
+ v = nil
560
+ end
561
+ Ops.add(v, 1)
562
+ EOT
563
+
564
+ expect(ZombieKiller.new.kill(original_code)).to eq(translated_code)
565
+ end
566
+
567
+ it "Trailing `if`" do
568
+ original_code = cleanup(<<-EOT)
569
+ v = 1
570
+ v = nil if cond
571
+ Ops.add(v, 1)
572
+ EOT
573
+
574
+ translated_code = cleanup(<<-EOT)
575
+ v = 1
576
+ v = nil if cond
577
+ Ops.add(v, 1)
578
+ EOT
579
+
580
+ expect(ZombieKiller.new.kill(original_code)).to eq(translated_code)
581
+ end
582
+
583
+ it "Plain `unless`" do
584
+ original_code = cleanup(<<-EOT)
585
+ v = 1
586
+ unless cond
587
+ v = nil
588
+ end
589
+ Ops.add(v, 1)
590
+ EOT
591
+
592
+ translated_code = cleanup(<<-EOT)
593
+ v = 1
594
+ unless cond
595
+ v = nil
596
+ end
597
+ Ops.add(v, 1)
598
+ EOT
599
+
600
+ expect(ZombieKiller.new.kill(original_code)).to eq(translated_code)
601
+ end
602
+
603
+ it "Trailing `unless`" do
604
+ original_code = cleanup(<<-EOT)
605
+ v = 1
606
+ v = nil unless cond
607
+ Ops.add(v, 1)
608
+ EOT
609
+
610
+ translated_code = cleanup(<<-EOT)
611
+ v = 1
612
+ v = nil unless cond
613
+ Ops.add(v, 1)
614
+ EOT
615
+
616
+ expect(ZombieKiller.new.kill(original_code)).to eq(translated_code)
617
+ end
618
+ end
619
+
620
+ describe "resuming with a clean slate after an `if`:" do
621
+ it "It translates zombies whose arguments were found nice after an `if`" do
622
+ original_code = cleanup(<<-EOT)
623
+ if cond
624
+ v = nil
625
+ end
626
+ v = 1
627
+ Ops.add(v, 1)
628
+ EOT
629
+
630
+ translated_code = cleanup(<<-EOT)
631
+ if cond
632
+ v = nil
633
+ end
634
+ v = 1
635
+ v + 1
636
+ EOT
637
+
638
+ expect(ZombieKiller.new.kill(original_code)).to eq(translated_code)
639
+ end
640
+ end
641
+ end
642
+
643
+ describe "case:" do
644
+ it "translates the `when` body of a `case` statement" do
645
+ original_code = cleanup(<<-EOT)
646
+ case expr
647
+ when 1
648
+ Ops.add(1, 1)
649
+ end
650
+ EOT
651
+
652
+ translated_code = cleanup(<<-EOT)
653
+ case expr
654
+ when 1
655
+ 1 + 1
656
+ end
657
+ EOT
658
+
659
+ expect(ZombieKiller.new.kill(original_code)).to eq(translated_code)
660
+ end
661
+
662
+ it "It translates all branches of a `case` statement, independently of each other" do
663
+ original_code = cleanup(<<-EOT)
664
+ v = 1
665
+ case expr
666
+ when 1
667
+ Ops.add(v, 1)
668
+ v = nil
669
+ when 2
670
+ Ops.add(v, 2)
671
+ v = nil
672
+ else
673
+ Ops.add(1, v)
674
+ v = nil
675
+ end
676
+ EOT
677
+
678
+ translated_code = cleanup(<<-EOT)
679
+ v = 1
680
+ case expr
681
+ when 1
682
+ v + 1
683
+ v = nil
684
+ when 2
685
+ v + 2
686
+ v = nil
687
+ else
688
+ 1 + v
689
+ v = nil
690
+ end
691
+ EOT
692
+
693
+ expect(ZombieKiller.new.kill(original_code)).to eq(translated_code)
694
+ end
695
+
696
+ it "The expression also contributes to the data state" do
697
+ original_code = cleanup(<<-EOT)
698
+ case v = 1
699
+ when 1
700
+ Ops.add(v, 1)
701
+ end
702
+ EOT
703
+
704
+ translated_code = cleanup(<<-EOT)
705
+ case v = 1
706
+ when 1
707
+ v + 1
708
+ end
709
+ EOT
710
+
711
+ expect(ZombieKiller.new.kill(original_code)).to eq(translated_code)
712
+ end
713
+
714
+ it "The test also contributes to the data state" do
715
+ original_code = cleanup(<<-EOT)
716
+ case expr
717
+ when v = 1
718
+ Ops.add(v, 1)
719
+ end
720
+ EOT
721
+
722
+ translated_code = cleanup(<<-EOT)
723
+ case expr
724
+ when v = 1
725
+ v + 1
726
+ end
727
+ EOT
728
+
729
+ expect(ZombieKiller.new.kill(original_code)).to eq(translated_code)
730
+ end
731
+
732
+ describe "a variable is not nice after its niceness was invalidated by a `case`:" do
733
+ it "The test also contributes to the data state" do
734
+ original_code = cleanup(<<-EOT)
735
+ v = 1
736
+ case expr
737
+ when 1
738
+ v = nil
739
+ end
740
+ Ops.add(v, 1)
741
+ EOT
742
+
743
+ translated_code = cleanup(<<-EOT)
744
+ v = 1
745
+ case expr
746
+ when 1
747
+ v = nil
748
+ end
749
+ Ops.add(v, 1)
750
+ EOT
751
+
752
+ expect(ZombieKiller.new.kill(original_code)).to eq(translated_code)
753
+ end
754
+ end
755
+
756
+ describe "resuming with a clean slate after a `case`:" do
757
+ it "It translates zombies whose arguments were found nice after a `case`" do
758
+ original_code = cleanup(<<-EOT)
759
+ case expr
760
+ when 1
761
+ v = nil
762
+ end
763
+ v = 1
764
+ Ops.add(v, 1)
765
+ EOT
766
+
767
+ translated_code = cleanup(<<-EOT)
768
+ case expr
769
+ when 1
770
+ v = nil
771
+ end
772
+ v = 1
773
+ v + 1
774
+ EOT
775
+
776
+ expect(ZombieKiller.new.kill(original_code)).to eq(translated_code)
777
+ end
778
+ end
779
+ end
780
+
781
+ describe "loops:" do
782
+ describe "while and until:" do
783
+ it "does not translate anything in the outer scope that contains a `while`" do
784
+ original_code = cleanup(<<-EOT)
785
+ v = 1
786
+ while Ops.add(v, 1)
787
+ Ops.add(1, 1)
788
+ end
789
+ Ops.add(v, 1)
790
+ EOT
791
+
792
+ translated_code = cleanup(<<-EOT)
793
+ v = 1
794
+ while Ops.add(v, 1)
795
+ Ops.add(1, 1)
796
+ end
797
+ Ops.add(v, 1)
798
+ EOT
799
+
800
+ expect(ZombieKiller.new.kill(original_code)).to eq(translated_code)
801
+ end
802
+
803
+ it "does not translate anything in the outer scope that contains an `until`" do
804
+ original_code = cleanup(<<-EOT)
805
+ v = 1
806
+ until Ops.add(v, 1)
807
+ Ops.add(1, 1)
808
+ end
809
+ Ops.add(v, 1)
810
+ EOT
811
+
812
+ translated_code = cleanup(<<-EOT)
813
+ v = 1
814
+ until Ops.add(v, 1)
815
+ Ops.add(1, 1)
816
+ end
817
+ Ops.add(v, 1)
818
+ EOT
819
+
820
+ expect(ZombieKiller.new.kill(original_code)).to eq(translated_code)
821
+ end
822
+
823
+ it "can continue processing after a `while`" do
824
+ original_code = cleanup(<<-EOT)
825
+ while cond
826
+ foo
827
+ end
828
+ v = 1
829
+ Ops.add(v, 1)
830
+ EOT
831
+
832
+ translated_code = cleanup(<<-EOT)
833
+ while cond
834
+ foo
835
+ end
836
+ v = 1
837
+ v + 1
838
+ EOT
839
+
840
+ expect(ZombieKiller.new.kill(original_code)).to eq(translated_code)
841
+ end
842
+
843
+ it "can continue processing after an `until`" do
844
+ original_code = cleanup(<<-EOT)
845
+ until cond
846
+ foo
847
+ end
848
+ v = 1
849
+ Ops.add(v, 1)
850
+ EOT
851
+
852
+ translated_code = cleanup(<<-EOT)
853
+ until cond
854
+ foo
855
+ end
856
+ v = 1
857
+ v + 1
858
+ EOT
859
+
860
+ expect(ZombieKiller.new.kill(original_code)).to eq(translated_code)
861
+ end
862
+
863
+ it "can parse both the syntactic and semantic post-condition" do
864
+ original_code = cleanup(<<-EOT)
865
+ body_runs_after_condition while cond
866
+ body_runs_after_condition until cond
867
+
868
+ begin
869
+ body_runs_before_condition
870
+ end while cond
871
+
872
+ begin
873
+ body_runs_before_condition
874
+ end until cond
875
+ EOT
876
+
877
+ translated_code = cleanup(<<-EOT)
878
+ body_runs_after_condition while cond
879
+ body_runs_after_condition until cond
880
+
881
+ begin
882
+ body_runs_before_condition
883
+ end while cond
884
+
885
+ begin
886
+ body_runs_before_condition
887
+ end until cond
888
+ EOT
889
+
890
+ expect(ZombieKiller.new.kill(original_code)).to eq(translated_code)
891
+ end
892
+ end
893
+
894
+ describe "for:" do
895
+ it "does not translate inside a `for` and resumes with a clean slate" do
896
+ original_code = cleanup(<<-EOT)
897
+ v = 1
898
+ v = Ops.add(v, 1)
899
+
900
+ for i in [1, 2, 3]
901
+ v = Ops.add(v, 1)
902
+ v = uglify
903
+ end
904
+
905
+ v = Ops.add(v, 1)
906
+ w = 1
907
+ w = Ops.add(w, 1)
908
+ EOT
909
+
910
+ translated_code = cleanup(<<-EOT)
911
+ v = 1
912
+ v = v + 1
913
+
914
+ for i in [1, 2, 3]
915
+ v = Ops.add(v, 1)
916
+ v = uglify
917
+ end
918
+
919
+ v = Ops.add(v, 1)
920
+ w = 1
921
+ w = w + 1
922
+ EOT
923
+
924
+ expect(ZombieKiller.new.kill(original_code)).to eq(translated_code)
925
+ end
926
+ end
927
+ end
928
+
929
+ describe "exceptions:" do
930
+ it "translates the parts, joining else, rescue separately" do
931
+ original_code = cleanup(<<-EOT)
932
+ def foo
933
+ v = 1
934
+ Ops.add(v, 1)
935
+ rescue
936
+ w = 1
937
+ Ops.add(w, 1)
938
+ v = nil
939
+ rescue
940
+ Ops.add(w, 1)
941
+ else
942
+ Ops.add(v, 1)
943
+ end
944
+ EOT
945
+
946
+ translated_code = cleanup(<<-EOT)
947
+ def foo
948
+ v = 1
949
+ v + 1
950
+ rescue
951
+ w = 1
952
+ w + 1
953
+ v = nil
954
+ rescue
955
+ Ops.add(w, 1)
956
+ else
957
+ v + 1
958
+ end
959
+ EOT
960
+
961
+ expect(ZombieKiller.new.kill(original_code)).to eq(translated_code)
962
+ end
963
+
964
+ describe "skipping code:" do
965
+ it "does not translate code that depends on niceness skipped via an exception" do
966
+ original_code = cleanup(<<-EOT)
967
+ def a_problem
968
+ v = nil
969
+ w = 1 / 0
970
+ v = 1
971
+ rescue
972
+ puts "Oops", Ops.add(v, 1)
973
+ end
974
+ EOT
975
+
976
+ translated_code = cleanup(<<-EOT)
977
+ def a_problem
978
+ v = nil
979
+ w = 1 / 0
980
+ v = 1
981
+ rescue
982
+ puts "Oops", Ops.add(v, 1)
983
+ end
984
+ EOT
985
+
986
+ expect(ZombieKiller.new.kill(original_code)).to eq(translated_code)
987
+ end
988
+ end
989
+
990
+ describe "exception syntax:" do
991
+ it "can parse the syntactic variants of exception handling" do
992
+ original_code = cleanup(<<-EOT)
993
+ begin
994
+ foo
995
+ raise "LOL"
996
+ foo
997
+ rescue Error
998
+ foo
999
+ rescue Bug, Blunder => b
1000
+ foo
1001
+ rescue => e
1002
+ foo
1003
+ rescue
1004
+ foo
1005
+ ensure
1006
+ foo
1007
+ end
1008
+ yast rescue nil
1009
+ EOT
1010
+
1011
+ translated_code = cleanup(<<-EOT)
1012
+ begin
1013
+ foo
1014
+ raise "LOL"
1015
+ foo
1016
+ rescue Error
1017
+ foo
1018
+ rescue Bug, Blunder => b
1019
+ foo
1020
+ rescue => e
1021
+ foo
1022
+ rescue
1023
+ foo
1024
+ ensure
1025
+ foo
1026
+ end
1027
+ yast rescue nil
1028
+ EOT
1029
+
1030
+ expect(ZombieKiller.new.kill(original_code)).to eq(translated_code)
1031
+ end
1032
+ end
1033
+
1034
+ describe "retry:" do
1035
+ it "does not translate a begin-body when a rescue contains a retry" do
1036
+ original_code = cleanup(<<-EOT)
1037
+ def foo
1038
+ v = 1
1039
+ begin
1040
+ Ops.add(v, 1)
1041
+ maybe_raise
1042
+ rescue
1043
+ v = nil
1044
+ retry
1045
+ end
1046
+ end
1047
+ EOT
1048
+
1049
+ translated_code = cleanup(<<-EOT)
1050
+ def foo
1051
+ v = 1
1052
+ begin
1053
+ Ops.add(v, 1)
1054
+ maybe_raise
1055
+ rescue
1056
+ v = nil
1057
+ retry
1058
+ end
1059
+ end
1060
+ EOT
1061
+
1062
+ expect(ZombieKiller.new.kill(original_code)).to eq(translated_code)
1063
+ end
1064
+ end
1065
+ end
1066
+
1067
+ describe "blocks:" do
1068
+ it "does not translate inside a block and resumes with a clean slate" do
1069
+ original_code = cleanup(<<-EOT)
1070
+ v = 1
1071
+ v = Ops.add(v, 1)
1072
+
1073
+ 2.times do
1074
+ v = Ops.add(v, 1)
1075
+ v = uglify
1076
+ end
1077
+
1078
+ v = Ops.add(v, 1)
1079
+ w = 1
1080
+ w = Ops.add(w, 1)
1081
+ EOT
1082
+
1083
+ translated_code = cleanup(<<-EOT)
1084
+ v = 1
1085
+ v = v + 1
1086
+
1087
+ 2.times do
1088
+ v = Ops.add(v, 1)
1089
+ v = uglify
1090
+ end
1091
+
1092
+ v = Ops.add(v, 1)
1093
+ w = 1
1094
+ w = w + 1
1095
+ EOT
1096
+
1097
+ expect(ZombieKiller.new.kill(original_code)).to eq(translated_code)
1098
+ end
1099
+ end
1100
+
1101
+ describe "formatting:" do
1102
+ it "does not translate `Ops.add` if any argument has a comment" do
1103
+ original_code = cleanup(<<-EOT)
1104
+ Ops.add(
1105
+ "Hello",
1106
+ # foo
1107
+ "World"
1108
+ )
1109
+ EOT
1110
+
1111
+ translated_code = cleanup(<<-EOT)
1112
+ Ops.add(
1113
+ "Hello",
1114
+ # foo
1115
+ "World"
1116
+ )
1117
+ EOT
1118
+
1119
+ expect(ZombieKiller.new.kill(original_code)).to eq(translated_code)
1120
+ end
1121
+ end
1122
+
1123
+ describe "templates:" do
1124
+ it "It translates" do
1125
+ original_code = cleanup(<<-EOT)
1126
+
1127
+ EOT
1128
+
1129
+ translated_code = cleanup(<<-EOT)
1130
+
1131
+ EOT
1132
+
1133
+ expect(ZombieKiller.new.kill(original_code)).to eq(translated_code)
1134
+ end
1135
+
1136
+ it "It does not translate" do
1137
+ original_code = cleanup(<<-EOT)
1138
+
1139
+ EOT
1140
+
1141
+ translated_code = cleanup(<<-EOT)
1142
+
1143
+ EOT
1144
+
1145
+ expect(ZombieKiller.new.kill(original_code)).to eq(translated_code)
1146
+ end
1147
+ end
1148
+ end