File Coverage

blib/lib/OTRS/OPM/Validate.pm
Criterion Covered Total %
statement 111 176 63.0
branch 9 18 50.0
condition 7 8 87.5
subroutine 7 7 100.0
pod 1 1 100.0
total 135 210 64.2


line stmt bran cond sub pod time code
1             package OTRS::OPM::Validate;
2             $OTRS::OPM::Validate::VERSION = '0.03';
3             # ABSTRACT: Validate .opm files
4              
5 1     1   614 use v5.20;
  1         4  
6              
7 1     1   6 use strict;
  1         2  
  1         19  
8 1     1   4 use warnings;
  1         2  
  1         837  
9              
10             my %boundaries = (
11             # tag min max
12             CVS => [ 0, 1],
13             Name => [ 1, 1],
14             URL => [ 1, 1],
15             Vendor => [ 1, 1],
16             Version => [ 1, 1],
17             BuildDate => [ 0, 1],
18             BuildHost => [ 0, 1],
19             );
20              
21             sub validate {
22 5     5 1 4249 my ($class, $content) = @_;
23              
24 5         66 $content =~ s{
25            
26             }{}xmsg;
27              
28 5         13 my ($check,$grammar) = _grammar();
29 5         156 my $match = $content =~ $grammar;
30 5 100       27 die 'Invalid .opm file' if !$match;
31              
32 4         16 for my $key ( keys %boundaries ) {
33 28         45 $check->( $key );
34             }
35             }
36              
37             sub _grammar {
38 5     5   8 my %s;
39              
40             my $check = sub {
41 367     367   1013 my ($name, $max, $min) = @_;
42              
43 367 100 66     782 $max //= (exists $boundaries{$name} ? $boundaries{$name}->[-1] : 100_000);
44 367 100 100     879 $min //= (exists $boundaries{$name} ? $boundaries{$name}->[0] : 0);
45              
46 367   100     1004 $s{$name} //= 0;
47              
48 367 50       3821 if ( $s{$name} > $max ) {
    50          
49 0         0 die sprintf 'Too many "%s" elements. Max %s element(s) allowed.', $name, $max;
50             }
51             elsif ( $s{$name} < $min ) {
52 0         0 die sprintf 'Too few "%s" elements. Min %s element(s) required.', $name, $min;
53             }
54 5         29 };
55              
56             my $grammar = qr{
57             \A(?&PACKAGE)\z
58              
59             (?(DEFINE)
60             (?
61             \s* <\?xml \s* version="1.0" \s* encoding="[^"]+?" \s* \?> \s+
62             \s* <(?otrs|otobo)_package \s+ version="[12].[0-9]+">
63             (?:\s*(?&PACKAGE_TAGS))+
64             \s* \s*
65             )
66              
67             (?
68 3         12 (?:.*?(?{$s{CVS}++; $check->('CVS')})) |
  3         7  
69 5         13 (?:.*?(?{++$s{Name}; $check->('Name')})) |
  5         10  
70 5         12 (?:.*?(?{++$s{Version}; $check->('Version')})) |
  5         10  
71 4         9 (?:.*?(?{++$s{Vendor}; $check->('Vendor')})) |
  4         5  
72 4         9 (?:.*?(?{++$s{URL}; $check->('URL')})) |
  4         7  
73 3         7 (?:.*?(?{++$s{License}; $check->('License')})) |
  3         6  
74 3         10 (?:.*?(?{$s{BuildDate}++; $check->('BuildDate')})) |
  3         5  
75 3         8 (?:.*?(?{$s{BuildHost}++; $check->('BuildHost')})) |
  3         5  
76             (?:.*?) |
77             (?&FRAMEWORK) |
78             (?&DESCRIPTION) |
79             (?&INTRO) |
80             (?&CODE) |
81             (?&PREREQ) |
82             (?&FILELIST) |
83             (?&DATABASE) |
84             (?&CHANGELOG)
85             )
86              
87             (?
88 8         146 .*?
89             )
90              
91             (?
92 2         4 (?:Maximum=".*?"(?{++$s{'Framework.Max'}; $check->('Framework.Max',1)})) |
  2         4  
93 2         4 (?:Minimum=".*?"(?{++$s{'Framework.Min'}; $check->('Framework.Min',1)}))
  2         4  
94             )
95              
96             (?
97             .*?
98             )
99              
100             (?
101 10         24 (?:Lang="(?[a-zA-Z]+)"(?{++$s{'Description.Lang'}; $check->('Description.Lang',1)})) |
  10         13  
102 0         0 (?:Format="[a-zA-Z]+"(?{++$s{'Description.Format'}; $check->('Description.Format',1)})) |
  0         0  
103 0         0 (?:Translatable="[01]"(?{++$s{'Description.Translatable'}; $check->('Description.Translatable',1)}))
  0         0  
104             )
105              
106             (?
107 3         7
108             ( \s+ (?&CHANGELOG_ATTR))+>.*?
109 3         8 (?{$check->('ChangeLog.Date', 1, 1); $check->('ChangeLog.Version', 1, 1); })
  3         5  
110             )
111              
112             (?
113 3         8 (?:Date=".*?"(?{++$s{'ChangeLog.Date'}; $check->('ChangeLog.Date',1,1)})) |
  3         5  
114 3         6 (?:Version=".*?"(?{++$s{'ChangeLog.Version'}; $check->('ChangeLog.Version',1,1)}))
  3         7  
115             )
116              
117             (?
118 1         3 Install|Upgrade|Reinstall|Uninstall) (?{delete @s{map{'Intro.'. $_}qw/Type Lang Title Translatable Version Format/};})
  6         18  
119             ( \s+ (?&INTRO_ATTR))+>.*?
120 1         3 (?{$check->('Intro.Type', 1, 1);})
121             )
122              
123             (?
124 1         4 (?:Type="(?i:Post|Pre)"(?{++$s{'Intro.Type'}; $check->('Intro.Type',1,1)})) |
  1         2  
125 0         0 (?:Title=".*?"(?{++$s{'Intro.Title'}; $check->('Intro.Title',1)})) |
  0         0  
126 0         0 (?:Format=".*?"(?{++$s{'Intro.Format'}; $check->('Intro.Format',1)})) |
  0         0  
127 0         0 (?:Lang="[A-Za-z]+"(?{++$s{'Intro.Lang'}; $check->('Intro.Lang',1)})) |
  0         0  
128 0         0 (?:Translatable="[01]"(?{++$s{'Intro.Translatable'}; $check->('Intro.Translatable',1)})) |
  0         0  
129 1 0   1   551 (?:Version=".*?"(?{++$s{'Intro.Version'}; $check->('Intro.Version',$+{intro_type} eq 'Upgrade' ? 1 : 0)}))
  1         415  
  1         2056  
  0         0  
  0         0  
130             )
131            
132             (?
133 0         0 Install|Upgrade|Reinstall|Uninstall) (?{delete @s{map{'Code.'. $_}qw/Type Version/};})
  0         0  
134             ( \s+ (?&CODE_ATTR))+>.*?
135 0         0 (?{$check->('Code.Type', 1, 1);})
136             )
137              
138             (?
139 0         0 (?:Type="(?i:Post|Pre)"(?{++$s{'Code.Type'}; $check->('Code.Type',1,1)})) |
  0         0  
140 0 0       0 (?:Version=".*?"(?{++$s{'Code.Version'}; $check->('Code.Version',$+{code_type} eq 'Upgrade' ? 1 : 0)}))
  0         0  
141             )
142              
143             (?
144             <(?Module|Package)Required (?{delete $s{'Prereq.Version'};})
145             (\s+ (?&VERSION))?>.*?
146 3         8 (?{$check->('Prereq.Version', 1);})
147             )
148              
149             (?
150 3         9 (?:Version=".*?"(?{++$s{'Prereq.Version'}; $check->('Prereq.Version', 1)}))
  3         4  
151             )
152              
153             (?
154             (\s*(?&FILE))+\s*
155             )
156              
157             (?
158 34         97
  102         439  
159             ( \s+ (?&FILE_ATTR))+>.*?
160 34         127 (?{$check->('File.' . $_ , 1, 1) for qw/Location Permission Encode/;})
161             )
162              
163             (?
164 34         89 (?:Location=".*?"(?{++$s{'File.Location'}; $check->('File.Location',1,1)})) |
  34         59  
165 34         82 (?:Encode=".*?"(?{++$s{'File.Encode'}; $check->('File.Encode',1,1)})) |
  34         59  
166 34         97 (?:Permission=".*?"(?{++$s{'File.Permission'}; $check->('File.Permission',1,1)}))
  34         57  
167             )
168              
169             (?
170 3         13 Install|Upgrade|Reinstall|Uninstall) (?{delete @s{map{'Database.'. $_}qw/Type Version/};})
  6         38  
171             ( \s+ (?&DATABASE_ATTR))+>
172             (\s* (?&DATABASE_TAGS) )+ \s*
173            
174             )
175              
176             (?
177 3         11 (?:Type="(?i:Post|Pre)"(?{++$s{'Database.Type'}; $check->('Database.Type',1)})) |
  3         7  
178 0 0       0 (?:Version=".*?"(?{++$s{'Database.Version'}; $check->('Database.Version',$+{database_type} eq 'Upgrade' ? 1 : 0)}))
  0         0  
179             )
180              
181             (?
182             (?&TABLE_CREATE) |
183             (?&TABLE_DROP) |
184             (?&TABLE_ALTER) |
185             (?&INSERT)
186             )
187              
188             (?
189 1         6
  3         15  
190             ( \s+ (?&TABLE_ATTR))+>
191             (\s* (?&TABLE_CREATE_TAGS) )+ \s*
192            
193             )
194              
195             (?
196             (?&COLUMN) |
197             (?&FOREIGN_KEY) |
198             (?&INDEX) |
199             (?&UNIQUE)
200             )
201              
202             (?
203 3         13
  9         47  
204             ( \s+ (?&TABLE_ATTR))+>
205             (\s* (?&TABLE_ALTER_TAGS) )+ \s*
206            
207             )
208              
209             (?
210             (?&COLUMN_ADD) |
211             (?&COLUMN_DROP) |
212             (?&COLUMN_CHANGE) |
213             (?&FOREIGN_KEY_CREATE) |
214             (?&FOREIGN_KEY_DROP) |
215             (?&INDEX_CREATE) |
216             (?&INDEX_DROP) |
217             (?&UNIQUE_CREATE) |
218             (?&UNIQUE_DROP)
219             )
220              
221             (?
222 1         6
  3         17  
223             ( \s+ (?&TABLE_ATTR))+ (?:/>|>\s*)
224             )
225              
226             (?
227 5         19 (?:Name=".*?"(?{++$s{'Table.Name'}; $check->('Table.Name',1,1)})) |
  5         9  
228 0         0 (?:Type="(?i:Post|Pre)"(?{++$s{'Table.Type'}; $check->('Table.Type',1)})) |
  0         0  
229 3 50       12 (?:Version=".*?"(?{++$s{'Table.Version'}; $check->('Table.Version',$+{database_type} eq 'Upgrade' ? 1 : 0)}))
  3         27  
230             )
231              
232             (?
233 12         48
  84         272  
234             ( \s+ (?&COLUMN_ATTR))+ (?:/>|>\s*)
235             )
236              
237             (?
238 3         16
  21         69  
239             ( \s+ (?&COLUMN_ATTR))+ (?:/>|>\s*)
240             )
241              
242             (?
243 15         86 (?:Name=".*?"(?{++$s{'Column.Name'}; $check->('Column.Name',1,1)})) |
  15         32  
244 1         4 (?:AutoIncrement="(?:true|false)"(?{++$s{'Column.AutoIncrement'}; $check->('Column.AutoIncrement',1)})) |
  1         2  
245 15         55 (?:Required="(?:true|false)"(?{++$s{'Column.Required'}; $check->('Column.Required',1)})) |
  15         29  
246 1         6 (?:PrimaryKey="(?:true|false)"(?{++$s{'Column.PrimaryKey'}; $check->('Column.PrimaryKey',1)})) |
  1         3  
247 15         53 (?:Type=".*?"(?{++$s{'Column.Type'}; $check->('Column.Type',1)})) |
  15         26  
248 5         17 (?:Size="\d+"(?{++$s{'Column.Size'}; $check->('Column.Size',1)})) |
  5         10  
249 0         0 (?:Default=".*?"(?{++$s{'Column.Default'}; $check->('Column.Default',1)}))
  0         0  
250             )
251              
252             (?
253 0         0
  0         0  
254             ( \s+ (?&COLUMN_CHANGE_ATTR))+ (?:/>|>\s*)
255             )
256              
257             (?
258 0         0 (?:NameOld=".*?"(?{++$s{'Column.NameOld'}; $check->('Column.NameOld',1)})) |
  0         0  
259 0         0 (?:NameNew=".*?"(?{++$s{'Column.NameNew'}; $check->('Column.NameNew',1)})) |
  0         0  
260 0         0 (?:AutoIncrement="(?:true|false)"(?{++$s{'Column.AutoIncrement'}; $check->('Column.AutoIncrement',1)})) |
  0         0  
261 0         0 (?:Required="(?:true|false)"(?{++$s{'Column.Required'}; $check->('Column.Required',1)})) |
  0         0  
262 0         0 (?:PrimaryKey="(?:true|false)"(?{++$s{'Column.PrimaryKey'}; $check->('Column.PrimaryKey',1)})) |
  0         0  
263 0         0 (?:Type=".*?"(?{++$s{'Column.Type'}; $check->('Column.Type',1)})) |
  0         0  
264 0         0 (?:Size="\d+"(?{++$s{'Column.Size'}; $check->('Column.Size',1)})) |
  0         0  
265 0         0 (?:Default=".*?"(?{++$s{'Column.Default'}; $check->('Column.Default',1)}))
  0         0  
266             )
267              
268             (?
269            
270             ( \s+ (?&COLUMN_ATTR))+ (?:/>|>\s*)
271             )
272              
273             (?
274 0         0 (?:Name=".*?"(?{++$s{'Column.Name'}; $check->('Column.Name',1,1)}))
  0         0  
275             )
276              
277             (?
278 0         0
  0         0  
279             ( \s+ (?&INSERT_ATTR))+>
280             (\s+ (?&INSERT_DATA) )+ \s*
281            
282             )
283              
284             (?
285 0         0 (?:Table=".*?"(?{++$s{'Insert.Table'}; $check->('Insert.Table',1,1)})) |
  0         0  
286 0         0 (?:Type=".*?"(?{++$s{'Insert.Type'}; $check->('Insert.Type',1)})) |
  0         0  
287 0         0 (?:Version=".*?"(?{++$s{'Insert.Version'}; $check->('Insert.Version',1)}))
  0         0  
288             )
289              
290             (?
291 0         0
  0         0  
292             ( \s+ (?&INSERT_DATA_ATTR))+>
293             .*?
294            
295             )
296              
297             (?
298 0         0 (?:Key=".*?"(?{++$s{'Data.Key'}; $check->('Data.Key',1,1)})) |
  0         0  
299 0         0 (?:Type=".*?"(?{++$s{'Data.Type'}; $check->('Data.Type',1)}))
  0         0  
300             )
301              
302             (?
303            
304             (\s+ (?&INDEX_COLUMN) )+ \s*
305            
306             )
307              
308             (?
309            
310             ( \s+ (?&NAME_ATTR))? (?:/>|>\s*)
311             )
312              
313             (?
314            
315             ( \s+ (?&NAME_ATTR))? (?:/>|>\s*)
316             )
317              
318             (?
319            
320             ( \s+ (?&NAME_ATTR))? (?:/>|>\s*)
321             )
322              
323             (?
324            
325             (\s+ (?&UNIQUE_COLUMN) )+ \s*
326            
327             )
328              
329             (?
330            
331             ( \s+ (?&NAME_ATTR))? (?:/>|>\s*)
332             )
333              
334             (?
335            
336             ( \s+ (?&NAME_ATTR))? (?:/>|>\s*)
337             )
338              
339             (?
340             |>\s*)
341             )
342              
343             (?
344 0         0 (?:Name=".*?"(?{++$s{'Generic.Name'}; $check->('Generic.Name',1,1)}))
  0         0  
345             )
346            
347             (?
348            
349             (\s+ (?&REFERENCE) )+ \s*
350            
351             )
352              
353             (?
354            
355             ( \s+ (?&NAME_ATTR))? (?:/>|>\s*)
356             )
357              
358             (?
359             |>\s*)
360             )
361              
362             (?
363 2         8 (?:ForeignTable=".*?"(?{++$s{'ForeignTable'}; $check->('ForeignTable',1,1)}))
  2         4  
364             )
365              
366             (?
367 3         79
368             ( \s+ (?&REFERENCE_ATTR) )+ \s*
369             (?:\s*/>|>\s*)
370             )
371              
372             (?
373 3         13 (?:Local=".*?"(?{++$s{'Reference.Local'}; $check->('Reference.Local',1,1)})) |
  3         8  
374 3         12 (?:Foreign=".*?"(?{++$s{'Reference.Foreign'}; $check->('Reference.Foreign',1,1)}))
  3         6  
375             )
376             )
377 5         42 }xms;
378              
379 5         23 return $check, $grammar;
380             }
381              
382             1;
383              
384             __END__