# Copyright (C) 2001-2022 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 . 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; 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; } exit (test_basics || test_invert || test_simplify || test_sub_conditions || test_ambig);