Home | History | Annotate | Download | only in Runtime
      1 package ANTLR::Runtime::Test;
      2 
      3 use strict;
      4 use warnings;
      5 
      6 use base 'Test::Builder::Module';
      7 
      8 my $CLASS = __PACKAGE__;
      9 
     10 our @EXPORT = qw( g_test_output_is );
     11 
     12 use Carp;
     13 use Cwd;
     14 use File::Spec;
     15 use File::Temp qw( tempdir );
     16 
     17 sub read_file {
     18     my ($filename) = @_;
     19 
     20     local $/;
     21     open my $in, '<', $filename or die "Can't open $filename: $!";
     22     my $content = <$in>;
     23     close $in or warn "Can't close $filename: $!";
     24 
     25     return $content;
     26 }
     27 
     28 sub write_file {
     29     my ($filename, $content) = @_;
     30 
     31     open my $out, '>', $filename or die "Can't open $filename: $!";
     32     print $out $content;
     33     close $out or warn "Can't close $filename: $!";
     34 
     35     return;
     36 }
     37 
     38 sub get_perl {
     39     if (defined $ENV{HARNESS_PERL}) {
     40         return $ENV{HARNESS_PERL};
     41     }
     42 
     43     if ($^O =~ /^(MS)?Win32$/) {
     44         return Win32::GetShortPathName($^X);
     45     }
     46 
     47     return $^X;
     48 }
     49 
     50 sub g_test_output_is {
     51     my ($args) = @_;
     52     my $grammar = $args->{grammar};
     53     my $test_program = $args->{test_program};
     54     my $expected = $args->{expected};
     55     my $name = $args->{name} || undef;
     56     my $tb = $CLASS->builder;
     57 
     58     my $tmpdir = tempdir( CLEANUP => 1 );
     59 
     60     my $grammar_name;
     61     if ($grammar =~ /^(?:(?:lexer|parser|tree)\s+)? grammar \s+ (\w+)/xms) {
     62         $grammar_name = $1;
     63     } else {
     64         croak "Can't determine grammar name";
     65     }
     66 
     67     # write grammar file
     68     my $grammar_file = File::Spec->catfile($tmpdir, "$grammar_name.g");
     69     write_file($grammar_file, $grammar);
     70 
     71     # write test program file
     72     my $test_program_file = File::Spec->catfile($tmpdir, 'test.pl');
     73     write_file($test_program_file, $test_program);
     74 
     75     my $cwd = cwd;
     76     my $test_result;
     77     eval {
     78         # compile grammar
     79         my $antlr;
     80         if ($^O =~ /linux/) {
     81             $antlr = 'antlr.sh';
     82         }
     83         elsif ($^O =~ /MSWin32/) {
     84             $antlr = 'antlr.bat';
     85         }
     86         else {
     87             $antlr = 'antlr';
     88         }
     89         my $g_result = run_program([ File::Spec->catfile($cwd, 'tools', $antlr), '-o', $tmpdir, $grammar_file ]);
     90         if ($g_result->{exit_code} >> 8 != 0) {
     91             croak $g_result->{err};
     92         }
     93 
     94         # run test program
     95         {
     96             #local $ENV{PERLCOV_DB} = File::Spec->catfile($tmpdir, 'perlcov.db');
     97             #local $ENV{NYTPROF} = 'file=' . File::Spec->catfile($tmpdir, 'nytprof.out');
     98             $test_result = run_program([ get_perl(), '-Mblib', "-I$tmpdir", $test_program_file ]);
     99             if ($test_result->{exit_code} >> 8 != 0) {
    100                 croak $test_result->{err};
    101             }
    102         }
    103     };
    104     die $@ if $@;
    105 
    106     my $actual = $test_result->{out};
    107 
    108     # compare with $expected
    109     return $tb->is_eq($actual, $expected, $name);
    110 }
    111 
    112 sub run_program {
    113     my ($command) = @_;
    114 
    115     open my $old_out, '>&STDOUT' or die "Can't capture stdout: $!";
    116     close STDOUT or die "Can't close stdout: $!";
    117     open STDOUT, '>', 'out.tmp' or die "Can't redirect stdout: $!";
    118 
    119     open my $old_err, '>&STDERR' or die "Can't capture stderr: $!";
    120     close STDERR or die "Can't close stderr: $!";
    121     open STDERR, '>', 'err.tmp' or die "Can't redirect stderr: $!";
    122 
    123     system @$command;
    124     my $exit_code = $?;
    125 
    126     # restore stderr
    127     my $err = read_file('err.tmp');
    128     close STDERR or die "Can't close stderr: $!";
    129     open STDERR, '>&', $old_err or die "Can't restore stderr: $!";
    130     unlink 'err.tmp' or warn "Can't remove err.tmp: $!";
    131 
    132     # restore stdout
    133     my $out = read_file('out.tmp');
    134     close STDOUT or die "Can't close stdout: $!";
    135     open STDOUT, '>&', $old_out or die "Can't restore stdout: $!";
    136     unlink 'out.tmp' or warn "Can't remove out.tmp: $!";
    137 
    138     my $exit_value;
    139     if ($exit_code < 0) {
    140         $exit_value = $exit_code;
    141     } elsif ($exit_code && 0xff) {
    142         $exit_value = "[SIGNAL $exit_code]";
    143     } else {
    144         $exit_value = $exit_code >> 8;
    145     }
    146 
    147     return {
    148         exit_code => $exit_code,
    149         exit_value => $exit_value,
    150         out => $out,
    151         err => $err,
    152     };
    153 }
    154 
    155 1;
    156