#! /usr/local/bin/perl -w use strict; use Carp; my $master_template = do { local $/; }; my @pod_files = glob 't_source/*.pod6'; print "Building ", scalar(@pod_files), " tests\n"; POD_FILE: for my $pod_file (@pod_files) { my $rep_file = substr($pod_file,0,-5) . '.rep'; my $test_file = substr($pod_file,0,-5) . '.t'; $test_file =~ s{t_source/}{t/}xms; open my $pod_fh, '<', $pod_file or carp "Can't open Perldoc source file '$pod_file'" and next POD_FILE; open my $rep_fh, '<', $rep_file or carp "Can't open representation source file '$rep_file'" and next POD_FILE; open my $test_fh, '>', $test_file or carp "Can't create test file '$test_file'" and next POD_FILE; print "Creating $test_file\n"; print {$test_fh} fill_template($pod_fh, $rep_fh); } sub fill_template { my ($pod_fh, $rep_fh) = @_; my %data; local $/; $data{''} = <$pod_fh>; $data{''} = <$rep_fh>; my $template = $master_template; $template =~ s{( | )}{$data{$1}}gxms; return $template; } __DATA__ # Testing this Pod specification... my $perldoc_data = <<'END_PERLDOC'; END_PERLDOC # Expect it to parse to this ADT... my $expected_structure = eval <<'END_EXPECTED'; END_EXPECTED # Remove filenames from error messages (since two sources differ)... for my $msg ( @{ $expected_structure->{warnings} }, @{ $expected_structure->{errors} } ) { $msg =~ s{at \S+ line}{at line}; } use Perl6::Perldoc::Parser; use Test::More 'no_plan'; # Open input filehandle on Pod daa and parse it... open my $fh, '<', \$perldoc_data or die "Could not open file on test data"; my $representation = Perl6::Perldoc::Parser->parse($fh ,{all_pod=>1}); # Walk resulting representation and expectation tree in parallel, comparing... compare( ' ', # Indent 'return value', # Description {%{$representation}}, # What we got {%{$expected_structure}} # What we expected ); use Scalar::Util qw< reftype blessed >; # Only consider valid accessor methods... my %is_valid_scalar_method; my %is_valid_list_method; BEGIN { @is_valid_scalar_method{ qw< typename style number target > } = (); @is_valid_list_method{ qw< content rows cells > } = (); } # Walk two trees, comparing nodes as we go... sub compare { my ($indent, $desc, $rep, $expected) = @_; # Verify data at current node is of correct class... my ($rep_class, $expected_class) = map {ref($_) || q{STRING}} $rep, $expected; is $rep_class, $expected_class => "$indent$desc is $expected_class"; # Recurse down trees according to type of node expected... $indent .= q{ }; my $expected_type = reftype($expected) || q{STRING}; # If current node an object -> match keys as method calls... if (blessed $expected) { for my $attr ( keys %{ $expected } ) { # Expected subnode must be retrieved via known accessor... my $is_scalar = exists $is_valid_scalar_method{$attr}; my $is_list = exists $is_valid_list_method{$attr}; if (!$is_scalar && !$is_list) { fail "Internal error: unknown method $attr() " . "expected for $rep_class node"; } # Known accessor must be available... elsif (! $rep->can($attr) ) { fail "Can't call $attr() on $rep_class node"; } # If accessor returns a list, recursively compare the lists... elsif ($is_list) { compare($indent,$attr, [$rep->$attr], $expected->{$attr}); } # If accessor returns a scalar, string-compare the values... else { compare($indent,$attr, scalar($rep->$attr), $expected->{$attr}); } } } # If current node a hash -> match keys as hash entries... elsif ($expected_type eq 'HASH') { for my $attr ( keys %{ $expected } ) { compare($indent, $attr, $rep->{$attr}, $expected->{$attr}); } } # If current node an array -> match each element in sequence... elsif ($expected_type eq 'ARRAY') { for my $idx ( 0..$#{$expected} ) { compare($indent,"[$idx]", $rep->[$idx], $expected->[$idx]); } } # Otherwise current node is raw text -> simple string comparison... else { is $rep, $expected => "$indent$desc content was correct"; } }