File: error_reporting.t

package info (click to toggle)
libmethod-signatures-perl 20170211-4
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 696 kB
  • sloc: perl: 3,863; makefile: 2
file content (196 lines) | stat: -rw-r--r-- 8,924 bytes parent folder | download | duplicates (6)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
#!/usr/bin/perl

use strict;
use warnings;
use lib 't/lib';
use GenErrorRegex;                                                      # error-generating subs imported below

use Test::More;
use Test::Exception;


# This test file is all about making sure that errors are reported at the right places.  That is,
# when you make a compile-time mistake, we should report the error at the place where you declare
# the method, and when you make a run-time mistake, we should report it at the place where you
# _call_ the method, not in the method itself, or (even worse) somewhere deep inside
# Method::Signatures.
#
# The errors we're concerned about are:
#
#   *)  The error thrown when you fail to pass a required argument.
#   *)  The error thrown when you pass a named argument that was not declared.
#   *)  The error thrown when you try to pass a type that is unrecognized.
#   *)  The error thrown when you try to pass an argument of the wrong type.
#
# This is mildly tricky, since trapping the error to check it means the error could end up reported
# as being in "eval 27" or somesuch.  So we're going to use a few different layers of files that
# include each other to work around that for the run-time errors.  For the compile-time errors,
# we'll just call require instead of use.
#
# Ready? Here we go.

my %compile_time_errors =
(
    BadParameter        =>  {
                                error_gen   =>  'bad_param_error',
                                error_args  =>  [
                                                    '&$bar',
                                                ],
                                test_name   =>  'illegal param spec reports correctly',
                            },
    TrailingGarbage     =>  {
                                error_gen   =>  'unexpected_after_error',
                                error_args  =>  [
                                                    '&',
                                                ],
                                test_name   =>  'trailing code after param reports correctly',
                            },
    NamedAfterOptPos    =>  {
                                error_gen   =>  'named_after_optpos_error',
                                error_args  =>  [
                                                    '$baz',
                                                    '$bar',
                                                ],
                                test_name   =>  'named param following optional positional reports correctly',
                            },
    PosAfterNamed       =>  {
                                error_gen   =>  'pos_after_named_error',
                                error_args  =>  [
                                                    '$baz',
                                                    '$bar',
                                                ],
                                test_name   =>  'positional param following named reports correctly',
                            },
    MispositionedSlurpy =>  {
                                error_gen   =>  'mispositioned_slurpy_error',
                                error_args  =>  [
                                                    '@bar',
                                                ],
                                test_name   =>  'mispositioned slurpy param reports correctly',
                            },
    MultipleSlurpy =>       {
                                error_gen   =>  'multiple_slurpy_error',
                                error_args  =>  [
                                                ],
                                test_name   =>  'multiple slurpy params reports correctly',
                            },
    NamedSlurpy =>          {
                                error_gen   =>  'named_slurpy_error',
                                error_args  =>  [
                                                    '@bar',
                                                ],
                                test_name   =>  'named slurpy param reports correctly',
                            },
    RequiredAfterOpt =>     {
                                error_gen   =>  'required_after_optional_error',
                                error_args  => [
                                                    '$baz',
                                                    '$bar',
                                               ],
                                test_name   => 'required param after an optional param',
                            },
);

my %run_time_errors =
(
    MissingRequired     =>  {
                                method      =>  'bar',
                                error_gen   =>  'required_error',
                                error_args  =>  [
                                                    'InnerMissingRequired',
                                                    '$bar',
                                                    'foo',
                                                ],
                                test_name   =>  'missing required param reports correctly',
                            },
    NoSuchNamed         =>  {
                                method      =>  'bar',
                                error_gen   =>  'named_param_error',
                                error_args  =>  [
                                                    'InnerNoSuchNamed',
                                                    'bmoogle',
                                                    'foo',
                                                ],
                                test_name   =>  'no such named param reports correctly',
                            },
    UnknownType         =>  {
                                method      =>  'bar',
                                error_gen   =>  'badtype_error',
                                error_args  =>  [
                                                    'InnerUnknownType',
                                                    'Foo::Bmoogle',
                                                    'perhaps you forgot to load it?',
                                                    'foo',
                                                ],
                                test_name   =>  'unrecognized type reports correctly',
                            },
    BadType             =>  {
                                method      =>  'bar',
                                error_gen   =>  'badval_error',
                                error_args  =>  [
                                                    'InnerBadType',
                                                    'bar',
                                                    'Int',
                                                    'thing',
                                                    'foo',
                                                ],
                                test_name   =>  'incorrect type reports correctly',
                            },
);

# this is *much* easier (and less error-prone) than having to update the import list manually up top
GenErrorRegex->import( map { $_->{error_gen} } values %compile_time_errors, values %run_time_errors );


while (my ($testclass, $test) = each %compile_time_errors)
{
    (my $testmod = "$testclass.pm") =~ s{::}{/}g;
    no strict 'refs';

    throws_ok  { require $testmod }
            $test->{error_gen}->(@{$test->{error_args}}, FILE => "t/lib/$testmod", LINE => 1133),
            $test->{test_name};
}

while (my ($testclass, $test) = each %run_time_errors)
{
    (my $testmod = "$testclass.pm") =~ s{::}{/}g;
    no strict 'refs';

    lives_ok  { require $testmod } "$testclass loads correctly";
    throws_ok { &{ $testclass . '::' . $test->{method} }->() }
            $test->{error_gen}->(@{$test->{error_args}}, FILE => "t/lib/$testmod", LINE => 1133),
            $test->{test_name};
}


# modifiers bad type value checks (handled a bit differently than those above)
SKIP:
{
    eval { require MooseX::Declare } or skip "MooseX::Declare required for this test", 1;

    # different modifiers will throw different types in their errors
    my %bad_types =
    (
        before      =>  'Int',
        around      =>  'Int',
        after       =>  'Num',
        override    =>  'Int',
        augment     =>  'Num',
    );

    lives_ok { require ModifierBadType } 'incorrect type loads correctly';

    foreach ( qw< before around after override augment > )
    {
        my $test_meth = "test_$_";
        my $error_args = [ 'Foo::Bar', num => $bad_types{$_} => 'thing', $test_meth, ];

        throws_ok{ ModifierBadType::bar($test_meth) }
                badval_error(@$error_args, FILE => 't/lib/ModifierBadType.pm', LINE => 1133),
                "incorrect type for $_ modifier reports correctly";
    }
}


done_testing;