1#!./perl -w
2
3# Verify that all files generated by perl scripts are up to date.
4
5BEGIN {
6    if (-f "./TestInit.pm") {
7        push @INC, ".";
8    } elsif (-f '../TestInit.pm') {
9        push @INC, "..";
10    }
11}
12use TestInit qw(T A); # T is chdir to the top level, A makes paths absolute
13use strict;
14
15# this tests the functions in HeaderParser.pm which we use for make regen.
16
17require './t/test.pl';
18require './regen/HeaderParser.pm';
19
20skip_all_if_miniperl("needs Data::Dumper");
21
22require Data::Dumper;
23
24sub show_text {
25    my ($as_text)= @_;
26    print STDERR $as_text=~s/^/" " x 8/mger;
27}
28
29my $hp= HeaderParser->new();
30$hp->parse_text(<<~'EOF');
31    #ifdef A
32    #ifdef B
33    #define AB
34    content 1
35    #endif
36    content 2
37    #define A
38    #endif
39    /*comment
40      line */
41    #define C /* this is
42                 a hidden line continuation */ D
43    EOF
44my $normal= $hp->lines_as_str();
45my $lines= $hp->lines();
46my $lines_as_str= Data::Dumper->new([$lines])->Sortkeys(1)->Useqq(1)->Indent(1)->Dump();
47is($lines_as_str,<<~'DUMP_EOF', "Simple data structure as expected") or show_text($lines_as_str);
48        $VAR1 = [
49          bless( {
50            "cond" => [
51              [
52                "defined(A)"
53              ]
54            ],
55            "flat" => "#if defined(A)",
56            "level" => 0,
57            "line" => "#if defined(A)\n",
58            "n_lines" => 1,
59            "raw" => "#ifdef A\n",
60            "source" => "(buffer)",
61            "start_line_num" => 1,
62            "sub_type" => "#if",
63            "type" => "cond"
64          }, 'HeaderLine' ),
65          bless( {
66            "cond" => [
67              [
68                "defined(A)"
69              ],
70              [
71                "defined(B)"
72              ]
73            ],
74            "flat" => "#if defined(B)",
75            "level" => 1,
76            "line" => "# if defined(B)\n",
77            "n_lines" => 1,
78            "raw" => "#ifdef B\n",
79            "source" => "(buffer)",
80            "start_line_num" => 2,
81            "sub_type" => "#if",
82            "type" => "cond"
83          }, 'HeaderLine' ),
84          bless( {
85            "cond" => [
86              [
87                "defined(A)"
88              ],
89              [
90                "defined(B)"
91              ]
92            ],
93            "flat" => "#define AB",
94            "level" => 2,
95            "line" => "#   define AB\n",
96            "n_lines" => 1,
97            "raw" => "#define AB\n",
98            "source" => "(buffer)",
99            "start_line_num" => 3,
100            "sub_type" => "#define",
101            "type" => "content"
102          }, 'HeaderLine' ),
103          bless( {
104            "cond" => [
105              [
106                "defined(A)"
107              ],
108              [
109                "defined(B)"
110              ]
111            ],
112            "flat" => "content 1",
113            "level" => 2,
114            "line" => "content 1\n",
115            "n_lines" => 1,
116            "raw" => "content 1\n",
117            "source" => "(buffer)",
118            "start_line_num" => 4,
119            "sub_type" => "text",
120            "type" => "content"
121          }, 'HeaderLine' ),
122          bless( {
123            "cond" => [
124              [
125                "defined(A)"
126              ],
127              [
128                "defined(B)"
129              ]
130            ],
131            "flat" => "#endif",
132            "inner_lines" => 3,
133            "level" => 1,
134            "line" => "# endif\n",
135            "n_lines" => 1,
136            "raw" => "#endif\n",
137            "source" => "(buffer)",
138            "start_line_num" => 5,
139            "sub_type" => "#endif",
140            "type" => "cond"
141          }, 'HeaderLine' ),
142          bless( {
143            "cond" => [
144              [
145                "defined(A)"
146              ]
147            ],
148            "flat" => "content 2",
149            "level" => 1,
150            "line" => "content 2\n",
151            "n_lines" => 1,
152            "raw" => "content 2\n",
153            "source" => "(buffer)",
154            "start_line_num" => 6,
155            "sub_type" => "text",
156            "type" => "content"
157          }, 'HeaderLine' ),
158          bless( {
159            "cond" => [
160              [
161                "defined(A)"
162              ]
163            ],
164            "flat" => "#define A",
165            "level" => 1,
166            "line" => "# define A\n",
167            "n_lines" => 1,
168            "raw" => "#define A\n",
169            "source" => "(buffer)",
170            "start_line_num" => 7,
171            "sub_type" => "#define",
172            "type" => "content"
173          }, 'HeaderLine' ),
174          bless( {
175            "cond" => [
176              [
177                "defined(A)"
178              ]
179            ],
180            "flat" => "#endif",
181            "inner_lines" => 7,
182            "level" => 0,
183            "line" => "#endif\n",
184            "n_lines" => 1,
185            "raw" => "#endif\n",
186            "source" => "(buffer)",
187            "start_line_num" => 8,
188            "sub_type" => "#endif",
189            "type" => "cond"
190          }, 'HeaderLine' ),
191          bless( {
192            "cond" => [],
193            "flat" => "",
194            "level" => 0,
195            "line" => "/*comment\n  line */\n",
196            "n_lines" => 2,
197            "raw" => "/*comment\n  line */\n",
198            "source" => "(buffer)",
199            "start_line_num" => 9,
200            "sub_type" => "text",
201            "type" => "content"
202          }, 'HeaderLine' ),
203          bless( {
204            "cond" => [],
205            "flat" => "#define C D",
206            "level" => 0,
207            "line" => "#define C /* this is\n             a hidden line continuation */ D\n",
208            "n_lines" => 2,
209            "raw" => "#define C /* this is\n             a hidden line continuation */ D\n",
210            "source" => "(buffer)",
211            "start_line_num" => 11,
212            "sub_type" => "#define",
213            "type" => "content"
214          }, 'HeaderLine' )
215        ];
216        DUMP_EOF
217
218is($normal,<<~'EOF',"Normalized text as expected");
219    #if defined(A)
220    # if defined(B)
221    #   define AB
222    content 1
223    # endif
224    content 2
225    # define A
226    #endif
227    /*comment
228      line */
229    #define C /* this is
230                 a hidden line continuation */ D
231    EOF
232
233{
234    my @warn;
235    local $SIG{__WARN__}= sub { push @warn, $_[0]; warn $_[0] };
236    my $ok= eval {
237        HeaderParser->new(add_commented_expr_after=>0)->parse_text(<<~'EOF'); 1
238        #ifdef A
239        #ifdef B
240        #endif
241        EOF
242    };
243    my $err= !$ok ? $@ : "";
244    ok(!$ok,"Should throw an error");
245    like($err,qr/Unterminated conditional block starting line 1 with last conditional operation at line 3/,
246         "Got expected error message");
247}
248{
249    my @warn;
250    local $SIG{__WARN__}= sub { push @warn, $_[0]; warn $_[0] };
251    my $ok= eval {
252        HeaderParser->new(add_commented_expr_after=>0)->parse_text(<<~'EOF'); 1
253        #ifdef A
254        #ifdef B
255        #elif C
256        EOF
257    };
258    my $err= !$ok ? $@ : "";
259    ok(!$ok,"Should throw an error");
260    like($err,qr/Unterminated conditional block starting line 3/,
261         "Unterminated block detected");
262}
263{
264    my @warn;
265    local $SIG{__WARN__}= sub { push @warn, $_[0]; warn $_[0] };
266    my $ok= eval {
267        HeaderParser->new(add_commented_expr_after=>0)->parse_text(<<~'EOF'); 1
268        #if 1 * * 10 > 5
269        #elifdef C
270        EOF
271    };
272    my $err= !$ok ? $@ : "";
273    ok(!$ok,"Should throw an error");
274    is($err,
275       "Error at line 1\n" .
276       "Line 1: #if 1 * * 10 > 5\n" .
277       "Error in multiplication expression: " .
278       "Unexpected token '*', expecting literal, unary, or expression.\n",
279         "Expected token error") or warn $err;
280}
281{
282    my $hp= HeaderParser->new(debug=>0,add_commented_expr_after=>0);
283
284    $hp->parse_text(<<~'EOF');
285        #ifdef A
286        # ifdef B
287        #   define P
288        # else
289        #   define Q
290        # endif
291        # if !defined B
292        #   define R
293        # else
294        #   define S
295        # endif
296        #endif
297        EOF
298    my $grouped= $hp->group_content();
299    my $as_text= $hp->lines_as_str($grouped);
300    is($as_text,<<~'EOF',"inverted simple clauses get merged properly") or show_text($as_text);
301        #if defined(A)
302        # if defined(B)
303        #   define P
304        #   define S
305        # else /* if !defined(B) */
306        #   define Q
307        #   define R
308        # endif /* !defined(B) */
309        #endif /* defined(A) */
310        EOF
311}
312{
313    my $hp= HeaderParser->new(debug=>0,add_commented_expr_after=>0);
314    $hp->parse_text(<<~'EOF');
315        #if defined(A) && defined(B)
316        # if (defined(C) && defined(D))
317        #   define P
318        # else
319        #   define Q
320        # endif
321        # if !(defined C && defined D)
322        #   define R
323        # else
324        #   define S
325        # endif
326        #endif
327        EOF
328    my $grouped= $hp->group_content();
329    my $as_text= $hp->lines_as_str($grouped);
330    is($as_text,<<~'EOF',"inverted complex clauses get merged properly") or show_text($as_text);
331        #if defined(A) && defined(B)
332        # if defined(C) && defined(D)
333        #   define P
334        #   define S
335        # else /* if !( defined(C) && defined(D) ) */
336        #   define Q
337        #   define R
338        # endif /* !( defined(C) && defined(D) ) */
339        #endif /* defined(A) && defined(B) */
340        EOF
341}
342{
343    my $hp= HeaderParser->new(debug=>0,add_commented_expr_after=>0);
344    $hp->parse_text(<<~'EOF');
345        #if defined(A)
346        #define HAS_A
347        #elif defined(B)
348        #define HAS_B
349        #elif defined(C)
350        #define HAS_C
351        #else
352        #define HAS_D
353        #endif
354        EOF
355    my $grouped= $hp->group_content();
356    my $as_text= $hp->lines_as_str($grouped);
357    is($as_text,<<~'EOF',"test nested elif round trip") or show_text($as_text);
358        #if defined(A)
359        # define HAS_A
360        #elif defined(B) /* && !defined(A) */
361        # define HAS_B
362        #elif defined(C) /* && !defined(A) && !defined(B) */
363        # define HAS_C
364        #else /* if !defined(A) && !defined(B) && !defined(C) */
365        # define HAS_D
366        #endif /* !defined(A) && !defined(B) && !defined(C) */
367        EOF
368}
369{
370    my $hp= HeaderParser->new(debug=>0,add_commented_expr_after=>0);
371    $hp->parse_text(<<~'EOF');
372        #if defined(A)
373        #define HAS_A
374        #endif
375        #if !defined(A) && defined(B)
376        #define HAS_B
377        #endif
378        #if defined(C)
379        #if !defined(A)
380        #if !defined(B)
381        #define HAS_C
382        #endif
383        #endif
384        #endif
385        #if !defined(B) && !defined(A) && !defined(C)
386        #define HAS_D
387        #endif
388        EOF
389    my $grouped= $hp->group_content();
390    my $as_text= $hp->lines_as_str($grouped);
391    is($as_text,<<~'EOF',"test elif composition from disparate statements") or show_text($as_text);
392        #if defined(A)
393        # define HAS_A
394        #elif defined(B) /* && !defined(A) */
395        # define HAS_B
396        #elif defined(C) /* && !defined(A) && !defined(B) */
397        # define HAS_C
398        #else /* if !defined(A) && !defined(B) && !defined(C) */
399        # define HAS_D
400        #endif /* !defined(A) && !defined(B) && !defined(C) */
401        EOF
402}
403{
404    my $hp= HeaderParser->new(debug=>0,add_commented_expr_after=>0);
405    $hp->parse_text(<<~'EOF');
406        #if defined(A)
407        #define HAS_A
408        #endif
409        #if !defined(A)
410        #define HAS_NOT_A
411        #if !defined(C)
412        #define HAS_A_NOT_C
413        #endif
414        #endif
415        #if defined(C)
416        #define HAS_C
417        #if defined(A)
418        #define HAS_A_C
419        #endif
420        #else
421        #if defined(A)
422        #define HAS_NOT_C_A
423        #endif
424        #endif
425        EOF
426    my $grouped= $hp->group_content();
427    my $as_text= $hp->lines_as_str($grouped);
428    is($as_text,<<~'EOF',"test else composition") or show_text($as_text);
429        #if defined(A)
430        # define HAS_A
431        # if defined(C)
432        #   define HAS_A_C
433        # else /* if !defined(C) */
434        #   define HAS_NOT_C_A
435        # endif /* !defined(C) */
436        #else /* if !defined(A) */
437        # define HAS_NOT_A
438        # if !defined(C)
439        #   define HAS_A_NOT_C
440        # endif /* !defined(C) */
441        #endif /* !defined(A) */
442        #if defined(C)
443        # define HAS_C
444        #endif /* defined(C) */
445        EOF
446}
447{
448    my $hp= HeaderParser->new(debug=>0,add_commented_expr_after=>0);
449    $hp->parse_text(<<~'EOF');
450        #if !defined(A)
451        #define NOT_A1
452        #else
453        #define A1
454        #endif
455        #if !!!!defined(A)
456        #define A2
457        #else
458        #define NOT_A2
459        #endif
460        EOF
461    my $grouped= $hp->group_content();
462    my $as_text= $hp->lines_as_str($grouped);
463    is($as_text,<<~'EOF',"normalization into if/else") or show_text($as_text);
464        #if defined(A)
465        # define A1
466        # define A2
467        #else /* if !defined(A) */
468        # define NOT_A1
469        # define NOT_A2
470        #endif /* !defined(A) */
471        EOF
472}
473{
474    my $hp= HeaderParser->new(debug=>0,add_commented_expr_after=>0);
475    $hp->parse_text(<<~'EOF');
476        #if !!!(defined(A) && defined(B))
477        #define NOT_A_AND_B
478        #endif
479        #if defined(A)
480        #if defined(B)
481        #define A_AND_B
482        #endif
483        #endif
484        EOF
485    my $grouped= $hp->group_content();
486    my $as_text= $hp->lines_as_str($grouped);
487    is($as_text,<<~'EOF',"normalization with complex else") or show_text($as_text);
488        #if defined(A) && defined(B)
489        # define A_AND_B
490        #else /* if !( defined(A) && defined(B) ) */
491        # define NOT_A_AND_B
492        #endif /* !( defined(A) && defined(B) ) */
493        EOF
494}
495{
496    my $hp= HeaderParser->new(debug=>0,add_commented_expr_after=>0);
497    $hp->parse_text(<<~'EOF');
498        #if defined(A) && !!defined(A) && !!!!defined(A)
499        #define HAS_A
500        #endif
501        EOF
502    my $grouped= $hp->group_content();
503    my $as_text= $hp->lines_as_str($grouped);
504    is($as_text,<<~'EOF',"simplification") or show_text($as_text);
505        #if defined(A)
506        # define HAS_A
507        #endif /* defined(A) */
508        EOF
509}
510{
511    local $::TODO;
512    $::TODO= "Absorbtion not implemented yet";
513    # currently we don't handle absorbtion: (A && (A || B || C ...)) == A
514    my $hp= HeaderParser->new(debug=>0,add_commented_expr_after=>0);
515    $hp->parse_text(<<~'EOF');
516        #if defined(X) && (defined(X) || defined(Y))
517        #define HAS_X
518        #endif
519        EOF
520    my $grouped= $hp->group_content();
521    my $as_text= $hp->lines_as_str($grouped);
522    is($as_text,<<~'EOF',"simplification by absorbtion"); # or show_text($as_text);
523        #if defined(X)
524        # define HAS_X
525        #endif /* defined(X) */
526        EOF
527}
528{
529    my $hp= HeaderParser->new(debug=>0,add_commented_expr_after=>0);
530    $hp->parse_text(<<~'EOF');
531        #if defined(A) && (defined(B) && defined(C))
532        #define HAS_A
533        #endif
534        EOF
535    my $grouped= $hp->group_content();
536    my $as_text= $hp->lines_as_str($grouped);
537    is($as_text,<<~'EOF',"expression flattening") or show_text($as_text);
538        #if defined(A) && defined(B) && defined(C)
539        # define HAS_A
540        #endif /* defined(A) && defined(B) && defined(C) */
541        EOF
542}
543{
544    my $hp= HeaderParser->new(debug=>0,add_commented_expr_after=>3);
545    $hp->parse_text(<<~'EOF');
546        #if defined(A)
547        #define HAS_A1
548        #define HAS_A2
549        #define HAS_A3
550        #endif
551        #if defined(B)
552        #define HAS_B1
553        #else
554        #define HAS_B1e
555        #define HAS_B2e
556        #define HAS_B3e
557        #endif
558        #if defined(C)
559        #if defined(D)
560        #define HAS_D1
561        #endif
562        #elif defined(CC)
563        #define HAS_CC1
564        #define HAS_CC2
565        #define HAS_CC3
566        #endif
567        EOF
568    my $grouped= $hp->group_content();
569    my $as_text= $hp->lines_as_str($grouped);
570    is($as_text,<<~'EOF',"auto-comments") or show_text($as_text);
571        #if defined(A)
572        # define HAS_A1
573        # define HAS_A2
574        # define HAS_A3
575        #endif /* defined(A) */
576        #if defined(B)
577        # define HAS_B1
578        #else
579        # define HAS_B1e
580        # define HAS_B2e
581        # define HAS_B3e
582        #endif /* !defined(B) */
583        #if defined(C)
584        # if defined(D)
585        #   define HAS_D1
586        # endif
587        #elif defined(CC) /* && !defined(C) */
588        # define HAS_CC1
589        # define HAS_CC2
590        # define HAS_CC3
591        #endif /* !defined(C) && defined(CC) */
592        EOF
593}
594{
595    my $hp= HeaderParser->new(debug=>0,add_commented_expr_after=>0);
596    $hp->parse_text(<<~'EOF');
597        #if  defined(DEBUGGING)                                                    \
598             || (defined(USE_LOCALE) && (    defined(USE_THREADS)                  \
599                                        ||   defined(HAS_IGNORED_LOCALE_CATEGORIES)\
600                                        ||   defined(USE_POSIX_2008_LOCALE)        \
601                                        || ! defined(LC_ALL)))
602        # define X
603        #endif
604        EOF
605    my $grouped= $hp->group_content();
606    my $as_text= $hp->lines_as_str($grouped);
607    is($as_text,<<~'EOF',"Karls example") or show_text($as_text);
608        #if   defined(DEBUGGING) ||                                         \
609            ( defined(USE_LOCALE) &&                                        \
610            ( defined(HAS_IGNORED_LOCALE_CATEGORIES) || !defined(LC_ALL) || \
611              defined(USE_POSIX_2008_LOCALE) || defined(USE_THREADS) ) )
612        # define X
613        #endif /*   defined(DEBUGGING) ||
614                  ( defined(USE_LOCALE) &&
615                  ( defined(HAS_IGNORED_LOCALE_CATEGORIES) || !defined(LC_ALL) ||
616                    defined(USE_POSIX_2008_LOCALE) || defined(USE_THREADS) ) ) */
617        EOF
618}
619
620done_testing();
621