zombie-killer 0.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -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