File Coverage

blib/lib/ABNF/Generator/Liar.pm
Criterion Covered Total %
statement 101 103 98.0
branch 33 60 55.0
condition 12 33 36.3
subroutine 24 24 100.0
pod n/a
total 170 220 77.2


line stmt bran cond sub pod time code
1             package ABNF::Generator::Liar;
2              
3             =pod
4              
5             =head1 NAME
6              
7             B<ABNF::Generator::Liar> - class to generate invalid messages for ABNF-based generators
8              
9             =head1 INHERITANCE
10              
11             B<ABNF::Generator::Liar>
12             isa B<BNF::Generator>
13              
14             =head1 DESCRIPTION
15              
16             =head1 METHODS
17              
18             =cut
19              
20 1     1   1016 use 5.014;
  1         3  
  1         34  
21              
22 1     1   6 use strict;
  1         1  
  1         30  
23 1     1   5 use warnings;
  1         2  
  1         27  
24              
25 1     1   6 use Readonly;
  1         3  
  1         52  
26 1     1   7 use Data::Dumper;
  1         2  
  1         47  
27 1     1   5 use Carp;
  1         2  
  1         70  
28              
29 1     1   906 use POSIX;
  1         7902  
  1         9  
30              
31 1     1   3536 use base qw(ABNF::Generator Exporter);
  1         2  
  1         731  
32              
33 1     1   11 use Method::Signatures; #some bug in B<Devel::Declare>...
  1         1  
  1         5  
34              
35 1     1   505 use ABNF::Grammar qw(splitRule $BASIC_RULES);
  1         3  
  1         380  
36              
37             Readonly my $STRING_LEN => 20;
38             Readonly my $CHARS => [map { chr($_) } (0 .. 0x0D - 1), (0x0D + 1 .. 255)];
39             Readonly my $ACHARS => [('A'..'Z', 'a'..'z')];
40             Readonly our $ENDLESS => 513 * 1024 / 4; # 513 kB of chars
41              
42             our @EXPORT_OK = qw(Liar);
43              
44             =pod
45              
46             =head1 ABNF::Generator::Liar->C<new>($grammar, $validator?)
47              
48             Creates a new B<ABNF::Generator::Liar> object.
49              
50             $grammar isa B<ABNF::Grammar>.
51              
52             $validator isa B<ABNF::Validator>.
53              
54             =cut
55              
56 1 50 33 1   3994 method new(ABNF::Grammar $grammar, ABNF::Validator $validator?) {
  1 50 33 1   3  
  1 50 33     5  
  1 50       24  
  1         3  
  1         17  
  1         241  
  1         3  
57 1 50       17 $self->SUPER::new($grammar, $validator ? $validator : ());
58             }
59              
60             =pod
61              
62             =head1 $liar->C<generate>($rule, $tail="")
63              
64             Generates one invalid sequence string for command $rule.
65              
66             Using cache $self->{_cache}->{$rule} for this rule, that speeds up this call.
67              
68             $rule is a command name.
69              
70             $tail is a string added to result if it absent.
71              
72             dies if there is no command like $rule.
73              
74             =cut
75              
76 1 50   1   2985 method _rule($rule, $recursion) {
  20 50   20   20  
  20 50       34  
  20         21  
  20         31  
  20         21  
  20         31  
77 20         18 my $result = "";
78              
79 20 50       45 if ( my $prefix = splitRule($rule) ) {
80 20         20 do {
81 20         31 $result = _stringRand($ACHARS);
82             } while $self->{_validator}->validateArguments($rule->{name}, $result);
83 20         38 $result = $prefix . $result;
84             } else {
85 0         0 do {
86 0         0 $result = _stringRand($ACHARS);
87             } while $self->{_validator}->validate($rule->{name}, $result);
88             }
89              
90 20         93 return {class => "Atom", value => $result};
91             }
92              
93 1 50   1   3192 func _stringRand($chars, $len?) {
  22 50   22   46  
  22         58  
  22         78  
  22         47  
94 22   66     161 $len ||= rand($STRING_LEN) + 1;
95 22         111 my @gen = ();
96 22         63 for ( my $i = 0; $i < $len; $i++ ) {
97 131619         319051 push(@gen, @$chars[rand @$chars]);
98             }
99 22         18465 return join("", @gen);
100             }
101              
102             =pod
103              
104             =head1 $liar->C<withoutArguments>($name, $tail="")
105              
106             Return a string starts like command $name and without arguments if it possible.
107              
108             Return an empty string if command may have no arguments.
109              
110             $tail is a string added to result if it absent.
111              
112             dies if there is no command like $rule.
113              
114             =cut
115              
116 1 50 33 1   5630 method withoutArguments(Str $name, Str $tail="") {
  3 50 33 3   421  
  3 50 66     12  
  3 100       30  
  3 50       6  
  3         28  
  3         8  
  3         7  
117 3         18 my $result = $self->SUPER::withoutArguments($name, $tail);
118 2 100       8 return $self->{_validator}->validate($name, $result) ? "" : $result;
119             }
120              
121             =pod
122              
123             =head1 $liar->C<unExistedCommand>()
124              
125             Return an string starts with char sequence that doesn't match any command
126              
127             $tail is a string added to result if it absent.
128              
129             dies if there is no command like $rule.
130              
131             =cut
132              
133 1 50 0 1   4321 method unExistedCommand(Str $tail="") {
  1 50 33 1   395  
  1 50       6  
  1         4  
  1         4  
134 1         2 my $result = "";
135 1         2 do {
136 1         4 $result = _stringRand($ACHARS);
137             } while $self->{_validator}->validateCommand($result);
138              
139 1         3 my $rx = eval { qr/$tail$/ };
  1         14  
140 1 50       7 croak "Bad tail" if $@;
141 1 50       16 return $result =~ $rx ? $result : $result . $tail;
142             }
143              
144             =pod
145              
146             =head1 $liar->C<endlessCommand>($name)
147              
148             Return an string starts like command $name and length more then $ENDLESS = 513 * 1024 / 4
149              
150             $tail is a string added to result if it absent.
151              
152             dies if there is no command like $rule.
153              
154             =cut
155              
156 1 50 33 1   5315 method endlessCommand($name, Str $tail="") {
  2 50 33 2   4  
  2 50       10  
  2 50       4  
  2         40  
  2         8  
  2         7  
157 2 100       10 croak "Unexisted commadn $name" unless $self->hasCommand($name);
158 1         5 my $prefix = splitRule($self->{_grammar}->rule($name));
159 1         4 my $result = $prefix . _stringRand($ACHARS, $ENDLESS);
160 1         13 my $rx = eval { qr/$tail$/ };
  1         39  
161 1 50       9 croak "Bad tail" if $@;
162 1 50       48 return $result =~ $rx ? $result : $result . $tail;
163             }
164              
165             =pod
166              
167             =head1 FUNCTIONS
168              
169             =head1 C<Liar>()
170              
171             Return __PACKAGE__ to reduce class name :3
172              
173             =cut
174              
175 1 50   1   983 func Liar() {
  1     1   14  
176 1         15 return __PACKAGE__;
177             }
178              
179             1;
180              
181             =pod
182              
183             =head1 AUTHOR / COPYRIGHT / LICENSE
184              
185             Copyright (c) 2013 Arseny Krasikov <nyaapa@cpan.org>.
186              
187             This module is licensed under the same terms as Perl itself.
188              
189             =cut