From c15d9a8e130cd79e9d79a8ede5a8f431ead5216f Mon Sep 17 00:00:00 2001 From: Ralf Wildenhues Date: Sun, 19 Oct 2008 19:54:12 +0200 Subject: [PATCH] Fix DisjConditions module to be thread-safe for perl >= 5.7.2. Self-hashes of blessed references are not correctly transported through thread creation. This patch fixes that by recreating the hashes upon thread creation with a CLONE special subroutine, which is automatically invoked by new enough Perl versions. * lib/Automake/DisjConditions.pm (CLONE): New special subroutine to fix self hashes upon thread creation. * lib/Automake/tests/Condition-t.pl: New, sister test to Condition.pl, but spawns a new threads after each creation of a new condition; skip test if perl is too old or ithreads are not available. * lib/Automake/tests/DisjConditions-t.pl: Likewise. * lib/Automake/tests/Makefile.am (TESTS): Add them. Signed-off-by: Ralf Wildenhues --- ChangeLog | 16 + lib/Automake/DisjConditions.pm | 20 ++ lib/Automake/tests/Condition-t.pl | 300 +++++++++++++++++ lib/Automake/tests/DisjConditions-t.pl | 435 +++++++++++++++++++++++++ lib/Automake/tests/Makefile.am | 4 +- lib/Automake/tests/Makefile.in | 2 + 6 files changed, 776 insertions(+), 1 deletion(-) create mode 100644 lib/Automake/tests/Condition-t.pl create mode 100644 lib/Automake/tests/DisjConditions-t.pl diff --git a/ChangeLog b/ChangeLog index 6c9052956..9edc0572a 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,19 @@ +2008-10-19 Ralf Wildenhues + + Fix DisjConditions module to be thread-safe for perl >= 5.7.2. + Self-hashes of blessed references are not correctly transported + through thread creation. This patch fixes that by recreating + the hashes upon thread creation with a CLONE special subroutine, + which is automatically invoked by new enough Perl versions. + * lib/Automake/DisjConditions.pm (CLONE): New special + subroutine to fix self hashes upon thread creation. + * lib/Automake/tests/Condition-t.pl: New, sister test to + Condition.pl, but spawns a new threads after each creation of a + new condition; skip test if perl is too old or ithreads are not + available. + * lib/Automake/tests/DisjConditions-t.pl: Likewise. + * lib/Automake/tests/Makefile.am (TESTS): Add them. + 2008-10-18 Ralf Wildenhues Fix comment typos. diff --git a/lib/Automake/DisjConditions.pm b/lib/Automake/DisjConditions.pm index 1f09c0fd4..ae759e27c 100644 --- a/lib/Automake/DisjConditions.pm +++ b/lib/Automake/DisjConditions.pm @@ -192,6 +192,26 @@ sub new ($;@) return $self; } + +=item C + +Internal special subroutine to fix up the self hashes in +C<%_disjcondition_singletons> upon thread creation. C is invoked +automatically with ithreads from Perl 5.7.2 or later, so if you use this +module with earlier versions of Perl, it is not thread-safe. + +=cut + +sub CLONE +{ + foreach my $self (values %_disjcondition_singletons) + { + my %h = map { $_ => $_ } @{$self->{'conds'}}; + $self->{'hash'} = \%h; + } +} + + =item C<@conds = $set-Econds> Return the list of C objects involved in C<$set>. diff --git a/lib/Automake/tests/Condition-t.pl b/lib/Automake/tests/Condition-t.pl new file mode 100644 index 000000000..8b632fa8f --- /dev/null +++ b/lib/Automake/tests/Condition-t.pl @@ -0,0 +1,300 @@ +# Copyright (C) 2001, 2002, 2003, 2008 Free Software Foundation, Inc. +# +# This file is part of GNU Automake. +# +# GNU Automake 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 3, or (at your option) +# any later version. +# +# GNU Automake 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}) + { + use threads; + } + else + { + exit 77; + } +} +use Automake::Condition qw/TRUE FALSE/; + +sub test_basics () +{ + my @tests = (# [[Conditions], is_true?, is_false?, string, subst-string] + [[], 1, 0, 'TRUE', ''], + [['TRUE'], 1, 0, 'TRUE', ''], + [['FALSE'], 0, 1, 'FALSE', '#'], + [['A_TRUE'], 0, 0, 'A_TRUE', '@A_TRUE@'], + [['A_TRUE', 'B_FALSE'], + 0, 0, 'A_TRUE B_FALSE', '@A_TRUE@@B_FALSE@'], + [['B_TRUE', 'FALSE'], 0, 1, 'FALSE', '#'], + [['B_TRUE', 'B_FALSE'], 0, 1, 'FALSE', '#']); + + for (@tests) + { + my $a = new Automake::Condition @{$_->[0]}; + return 1 + if threads->new(sub { + return 1 if $_->[1] != $a->true; + return 1 if $_->[1] != ($a == TRUE); + return 1 if $_->[2] != $a->false; + return 1 if $_->[2] != ($a == FALSE); + return 1 if $_->[3] ne $a->string; + return 1 if $_->[4] ne $a->subst_string; + })->join; + } + return 0; +} + +sub test_true_when () +{ + my $failed = 0; + + my @tests = (# [When, + # [Implied-Conditions], + # [Not-Implied-Conditions]] + [['TRUE'], + [['TRUE']], + [['A_TRUE'], ['A_TRUE', 'B_FALSE'], ['FALSE']]], + [['A_TRUE'], + [['TRUE'], ['A_TRUE']], + [['A_TRUE', 'B_FALSE'], ['FALSE']]], + [['A_TRUE', 'B_FALSE'], + [['TRUE'], ['A_TRUE'], ['B_FALSE'], ['A_TRUE', 'B_FALSE']], + [['FALSE'], ['C_FALSE'], ['C_FALSE', 'A_TRUE']]]); + + for my $t (@tests) + { + my $a = new Automake::Condition @{$t->[0]}; + return 1 + if threads->new(sub { + for my $u (@{$t->[1]}) + { + my $b = new Automake::Condition @$u; + return threads->new(sub { + if (! $b->true_when ($a)) + { + print "`" . $b->string . + "' not implied by `" . $a->string . "'?\n"; + $failed = 1; + } + })->join; + } + for my $u (@{$t->[2]}) + { + my $b = new Automake::Condition @$u; + return threads->new(sub { + if ($b->true_when ($a)) + { + print "`" . $b->string . + "' implied by `" . $a->string . "'?\n"; + $failed = 1; + } + + return threads->new(sub { + return 1 if $b->true_when ($a); + })->join; + })->join; + } + })->join; + } + return $failed; +} + +sub test_reduce_and () +{ + my @tests = (# If no conditions are given, TRUE should be returned + [[], ["TRUE"]], + # An empty condition is TRUE + [[""], ["TRUE"]], + # A single condition should be passed through unchanged + [["FOO"], ["FOO"]], + [["FALSE"], ["FALSE"]], + [["TRUE"], ["TRUE"]], + # TRUE and false should be discarded and overwhelm + # the result, respectively + [["FOO", "TRUE"], ["FOO"]], + [["FOO", "FALSE"], ["FALSE"]], + # Repetitions should be removed + [["FOO", "FOO"], ["FOO"]], + [["TRUE", "FOO", "FOO"], ["FOO"]], + [["FOO", "TRUE", "FOO"], ["FOO"]], + [["FOO", "FOO", "TRUE"], ["FOO"]], + # Two different conditions should be preserved, + # but TRUEs should be removed + [["FOO", "BAR"], ["BAR,FOO"]], + [["TRUE", "FOO", "BAR"], ["BAR,FOO"]], + [["FOO", "TRUE", "BAR"], ["BAR,FOO"]], + [["FOO", "BAR", "TRUE"], ["BAR,FOO"]], + # A condition implied by another condition should be removed. + [["FOO BAR", "BAR"], ["FOO BAR"]], + [["BAR", "FOO BAR"], ["FOO BAR"]], + [["TRUE", "FOO BAR", "BAR"], ["FOO BAR"]], + [["FOO BAR", "TRUE", "BAR"], ["FOO BAR"]], + [["FOO BAR", "BAR", "TRUE"], ["FOO BAR"]], + + [["BAR FOO", "BAR"], ["BAR FOO"]], + [["BAR", "BAR FOO"], ["BAR FOO"]], + [["TRUE", "BAR FOO", "BAR"], ["BAR FOO"]], + [["BAR FOO", "TRUE", "BAR"], ["BAR FOO"]], + [["BAR FOO", "BAR", "TRUE"], ["BAR FOO"]], + + # Check that reduction happens even when there are + # two conditions to remove. + [["FOO", "FOO BAR", "BAR"], ["FOO BAR"]], + [["FOO", "FOO BAR", "BAZ", "FOO BAZ"], ["FOO BAR", "FOO BAZ"]], + [["FOO", "FOO BAR", "BAZ", "FOO BAZ", "FOO BAZ BAR"], + ["FOO BAZ BAR"]], + + # Duplicated conditionals should be removed. + [["FOO", "BAR", "BAR"], ["BAR,FOO"]], + + # Equivalent conditions in different forms should be + # reduced: which one is left is unfortunately order + # dependent. + [["BAR FOO", "FOO BAR"], ["FOO BAR"]], + [["FOO BAR", "BAR FOO"], ["BAR FOO"]]); + + my $failed = 0; + foreach (@tests) + { + my ($inref, $outref) = @$_; + my @inconds = map { new Automake::Condition $_ } @$inref; + return 1 + if threads->new(sub { + my @outconds = map { (new Automake::Condition $_)->string } @$outref; + return threads->new(sub { + my @res = + map { $_->string } (Automake::Condition::reduce_and (@inconds)); + return threads->new(sub { + my $result = join (",", sort @res); + my $exresult = join (",", @outconds); + + if ($result ne $exresult) + { + print '"' . join(",", @$inref) . '" => "' . + $result . '" expected "' . + $exresult . '"' . "\n"; + $failed = 1; + } + return $failed; + })->join; + })->join; + })->join; + } + return $failed; +} + +sub test_reduce_or () +{ + my @tests = (# If no conditions are given, FALSE should be returned + [[], ["FALSE"]], + # An empty condition is TRUE + [[""], ["TRUE"]], + # A single condition should be passed through unchanged + [["FOO"], ["FOO"]], + [["FALSE"], ["FALSE"]], + [["TRUE"], ["TRUE"]], + # FALSE and TRUE should be discarded and overwhelm + # the result, respectively + [["FOO", "TRUE"], ["TRUE"]], + [["FOO", "FALSE"], ["FOO"]], + # Repetitions should be removed + [["FOO", "FOO"], ["FOO"]], + [["FALSE", "FOO", "FOO"], ["FOO"]], + [["FOO", "FALSE", "FOO"], ["FOO"]], + [["FOO", "FOO", "FALSE"], ["FOO"]], + # Two different conditions should be preserved, + # but FALSEs should be removed + [["FOO", "BAR"], ["BAR,FOO"]], + [["FALSE", "FOO", "BAR"], ["BAR,FOO"]], + [["FOO", "FALSE", "BAR"], ["BAR,FOO"]], + [["FOO", "BAR", "FALSE"], ["BAR,FOO"]], + # A condition implying another condition should be removed. + [["FOO BAR", "BAR"], ["BAR"]], + [["BAR", "FOO BAR"], ["BAR"]], + [["FALSE", "FOO BAR", "BAR"], ["BAR"]], + [["FOO BAR", "FALSE", "BAR"], ["BAR"]], + [["FOO BAR", "BAR", "FALSE"], ["BAR"]], + + [["BAR FOO", "BAR"], ["BAR"]], + [["BAR", "BAR FOO"], ["BAR"]], + [["FALSE", "BAR FOO", "BAR"], ["BAR"]], + [["BAR FOO", "FALSE", "BAR"], ["BAR"]], + [["BAR FOO", "BAR", "FALSE"], ["BAR"]], + + # Check that reduction happens even when there are + # two conditions to remove. + [["FOO", "FOO BAR", "BAR"], ["BAR,FOO"]], + [["FOO", "FOO BAR", "BAZ", "FOO BAZ"], ["BAZ,FOO"]], + [["FOO", "FOO BAR", "BAZ", "FOO BAZ", "FOO BAZ BAR"], + ["BAZ,FOO"]], + + # Duplicated conditionals should be removed. + [["FOO", "BAR", "BAR"], ["BAR,FOO"]], + + # Equivalent conditions in different forms should be + # reduced: which one is left is unfortunately order + # dependent. + [["BAR FOO", "FOO BAR"], ["FOO BAR"]], + [["FOO BAR", "BAR FOO"], ["BAR FOO"]]); + + my $failed = 0; + foreach (@tests) + { + my ($inref, $outref) = @$_; + my @inconds = map { new Automake::Condition $_ } @$inref; + return 1 + if threads->new(sub { + my @outconds = map { (new Automake::Condition $_)->string } @$outref; + return threads->new(sub { + my @res = + map { $_->string } (Automake::Condition::reduce_or (@inconds)); + return threads->new(sub { + my $result = join (",", sort @res); + my $exresult = join (",", @outconds); + + if ($result ne $exresult) + { + print '"' . join(",", @$inref) . '" => "' . + $result . '" expected "' . + $exresult . '"' . "\n"; + $failed = 1; + } + return $failed; + })->join; + })->join; + })->join; + } + return $failed; +} + +exit (test_basics || test_true_when || test_reduce_and || test_reduce_or); + +### Setup "GNU" style for perl-mode and cperl-mode. +## Local Variables: +## perl-indent-level: 2 +## perl-continued-statement-offset: 2 +## perl-continued-brace-offset: 0 +## perl-brace-offset: 0 +## perl-brace-imaginary-offset: 0 +## perl-label-offset: -2 +## cperl-indent-level: 2 +## cperl-brace-offset: 0 +## cperl-continued-brace-offset: 0 +## cperl-label-offset: -2 +## cperl-extra-newline-before-brace: t +## cperl-merge-trailing-else: nil +## cperl-continued-statement-offset: 2 +## End: diff --git a/lib/Automake/tests/DisjConditions-t.pl b/lib/Automake/tests/DisjConditions-t.pl new file mode 100644 index 000000000..2b8ca3e3b --- /dev/null +++ b/lib/Automake/tests/DisjConditions-t.pl @@ -0,0 +1,435 @@ +# Copyright (C) 2001, 2002, 2003, 2008 Free Software Foundation, Inc. +# +# This file is part of GNU Automake. +# +# GNU Automake 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 3, or (at your option) +# any later version. +# +# GNU Automake 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}) + { + use threads; + } + else + { + exit 77; + } +} +use Automake::Condition qw/TRUE FALSE/; +use Automake::DisjConditions; + +sub test_basics () +{ + my $cond = new Automake::Condition "COND1_TRUE", "COND2_FALSE"; + return threads->new (sub { + my $other = new Automake::Condition "COND3_FALSE"; + return threads->new (sub { + my $set1 = new Automake::DisjConditions $cond, $other; + return threads->new (sub { + my $set2 = new Automake::DisjConditions $other, $cond; + 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; + })->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); + +### Setup "GNU" style for perl-mode and cperl-mode. +## Local Variables: +## perl-indent-level: 2 +## perl-continued-statement-offset: 2 +## perl-continued-brace-offset: 0 +## perl-brace-offset: 0 +## perl-brace-imaginary-offset: 0 +## perl-label-offset: -2 +## cperl-indent-level: 2 +## cperl-brace-offset: 0 +## cperl-continued-brace-offset: 0 +## cperl-label-offset: -2 +## cperl-extra-newline-before-brace: t +## cperl-merge-trailing-else: nil +## cperl-continued-statement-offset: 2 +## End: diff --git a/lib/Automake/tests/Makefile.am b/lib/Automake/tests/Makefile.am index 705f19535..529a02f4d 100644 --- a/lib/Automake/tests/Makefile.am +++ b/lib/Automake/tests/Makefile.am @@ -1,6 +1,6 @@ ## Process this file with automake to create Makefile.in -## Copyright (C) 2002, 2003 Free Software Foundation, Inc. +## Copyright (C) 2002, 2003, 2008 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 @@ -18,7 +18,9 @@ TESTS_ENVIRONMENT = $(PERL) -Mstrict -I $(top_srcdir)/lib -w TESTS = \ Condition.pl \ +Condition-t.pl \ DisjConditions.pl \ +DisjConditions-t.pl \ Version.pl \ Wrap.pl diff --git a/lib/Automake/tests/Makefile.in b/lib/Automake/tests/Makefile.in index 2c52e8209..087301fae 100644 --- a/lib/Automake/tests/Makefile.in +++ b/lib/Automake/tests/Makefile.in @@ -154,7 +154,9 @@ top_srcdir = @top_srcdir@ TESTS_ENVIRONMENT = $(PERL) -Mstrict -I $(top_srcdir)/lib -w TESTS = \ Condition.pl \ +Condition-t.pl \ DisjConditions.pl \ +DisjConditions-t.pl \ Version.pl \ Wrap.pl -- 2.47.2