]> git.ipfire.org Git - thirdparty/automake.git/commitdiff
Fix DisjConditions module to be thread-safe for perl >= 5.7.2.
authorRalf Wildenhues <Ralf.Wildenhues@gmx.de>
Sun, 19 Oct 2008 17:54:12 +0000 (19:54 +0200)
committerRalf Wildenhues <Ralf.Wildenhues@gmx.de>
Sun, 19 Oct 2008 17:54:12 +0000 (19:54 +0200)
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 <Ralf.Wildenhues@gmx.de>
ChangeLog
lib/Automake/DisjConditions.pm
lib/Automake/tests/Condition-t.pl [new file with mode: 0644]
lib/Automake/tests/DisjConditions-t.pl [new file with mode: 0644]
lib/Automake/tests/Makefile.am
lib/Automake/tests/Makefile.in

index 6c90529562665f697a24416253874a34ba359625..9edc0572a236cf475cb4584bd6e596cbf7ffbab6 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,19 @@
+2008-10-19  Ralf Wildenhues  <Ralf.Wildenhues@gmx.de>
+
+       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  <Ralf.Wildenhues@gmx.de>
 
        Fix comment typos.
index 1f09c0fd4142fbcd6aa89e8033ff0a52619b5ef8..ae759e27ca7f10f4ca55698e762bd9716fd8bedb 100644 (file)
@@ -192,6 +192,26 @@ sub new ($;@)
   return $self;
 }
 
+
+=item C<CLONE>
+
+Internal special subroutine to fix up the self hashes in
+C<%_disjcondition_singletons> upon thread creation.  C<CLONE> 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-E<gt>conds>
 
 Return the list of C<Condition> 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 (file)
index 0000000..8b632fa
--- /dev/null
@@ -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 <http://www.gnu.org/licenses/>.
+
+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 (file)
index 0000000..2b8ca3e
--- /dev/null
@@ -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 <http://www.gnu.org/licenses/>.
+
+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:
index 705f195354d031326a678f0703420e5f03c6a626..529a02f4d729bdcb443fc273a8e8c95b52f5beef 100644 (file)
@@ -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
 
index 2c52e82098b5c8896c06e709fa9eac33ec723330..087301faeab11eb389932c8f9e7f81f22cb08a0d 100644 (file)
@@ -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