diff --git a/t/feature_tracking.t b/t/feature_tracking.t index 163407fd..d21b60ee 100644 --- a/t/feature_tracking.t +++ b/t/feature_tracking.t @@ -8,6 +8,7 @@ use B 'perlstring'; use PPI (); use PPI::Dumper; +use Helper 'test_document'; #use DB::Skip subs => [ # qw( PPI::Document::new PPI::Lexer::lex_source PPI::Lexer::new @@ -16,8 +17,6 @@ use PPI::Dumper; # qr/^PPI::Tokenizer::__ANON__.*237.*$/ #]; -sub test_document; - FEATURE_TRACKING: { test_document <<'END_PERL', @@ -435,42 +434,3 @@ SIMPLE_LIST: { ok( PPI::Tokenizer->new( \"d()" )->all_tokens, "bare tokenizer auto-vivifies document object" ); -### TODO from ppi_token_unknown.t , deduplicate - -sub one_line_explain { - my ($data) = @_; - my @explain = explain $data; - s/\n//g for @explain; - return join "", @explain; -} - -sub main_level_line { - return "" if not $TODO; - my @outer_final; - my $level = 0; - while ( my @outer = caller( $level++ ) ) { - @outer_final = @outer; - } - return "l $outer_final[2] - "; -} - -sub test_document { - local $Test::Builder::Level = $Test::Builder::Level + 1; - my $args = ref $_[0] eq "ARRAY" ? shift : []; - my ( $code, $expected, $msg ) = @_; - $msg = perlstring $code if !defined $msg; - - my $d = PPI::Document->new( \$code, @{$args} ) or die explain $@; - my $tokens = $d->find( sub { $_[1]->significant } ); - $tokens = [ map { ref($_), $_->content } @$tokens ]; - - my $ok = is_deeply( $tokens, $expected, main_level_line . $msg ); - if ( !$ok ) { - diag ">>> $code -- $msg\n"; - diag( PPI::Dumper->new($d)->string ); - diag one_line_explain $tokens; - diag one_line_explain $expected; - } - - return; -} diff --git a/t/helper_test_functions.t b/t/helper_test_functions.t new file mode 100644 index 00000000..ee1a228c --- /dev/null +++ b/t/helper_test_functions.t @@ -0,0 +1,69 @@ +#!/usr/bin/perl + +# Test that Helper.pm exports generalized test_document and test_statement + +use lib 't/lib'; +use PPI::Test::pragmas; +use Test::More tests => 8 + ( $ENV{AUTHOR_TESTING} ? 1 : 0 ); + +use Helper qw( test_document test_statement ); +use PPI (); + +# test_statement: with explicit Statement class in expected +test_statement( + 'my $x = 1;', + [ + 'PPI::Statement::Variable' => 'my $x = 1;', + 'PPI::Token::Word' => 'my', + 'PPI::Token::Symbol' => '$x', + 'PPI::Token::Operator' => '=', + 'PPI::Token::Number' => '1', + 'PPI::Token::Structure' => ';', + ], + "test_statement with explicit Statement in expected" +); + +# test_statement: auto-wraps in PPI::Statement when no Statement prefix +test_statement( + 'print 1;', + [ + 'PPI::Token::Word' => 'print', + 'PPI::Token::Number' => '1', + 'PPI::Token::Structure' => ';', + ], + "test_statement auto-wraps in PPI::Statement" +); + +# test_document: simple variable declaration +test_document( + 'my $x = 1;', + [ + 'PPI::Statement::Variable', 'my $x = 1;', + 'PPI::Token::Word', 'my', + 'PPI::Token::Symbol', '$x', + 'PPI::Token::Operator', '=', + 'PPI::Token::Number', '1', + 'PPI::Token::Structure', ';', + ], + "test_document with simple variable declaration" +); + +# test_document: with PPI::Document options passed as first arrayref +test_document( + [ feature_mods => { signatures => 1 } ], + 'sub foo ($x) {}', + [ + 'PPI::Statement::Sub', 'sub foo ($x) {}', + 'PPI::Token::Word', 'sub', + 'PPI::Token::Word', 'foo', + 'PPI::Structure::Signature', '($x)', + 'PPI::Token::Structure', '(', + 'PPI::Statement::Expression', '$x', + 'PPI::Token::Symbol', '$x', + 'PPI::Token::Structure', ')', + 'PPI::Structure::Block', '{}', + 'PPI::Token::Structure', '{', + 'PPI::Token::Structure', '}', + ], + "test_document with feature_mods option" +); diff --git a/t/lib/Helper.pm b/t/lib/Helper.pm index 74257e2d..57d105ea 100644 --- a/t/lib/Helper.pm +++ b/t/lib/Helper.pm @@ -5,10 +5,12 @@ use warnings; use parent 'Exporter'; use Test::More; +use B 'perlstring'; use PPI::Document (); +use PPI::Dumper (); -our @EXPORT_OK = qw( check_with safe_new ); +our @EXPORT_OK = qw( check_with safe_new test_document test_statement ); =head1 safe_new @args @@ -54,4 +56,110 @@ sub check_with { return $checker->(); } +=head1 test_document + + test_document( + 'my $x = 1;', + [ 'PPI::Statement::Variable', 'my $x = 1;', ... ], + "optional message" + ); + + test_document( + [ feature_mods => { signatures => 1 } ], + 'sub foo ($x) {}', + [ ... ], + "with document options" + ); + +Parses the given code into a PPI::Document, extracts all significant elements +(class name and content pairs), and compares against the expected arrayref. + +An optional first arrayref argument passes options to PPI::Document->new(). + +=cut + +sub test_document { + local $Test::Builder::Level = $Test::Builder::Level + 1; + my $args = ref $_[0] eq "ARRAY" ? shift : []; + my ( $code, $expected, $msg ) = @_; + $msg = perlstring $code if !defined $msg; + + my $d = PPI::Document->new( \$code, @{$args} ) or die explain $@; + my $tokens = $d->find( sub { $_[1]->significant } ); + $tokens = [ map { ref($_), $_->content } @$tokens ]; + + my $ok = is_deeply( $tokens, $expected, _main_level_line() . $msg ); + if ( !$ok ) { + diag ">>> $code -- $msg\n"; + diag( PPI::Dumper->new($d)->string ); + diag _one_line_explain($tokens); + diag _one_line_explain($expected); + } + + return; +} + +=head1 test_statement + + test_statement( + 'my $x = 1;', + [ + 'PPI::Token::Word' => 'my', + 'PPI::Token::Symbol' => '$x', + 'PPI::Token::Operator' => '=', + 'PPI::Token::Number' => '1', + 'PPI::Token::Structure' => ';', + ], + "optional message" + ); + +Parses the given code into a PPI::Document, extracts all significant elements +(class name and content pairs), and compares against the expected arrayref. + +If the first element of the expected array does not start with +C, the expected array is automatically wrapped with the +statement class and the full code as its content. + +=cut + +sub test_statement { + local $Test::Builder::Level = $Test::Builder::Level + 1; + my ( $code, $expected, $msg ) = @_; + $msg = perlstring $code if !defined $msg; + + my $d = safe_new \$code; + my $tokens = $d->find( sub { $_[1]->significant } ); + $tokens = [ map { ref($_), $_->content } @$tokens ]; + + if ( $expected->[0] !~ /^PPI::Statement/ ) { + $expected = [ 'PPI::Statement', $code, @$expected ]; + } + my $ok = is_deeply( $tokens, $expected, _main_level_line() . $msg ); + if ( !$ok ) { + diag ">>> $code -- $msg\n"; + diag( PPI::Dumper->new($d)->string ); + diag _one_line_explain($tokens); + diag _one_line_explain($expected); + } + + return; +} + +sub _one_line_explain { + my ($data) = @_; + my @explain = explain $data; + s/\n//g for @explain; + return join "", @explain; +} + +sub _main_level_line { + return "" if not $TODO; + my @outer_final; + my $level = 0; + while ( my @outer = caller( $level++ ) ) { + @outer_final = @outer; + } + return "l $outer_final[2] - "; +} + 1; diff --git a/t/marpa.t b/t/marpa.t index 72852444..1a9c197f 100644 --- a/t/marpa.t +++ b/t/marpa.t @@ -8,7 +8,7 @@ use Test::More tests => 69 + ( $ENV{AUTHOR_TESTING} ? 1 : 0 ); use B qw( perlstring ); use PPI (); -use Helper 'safe_new'; +use Helper qw( safe_new test_statement ); test_statement( 'use v5 ;', @@ -305,41 +305,3 @@ test_statement( ] ); -sub one_line_explain { - my ( $data ) = @_; - my @explain = explain $data; - s/\n//g for @explain; - return join "", @explain; -} - -sub main_level_line { - return "" if not $TODO; - my @outer_final; - my $level = 0; - while ( my @outer = caller( $level++ ) ) { - @outer_final = @outer; - } - return "l $outer_final[2] - "; -} - -sub test_statement { - local $Test::Builder::Level = $Test::Builder::Level + 1; - my ( $code, $expected, $msg ) = @_; - $msg = perlstring $code if !defined $msg; - - my $d = safe_new \$code; - my $tokens = $d->find( sub { $_[1]->significant } ); - $tokens = [ map { ref( $_ ), $_->content } @$tokens ]; - - if ( $expected->[0] !~ /^PPI::Statement/ ) { - $expected = [ 'PPI::Statement', $code, @$expected ]; - } - my $ok = is_deeply( $tokens, $expected, main_level_line . $msg ); - if ( !$ok ) { - diag ">>> $code -- $msg\n"; - diag "GOT: " . one_line_explain $tokens; - diag "EXP: " . one_line_explain $expected; - } - - return; -} diff --git a/t/ppi_token_quote_literal.t b/t/ppi_token_quote_literal.t index 8dfc9245..3ef41f70 100644 --- a/t/ppi_token_quote_literal.t +++ b/t/ppi_token_quote_literal.t @@ -8,7 +8,7 @@ use Test::More tests => 23 + ( $ENV{AUTHOR_TESTING} ? 1 : 0 ); use B qw( perlstring ); use PPI (); -use Helper 'safe_new'; +use Helper qw( safe_new test_statement ); STRING: { my $Document = safe_new \"print q{foo}, q!bar!, q , q((foo));"; @@ -61,41 +61,3 @@ test_statement( "invalid syntax is identified correctly", ); -sub one_line_explain { - my ( $data ) = @_; - my @explain = explain $data; - s/\n//g for @explain; - return join "", @explain; -} - -sub main_level_line { - return "" if not $TODO; - my @outer_final; - my $level = 0; - while ( my @outer = caller( $level++ ) ) { - @outer_final = @outer; - } - return "l $outer_final[2] - "; -} - -sub test_statement { - local $Test::Builder::Level = $Test::Builder::Level + 1; - my ( $code, $expected, $msg ) = @_; - $msg = perlstring $code if !defined $msg; - - my $d = safe_new \$code; - my $tokens = $d->find( sub { $_[1]->significant } ); - $tokens = [ map { ref( $_ ), $_->content } @$tokens ]; - - if ( $expected->[0] !~ /^PPI::Statement/ ) { - $expected = [ 'PPI::Statement', $code, @$expected ]; - } - my $ok = is_deeply( $tokens, $expected, main_level_line . $msg ); - if ( !$ok ) { - diag ">>> $code -- $msg\n"; - diag one_line_explain $tokens; - diag one_line_explain $expected; - } - - return; -} diff --git a/t/ppi_token_unknown.t b/t/ppi_token_unknown.t index 35c52b10..4886984d 100644 --- a/t/ppi_token_unknown.t +++ b/t/ppi_token_unknown.t @@ -8,7 +8,7 @@ use Test::More tests => 2328 + ($ENV{AUTHOR_TESTING} ? 1 : 0); use PPI (); use B qw( perlstring ); -use Helper 'safe_new'; +use Helper qw( safe_new test_statement ); our %known_bad_seps; @@ -640,44 +640,6 @@ OPERATOR_CAST: { } } -sub one_line_explain { - my ($data) = @_; - my @explain = explain $data; - s/\n//g for @explain; - return join "", @explain; -} - -sub main_level_line { - return "" if not $TODO; - my @outer_final; - my $level = 0; - while ( my @outer = caller($level++) ) { - @outer_final = @outer; - } - return "l $outer_final[2] - "; -} - -sub test_statement { - local $Test::Builder::Level = $Test::Builder::Level+1; - my ( $code, $expected, $msg ) = @_; - $msg = perlstring $code if !defined $msg; - - my $d = safe_new \$code; - my $tokens = $d->find( sub { $_[1]->significant } ); - $tokens = [ map { ref($_), $_->content } @$tokens ]; - - if ( $expected->[0] !~ /^PPI::Statement/ ) { - $expected = [ 'PPI::Statement', $code, @$expected ]; - } - my $ok = is_deeply( $tokens, $expected, main_level_line.$msg ); - if ( !$ok ) { - diag ">>> $code -- $msg\n"; - diag one_line_explain $tokens; - diag one_line_explain $expected; - } - - return; -} sub test_varying_whitespace { local $Test::Builder::Level = $Test::Builder::Level+1; diff --git a/t/signature_details.t b/t/signature_details.t index c2fc9802..7c5a617e 100644 --- a/t/signature_details.t +++ b/t/signature_details.t @@ -8,8 +8,7 @@ use B 'perlstring'; use PPI (); use PPI::Dumper; - -sub test_document; +use Helper 'test_document'; BASE_SIGNATURE_EXAMPLE: { test_document @@ -418,42 +417,3 @@ END_PERL "complex signature example"; } -### TODO from ppi_token_unknown.t , deduplicate - -sub one_line_explain { - my ($data) = @_; - my @explain = explain $data; - s/\n//g for @explain; - return join "", @explain; -} - -sub main_level_line { - return "" if not $TODO; - my @outer_final; - my $level = 0; - while ( my @outer = caller( $level++ ) ) { - @outer_final = @outer; - } - return "l $outer_final[2] - "; -} - -sub test_document { - local $Test::Builder::Level = $Test::Builder::Level + 1; - my $args = ref $_[0] eq "ARRAY" ? shift : []; - my ( $code, $expected, $msg ) = @_; - $msg = perlstring $code if !defined $msg; - - my $d = PPI::Document->new( \$code, @{$args} ) or die explain $@; - my $tokens = $d->find( sub { $_[1]->significant } ); - $tokens = [ map { ref($_), $_->content } @$tokens ]; - - my $ok = is_deeply( $tokens, $expected, main_level_line . $msg ); - if ( !$ok ) { - diag ">>> $code -- $msg\n"; - diag( PPI::Dumper->new($d)->string ); - diag one_line_explain $tokens; - diag one_line_explain $expected; - } - - return; -}