File Coverage

blib/lib/ABNF/Generator/Honest.pm
Criterion Covered Total %
statement 151 160 94.3
branch 43 86 50.0
condition 12 25 48.0
subroutine 35 36 97.2
pod n/a
total 241 307 78.5


line stmt bran cond sub pod time code
1             package ABNF::Generator::Honest;
2              
3             =pod
4              
5             =head1 NAME
6              
7             B<ABNF::Generator::Honest> - class to generate valid messages for ABNF-based generators
8              
9             It have $RECURSION_LIMIT = 16. You can change it to increase lower alarm bound on choices and repetition recursion.
10             but use it carefully!
11              
12             =head1 INHERITANCE
13              
14             B<ABNF::Generator::Honest>
15             isa B<ABNF::Generator>
16              
17             =head1 DESCRIPTION
18              
19             =head1 METHODS
20              
21             =cut
22              
23 1     1   922 use 5.014;
  1         4  
  1         36  
24              
25 1     1   5 use strict;
  1         1  
  1         33  
26 1     1   7 use warnings;
  1         2  
  1         34  
27 1     1   5 no warnings "recursion";
  1         2  
  1         36  
28              
29 1     1   6 use Data::Dumper;
  1         2  
  1         52  
30 1     1   5 use Readonly;
  1         2  
  1         59  
31 1     1   5 use List::Util qw(reduce);
  1         2  
  1         117  
32              
33 1     1   1017 use POSIX;
  1         7694  
  1         8  
34              
35 1     1   3225 use base qw(ABNF::Generator Exporter);
  1         2  
  1         703  
36              
37 1     1   9 use Method::Signatures; #some bug in B<Devel::Declare>...
  1         3  
  1         6  
38              
39 1     1   558 use ABNF::Generator qw($CONVERTERS);
  1         2  
  1         187  
