tagged release 0.6.4
[parrot.git] / t / tools / ops2pmutils / 06-load_op_map_files.t
blob2f7f7e805378edd9cd55c433f294bea3ebb1bf1e
1 #! perl
2 # Copyright (C) 2007, The Perl Foundation.
3 # $Id$
4 # 06-load_op_map_files.t
6 use strict;
7 use warnings;
9 BEGIN {
10     use FindBin qw($Bin);
11     use Cwd qw(cwd realpath);
12     realpath($Bin) =~ m{^(.*\/parrot)\/[^/]*\/[^/]*\/[^/]*$};
13     our $topdir = $1;
14     if ( defined $topdir ) {
15         print "\nOK:  Parrot top directory located\n";
16     }
17     else {
18         $topdir = realpath($Bin) . "/../../..";
19     }
20     unshift @INC, qq{$topdir/lib};
22 use Test::More tests => 76;
23 use Cwd;
24 use File::Copy;
25 use File::Temp (qw| tempdir |);
26 use IO::File;
28 use_ok('Parrot::Ops2pm::Utils');
30 use constant NUM_FILE  => "src/ops/ops.num";
31 use constant SKIP_FILE => "src/ops/ops.skip";
33 ok( chdir $main::topdir, "Positioned at top-level Parrot directory" );
35     local @ARGV = qw(
36         src/ops/core.ops
37         src/ops/bit.ops
38     );
39     my $cwd = cwd();
40     {
41         my $tdir = tempdir( CLEANUP => 1 );
42         ok( chdir $tdir, 'changed to temp directory for testing' );
43         ok( ( mkdir qq{$tdir/src} ),     "able to make tempdir/src" );
44         ok( ( mkdir qq{$tdir/src/ops} ), "able to make tempdir/src" );
45         foreach my $f (@ARGV) {
46             ok( copy( qq{$cwd/$f}, qq{$tdir/$f} ), "copied .ops file" );
47         }
48         my $num  = NUM_FILE;
49         my $skip = SKIP_FILE;
50         ok( copy( qq{$cwd/$num},  qq{$tdir/$num} ),  "copied ops.num file" );
51         ok( copy( qq{$cwd/$skip}, qq{$tdir/$skip} ), "copied ops.skip file" );
52         my @opsfiles = glob("./src/ops/*.ops");
54         my $self = Parrot::Ops2pm::Utils->new(
55             {
56                 argv    => [@opsfiles],
57                 script  => "tools/build/ops2pm.pl",
58                 nolines => undef,
59                 renum   => undef,
60             }
61         );
62         isa_ok( $self, q{Parrot::Ops2pm::Utils} );
64         ok( $self->prepare_ops, "prepare_ops() returned successfully" );
65         ok( defined( $self->{ops} ), "'ops' key has been defined" );
67         ok( $self->load_op_map_files(), "load_op_map_files() completed successfully" );
68         ok( -f $num,                    "ops.num located after renumbering" );
69         ok( -f $skip,                   "ops.skip located after renumbering" );
71         ok( chdir $cwd, 'changed back to starting directory after testing' );
72     }
75 ## fail to provide ops.num file
77     local @ARGV = qw(
78         src/ops/core.ops
79         src/ops/bit.ops
80     );
81     my $cwd = cwd();
82     {
83         my $tdir = tempdir( CLEANUP => 1 );
84         ok( chdir $tdir, 'changed to temp directory for testing' );
85         ok( ( mkdir qq{$tdir/src} ),     "able to make tempdir/src" );
86         ok( ( mkdir qq{$tdir/src/ops} ), "able to make tempdir/src" );
87         foreach my $f (@ARGV) {
88             ok( copy( qq{$cwd/$f}, qq{$tdir/$f} ), "copied .ops file" );
89         }
90         my $num  = NUM_FILE;
91         my $skip = SKIP_FILE;
93         #        ok(copy(qq{$cwd/$num}, qq{$tdir/$num}), "copied ops.num file");
94         ok( copy( qq{$cwd/$skip}, qq{$tdir/$skip} ), "copied ops.skip file" );
95         my @opsfiles = glob("./src/ops/*.ops");
97         my $self = Parrot::Ops2pm::Utils->new(
98             {
99                 argv    => [@opsfiles],
100                 script  => "tools/build/ops2pm.pl",
101                 nolines => undef,
102                 renum   => undef,
103             }
104         );
105         isa_ok( $self, q{Parrot::Ops2pm::Utils} );
107         ok( $self->prepare_ops, "prepare_ops() returned successfully" );
108         ok( defined( $self->{ops} ), "'ops' key has been defined" );
110         eval { $self->load_op_map_files(); };
111         like(
112             $@, qr|^Can't open.*src/ops/ops\.num|,    #'
113             "Failure to prove ops.num correctly detected"
114         );
116         ok( chdir $cwd, 'changed back to starting directory after testing' );
117     }
120 # provide defective ops.num file:  hole:  missing number
122     local @ARGV = qw(
123         src/ops/core.ops
124         src/ops/bit.ops
125     );
126     my $cwd = cwd();
127     {
128         my $tdir = tempdir( CLEANUP => 1 );
129         ok( chdir $tdir, 'changed to temp directory for testing' );
130         ok( ( mkdir qq{$tdir/src} ),     "able to make tempdir/src" );
131         ok( ( mkdir qq{$tdir/src/ops} ), "able to make tempdir/src" );
132         foreach my $f (@ARGV) {
133             ok( copy( qq{$cwd/$f}, qq{$tdir/$f} ), "copied .ops file" );
134         }
135         my $num     = NUM_FILE;
136         my $skip    = SKIP_FILE;
137         my $realnum = qq{$tdir/$num};
138         my $tmpnum  = $realnum . q{.tmp};
139         ok( copy( qq{$cwd/$num}, $tmpnum ), "copied ops.num file to temporary file" );
141         my $fhin = IO::File->new();
142         ok( ( $fhin->open("<$tmpnum") ), "Able to open file for reading" );
143         my $fhout = IO::File->new();
144         ok( ( $fhout->open(">$realnum") ), "Able to open file for writing" );
145         while ( defined( my $line = <$fhin> ) ) {
146             chomp $line;
147             next if $line =~ /^#/;
148             next if $line =~ /^\s*$/;
149             next if $line =~ /^c/;      # to create holes
150             $fhout->print("$line\n");
151         }
152         ok( $fhout->close(), "Able to close file after writing" );
153         ok( $fhin->close(),  "Able to close file after reading" );
155         ok( copy( qq{$cwd/$skip}, qq{$tdir/$skip} ), "copied ops.skip file" );
156         my @opsfiles = glob("./src/ops/*.ops");
158         my $self = Parrot::Ops2pm::Utils->new(
159             {
160                 argv    => [@opsfiles],
161                 script  => "tools/build/ops2pm.pl",
162                 nolines => undef,
163                 renum   => undef,
164             }
165         );
166         isa_ok( $self, q{Parrot::Ops2pm::Utils} );
168         ok( $self->prepare_ops, "prepare_ops() returned successfully" );
169         ok( defined( $self->{ops} ), "'ops' key has been defined" );
171         eval { $self->load_op_map_files(); };
172         like( $@, qr|^hole in ops\.num before|, "Holes in ops.num correctly detected" );
174         ok( chdir $cwd, 'changed back to starting directory after testing' );
175     }
178 # provide defective ops.num file:  opname mentioned twice
180     local @ARGV = qw(
181         src/ops/core.ops
182         src/ops/bit.ops
183     );
184     my $cwd = cwd();
185     {
186         my $tdir = tempdir( CLEANUP => 1 );
187         ok( chdir $tdir, 'changed to temp directory for testing' );
188         ok( ( mkdir qq{$tdir/src} ),     "able to make tempdir/src" );
189         ok( ( mkdir qq{$tdir/src/ops} ), "able to make tempdir/src" );
190         foreach my $f (@ARGV) {
191             ok( copy( qq{$cwd/$f}, qq{$tdir/$f} ), "copied .ops file" );
192         }
193         my $num     = NUM_FILE;
194         my $skip    = SKIP_FILE;
195         my $realnum = qq{$tdir/$num};
196         my $tmpnum  = $realnum . q{.tmp};
197         ok( copy( qq{$cwd/$num}, $tmpnum ), "copied ops.num file to temporary file" );
199         my $fhin = IO::File->new();
200         ok( ( $fhin->open("<$tmpnum") ), "Able to open file for reading" );
201         my @outopnames;
202         while ( defined( my $line = <$fhin> ) ) {
203             chomp $line;
204             next if $line =~ /^#/;
205             next if $line =~ /^\s*$/;
206             my ( $name, $number ) = split /\s+/, $line, 2;
207             push @outopnames, $name;
208         }
209         ok( $fhin->close(), "Able to close file after reading" );
210         my $fhout = IO::File->new();
211         ok( ( $fhout->open(">$realnum") ), "Able to open file for writing" );
212         for ( my $n = 0 ; $n < 3 ; $n++ ) {
213             $fhout->print("$outopnames[$n]\t$n\n");
214         }
215         my $i = 3;
216         $fhout->print("$outopnames[3]\t$i\n");
217         $i++;
218         for ( my $m = 3 ; $m <= $#outopnames ; $m++ ) {
219             $fhout->print("$outopnames[$m]\t$i\n");
220             $i++;
221         }
222         ok( $fhout->close(), "Able to close file after writing" );
224         ok( copy( qq{$cwd/$skip}, qq{$tdir/$skip} ), "copied ops.skip file" );
225         my @opsfiles = glob("./src/ops/*.ops");
227         my $self = Parrot::Ops2pm::Utils->new(
228             {
229                 argv    => [@opsfiles],
230                 script  => "tools/build/ops2pm.pl",
231                 nolines => undef,
232                 renum   => undef,
233             }
234         );
235         isa_ok( $self, q{Parrot::Ops2pm::Utils} );
237         ok( $self->prepare_ops, "prepare_ops() returned successfully" );
238         ok( defined( $self->{ops} ), "'ops' key has been defined" );
240         eval { $self->load_op_map_files(); };
241         like( $@, qr|^duplicate opcode|, "Duplicate opcode correctly detected" );
243         ok( chdir $cwd, 'changed back to starting directory after testing' );
244     }
247 # provide defective ops.skip file:  opname also found in ops.num
249     local @ARGV = qw(
250         src/ops/core.ops
251         src/ops/bit.ops
252     );
253     my $cwd = cwd();
254     {
255         my $tdir = tempdir( CLEANUP => 1 );
256         ok( chdir $tdir, 'changed to temp directory for testing' );
257         ok( ( mkdir qq{$tdir/src} ),     "able to make tempdir/src" );
258         ok( ( mkdir qq{$tdir/src/ops} ), "able to make tempdir/src" );
259         foreach my $f (@ARGV) {
260             ok( copy( qq{$cwd/$f}, qq{$tdir/$f} ), "copied .ops file" );
261         }
262         my $num  = NUM_FILE;
263         my $skip = SKIP_FILE;
264         ok( copy( qq{$cwd/$num}, qq{$tdir/$num} ), "copied ops.num file" );
266         #        ok(copy(qq{$cwd/$skip}, qq{$tdir/$skip}), "copied ops.skip file");
268         my $realskip = qq{$tdir/$skip};
269         my $tmpskip  = $realskip . q{.tmp};
270         ok( copy( qq{$cwd/$skip}, $tmpskip ), "copied ops.skip file to temporary file" );
272         my $fhin = IO::File->new();
273         ok( ( $fhin->open("<$tmpskip") ), "Able to open file for reading" );
274         my @outopnames;
275         while ( defined( my $line = <$fhin> ) ) {
276             chomp $line;
277             next if $line =~ /^#/;
278             next if $line =~ /^\s*$/;
279             $line =~ s/\s+$//;
280             $line =~ s/^\s+//;
281             push @outopnames, $line;
282         }
283         ok( $fhin->close(), "Able to close file after reading" );
284         my $fhout = IO::File->new();
285         ok( ( $fhout->open(">$realskip") ), "Able to open file for writing" );
286         $fhout->print("noop\n");
287         for my $l (@outopnames) {
288             $fhout->print("$l\n");
289         }
290         ok( $fhout->close(), "Able to close file after writing" );
292         my @opsfiles = glob("./src/ops/*.ops");
294         my $self = Parrot::Ops2pm::Utils->new(
295             {
296                 argv    => [@opsfiles],
297                 script  => "tools/build/ops2pm.pl",
298                 nolines => undef,
299                 renum   => undef,
300             }
301         );
302         isa_ok( $self, q{Parrot::Ops2pm::Utils} );
304         ok( $self->prepare_ops, "prepare_ops() returned successfully" );
305         ok( defined( $self->{ops} ), "'ops' key has been defined" );
307         eval { $self->load_op_map_files(); };
308         like( $@, qr|^skipped opcode is also in|, "Opcode detected in both ops.num and ops.skip" );
310         ok( chdir $cwd, 'changed back to starting directory after testing' );
311     }
314 pass("Completed all tests in $0");
316 ################### DOCUMENTATION ###################
318 =head1 NAME
320 06-load_op_map_files.t - test C<Parrot::Ops2pm::Utils::load_op_map_files()>
322 =head1 SYNOPSIS
324     % prove t/tools/ops2pmutils/06-load_op_map_files.t
326 =head1 DESCRIPTION
328 The files in this directory test the publicly callable methods of
329 F<lib/Parrot/Ops2pm/Utils.pm> and F<lib/Parrot/Ops2pm/Auxiliary.pm>.
330 By doing so, they test the functionality of the F<ops2pm.pl> utility.
331 That functionality has largely been extracted
332 into the methods of F<Utils.pm>.
334 F<06-load_op_map_files.t> tests whether
335 C<Parrot::Ops2pm::Utils::load_op_map_files()> works properly.
337 =head1 TODO
339 The following statements, branches and conditions in C<load_op_map_files()>
340 are as yet uncovered:
342 =over 4
344 =item *
346 Uncovered implicit 'else':
348     $self->{max_op_num} ||= 0;
350 Real question:  can C<$self->{max_op_num}> ever be C<undef>, C<0>
351 or empty string?
353 =item *
355 Can these C<die> statements be provoked?
357         if ( exists $self->{optable}->{$name} ) {
358             die "duplicate opcode $name and $number";
359         }
361 =item *
363 Can this C<die> statement be provoked?
365         if ( exists $self->{optable}->{$name} ) {
366             die "skipped opcode is also in $num_file";
367         }
369 =back
371 =head1 AUTHOR
373 James E Keenan
375 =head1 SEE ALSO
377 Parrot::Ops2pm::Utils, F<ops2pm.pl>.
379 =cut
381 # Local Variables:
382 #   mode: cperl
383 #   cperl-indent-level: 4
384 #   fill-column: 100
385 # End:
386 # vim: expandtab shiftwidth=4: