Re: [QUIZ] Perl 'Easy' Quiz #2005-2

Daniel Martin <martin-+m399P62/[email protected]> Fri, 04 Feb 2005 08:40:45 -0500
Newsgroups gmane.comp.lang.perl.qotw.discuss
Message-ID <[email protected]>
Rod Adams <[email protected]> writes:

> I came up with the following block to put at the head of a single
> script file to make life a little easier.

Oooh.  Nice.  I was working toward something like that, but got
distracted.

However, the attached program based on that technique might be
interesting; it's based on my check for the 'medium' quiz given a
litte ways back.

Simply run the attached program passing as arguments a filename and
(optionally) several test strings.  If you don't pass any test
strings, it'll make up 100 random test strings for you.

The tough part here was coming up with a way to check the answer that
was not a spoiler of the problem.  I /think/ I succeeded, but this was
certainly more difficult than a few attacks on the problem.

However, I'm sure someone will prove me wrong and pull out of the test
another way to solve the puzzle.
checkit.pl (text/x-perl, 1.6 KB)
#!/usr/bin/perl

use Symbol;
use strict;

sub testanswer($$) {
  my ($input, $output) = @_;
  return 0 if $output =~ /\..*\./;
  if ($input =~ /(\.[^.]*)$/)
  {
    return 0 unless $output =~ /$1$/;
  }
  $input =~ s/\.//g;
  $output =~ s/\.//g;
  return ($input eq $output);
}

my @testbits = ( ("") x 10, (".") x 30, 'a'..'z', '0'..'9', 'A'..'Z');

sub randomtests {
  my @retval = ("");
  while ($#retval < 100) {
    my $bit = $testbits[rand($#testbits)];
    if (length($bit)) {$retval[0] .= $bit;}
    else              {unshift @retval, $bit;}
  }
  shift @retval;
  return @retval;
}

sub docheck ($@) {
  my ($filename, @testpoints) = @_;
  if (! @testpoints) {@testpoints = randomtests();}
  my ($shortfilename) = $filename;
  $shortfilename =~ s/\W//;
  my ($packagename) = sprintf('Qotw::Test::File%s::p%04X',
                              $shortfilename, rand (1 << 31));
  $!=$@='';
  eval "{ package $packagename; no strict; do '$filename'; die(\$\@) if (\$\@); } ";
  if ($!) {
    print STDERR "Couldn't read $filename: $!\n";
    return 0;
  }
  if ($@) {
    print STDERR "Couldn't compile $filename: $@\n";
    return 0;
  }
  my (@keys) = eval "sort keys \%${packagename}::";
  for my $name (@keys) {
    next if $name =~ /^_/;
    my $ref = qualify_to_ref($name, $packagename);
    next unless *{$ref}{CODE};
    my $failed = 0;
    for my $input (@testpoints) {
      my $output = *{$ref}{CODE}->($input);
      if (!testanswer($input,$output)) {
        print "$name failed on $input; gave $output\n";
	$failed=1;
      }
    }
    print "$name passed all tests\n" unless $failed;
  }
}

my $file = shift;
docheck $file, @ARGV;