This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
Make cproto.t more stringent
[perl5.git] / t / x2p / s2p.t
1 #!./perl
2
3 =head1 NAME
4
5 s2p.t - test suite for s2p/psed
6
7 =head1 NOTES
8
9 The general idea is to
10
11   (a) run psed with a sed script and input data to obtain some output
12   (b) run s2p with a sed script creating a Perl program and then run the
13       Perl program with the input data, again producing output
14
15 Both final outputs should be identical to the expected output.
16
17 A $testcase{<name>} contains entries (after the comment ### <name> ###):
18
19   - script: the sed script
20   - input:  the key of the input data, stored in $input{<input>}
21   - expect: the expected output
22   - datfil: an additional file [ <path>, <data> ] (if required)
23
24 Temporary files are created in the working directory (embedding $$
25 in the name), and removed after the test.
26
27 Except for bin2dec (which indeed converts binary to decimal) none of the
28 sed scripts is doing something useful.
29
30 Author: Wolfgang Laun.
31
32 =cut
33
34 BEGIN {
35     chdir 't' if -d 't';
36     @INC = ( '../lib' );
37 }
38
39 use File::Copy;
40 use File::Spec;
41 require './test.pl';
42
43 # BRE extensions
44 $ENV{PSEDEXTBRE} = '<>wW';
45
46 our %input = (
47    bins => <<'[TheEnd]',
48 0
49 111
50 1000
51 10001
52 [TheEnd]
53
54    text => <<'[TheEnd]',
55 line 1
56 line 2
57 line 3
58 line 4
59 line 5
60 line 6
61 line 7
62 line 8
63 [TheEnd]
64
65    adr1 => <<'[TheEnd]',
66 #no autoprint
67 # This script should be run on itself
68 /^#__DATA__$/,${
69    /^#A$/p
70    s/^# *[0-9]* *//
71    /^#\*$/p
72    /^#\.$/p
73    /^#\(..\)\(..\)\2\1*$/p
74    /^#[abc]\{1,\}[def]\{1,\}$/p
75 }
76 #__DATA__
77 #A
78 #*
79 #.
80 #abxyxy
81 #abxyxyab
82 #abxyxyabab
83 #ad
84 #abcdef
85 [TheEnd]
86 );
87
88
89 our %testcase = (
90
91 ### bin2dec ###
92 'bin2dec' => {
93   script => <<'[TheEnd]',
94 # binary -> decimal
95 s/^[    ]*\([01]\{1,\}\)[       ]*/\1/
96 t go
97 i\
98 is not a binary number
99 d
100
101 # expand binary to Xs
102 : go
103 s/^0*//
104 s/^1/X/
105 : expand
106 s/^\(X\{1,\}\)0/\1\1/
107 s/^\(X\{1,\}\)1/\1\1X/
108 t expand
109
110 # count Xs in decimal
111 : count
112 s/^X/1/
113 s/0X/1/
114 s/1X/2/
115 s/2X/3/
116 s/3X/4/
117 s/4X/5/
118 s/5X/6/
119 s/6X/7/
120 s/7X/8/
121 s/8X/9/
122 s/9X/X0/
123 t count
124 s/^$/0/
125 [TheEnd]
126   input  => 'bins',
127   expect => <<'[TheEnd]',
128 0
129 7
130 8
131 17
132 [TheEnd]
133 },
134
135
136 ### = ###
137 '=' => {
138   script => <<'[TheEnd]',
139 1=
140 $=
141 [TheEnd]
142   input  => 'text',
143   expect => <<'[TheEnd]',
144 1
145 line 1
146 line 2
147 line 3
148 line 4
149 line 5
150 line 6
151 line 7
152 8
153 line 8
154 [TheEnd]
155 },
156
157 ### D ###
158 'D' => {
159   script => <<'[TheEnd]',
160 #no autoprint
161 /1/{
162 N
163 N
164 N
165 D
166 }
167 p
168 /2/D
169 =
170 p
171 [TheEnd]
172   input  => 'text',
173   expect => <<'[TheEnd]',
174 line 2
175 line 3
176 line 4
177 line 3
178 line 4
179 4
180 line 3
181 line 4
182 line 5
183 5
184 line 5
185 line 6
186 6
187 line 6
188 line 7
189 7
190 line 7
191 line 8
192 8
193 line 8
194 [TheEnd]
195 },
196
197 ### H ###
198 'H' => {
199   script => <<'[TheEnd]',
200 #no autoprint
201 1,$H
202 $g
203 $=
204 $p
205 [TheEnd]
206   input  => 'text',
207   expect => <<'[TheEnd]',
208 8
209
210 line 1
211 line 2
212 line 3
213 line 4
214 line 5
215 line 6
216 line 7
217 line 8
218 [TheEnd]
219 },
220
221 ### N ###
222 'N' => {
223   script => <<'[TheEnd]',
224 3a\
225 added line
226 4a\
227 added line
228 5a\
229 added line
230 3,5N
231 =
232 d
233 [TheEnd]
234   input  => 'text',
235   expect => <<'[TheEnd]',
236 1
237 2
238 added line
239 4
240 added line
241 6
242 7
243 8
244 [TheEnd]
245 },
246
247 ### P ###
248 'P' => {
249   script => <<'[TheEnd]',
250 1N
251 2N
252 3N
253 4=
254 4P
255 4,$d
256 [TheEnd]
257   input  => 'text',
258   expect => <<'[TheEnd]',
259 4
260 line 1
261 [TheEnd]
262 },
263
264 ### a ###
265 'a' => {
266   script => <<'[TheEnd]',
267 1a\
268 added line 1.1\
269 added line 1.2
270
271 3a\
272 added line 3.1
273 3a\
274 added line 3.2
275
276 [TheEnd]
277   input  => 'text',
278   expect => <<'[TheEnd]',
279 line 1
280 added line 1.1
281 added line 1.2
282 line 2
283 line 3
284 added line 3.1
285 added line 3.2
286 line 4
287 line 5
288 line 6
289 line 7
290 line 8
291 [TheEnd]
292 },
293
294 ### b ###
295 'b' => {
296   script => <<'[TheEnd]',
297 #no autoprint
298 2 b eos
299 4 b eos
300 p
301 : eos
302 [TheEnd]
303   input  => 'text',
304   expect => <<'[TheEnd]',
305 line 1
306 line 3
307 line 5
308 line 6
309 line 7
310 line 8
311 [TheEnd]
312 },
313
314 ### block ###
315 'block' => {
316   script => "#no autoprint\n1,3{\n=\np\n}",
317   input  => 'text',
318   expect => <<'[TheEnd]',
319 1
320 line 1
321 2
322 line 2
323 3
324 line 3
325 [TheEnd]
326 },
327
328 ### c ###
329 'c' => {
330   script => <<'[TheEnd]',
331 2=
332
333 2,4c\
334 change 2,4 line 1\
335 change 2,4 line 2
336
337 2=
338
339 3,5c\
340 change 3,5 line 1\
341 change 3,5 line 2
342
343 3=
344
345 [TheEnd]
346   input  => 'text',
347   expect => <<'[TheEnd]',
348 line 1
349 2
350 change 2,4 line 1
351 change 2,4 line 2
352 line 5
353 line 6
354 line 7
355 line 8
356 [TheEnd]
357 },
358
359 ### c1 ###
360 'c1' => {
361   script => <<'[TheEnd]',
362 1c\
363 replaces line 1
364
365 2,3c\
366 replaces lines 2-3
367
368 /5/,/6/c\
369 replaces lines 3-4
370
371 8,10c\
372 replaces lines 6-10
373 [TheEnd]
374   input  => 'text',
375   expect => <<'[TheEnd]',
376 replaces line 1
377 replaces lines 2-3
378 line 4
379 replaces lines 3-4
380 line 7
381 [TheEnd]
382 },
383
384 ### c2 ###
385 'c2' => {
386   script => <<'[TheEnd]',
387 3!c\
388 replace all except line 3
389
390 [TheEnd]
391   input  => 'text',
392   expect => <<'[TheEnd]',
393 replace all except line 3
394 replace all except line 3
395 line 3
396 replace all except line 3
397 replace all except line 3
398 replace all except line 3
399 replace all except line 3
400 replace all except line 3
401 [TheEnd]
402 },
403
404 ### c3 ###
405 'c3' => {
406   script => <<'[TheEnd]',
407 1,4!c\
408 replace all except 1-4
409
410 /5/,/8/!c\
411 replace all except 5-8
412 [TheEnd]
413   input  => 'text',
414   expect => <<'[TheEnd]',
415 replace all except 5-8
416 replace all except 5-8
417 replace all except 5-8
418 replace all except 5-8
419 replace all except 1-4
420 replace all except 1-4
421 replace all except 1-4
422 replace all except 1-4
423 [TheEnd]
424 },
425
426 ### d ###
427 'd' => {
428   script => <<'[TheEnd]',
429 # d delete pattern space, start next cycle
430 2,4 d
431 5 d
432 [TheEnd]
433   input  => 'text',
434   expect => <<'[TheEnd]',
435 line 1
436 line 6
437 line 7
438 line 8
439 [TheEnd]
440 },
441
442 ### gh ###
443 'gh' => {
444   script => <<'[TheEnd]',
445 1h
446 2g
447 3h
448 4g
449 5q
450 [TheEnd]
451   input  => 'text',
452   expect => <<'[TheEnd]',
453 line 1
454 line 1
455 line 3
456 line 3
457 line 5
458 [TheEnd]
459 },
460
461 ### i ###
462 'i' => {
463   script => <<'[TheEnd]',
464 1i\
465 inserted line 1.1\
466 inserted line 1.2
467
468 3i\
469 inserted line 3.1
470 3i\
471 inserted line 3.2
472 [TheEnd]
473   input  => 'text',
474   expect => <<'[TheEnd]',
475 inserted line 1.1
476 inserted line 1.2
477 line 1
478 line 2
479 inserted line 3.1
480 inserted line 3.2
481 line 3
482 line 4
483 line 5
484 line 6
485 line 7
486 line 8
487 [TheEnd]
488 },
489
490 ### n ###
491 'n' => {
492   script => <<'[TheEnd]',
493 3a\
494 added line
495 4a\
496 added line
497 5a\
498 added line
499 3,5n
500 =
501 d
502 [TheEnd]
503   input  => 'text',
504   expect => <<'[TheEnd]',
505 1
506 2
507 line 3
508 added line
509 4
510 line 5
511 added line
512 6
513 7
514 8
515 [TheEnd]
516 },
517
518 ### o ###
519 'o' => {
520   script => <<'[TheEnd]',
521 /abc/,/def/ s//XXX/
522 // i\
523 cheers
524 [TheEnd]
525   input  => 'text',
526   expect => <<'[TheEnd]',
527 line 1
528 line 2
529 line 3
530 line 4
531 line 5
532 line 6
533 line 7
534 line 8
535 [TheEnd]
536 },
537
538 ### q ###
539 'q' => {
540   script => <<'[TheEnd]',
541 2a\
542 append to line 2
543 3a\
544 append to line 3 - should not appear in output
545 3q
546 [TheEnd]
547   input  => 'text',
548   expect => <<'[TheEnd]',
549 line 1
550 line 2
551 append to line 2
552 line 3
553 [TheEnd]
554 },
555
556 ### r ###
557 'r' => {
558   datfil => [ 'r.txt', "r.txt line 1\nr.txt line 2\nr.txt line 3\n" ],
559   script => <<'[TheEnd]',
560 2r%r.txt%
561 4r %r.txt%
562 [TheEnd]
563   input  => 'text',
564   expect => <<'[TheEnd]',
565 line 1
566 line 2
567 r.txt line 1
568 r.txt line 2
569 r.txt line 3
570 line 3
571 line 4
572 r.txt line 1
573 r.txt line 2
574 r.txt line 3
575 line 5
576 line 6
577 line 7
578 line 8
579 [TheEnd]
580 },
581
582 ### s ###
583 's' => {
584   script => <<'[TheEnd]',
585 # enclose any '(a)'.. '(c)' in '-'
586 s/([a-z])/-\1-/g
587
588 s/\([abc]\)/-\1-/g
589 [TheEnd]
590   input  => 'text',
591   expect => <<'[TheEnd]',
592 line 1
593 line 2
594 line 3
595 line 4
596 line 5
597 line 6
598 line 7
599 line 8
600 [TheEnd]
601 },
602
603 ### s1 ###
604 's1' => {
605   script => <<'[TheEnd]',
606 s/\w/@1/
607 s/\y/@2/
608
609 s/\n/@3/
610
611 # this is literal { }
612 s/a{3}/@4/
613
614 # proper repetition
615 s/a\{3\}/a rep 3/
616 [TheEnd]
617   input  => 'text',
618   expect => <<'[TheEnd]',
619 @1ine 1
620 @1ine 2
621 @1ine 3
622 @1ine 4
623 @1ine 5
624 @1ine 6
625 @1ine 7
626 @1ine 8
627 [TheEnd]
628 },
629
630 ### t ###
631 't' => {
632   script => join( "\n",
633    '#no autoprint', 's/./X/p', 's/foo/bar/p', 't bye', '=', 'p', ':bye' ),
634   input  => 'text',
635   expect => <<'[TheEnd]',
636 Xine 1
637 Xine 2
638 Xine 3
639 Xine 4
640 Xine 5
641 Xine 6
642 Xine 7
643 Xine 8
644 [TheEnd]
645 },
646
647 ### w ###
648 'w' => {
649   datfil => [ 'w.txt', '' ],
650   script => <<'[TheEnd]',
651 w %w.txt%
652 [TheEnd]
653   input  => 'text',
654   expect => <<'[TheEnd]',
655 line 1
656 line 2
657 line 3
658 line 4
659 line 5
660 line 6
661 line 7
662 line 8
663 [TheEnd]
664 },
665
666 ### x ###
667 'x' => {
668   script => <<'[TheEnd]',
669 1h
670 1d
671 2x
672 2,$G
673 [TheEnd]
674   input  => 'text',
675   expect => <<'[TheEnd]',
676 line 1
677 line 2
678 line 3
679 line 2
680 line 4
681 line 2
682 line 5
683 line 2
684 line 6
685 line 2
686 line 7
687 line 2
688 line 8
689 line 2
690 [TheEnd]
691 },
692
693 ### y ###
694 'y' => {
695   script => <<'[TheEnd]',
696 y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/
697 y/|/\
698
699 [TheEnd]
700   input  => 'text',
701   expect => <<'[TheEnd]',
702 LINE 1
703 LINE 2
704 LINE 3
705 LINE 4
706 LINE 5
707 LINE 6
708 LINE 7
709 LINE 8
710 [TheEnd]
711 },
712
713 ### cnt ###
714 'cnt' => {
715   script => <<'[TheEnd]',
716 #no autoprint
717
718 # delete line, append NL to hold space
719 s/.*//
720 H
721 $!b
722
723 # last line only: get hold
724 g
725 s/./X/g
726 t count
727 : count
728 s/^X/1/
729 s/0X/1/
730 s/1X/2/
731 s/2X/3/
732 s/3X/4/
733 s/4X/5/
734 s/5X/6/
735 s/6X/7/
736 s/7X/8/
737 s/8X/9/
738 s/9X/X0/
739 t count
740 p
741 [TheEnd]
742   input  => 'text',
743   expect => <<'[TheEnd]',
744 8
745 [TheEnd]
746 },
747
748 ### adr1 ###
749 'adr1' => {
750   script => <<'[TheEnd]',
751 #no autoprint
752 # This script should be run on itself
753 /^#__DATA__$/,${
754    /^#A$/p
755    s/^# *[0-9]* *//
756    /^#\*$/p
757    /^#\.$/p
758    /^#\(..\)\(..\)\2\1*$/p
759    /^#[abc]\{1,\}[def]\{1,\}$/p
760 }
761 #__DATA__
762 #A
763 #*
764 #.
765 #abxyxy
766 #abxyxyab
767 #abxyxyabab
768 #ad
769 #abcdef
770 [TheEnd]
771   input  => 'adr1',
772   expect => <<'[TheEnd]',
773 #A
774 [TheEnd]
775 },
776
777 );
778
779 my @aux = ();
780 my $ntc = 2 * keys %testcase;
781 plan( $ntc );
782
783 # temporary file names
784 my $script = "s2pt$$.sed";
785 my $stdin  = "s2pt$$.in";
786 my $plsed  = "s2pt$$.pl";
787
788 # various command lines for 
789 my $s2p  = File::Spec->catfile( File::Spec->updir(), 'x2p', 's2p' );
790 my $psed = File::Spec->catfile( File::Spec->curdir(), 'psed' );
791 if ($^O eq 'VMS') {
792   # default in the .com extension if it's not already there
793   $s2p = VMS::Filespec::vmsify($s2p);
794   $psed = VMS::Filespec::vmsify($psed);
795   # Converting file specs from Unix format to VMS with the extended
796   # character set active can result in a trailing '.' added for null
797   # extensions.  This must be removed if the intent is to default the
798   # extension.
799   $s2p =~ s/\.$//;
800   $psed =~ s/\.$//;
801   $s2p = VMS::Filespec::rmsexpand($s2p, '.com');
802   $psed = VMS::Filespec::rmsexpand($psed, '.com');
803 }
804 my $sedcmd = [ $psed, '-f', $script, $stdin ];
805 my $s2pcmd = [ $s2p,  '-f', $script ];
806 my $plcmd  = [ $plsed, $stdin ];
807
808 # psed: we create a local copy as linking may not work on some systems.
809 copy( $s2p, $psed );
810 push( @aux, $psed );
811
812 # process all testcases
813 #
814 my $indat = '';
815 for my $tc ( sort keys %testcase ){
816     my( $psedres, $s2pres );
817
818     # 1st test: run psed
819     # prepare the script 
820     open( SED, ">$script" ) || goto FAIL_BOTH;
821     my $script = $testcase{$tc}{script};
822
823     # additional files for r, w: patch script, inserting temporary names
824     if( exists( $testcase{$tc}{datfil} ) ){
825         my( $datnam, $datdat ) = @{$testcase{$tc}{datfil}};
826         my $datfil = "s2pt$$" . $datnam;
827         push( @aux, $datfil );
828         open( DAT, ">$datfil" ) || goto FAIL_BOTH;
829         print DAT $datdat;
830         close( DAT );
831         $script =~ s/\%$datnam\%/$datfil/eg;
832     }
833     print SED $script;
834     close( SED ) || goto FAIL_BOTH;
835
836     # prepare input
837     #
838     if( $indat ne $testcase{$tc}{input} ){
839         $indat = $testcase{$tc}{input};
840         open( IN, ">$stdin" ) || goto FAIL_BOTH;
841         print IN $input{$indat};
842         close( IN ) || goto FAIL_BOTH;
843     }
844
845     # on VMS, runperl eats blank lines to work around 
846     # spurious newlines in pipes
847     $testcase{$tc}{expect} =~ s/\n\n/\n/ if $^O eq 'VMS';
848
849     # run and compare
850     #
851     $psedres = runperl( args => $sedcmd );
852     is( $psedres, $testcase{$tc}{expect}, "psed $tc" );
853
854     # 2nd test: run s2p
855     # translate the sed script to a Perl program
856
857     my $perlprog = runperl( args => $s2pcmd );
858     open( PP, ">$plsed" ) || goto FAIL_S2P;
859     print PP $perlprog;
860     close( PP ) || goto FAIL_S2P;
861
862     # execute generated Perl program, compare
863     $s2pres = runperl( args => $plcmd );
864     is( $s2pres, $testcase{$tc}{expect}, "s2p $tc" );
865     next;
866
867 FAIL_BOTH:
868     fail( "psed $tc" );
869 FAIL_S2P:
870     fail( "s2p $tc" );
871 }
872
873 END {
874     for my $f ( $script, $stdin, $plsed, @aux ){
875         1 while unlink( $f ); # hats off to VMS...
876     }
877 }