#!./perl -w # Tests for the source filters in coderef-in-@INC BEGIN { chdir 't' if -d 't'; @INC = qw(. ../lib); require 'test.pl'; skip_all_if_miniperl('no dynamic loading on miniperl, no Filter::Util::Call'); skip_all_without_perlio(); } use strict; use Config; use Filter::Util::Call; plan(tests => 144); unshift @INC, sub { no warnings 'uninitialized'; ref $_[1] eq 'ARRAY' ? @{$_[1]} : $_[1]; }; my $fh; open $fh, "<", \'pass("Can return file handles from \@INC");'; do $fh or die; my @origlines = ("# This is a blank line\n", "pass('Can return generators from \@INC');\n", "pass('Which return multiple lines');\n", "1", ); my @lines = @origlines; sub generator { $_ = shift @lines; # Return of 0 marks EOF return defined $_ ? 1 : 0; }; do \&generator or die; @lines = @origlines; # Check that the array dereferencing works ready for the more complex tests: do [\&generator] or die; sub generator_with_state { my $param = $_[1]; is (ref $param, 'ARRAY', "Got our parameter"); $_ = shift @$param; return defined $_ ? 1 : 0; } do [\&generator_with_state, ["pass('Can return generators which take state');\n", "pass('And return multiple lines');\n", ]] or die; open $fh, "<", \'fail("File handles and filters work from \@INC");'; do [$fh, sub {s/fail/pass/; return;}] or die; open $fh, "<", \'fail("File handles and filters with state work from \@INC");'; do [$fh, sub {s/$_[1]/pass/; return;}, 'fail'] or die; print "# 2 tests with pipes from subprocesses.\n"; my ($echo_command, $pass_arg, $fail_arg); if ($^O eq 'VMS') { $echo_command = 'write sys$output'; $pass_arg = '"pass"'; $fail_arg = '"fail"'; } else { $echo_command = 'echo'; $pass_arg = 'pass'; $fail_arg = 'fail'; } open $fh, "$echo_command $pass_arg|" or die $!; do $fh or die; open $fh, "$echo_command $fail_arg|" or die $!; do [$fh, sub {s/$_[1]/pass/; return;}, 'fail'] or die; sub rot13_filter { filter_add(sub { my $status = filter_read(); tr/A-Za-z/N-ZA-Mn-za-m/; $status; }) } open $fh, "<", \<<'EOC'; BEGIN {rot13_filter}; cnff("This will rot13'ed prepend"); EOC do $fh or die; open $fh, "<", \<<'EOC'; ORTVA {ebg13_svygre}; pass("This will rot13'ed twice"); EOC do [$fh, sub {tr/A-Za-z/N-ZA-Mn-za-m/; return;}] or die; my $count = 32; sub prepend_rot13_filter { filter_add(sub { my $previous = $_; # Filters should append to any existing data in $_ # But (logically) shouldn't filter it twice. my $test = "fzrt!"; $_ = $test; my $status = filter_read(); my $got = substr $_, 0, length $test, ''; is $got, $test, "Upstream didn't alter existing data"; tr/A-Za-z/N-ZA-Mn-za-m/; $_ = $previous . $_; die "Looping infinitely" unless $count--; $status; }) } open $fh, "<", \<<'EOC'; ORTVA {cercraq_ebg13_svygre}; pass("This will rot13'ed twice"); EOC do [$fh, sub {tr/A-Za-z/N-ZA-Mn-za-m/; return;}] or die; # This generates a heck of a lot of oks, but I think it's necessary. my $amount = 1; sub prepend_block_counting_filter { filter_add(sub { my $output = $_; my $count = 256; while (--$count) { $_ = ''; my $status = filter_read($amount); cmp_ok (length $_, '<=', $amount, "block mode works?"); $output .= $_; if ($status <= 0 or /\n/s) { $_ = $output; return $status; } } die "Looping infinitely"; }) } open $fh, "<", \<<'EOC'; BEGIN {prepend_block_counting_filter}; pass("one by one"); pass("and again"); EOC do [$fh, sub {return;}] or die; open $fh, "<", \<<'EOC'; BEGIN {prepend_block_counting_filter}; pas("SSS make s fast SSS"); EOC TODO: { todo_skip "disabled under -Dmad", 50 if $Config{mad}; do [$fh, sub {s/s/ss/gs; s/([\nS])/$1$1$1/gs; return;}] or die; } sub prepend_line_counting_filter { filter_add(sub { my $output = $_; $_ = ''; my $status = filter_read(); my $newlines = tr/\n//; cmp_ok ($newlines, '<=', 1, "1 line at most?"); $_ = $output . $_ if defined $output; return $status; }) } open $fh, "<", \<<'EOC'; BEGIN {prepend_line_counting_filter}; pass("You should see this line thrice"); EOC do [$fh, sub {$_ .= $_ . $_; return;}] or die; do \"pass\n(\n'Scalar references are treated as initial file contents'\n)\n" or die; open $fh, "<", \"ss('The file is concatenated');"; do [\'pa', $fh] or die; open $fh, "<", \"ff('Gur svygre vf bayl eha ba gur svyr');"; do [\'pa', $fh, sub {tr/A-Za-z/N-ZA-Mn-za-m/; return;}] or die; open $fh, "<", \"SS('State also works');"; do [\'pa', $fh, sub {s/($_[1])/lc $1/ge; return;}, "S"] or die; @lines = ('ss', '(', "'you can use a generator'", ')'); do [\'pa', \&generator] or die; do [\'pa', \&generator_with_state, ["ss('And generators which take state');\n", "pass('And return multiple lines');\n", ]] or die; # d8723a6a74b2c12e wasn't perfect, as the char * returned by SvPV*() can be # a temporary, freed at the next FREETMPS. And there is a FREETMPS in # pp_require for (0 .. 1) { # Need both alternatives on the regexp, because currently the logic in # pp_require for what is written to %INC is somewhat confused open $fh, "<", \'like(__FILE__, qr/(?:GLOB|CODE)\(0x[0-9a-f]+\)/, "__FILE__ is valid");'; do $fh or die; } # [perl #91880] $_ having the wrong refcount inside a { # filter sub local @INC; local $|; unshift @INC, sub { sub { undef *_; --$| }}; do "dah"; pass '$_ has the right refcount inside a filter sub'; }