#!./perl
=head1 NAME
s2p.t - test suite for s2p/psed
=head1 NOTES
The general idea is to
(a) run psed with a sed script and input data to obtain some output
(b) run s2p with a sed script creating a Perl program and then run the
Perl program with the input data, again producing output
Both final outputs should be identical to the expected output.
A $testcase{<name>} contains entries (after the comment ### <name> ###):
- script: the sed script
- input: the key of the input data, stored in $input{<input>}
- expect: the expected output
- datfil: an additional file [ <path>, <data> ] (if required)
Temporary files are created in the working directory (embedding $$
in the name), and removed after the test.
Except for bin2dec (which indeed converts binary to decimal) none of the
sed scripts is doing something useful.
Author: Wolfgang Laun.
=cut
BEGIN {
chdir 't' if -d 't';
@INC = ( '../lib' );
}
### use Test::More;
use File::Copy;
use File::Spec;
require './test.pl';
# BRE extensions
$ENV{PSEDEXTBRE} = '<>wW';
our %input = (
bins => <<'[TheEnd]',
0
111
1000
10001
[TheEnd]
text => <<'[TheEnd]',
line 1
line 2
line 3
line 4
line 5
line 6
line 7
line 8
[TheEnd]
adr1 => <<'[TheEnd]',
#no autoprint
# This script should be run on itself
/^#__DATA__$/,${
/^#A$/p
s/^# *[0-9]* *//
/^#\*$/p
/^#\.$/p
/^#\(..\)\(..\)\2\1*$/p
/^#[abc]\{1,\}[def]\{1,\}$/p
}
#__DATA__
#A
#*
#.
#abxyxy
#abxyxyab
#abxyxyabab
#ad
#abcdef
[TheEnd]
);
our %testcase = (
### bin2dec ###
'bin2dec' => {
script => <<'[TheEnd]',
# binary -> decimal
s/^[ ]*\([01]\{1,\}\)[ ]*/\1/
t go
i\
is not a binary number
d
# expand binary to Xs
: go
s/^0*//
s/^1/X/
: expand
s/^\(X\{1,\}\)0/\1\1/
s/^\(X\{1,\}\)1/\1\1X/
t expand
# count Xs in decimal
: count
s/^X/1/
s/0X/1/
s/1X/2/
s/2X/3/
s/3X/4/
s/4X/5/
s/5X/6/
s/6X/7/
s/7X/8/
s/8X/9/
s/9X/X0/
t count
s/^$/0/
[TheEnd]
input => 'bins',
expect => <<'[TheEnd]',
0
7
8
17
[TheEnd]
},
### = ###
'=' => {
script => <<'[TheEnd]',
1=
$=
[TheEnd]
input => 'text',
expect => <<'[TheEnd]',
1
line 1
line 2
line 3
line 4
line 5
line 6
line 7
8
line 8
[TheEnd]
},
### D ###
'D' => {
script => <<'[TheEnd]',
#no autoprint
/1/{
N
N
N
D
}
p
/2/D
=
p
[TheEnd]
input => 'text',
expect => <<'[TheEnd]',
line 2
line 3
line 4
line 3
line 4
4
line 3
line 4
line 5
5
line 5
line 6
6
line 6
line 7
7
line 7
line 8
8
line 8
[TheEnd]
},
### H ###
'H' => {
script => <<'[TheEnd]',
#no autoprint
1,$H
$g
$=
$p
[TheEnd]
input => 'text',
expect => <<'[TheEnd]',
8
line 1
line 2
line 3
line 4
line 5
line 6
line 7
line 8
[TheEnd]
},
### N ###
'N' => {
script => <<'[TheEnd]',
3a\
added line
4a\
added line
5a\
added line
3,5N
=
d
[TheEnd]
input => 'text',
expect => <<'[TheEnd]',
1
2
added line
4
added line
6
7
8
[TheEnd]
},
### P ###
'P' => {
script => <<'[TheEnd]',
1N
2N
3N
4=
4P
4,$d
[TheEnd]
input => 'text',
expect => <<'[TheEnd]',
4
line 1
[TheEnd]
},
### a ###
'a' => {
script => <<'[TheEnd]',
1a\
added line 1.1\
added line 1.2
3a\
added line 3.1
3a\
added line 3.2
[TheEnd]
input => 'text',
expect => <<'[TheEnd]',
line 1
added line 1.1
added line 1.2
line 2
line 3
added line 3.1
added line 3.2
line 4
line 5
line 6
line 7
line 8
[TheEnd]
},
### b ###
'b' => {
script => <<'[TheEnd]',
#no autoprint
2 b eos
4 b eos
p
: eos
[TheEnd]
input => 'text',
expect => <<'[TheEnd]',
line 1
line 3
line 5
line 6
line 7
line 8
[TheEnd]
},
### block ###
'block' => {
script => "#no autoprint\n1,3{\n=\np\n}",
input => 'text',
expect => <<'[TheEnd]',
1
line 1
2
line 2
3
line 3
[TheEnd]
},
### c ###
'c' => {
script => <<'[TheEnd]',
2=
2,4c\
change 2,4 line 1\
change 2,4 line 2
2=
3,5c\
change 3,5 line 1\
change 3,5 line 2
3=
[TheEnd]
input => 'text',
expect => <<'[TheEnd]',
line 1
2
change 2,4 line 1
change 2,4 line 2
line 5
line 6
line 7
line 8
[TheEnd]
},
### c1 ###
'c1' => {
script => <<'[TheEnd]',
1c\
replaces line 1
2,3c\
replaces lines 2-3
/5/,/6/c\
replaces lines 3-4
8,10c\
replaces lines 6-10
[TheEnd]
input => 'text',
expect => <<'[TheEnd]',
replaces line 1
replaces lines 2-3
line 4
replaces lines 3-4
line 7
[TheEnd]
},
### c2 ###
'c2' => {
script => <<'[TheEnd]',
3!c\
replace all except line 3
[TheEnd]
input => 'text',
expect => <<'[TheEnd]',
replace all except line 3
replace all except line 3
line 3
replace all except line 3
replace all except line 3
replace all except line 3
replace all except line 3
replace all except line 3
[TheEnd]
},
### c3 ###
'c3' => {
script => <<'[TheEnd]',
1,4!c\
replace all except 1-4
/5/,/8/!c\
replace all except 5-8
[TheEnd]
input => 'text',
expect => <<'[TheEnd]',
replace all except 5-8
replace all except 5-8
replace all except 5-8
replace all except 5-8
replace all except 1-4
replace all except 1-4
replace all except 1-4
replace all except 1-4
[TheEnd]
},
### d ###
'd' => {
script => <<'[TheEnd]',
# d delete pattern space, start next cycle
2,4 d
5 d
[TheEnd]
input => 'text',
expect => <<'[TheEnd]',
line 1
line 6
line 7
line 8
[TheEnd]
},
### gh ###
'gh' => {
script => <<'[TheEnd]',
1h
2g
3h
4g
5q
[TheEnd]
input => 'text',
expect => <<'[TheEnd]',
line 1
line 1
line 3
line 3
line 5
[TheEnd]
},
### i ###
'i' => {
script => <<'[TheEnd]',
1i\
inserted line 1.1\
inserted line 1.2
3i\
inserted line 3.1
3i\
inserted line 3.2
[TheEnd]
input => 'text',
expect => <<'[TheEnd]',
inserted line 1.1
inserted line 1.2
line 1
line 2
inserted line 3.1
inserted line 3.2
line 3
line 4
line 5
line 6
line 7
line 8
[TheEnd]
},
### n ###
'n' => {
script => <<'[TheEnd]',
3a\
added line
4a\
added line
5a\
added line
3,5n
=
d
[TheEnd]
input => 'text',
expect => <<'[TheEnd]',
1
2
line 3
added line
4
line 5
added line
6
7
8
[TheEnd]
},
### o ###
'o' => {
script => <<'[TheEnd]',
/abc/,/def/ s//XXX/
// i\
cheers
[TheEnd]
input => 'text',
expect => <<'[TheEnd]',
line 1
line 2
line 3
line 4
line 5
line 6
line 7
line 8
[TheEnd]
},
### q ###
'q' => {
script => <<'[TheEnd]',
2a\
append to line 2
3a\
append to line 3 - should not appear in output
3q
[TheEnd]
input => 'text',
expect => <<'[TheEnd]',
line 1
line 2
append to line 2
line 3
[TheEnd]
},
### r ###
'r' => {
datfil => [ 'r.txt', "r.txt line 1\nr.txt line 2\nr.txt line 3\n" ],
script => <<'[TheEnd]',
2r%r.txt%
4r %r.txt%
[TheEnd]
input => 'text',
expect => <<'[TheEnd]',
line 1
line 2
r.txt line 1
r.txt line 2
r.txt line 3
line 3
line 4
r.txt line 1
r.txt line 2
r.txt line 3
line 5
line 6
line 7
line 8
[TheEnd]
},
### s ###
's' => {
script => <<'[TheEnd]',
# enclose any `(a)'.. `(c)' in `-'
s/([a-z])/-\1-/g
s/\([abc]\)/-\1-/g
[TheEnd]
input => 'text',
expect => <<'[TheEnd]',
line 1
line 2
line 3
line 4
line 5
line 6
line 7
line 8
[TheEnd]
},
### s1 ###
's1' => {
script => <<'[TheEnd]',
s/\w/@1/
s/\y/@2/
s/\n/@3/
# this is literal { }
s/a{3}/@4/
# proper repetition
s/a\{3\}/a rep 3/
[TheEnd]
input => 'text',
expect => <<'[TheEnd]',
@1ine 1
@1ine 2
@1ine 3
@1ine 4
@1ine 5
@1ine 6
@1ine 7
@1ine 8
[TheEnd]
},
### t ###
't' => {
script => join( "\n",
'#no autoprint', 's/./X/p', 's/foo/bar/p', 't bye', '=', 'p', ':bye' ),
input => 'text',
expect => <<'[TheEnd]',
Xine 1
Xine 2
Xine 3
Xine 4
Xine 5
Xine 6
Xine 7
Xine 8
[TheEnd]
},
### w ###
'w' => {
datfil => [ 'w.txt', '' ],
script => <<'[TheEnd]',
w %w.txt%
[TheEnd]
input => 'text',
expect => <<'[TheEnd]',
line 1
line 2
line 3
line 4
line 5
line 6
line 7
line 8
[TheEnd]
},
### x ###
'x' => {
script => <<'[TheEnd]',
1h
1d
2x
2,$G
[TheEnd]
input => 'text',
expect => <<'[TheEnd]',
line 1
line 2
line 3
line 2
line 4
line 2
line 5
line 2
line 6
line 2
line 7
line 2
line 8
line 2
[TheEnd]
},
### y ###
'y' => {
script => <<'[TheEnd]',
y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/
y/|/\
/
[TheEnd]
input => 'text',
expect => <<'[TheEnd]',
LINE 1
LINE 2
LINE 3
LINE 4
LINE 5
LINE 6
LINE 7
LINE 8
[TheEnd]
},
### cnt ###
'cnt' => {
script => <<'[TheEnd]',
#no autoprint
# delete line, append NL to hold space
s/.*//
H
$!b
# last line only: get hold
g
s/./X/g
t count
: count
s/^X/1/
s/0X/1/
s/1X/2/
s/2X/3/
s/3X/4/
s/4X/5/
s/5X/6/
s/6X/7/
s/7X/8/
s/8X/9/
s/9X/X0/
t count
p
[TheEnd]
input => 'text',
expect => <<'[TheEnd]',
8
[TheEnd]
},
### adr1 ###
'adr1' => {
script => <<'[TheEnd]',
#no autoprint
# This script should be run on itself
/^#__DATA__$/,${
/^#A$/p
s/^# *[0-9]* *//
/^#\*$/p
/^#\.$/p
/^#\(..\)\(..\)\2\1*$/p
/^#[abc]\{1,\}[def]\{1,\}$/p
}
#__DATA__
#A
#*
#.
#abxyxy
#abxyxyab
#abxyxyabab
#ad
#abcdef
[TheEnd]
input => 'adr1',
expect => <<'[TheEnd]',
#A
[TheEnd]
},
);
my @aux = ();
my $ntc = 2 * keys %testcase;
plan( $ntc );
# temporary file names
my $script = "s2pt$$.sed";
my $stdin = "s2pt$$.in";
my $plsed = "s2pt$$.pl";
# various command lines for
my $s2p = File::Spec->catfile( File::Spec->updir(), 'x2p', 's2p' );
my $psed = File::Spec->catfile( File::Spec->curdir(), 'psed' );
if ($^O eq 'VMS') {
# default in the .com extenson if it's not already there
$s2p = VMS::Filespec::rmsexpand($s2p, '.com');
$psed = VMS::Filespec::rmsexpand($psed, '.com');
}
my $sedcmd = [ $psed, '-f', $script, $stdin ];
my $s2pcmd = [ $s2p, '-f', $script ];
my $plcmd = [ $plsed, $stdin ];
my $switches = '';
$switches = ['-x'] if $^O eq 'MacOS';
# psed: we create a local copy as linking may not work on some systems.
copy( $s2p, $psed );
push( @aux, $psed );
# process all testcases
#
my $indat = '';
for my $tc ( sort keys %testcase ){
my( $psedres, $s2pres );
# 1st test: run psed
# prepare the script
open( SED, ">$script" ) || goto FAIL_BOTH;
my $script = $testcase{$tc}{script};
# additional files for r, w: patch script, inserting temporary names
if( exists( $testcase{$tc}{datfil} ) ){
my( $datnam, $datdat ) = @{$testcase{$tc}{datfil}};
my $datfil = "s2pt$$" . $datnam;
push( @aux, $datfil );
open( DAT, ">$datfil" ) || goto FAIL_BOTH;
print DAT $datdat;
close( DAT );
$script =~ s/\%$datnam\%/$datfil/eg;
}
print SED $script;
close( SED ) || goto FAIL_BOTH;
# prepare input
#
if( $indat ne $testcase{$tc}{input} ){
$indat = $testcase{$tc}{input};
open( IN, ">$stdin" ) || goto FAIL_BOTH;
print IN $input{$indat};
close( IN ) || goto FAIL_BOTH;
}
# on VMS, runperl eats blank lines to work around
# spurious newlines in pipes
$testcase{$tc}{expect} =~ s/\n\n/\n/ if $^O eq 'VMS';
# run and compare
#
$psedres = runperl( args => $sedcmd, switches => $switches );
is( $psedres, $testcase{$tc}{expect}, "psed $tc" );
# 2nd test: run s2p
# translate the sed script to a Perl program
my $perlprog = runperl( args => $s2pcmd, switches => $switches );
open( PP, ">$plsed" ) || goto FAIL_S2P;
print PP $perlprog;
close( PP ) || goto FAIL_S2P;
# execute generated Perl program, compare
$s2pres = runperl( args => $plcmd, switches => $switches );
is( $s2pres, $testcase{$tc}{expect}, "s2p $tc" );
next;
FAIL_BOTH:
fail( "psed $tc" );
FAIL_S2P:
fail( "s2p $tc" );
}
END {
for my $f ( $script, $stdin, $plsed, @aux ){
1 while unlink( $f ); # hats off to VMS...
}
}
|