40              
41             our @EXPORT_OK = qw(Honest);
42             our $RECURSION_LIMIT = 16;
43              
44             =pod
45              
46             =head1 ABNF::Generator::Honest->C<new>($grammar, $validator?)
47              
48             Creates a new B<ABNF::Generator::Honest> object.
49              
50             $grammar isa B<ABNF::Grammar>.
51              
52             $validator isa B<ABNF::Validator>.
53              
54             =cut
55              
56 1 50 33 1   4885 method new(ABNF::Grammar $grammar, ABNF::Validator $validator?) {
  1 50 33 1   2  
  1 50 33     5  
  1 50       19  
  1         3  
  1         18  
  1         260  
  1         4  
57 1 50       17 $self->SUPER::new($grammar, $validator ? $validator : ());
58             }
59              
60             =pod
61              
62             =head1 $honest->C<generate>($rule, $tail="")
63              
64             Generates one valid 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   3551 method _range($rule, $recursion) {
  76375 50   76375   141852  
  76375 50       156765  
  76375         81724  
  76375         138744  
  76375         83042  
  76375         146353  
77 76375         212913 my $converter = $CONVERTERS->{$rule->{type}};
78 76375         559956 my $min = $converter->($rule->{min});
79 76375         205664 my $max = $converter->($rule->{max});
80 76375         798227 return {class => "Atom", value => chr($min + int(rand($max - $min + 1)))};
81             }
82              
83 1 50   1   3375 method _string($rule, $recursion) {
  54612 50   54612   71750  
  54612 50       115340  
  54612         57870  
  54612         106458  
  54612         57640  
  54612         123328  
84 54612         140544 my $converter = $CONVERTERS->{$rule->{type}};
85             return {
86 54612         144207 class => "Atom",
87 54612         296529 value => join("", map { chr($converter->($_)) } @{$rule->{value}})
  54612         122372  
88             };
89             }
90              
91 1 50   1   3196 method _literal($rule, $recursion) {
  38228 50   38228   49128  
  38228 50       76396  
  38228         39035  
  38228         72991  
  38228         44071  
  38228         84210  
92 38228         253471 return {class => "Atom", value => $rule->{value}};
93             }
94              
95 1 50   1   2888 method _repetition($rule, $recursion) {
  54613 50   54613   65383  
  54613 50       114108  
  54613         59943  
  54613         106436  
  54613         61973  
  54613         114400  
96 54613         85439 my $min = $rule->{min};
97 54613   50     240842 my $count = ($rule->{max} || LONG_MAX) - $min;
98 54613         72466 my @result = ();
99              
100 54613         243680 push(@result, $self->_generateChain($rule->{value}, $recursion)) while $min--;
101 54613 100       140714 if ( $recursion->{level} < $RECURSION_LIMIT ) {
102 21845   66     139300 push(@result, $self->_generateChain($rule->{value}, $recursion)) while $count-- && int(rand(2));
103             }
104              
105 54613         397587 return {class => "Sequence", value => \@result};
106             }
107              
108 1 0   1   3175 method _proseValue($rule, $recursion) {
  0 0   0   0  
  0 0       0  
  0         0  
  0         0  
  0         0  
  0         0  
109 0         0 return $self->_generateChain($rule->{name}, $recursion);
110             }
111              
112 1 50   1   2862 method _reference($rule, $recursion) {
  289364 50   289364   395543  
  289364 50       642472  
  289364         384723  
  289364         625356  
  289364         312505  
  289364         648023  
113 289364         890426 return $self->_generateChain($rule->{name}, $recursion);
114             }
115              
116 1 50   1   2978 method _group($rule, $recursion) {
  54612 50   54612   63557  
  54612 50       116266  
  54612         55067  
  54612         110177  
  54612         59949  
  54612         125156  
117 54612         64708 my @result = ();
118 54612         52036 foreach my $elem ( @{$rule->{value}} ) {
  54612         129945  
119 163836         513631 push(@result, $self->_generateChain($elem, $recursion));
120             }
121              
122 54612         376048 return {class => "Sequence", value => \@result};
123             }
124              
125 1 50   1   2885 method _choice($rule, $recursion) {
  81919 50   81919   130940  
  81919 50       188905  
  81919         96314  
  81919         168310  
  81919         121011  
  81919         167467  
126 81919         101862 $recursion->{level}++;
127 81919         104393 my @result = ();
128 81919 100       178272 if ( $recursion->{level} < $RECURSION_LIMIT ) {
129 32767         45691 foreach my $choice ( @{$rule->{value}} ) {
  32767         69320  
130 70995         225385 push(@result, $self->_generateChain($choice, $recursion));
131             }
132             } else {
133 49152   100     123341 $recursion->{choices} ||= {};
134             my $candidate = reduce {
135 49152 50   49152   168890 if ( not exists($recursion->{choices}->{$a}) ) {
    0          
136 49152         150668 $b
137             } elsif ( not exists($recursion->{choices}->{$b}) ) {
138 0         0 $a
139             } else {
140 0         0 $recursion->{choices}->{$a} <=> $recursion->{choices}->{$b}
141             }
142 49152         194969 } @{$rule->{value}};
  49152         269280  
143 49152         245259 $recursion->{choices}->{$candidate}++;
144 49152         156858 push(@result, $self->_generateChain( $candidate, $recursion));
145 49152         155656 $recursion->{choices}->{$candidate}--;
146             }
147 81919         139094 $recursion->{level}--;
148              
149 81919         539292 return {class => "Choice", value => \@result};
150             }
151              
152 1 50   1   3756 method _rule($rule, $recursion) {
  289365 50   289365   355658  
  289365 50       614920  
  289365         323825  
  289365         607689  
  289365         351568  
  289365         571089  
153 289365         943335 return $self->_generateChain($rule->{value}, $recursion);
154             }
155              
156             =pod
157              
158             =head1 $honest->C<withoutArguments>($name, $tail="")
159              
160             Return a string starts like command $name and without arguments if command may have no arguments.
161              
162             Return an empty string otherwise.
163              
164             $tail is a string added to result if it absent.
165              
166             dies if there is no command like $rule.
167              
168             =cut
169              
170 1 50 33 1   6816 method withoutArguments(Str $name, Str $tail="") {
  3 50 33 3   412  
  3 50 66     11  
  3 100       25  
  3 50       7  
  3         36  
  3         10  
  3         9  
171 3         22 my $result = $self->SUPER::withoutArguments($name, $tail);
172 2 100       16 return $self->{_validator}->validate($name, $result) ? $result : "";
173             }
174              
175             =pod
176              
177             =head1 FUNCTIONS
178              
179             =head1 C<Honest>()
180              
181             Return __PACKAGE__ to reduce class name :3
182              
183             =cut
184              
185 1 50   1   997 func Honest() {
  1     1   15  
186 1         13 return __PACKAGE__;
187             }
188              
189             1;
190              
191             =pod
192              
193             =head1 AUTHOR / COPYRIGHT / LICENSE
194              
195             Copyright (c) 2013 Arseny Krasikov <nyaapa@cpan.org>.
196              
197             This module is licensed under the same terms as Perl itself.
198              
199             =cut