### Params::Check test suite ### use strict; use Test::More tests => 45; $^W=1; ### case 1 ### BEGIN { use_ok( 'Params::Check' ) or diag "Check.pm not found. Dying", die; ### need to explicitly import 'check', use_ok cannot import. Params::Check->import(qw[check last_error allow]); } ### make sure it's verbose, good for debugging ### $Params::Check::VERBOSE = 0; my $tmpl = { firstname => { required => 1, }, lastname => { required => 1, }, gender => { required => 1, allow => [qr/M/i, qr/F/i], }, married => { allow => [0,1] }, age => { default => 21, allow => qr/^\d+$/, }, id_list => { default => [], strict_type => 1 }, phone => { allow => sub { return 1 if &valid_phone( @_ ); } }, bureau => { default => 'NSA', no_override => 1 }, }; my $standard = { firstname => 'joe', lastname => 'jackson', gender => 'M', }; my $default = { lastname => 'jackson', firstname => 'joe', married => undef, gender => 'M', id_list => [], phone => undef, age => 21, bureau => 'NSA', }; sub valid_phone { my $num = pop; ### dutch phone numbers are 10 digits ### $num =~ s/[\s-]//g; return $num =~ /^\d{10}$/ ? 1 : 0; } ### test defaults ### { my $hash = {%$standard}; my $args = check( $tmpl, $hash ); is_deeply($args, $default, "Just the defaults"); } ### test missing requirements ### { my $hash = {%$standard}; delete $hash->{gender}; my $args = check( $tmpl, $hash ); is($args, undef, "Missing required field"); like(last_error(), qr/^Required option 'gender' is not provided/, "Error string as expected" ); } ### remove non-template keys ### { my $hash = {%$standard}; $hash->{nonexistant} = 1; my $args = check( $tmpl, $hash ); is_deeply($args, $default, q[Non-mentioned key keys are ignored]); like( last_error(), qr/^Key 'nonexistant' is not a valid key/, "Error string as expected" ); { local $Params::Check::ALLOW_UNKNOWN = 1; $args = check ( $tmpl, $hash ); is( $args->{nonexistant}, $hash->{nonexistant}, q[ Except when told not to] ); is( last_error(), "", "Error string as expected" ); } } ### flexible values ### { my $hash = {%$standard}; $hash->{ID_LIST} = [qw|a b c|]; my $args = check( $tmpl, $hash ); is_deeply($args->{id_list}, $hash->{ID_LIST}, q[Setting non-required field]); } ### checking strict type ### { my $hash = {%$standard}; $hash->{ID_LIST} = {}; my $args = check( $tmpl, $hash ); is($args, undef, q[Enforcing strict type]); like( last_error(), qr/^Key 'id_list' is of invalid type/, "Error string as expected" ); } ### check 'no_override' ### { my $hash = {%$standard}; $hash->{bureau} = 'FBI'; my $args = check( $tmpl, $hash ); is( $args->{bureau}, $default->{bureau}, q[Can not change keys marked with 'no_override'] ); like( last_error(), qr/^You are not allowed to override key 'bureau'/, "Error string as expected" ); } ### check 'allow' #### { my $hash = {%$standard}; $hash->{phone} = '010 - 1234567'; my $args = check( $tmpl, $hash ); is_deeply($args->{phone}, $hash->{phone}, q[Allowing based on subroutine]); } { my $hash = {%$standard}; $hash->{phone} = '010 - 123456789'; my $args = check( $tmpl, $hash ); is($args, undef, q[Disallowing based on subroutine]); like( last_error(), qr/^Key 'phone' is of invalid type/, "Error string as expected" ); } { my $hash = {%$standard}; $hash->{age} = '23'; my $args = check( $tmpl, $hash ); is($args->{age}, $hash->{age}, q[Allowing based on regex]); } { my $hash = {%$standard}; $hash->{age} = 'fifty'; my $args = check( $tmpl, $hash ); is($args, undef, q[Disallowing based on regex]); like( last_error(), qr/^Key 'age' is of invalid type/, "Error string as expected" ); } { my $hash = {%$standard}; $hash->{married} = 1; my $args = check( $tmpl, $hash ); is($args->{married}, $hash->{married}, q[Allowing based on a list]); } { my $hash = {%$standard}; $hash->{married} = 2; my $args = check( $tmpl, $hash ); is($args, undef, q[Disallowing based on a list]); like( last_error(), qr/^Key 'married' is of invalid type/, "Error string as expected" ); } { my $hash = {%$standard}; $hash->{gender} = 'm'; my $args = check( $tmpl, $hash ); is($args->{gender}, $hash->{gender}, q[Allowing based on list of regexes]); } { my $hash = {%$standard}; $hash->{gender} = 'K'; my $args = check( $tmpl, $hash ); is($args, undef, q[Disallowing based on list of regexes]); like( last_error(), qr/^Key 'gender' is of invalid type/, "Error string as expected" ); } ### checks if 'undef' is being treated correctly ### { my $utmpl = {%$tmpl}; my $hash = {%$standard}; my $warning = ''; local $SIG{__WARN__} = sub { $warning .= join('', @_) }; $utmpl->{married}->{allow} = undef; my $args = check( $utmpl, $hash ); is( $args->{married}, undef, 'Allow undef succeeded' ); is( $warning, '', ' undef did not generate a warning' ); } { my $utmpl = {%$tmpl}; my $hash = {%$standard}; my $warning = ''; local $SIG{__WARN__} = sub { $warning .= join('', @_) }; $utmpl->{married}->{allow} = undef; $hash->{married} = 'foo'; my $args = check( $utmpl, $hash ); is ( $args, undef, 'Allow based on undef' ); unlike( $warning, qr/uninitialized value/, ' undef did not generate a warning' ); } { my $utmpl = {%$tmpl}; my $hash = {%$standard}; my $warning = ''; local $SIG{__WARN__} = sub { $warning .= join('', @_) }; push @{$utmpl->{married}->{allow}}, undef; $hash->{married} = undef; my $args = check( $utmpl, $hash ); is ( $args->{married}, undef, 'Allow based on undef in list' ); unlike( $warning, qr/uninitialized value/, ' undef did not generate a warning' ); } { my $utmpl = {%$tmpl}; my $hash = {%$standard}; my $warning = ''; local $SIG{__WARN__} = sub { $warning .= join('', @_) }; push @{$utmpl->{married}->{allow}}, undef; $hash->{married} = 'foo'; my $args = check( $utmpl, $hash ); warn Params::Check->last_error; is ( $args, undef, 'Allow based on undef' ); unlike( $warning, qr/uninitialized value/, ' undef did not generate a warning' ); } ### store/$NO_DUPLICATES tests ### { my $utmpl = {%$tmpl}; my $hash = {%$standard}; my $x; $utmpl->{firstname}->{store} = \$x; for( 0..1 ) { my $what = $_ ? 'Keeping' : 'Removing'; local $Params::Check::NO_DUPLICATES = $_; my $args = check( $utmpl, $hash ); is($x, $hash->{firstname}, q[Storing keys in scalars] ); is(defined $args->{firstname}, !$_,qq[$what in result set] ); } } ### $PRESERVE_CASE check ### { my $tmpl = { Foo => { default => 1 } }; my $try = { FOO => 2 }; for (0..1) { local $Params::Check::PRESERVE_CASE = $_; my $expect = $_ ? { Foo => 1 } : { foo => 2 }; my $state = $_ ? "" : " not"; my $rv = check( $tmpl, $try ); is_deeply( $rv, $expect, "Check while". $state ." preserving case" ); } } ### allow tests ### ok( allow( 42, qr/^\d+$/ ), "Allow based on regex" ); ok( allow( $0, $0), " Allow based on string" ); ok( allow( 42, [0,42] ), " Allow based on list" ); ok(!allow( $0, qr/^\d+$/ ), "Disallowing based on regex" ); ok(!allow( 42, $0 ), " Disallowing based on string" ); ok(!allow( 42, [0,$0] ), " Disallowing based on list" );