| # -*- mode:perl -*- |
| # Copyright (C) 2001-2018 Free Software Foundation, Inc. |
| # |
| # This program is free software; you can redistribute it and/or modify |
| # it under the terms of the GNU General Public License as published by |
| # the Free Software Foundation; either version 2, or (at your option) |
| # any later version. |
| # |
| # This program is distributed in the hope that it will be useful, |
| # but WITHOUT ANY WARRANTY; without even the implied warranty of |
| # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| # GNU General Public License for more details. |
| # |
| # You should have received a copy of the GNU General Public License |
| # along with this program. If not, see <https://www.gnu.org/licenses/>. |
| |
| BEGIN { |
| use Config; |
| if (eval { require 5.007_002; } # for CLONE support |
| && $Config{useithreads} |
| && !$ENV{WANT_NO_THREADS}) |
| { |
| require threads; |
| import threads; |
| } |
| else |
| { |
| exit 77; |
| } |
| } |
| use Automake::Condition qw/TRUE FALSE/; |
| use Automake::DisjConditions; |
| use Test::Simple tests => 5; |
| |
| sub test_basics () |
| { |
| my $true = new Automake::DisjConditions TRUE; |
| my $false = new Automake::DisjConditions FALSE; |
| my $cond = new Automake::Condition "COND1_TRUE", "COND2_FALSE"; |
| return threads->new (sub { |
| my $other = new Automake::Condition "COND3_FALSE"; |
| my $another = new Automake::Condition "COND3_TRUE", "COND4_FALSE"; |
| return threads->new (sub { |
| my $set1 = new Automake::DisjConditions $cond, $other; |
| return threads->new (sub { |
| my $set2 = new Automake::DisjConditions $other, $cond; |
| my $set3 = new Automake::DisjConditions FALSE, $another; |
| return 1 unless $set1 == $set2; |
| return 1 if $set1->false; |
| return 1 if $set1->true; |
| return 1 unless (new Automake::DisjConditions)->false; |
| return 1 if (new Automake::DisjConditions)->true; |
| return 1 unless $true->human eq 'TRUE'; |
| return 1 unless $false->human eq 'FALSE'; |
| return 1 unless $set1->human eq "(COND1 and !COND2) or (!COND3)"; |
| return 1 unless $set2->human eq "(COND1 and !COND2) or (!COND3)"; |
| my $one_cond_human = $set1->one_cond->human; |
| return 1 unless $one_cond_human eq "!COND3" |
| || $one_cond_human eq "COND1 and !COND2"; |
| return 1 unless $set1->string eq "COND1_TRUE COND2_FALSE | COND3_FALSE"; |
| |
| my $merged1 = $set1->merge ($set2); |
| my $merged2 = $set1->merge ($cond); |
| my $mult1 = $set1->multiply ($set3); |
| return threads->new (sub { |
| my $mult2 = $set1->multiply ($another); |
| return threads->new (sub { |
| return 1 unless $merged1->simplify->string eq "COND1_TRUE COND2_FALSE | COND3_FALSE"; |
| return 1 unless $merged2->simplify->string eq "COND1_TRUE COND2_FALSE | COND3_FALSE"; |
| return 1 unless $mult1->string eq "COND1_TRUE COND2_FALSE COND3_TRUE COND4_FALSE"; |
| return 1 unless $mult1 == $mult2; |
| return 0; |
| })->join; |
| })->join; |
| })->join; |
| })->join; |
| })->join; |
| } |
| |
| sub build_set (@) |
| { |
| my @conds = @_; |
| my @set = (); |
| for my $cond (@conds) |
| { |
| push @set, new Automake::Condition @$cond; |
| } |
| return new Automake::DisjConditions @set; |
| } |
| |
| sub test_invert () |
| { |
| my @tests = ([[["FALSE"]], |
| [["TRUE"]]], |
| |
| [[["TRUE"]], |
| [["FALSE"]]], |
| |
| [[["COND1_TRUE", "COND2_TRUE"], |
| ["COND3_FALSE", "COND2_TRUE"]], |
| [["COND2_FALSE"], |
| ["COND1_FALSE", "COND3_TRUE"]]], |
| |
| [[["COND1_TRUE", "COND2_TRUE"], |
| ["TRUE"]], |
| [["FALSE"]]], |
| |
| [[["COND1_TRUE", "COND2_TRUE"], |
| ["FALSE"]], |
| [["COND1_FALSE"], |
| ["COND2_FALSE"]]], |
| |
| [[["COND1_TRUE"], |
| ["COND2_FALSE"]], |
| [["COND1_FALSE", "COND2_TRUE"]]] |
| ); |
| |
| for my $t (@tests) |
| { |
| my $set = build_set @{$t->[0]}; |
| return 1 |
| if threads->new(sub { |
| my $res = build_set @{$t->[1]}; |
| my $inv = $set->invert; |
| if ($inv != $res) |
| { |
| print " (I) " . $set->string . "\n\t" |
| . $inv->string . ' != ' . $res->string . "\n"; |
| return 1; |
| } |
| return 0 |
| })-> join; |
| } |
| return 0; |
| } |
| |
| sub test_simplify () |
| { |
| my @tests = ([[["FOO_TRUE", "BAR_FALSE", "BAZ_FALSE"], |
| ["FOO_TRUE", "BAR_FALSE", "BAZ_TRUE"]], |
| [["FOO_TRUE", "BAR_FALSE"]]], |
| |
| [[["FOO_TRUE", "BAR_FALSE", "BAZ_FALSE"], |
| ["FOO_TRUE", "BAR_FALSE", "BAZ_TRUE"], |
| ["FOO_TRUE", "BAR_TRUE"]], |
| [["FOO_TRUE"]]], |
| |
| [[["FOO_TRUE", "BAR_FALSE", "BAZ_FALSE"], |
| ["FOO_TRUE", "BAR_FALSE", "BAZ_TRUE"], |
| ["FOO_TRUE", "BAR_TRUE"], |
| ["FOO_FALSE"]], |
| [["TRUE"]]], |
| |
| [[["FOO_TRUE", "BAR_FALSE", "BAZ_FALSE"], |
| ["FOO_TRUE", "BAR_FALSE", "BAZ_TRUE"], |
| ["BAR_TRUE", "BAZ_TRUE"], |
| ["BAR_FALSE", "BAZ_TRUE"]], |
| [["BAZ_TRUE"], ["FOO_TRUE", "BAR_FALSE"]]], |
| |
| [[["FOO_TRUE", "BAR_FALSE", "BAZ_FALSE"], |
| ["FOO_TRUE", "BAR_FALSE", "BAZ_TRUE"], |
| ["BAR_TRUE", "BAZ_TRUE"], |
| ["BAR_FALSE", "BAZ_TRUE"], |
| ["FOO_FALSE"]], |
| [["FOO_FALSE"], ["BAZ_TRUE"], ["BAR_FALSE"]]], |
| |
| [[["B_TRUE"], |
| ["A_FALSE", "B_TRUE"]], |
| [["B_TRUE"]]], |
| |
| [[["B_TRUE"], |
| ["A_FALSE", "B_FALSE", "C_TRUE"], |
| ["A_FALSE", "B_FALSE", "C_FALSE"]], |
| [["A_FALSE"], ["B_TRUE"]]], |
| |
| [[["B_TRUE"], |
| ["A_FALSE", "B_FALSE", "C_TRUE"], |
| ["A_FALSE", "B_FALSE", "C_FALSE"], |
| ["A_TRUE", "B_FALSE"]], |
| [["TRUE"]]], |
| |
| [[["A_TRUE", "B_TRUE"], |
| ["A_TRUE", "B_FALSE"], |
| ["A_TRUE", "C_FALSE", "D_FALSE"]], |
| [["A_TRUE"]]], |
| |
| [[["A_FALSE", "B_FALSE", "C_FALSE", "D_TRUE", "E_FALSE"], |
| ["A_FALSE", "B_FALSE", "C_TRUE", "D_TRUE", "E_TRUE"], |
| ["A_FALSE", "B_TRUE", "C_TRUE", "D_FALSE", "E_TRUE"], |
| ["A_FALSE", "B_TRUE", "C_FALSE", "D_FALSE", "E_FALSE"], |
| ["A_TRUE", "B_TRUE", "C_FALSE", "D_FALSE", "E_FALSE"], |
| ["A_TRUE", "B_TRUE", "C_TRUE", "D_FALSE", "E_TRUE"], |
| ["A_TRUE", "B_FALSE", "C_TRUE", "D_TRUE", "E_TRUE"], |
| ["A_TRUE", "B_FALSE", "C_FALSE", "D_TRUE", "E_FALSE"]], |
| [ ["B_FALSE", "C_FALSE", "D_TRUE", "E_FALSE"], |
| ["B_FALSE", "C_TRUE", "D_TRUE", "E_TRUE"], |
| ["B_TRUE", "C_TRUE", "D_FALSE", "E_TRUE"], |
| ["B_TRUE", "C_FALSE", "D_FALSE", "E_FALSE"]]], |
| |
| [[["A_FALSE", "B_FALSE", "C_FALSE", "D_TRUE", "E_FALSE"], |
| ["A_FALSE", "B_FALSE", "C_TRUE", "D_TRUE", "E_TRUE"], |
| ["A_FALSE", "B_TRUE", "C_TRUE", "D_FALSE", "E_TRUE"], |
| ["A_FALSE", "B_TRUE", "C_FALSE", "D_FALSE", "E_FALSE"], |
| ["A_TRUE", "B_TRUE", "C_FALSE", "D_FALSE", "E_FALSE"], |
| ["A_TRUE", "B_TRUE", "C_TRUE", "D_FALSE", "E_TRUE"], |
| ["A_TRUE", "B_FALSE", "C_TRUE", "D_TRUE", "E_TRUE"], |
| ["A_TRUE", "B_FALSE", "C_FALSE", "D_TRUE", "E_FALSE"], |
| ["A_FALSE", "B_FALSE", "C_FALSE", "D_FALSE", "E_FALSE"], |
| ["A_FALSE", "B_FALSE", "C_TRUE", "D_FALSE", "E_TRUE"], |
| ["A_FALSE", "B_TRUE", "C_TRUE", "D_TRUE", "E_TRUE"], |
| ["A_FALSE", "B_TRUE", "C_FALSE", "D_TRUE", "E_FALSE"], |
| ["A_TRUE", "B_TRUE", "C_FALSE", "D_TRUE", "E_FALSE"], |
| ["A_TRUE", "B_TRUE", "C_TRUE", "D_TRUE", "E_TRUE"], |
| ["A_TRUE", "B_FALSE", "C_TRUE", "D_FALSE", "E_TRUE"], |
| ["A_TRUE", "B_FALSE", "C_FALSE", "D_FALSE", "E_FALSE"]], |
| [["C_FALSE", "E_FALSE"], |
| ["C_TRUE", "E_TRUE"]]], |
| |
| [[["A_FALSE"], |
| ["A_TRUE", "B_FALSE"], |
| ["A_TRUE", "B_TRUE", "C_FALSE"], |
| ["A_TRUE", "B_TRUE", "C_TRUE", "D_FALSE"], |
| ["A_TRUE", "B_TRUE", "C_TRUE", "D_TRUE", "E_FALSE"], |
| ["A_TRUE", "B_TRUE", "C_TRUE", "D_TRUE", "E_TRUE", "F_FALSE"], |
| ["A_TRUE", "B_TRUE", "C_TRUE", "D_TRUE", "E_TRUE"]], |
| [["TRUE"]]], |
| |
| # Simplify should work with up to 31 variables. |
| [[["V01_TRUE", "V02_TRUE", "V03_TRUE", "V04_TRUE", "V05_TRUE", |
| "V06_TRUE", "V07_TRUE", "V08_TRUE", "V09_TRUE", "V10_TRUE", |
| "V11_TRUE", "V12_TRUE", "V13_TRUE", "V14_TRUE", "V15_TRUE", |
| "V16_TRUE", "V17_TRUE", "V18_TRUE", "V19_TRUE", "V20_TRUE", |
| "V21_TRUE", "V22_TRUE", "V23_TRUE", "V24_TRUE", "V25_TRUE", |
| "V26_TRUE", "V27_TRUE", "V28_TRUE", "V29_TRUE", "V30_TRUE", |
| "V31_TRUE"], |
| ["V01_TRUE", "V02_TRUE", "V03_TRUE", "V04_TRUE", "V05_TRUE", |
| "V06_TRUE", "V07_TRUE", "V08_TRUE", "V09_TRUE", "V10_TRUE", |
| "V11_TRUE", "V12_TRUE", "V13_TRUE", "V14_TRUE", "V15_TRUE", |
| "V16_TRUE", "V17_TRUE", "V18_TRUE", "V19_TRUE", "V20_TRUE", |
| "V21_TRUE", "V22_TRUE", "V23_TRUE", "V24_TRUE", "V25_TRUE", |
| "V26_TRUE", "V27_TRUE", "V28_TRUE", "V29_TRUE", "V30_TRUE", |
| "V31_FALSE"], |
| ["V01_FALSE","V02_TRUE", "V03_TRUE", "V04_TRUE", "V05_TRUE", |
| "V06_TRUE", "V07_TRUE", "V08_TRUE", "V09_TRUE", "V10_TRUE", |
| "V11_TRUE", "V12_TRUE", "V13_TRUE", "V14_TRUE", "V15_TRUE", |
| "V16_TRUE", "V17_TRUE", "V18_TRUE", "V19_TRUE", "V20_TRUE", |
| "V21_TRUE", "V22_TRUE", "V23_TRUE", "V24_TRUE", "V25_TRUE", |
| "V26_TRUE", "V27_TRUE", "V28_TRUE", "V29_TRUE", "V30_TRUE", |
| "V31_TRUE"], |
| ["V01_FALSE","V02_TRUE", "V03_TRUE", "V04_TRUE", "V05_TRUE", |
| "V06_TRUE", "V07_TRUE", "V08_TRUE", "V09_TRUE", "V10_TRUE", |
| "V11_TRUE", "V12_TRUE", "V13_TRUE", "V14_TRUE", "V15_TRUE", |
| "V16_TRUE", "V17_TRUE", "V18_TRUE", "V19_TRUE", "V20_TRUE", |
| "V21_TRUE", "V22_TRUE", "V23_TRUE", "V24_TRUE", "V25_TRUE", |
| "V26_TRUE", "V27_TRUE", "V28_TRUE", "V29_TRUE", "V30_TRUE", |
| "V31_FALSE"]], |
| [[ "V02_TRUE", "V03_TRUE", "V04_TRUE", "V05_TRUE", |
| "V06_TRUE", "V07_TRUE", "V08_TRUE", "V09_TRUE", "V10_TRUE", |
| "V11_TRUE", "V12_TRUE", "V13_TRUE", "V14_TRUE", "V15_TRUE", |
| "V16_TRUE", "V17_TRUE", "V18_TRUE", "V19_TRUE", "V20_TRUE", |
| "V21_TRUE", "V22_TRUE", "V23_TRUE", "V24_TRUE", "V25_TRUE", |
| "V26_TRUE", "V27_TRUE", "V28_TRUE", "V29_TRUE", "V30_TRUE" |
| ]]]); |
| |
| for my $t (@tests) |
| { |
| my $set = build_set @{$t->[0]}; |
| return 1 |
| if threads->new(sub { |
| my $res = build_set @{$t->[1]}; |
| return threads->new(sub { |
| |
| # Make sure simplify() yields the expected result. |
| my $sim = $set->simplify; |
| return threads->new(sub { |
| if ($sim != $res) |
| { |
| print " (S1) " . $set->string . "\n\t" |
| . $sim->string . ' != ' . $res->string . "\n"; |
| return 1; |
| } |
| |
| # Make sure simplify() is idempotent. |
| my $sim2 = $sim->simplify; |
| return threads->new(sub { |
| if ($sim2 != $sim) |
| { |
| print " (S2) " . $sim->string . "\n\t" |
| . $sim2->string . ' != ' . $sim->string . "\n"; |
| return 1; |
| } |
| |
| # Also exercise invert() while we are at it. |
| |
| my $inv1 = $set->invert->simplify; |
| return threads->new(sub { |
| my $inv2 = $sim->invert->simplify; |
| return threads->new(sub { |
| if ($inv1 != $inv2) |
| { |
| print " (S3) " . $set->string . ", " . $sim->string . "\n\t" |
| . $inv1->string . ' -= ' . $inv2->string . "\n"; |
| return 1; |
| } |
| })->join; |
| })->join; |
| })->join; |
| })->join; |
| })->join; |
| })->join; |
| } |
| |
| return 0; |
| } |
| |
| sub test_sub_conditions () |
| { |
| my @tests = ([[["FOO_TRUE", "BAR_FALSE", "BAZ_FALSE"], |
| ["FOO_TRUE", "BAR_FALSE", "BAZ_TRUE"], |
| ["FOO_FALSE"]], |
| ["FOO_TRUE"], |
| [["BAR_FALSE", "BAZ_FALSE"], |
| ["BAR_FALSE", "BAZ_TRUE"]]], |
| |
| [[["FOO_TRUE", "BAR_FALSE", "BAZ_FALSE"], |
| ["FOO_TRUE", "BAR_FALSE", "BAZ_TRUE"], |
| ["FOO_FALSE"]], |
| ["FOO_TRUE", "BAR_FALSE"], |
| [["BAZ_FALSE"], |
| ["BAZ_TRUE"]]], |
| |
| [[["FOO_TRUE", "BAR_FALSE", "BAZ_FALSE"], |
| ["FOO_TRUE", "BAR_FALSE", "BAZ_TRUE"], |
| ["FOO_FALSE"]], |
| ["FOO_TRUE", "BAR_TRUE"], |
| [["FALSE"]]], |
| |
| [[["FOO_TRUE", "BAR_FALSE", "BAZ_FALSE"], |
| ["FOO_TRUE", "BAZ_TRUE"], |
| ["FOO_FALSE"]], |
| ["FOO_TRUE", "BAR_TRUE"], |
| [["BAZ_TRUE"]]], |
| |
| [[["FOO_TRUE", "BAR_FALSE"], |
| ["FOO_TRUE", "BAR_TRUE"]], |
| ["FOO_TRUE", "BAR_TRUE"], |
| [["TRUE"]]], |
| |
| [[["TRUE"]], |
| ["TRUE"], |
| [["TRUE"]]], |
| |
| [[["FALSE"]], |
| ["TRUE"], |
| [["FALSE"]]], |
| |
| [[["FALSE"]], |
| ["FALSE"], |
| [["FALSE"]]]); |
| |
| for my $t (@tests) |
| { |
| my $t1 = build_set @{$t->[0]}; |
| return 1 |
| if threads->new(sub { |
| my $t2 = new Automake::Condition @{$t->[1]}; |
| return threads->new(sub { |
| my $t3 = build_set @{$t->[2]}; |
| return threads->new(sub { |
| |
| # Make sure sub_conditions() yields the expected result. |
| my $s = $t1->sub_conditions ($t2); |
| threads->new(sub { |
| if ($s != $t3) |
| { |
| print " (SC) " . $t1->string . "\n\t" |
| . $s->string . ' != ' . $t3->string . "\n"; |
| return 1; |
| } |
| })->join; |
| })->join; |
| })->join; |
| })->join; |
| } |
| } |
| |
| sub test_ambig () |
| { |
| my @tests = ([[["TRUE"]], |
| ["TRUE"], |
| "multiply defined"], |
| [[["C1_TRUE"]], |
| ["C1_TRUE"], |
| "multiply defined"], |
| [[["TRUE"]], |
| ["C1_FALSE"], |
| "which includes"], |
| [[["C1_TRUE"]], |
| ["C1_TRUE", "C2_TRUE"], |
| "which includes"], |
| [[["C1_TRUE", "C2_TRUE"]], |
| ["C2_TRUE"], |
| "which is included in"], |
| [[["C1_TRUE"]], |
| ["C2_TRUE"], |
| ''], |
| [[["C1_TRUE"], |
| ["C2_FALSE"]], |
| ["C1_FALSE", "C2_TRUE"], |
| '']); |
| |
| my $failed = 0; |
| for my $t (@tests) |
| { |
| my $t1 = build_set @{$t->[0]}; |
| $failed = 1 |
| if threads->new(sub { |
| my $t2 = new Automake::Condition @{$t->[1]}; |
| my $t3 = $t->[2]; |
| return threads->new(sub { |
| my ($ans, $cond) = $t1->ambiguous_p ("FOO", $t2); |
| return threads->new(sub { |
| if ($t3 && $ans !~ /FOO.*$t3/) |
| { |
| print " (A1) " . $t1->string . " vs. " . $t2->string . "\n\t" |
| . "Error message '$ans' does not match '$t3'\n"; |
| return 1; |
| } |
| if (!$t3 && $ans ne '') |
| { |
| print " (A2) " . $t1->string . " vs. " . $t2->string . "\n\t" |
| . "Unexpected error message: $ans\n"; |
| return 1; |
| } |
| })->join; |
| })->join; |
| })->join; |
| } |
| return $failed; |
| } |
| |
| ok (test_basics == 0, 'Basic tests'); |
| ok (test_invert == 0, 'Test inverts'); |
| ok (test_simplify == 0, 'Test condition simplifications'); |
| ok (test_sub_conditions == 0, 'Test sub conditions'); |
| ok (test_ambig == 0, 'Test ambiguous conditions'); |