Author: britter Date: Tue Oct 15 18:31:40 2013 New Revision: 1532476 URL: http://svn.apache.org/r1532476 Log: LANG-921 - BooleanUtils.xor(boolean...) produces wrong results
Modified: commons/proper/lang/trunk/src/changes/changes.xml commons/proper/lang/trunk/src/main/java/org/apache/commons/lang3/BooleanUtils.java commons/proper/lang/trunk/src/test/java/org/apache/commons/lang3/BooleanUtilsTest.java Modified: commons/proper/lang/trunk/src/changes/changes.xml URL: http://svn.apache.org/viewvc/commons/proper/lang/trunk/src/changes/changes.xml?rev=1532476&r1=1532475&r2=1532476&view=diff ============================================================================== --- commons/proper/lang/trunk/src/changes/changes.xml (original) +++ commons/proper/lang/trunk/src/changes/changes.xml Tue Oct 15 18:31:40 2013 @@ -22,6 +22,7 @@ <body> <release version="3.2" date="TBA" description="Next release"> + <action issue="LANG-921" type="fix" dev="britter">BooleanUtils.xor(boolean...) produces wrong results</action> <action issue="LANG-910" type="update" due-to="Timur Yarosh">StringUtils.normalizeSpace now handles non-breaking spaces (Unicode 00A0)</action> <action issue="LANG-804" type="update" dev="britter" due-to="Allon Mureinik">Redundant check for zero in HashCodeBuilder ctor</action> <action issue="LANG-893" type="add" dev="oheger" due-to="Woonsan Ko">StrSubstitutor now supports default values for variables</action> Modified: commons/proper/lang/trunk/src/main/java/org/apache/commons/lang3/BooleanUtils.java URL: http://svn.apache.org/viewvc/commons/proper/lang/trunk/src/main/java/org/apache/commons/lang3/BooleanUtils.java?rev=1532476&r1=1532475&r2=1532476&view=diff ============================================================================== --- commons/proper/lang/trunk/src/main/java/org/apache/commons/lang3/BooleanUtils.java (original) +++ commons/proper/lang/trunk/src/main/java/org/apache/commons/lang3/BooleanUtils.java Tue Oct 15 18:31:40 2013 @@ -1028,14 +1028,6 @@ public class BooleanUtils { * BooleanUtils.xor(true, false) = true * </pre> * - * <p>Note that this method behaves different from using the binary XOR operator (^). Instead of combining the given - * booleans using the XOR operator from left to right, this method counts the appearances of true in the given - * array. It will only return true if exactly one boolean in the given array is true:</p> - * <pre> - * true ^ true ^ false ^ true = true - * BooleanUtils.xor(true, true, false, true) = false - * </pre> - * * @param array an array of {@code boolean}s * @return {@code true} if the xor is successful. * @throws IllegalArgumentException if {@code array} is {@code null} @@ -1050,22 +1042,13 @@ public class BooleanUtils { throw new IllegalArgumentException("Array is empty"); } - // Loops through array, comparing each item - int trueCount = 0; + // false if the neutral element of the xor operator + boolean result = false; for (final boolean element : array) { - // If item is true, and trueCount is < 1, increments count - // Else, xor fails - if (element) { - if (trueCount < 1) { - trueCount++; - } else { - return false; - } - } + result ^= element; } - // Returns true if there was exactly 1 true item - return trueCount == 1; + return result; } /** @@ -1077,9 +1060,6 @@ public class BooleanUtils { * BooleanUtils.xor(new Boolean[] { Boolean.TRUE, Boolean.FALSE }) = Boolean.TRUE * </pre> * - * <p>Note that this method behaves different from using the binary XOR operator (^). See - * {@link #xor(boolean...)}.</p> - * * @param array an array of {@code Boolean}s * @return {@code true} if the xor is successful. * @throws IllegalArgumentException if {@code array} is {@code null} Modified: commons/proper/lang/trunk/src/test/java/org/apache/commons/lang3/BooleanUtilsTest.java URL: http://svn.apache.org/viewvc/commons/proper/lang/trunk/src/test/java/org/apache/commons/lang3/BooleanUtilsTest.java?rev=1532476&r1=1532475&r2=1532476&view=diff ============================================================================== --- commons/proper/lang/trunk/src/test/java/org/apache/commons/lang3/BooleanUtilsTest.java (original) +++ commons/proper/lang/trunk/src/test/java/org/apache/commons/lang3/BooleanUtilsTest.java Tue Oct 15 18:31:40 2013 @@ -446,56 +446,68 @@ public class BooleanUtilsTest { @Test public void testXor_primitive_validInput_2items() { - assertTrue( - "True result for (true, true)", - ! BooleanUtils.xor(new boolean[] { true, true })); - - assertTrue( - "True result for (false, false)", - ! BooleanUtils.xor(new boolean[] { false, false })); - - assertTrue( - "False result for (true, false)", + assertEquals( + "true ^ true", + true ^ true , + BooleanUtils.xor(new boolean[] { true, true })); + + assertEquals( + "false ^ false", + false ^ false, + BooleanUtils.xor(new boolean[] { false, false })); + + assertEquals( + "true ^ false", + true ^ false, BooleanUtils.xor(new boolean[] { true, false })); - assertTrue( - "False result for (false, true)", + assertEquals( + "false ^ true", + false ^ true, BooleanUtils.xor(new boolean[] { false, true })); } @Test public void testXor_primitive_validInput_3items() { - assertTrue( - "False result for (false, false, true)", + assertEquals( + "false ^ false ^ false", + false ^ false ^ false, + BooleanUtils.xor(new boolean[] { false, false, false })); + + assertEquals( + "false ^ false ^ true", + false ^ false ^ true, BooleanUtils.xor(new boolean[] { false, false, true })); - assertTrue( - "False result for (false, true, false)", + assertEquals( + "false ^ true ^ false", + false ^ true ^ false, BooleanUtils.xor(new boolean[] { false, true, false })); - assertTrue( - "False result for (true, false, false)", + assertEquals( + "false ^ true ^ true", + false ^ true ^ true, + BooleanUtils.xor(new boolean[] { false, true, true })); + + assertEquals( + "true ^ false ^ false", + true ^ false ^ false, BooleanUtils.xor(new boolean[] { true, false, false })); - assertTrue( - "True result for (true, true, true)", - ! BooleanUtils.xor(new boolean[] { true, true, true })); - - assertTrue( - "True result for (false, false)", - ! BooleanUtils.xor(new boolean[] { false, false, false })); - - assertTrue( - "True result for (true, true, false)", - ! BooleanUtils.xor(new boolean[] { true, true, false })); - - assertTrue( - "True result for (true, false, true)", - ! BooleanUtils.xor(new boolean[] { true, false, true })); - - assertTrue( - "False result for (false, true, true)", - ! BooleanUtils.xor(new boolean[] { false, true, true })); + assertEquals( + "true ^ false ^ true", + true ^ false ^ true, + BooleanUtils.xor(new boolean[] { true, false, true })); + + assertEquals( + "true ^ true ^ false", + true ^ true ^ false, + BooleanUtils.xor(new boolean[] { true, true, false })); + + assertEquals( + "true ^ true ^ true", + true ^ true ^ true, + BooleanUtils.xor(new boolean[] { true, true, true })); } @Test(expected = IllegalArgumentException.class) @@ -515,35 +527,50 @@ public class BooleanUtilsTest { @Test public void testXor_object_validInput_2items() { - assertTrue( - "True result for (true, true)", - ! BooleanUtils - .xor(new Boolean[] { Boolean.TRUE, Boolean.TRUE }) + assertEquals( + "false ^ false", + false ^ false, + BooleanUtils + .xor(new Boolean[] { Boolean.FALSE, Boolean.FALSE }) .booleanValue()); - assertTrue( - "True result for (false, false)", - ! BooleanUtils - .xor(new Boolean[] { Boolean.FALSE, Boolean.FALSE }) + assertEquals( + "false ^ true", + false ^ true, + BooleanUtils + .xor(new Boolean[] { Boolean.FALSE, Boolean.TRUE }) .booleanValue()); - assertTrue( - "False result for (true, false)", + assertEquals( + "true ^ false", + true ^ false, BooleanUtils .xor(new Boolean[] { Boolean.TRUE, Boolean.FALSE }) .booleanValue()); - assertTrue( - "False result for (false, true)", + assertEquals( + "true ^ true", + true ^ true, BooleanUtils - .xor(new Boolean[] { Boolean.FALSE, Boolean.TRUE }) + .xor(new Boolean[] { Boolean.TRUE, Boolean.TRUE }) .booleanValue()); } @Test public void testXor_object_validInput_3items() { - assertTrue( - "False result for (false, false, true)", + assertEquals( + "false ^ false ^ false", + false ^ false ^ false, + BooleanUtils.xor( + new Boolean[] { + Boolean.FALSE, + Boolean.FALSE, + Boolean.FALSE }) + .booleanValue()); + + assertEquals( + "false ^ false ^ true", + false ^ false ^ true, BooleanUtils .xor( new Boolean[] { @@ -552,8 +579,9 @@ public class BooleanUtilsTest { Boolean.TRUE }) .booleanValue()); - assertTrue( - "False result for (false, true, false)", + assertEquals( + "false ^ true ^ false", + false ^ true ^ false, BooleanUtils .xor( new Boolean[] { @@ -562,8 +590,9 @@ public class BooleanUtilsTest { Boolean.FALSE }) .booleanValue()); - assertTrue( - "False result for (true, false, false)", + assertEquals( + "true ^ false ^ false", + true ^ false ^ false, BooleanUtils .xor( new Boolean[] { @@ -572,47 +601,42 @@ public class BooleanUtilsTest { Boolean.FALSE }) .booleanValue()); - assertTrue( - "True result for (true, true, true)", - ! BooleanUtils - .xor(new Boolean[] { Boolean.TRUE, Boolean.TRUE, Boolean.TRUE }) - .booleanValue()); - - assertTrue( - "True result for (false, false)", - ! BooleanUtils.xor( - new Boolean[] { - Boolean.FALSE, - Boolean.FALSE, - Boolean.FALSE }) - .booleanValue()); - - assertTrue( - "True result for (true, true, false)", - ! BooleanUtils.xor( + assertEquals( + "true ^ false ^ true", + true ^ false ^ true, + BooleanUtils.xor( + new Boolean[] { + Boolean.TRUE, + Boolean.FALSE, + Boolean.TRUE }) + .booleanValue()); + + assertEquals( + "true ^ true ^ false", + true ^ true ^ false, + BooleanUtils.xor( new Boolean[] { Boolean.TRUE, Boolean.TRUE, Boolean.FALSE }) .booleanValue()); - assertTrue( - "True result for (true, false, true)", - ! BooleanUtils.xor( - new Boolean[] { - Boolean.TRUE, - Boolean.FALSE, - Boolean.TRUE }) - .booleanValue()); - - assertTrue( - "False result for (false, true, true)", - ! BooleanUtils.xor( + assertEquals( + "false ^ true ^ true", + false ^ true ^ true, + BooleanUtils.xor( new Boolean[] { Boolean.FALSE, Boolean.TRUE, Boolean.TRUE }) .booleanValue()); + + assertEquals( + "true ^ true ^ true", + true ^ true ^ true, + BooleanUtils + .xor(new Boolean[] { Boolean.TRUE, Boolean.TRUE, Boolean.TRUE }) + .booleanValue()); } // testAnd