LANG-921 - BooleanUtils.xor(boolean...) produces wrong results

git-svn-id: https://svn.apache.org/repos/asf/commons/proper/lang/trunk@1532476 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Benedikt Ritter 2013-10-15 18:31:40 +00:00
parent a01e450694
commit aadbea734d
3 changed files with 111 additions and 106 deletions

View File

@ -22,6 +22,7 @@
<body> <body>
<release version="3.2" date="TBA" description="Next release"> <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-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-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> <action issue="LANG-893" type="add" dev="oheger" due-to="Woonsan Ko">StrSubstitutor now supports default values for variables</action>

View File

@ -1028,14 +1028,6 @@ public class BooleanUtils {
* BooleanUtils.xor(true, false) = true * BooleanUtils.xor(true, false) = true
* </pre> * </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 * @param array an array of {@code boolean}s
* @return {@code true} if the xor is successful. * @return {@code true} if the xor is successful.
* @throws IllegalArgumentException if {@code array} is {@code null} * @throws IllegalArgumentException if {@code array} is {@code null}
@ -1050,22 +1042,13 @@ public class BooleanUtils {
throw new IllegalArgumentException("Array is empty"); throw new IllegalArgumentException("Array is empty");
} }
// Loops through array, comparing each item // false if the neutral element of the xor operator
int trueCount = 0; boolean result = false;
for (final boolean element : array) { for (final boolean element : array) {
// If item is true, and trueCount is < 1, increments count result ^= element;
// Else, xor fails
if (element) {
if (trueCount < 1) {
trueCount++;
} else {
return false;
}
}
} }
// Returns true if there was exactly 1 true item return result;
return trueCount == 1;
} }
/** /**
@ -1077,9 +1060,6 @@ public class BooleanUtils {
* BooleanUtils.xor(new Boolean[] { Boolean.TRUE, Boolean.FALSE }) = Boolean.TRUE * BooleanUtils.xor(new Boolean[] { Boolean.TRUE, Boolean.FALSE }) = Boolean.TRUE
* </pre> * </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 * @param array an array of {@code Boolean}s
* @return {@code true} if the xor is successful. * @return {@code true} if the xor is successful.
* @throws IllegalArgumentException if {@code array} is {@code null} * @throws IllegalArgumentException if {@code array} is {@code null}

View File

@ -446,56 +446,68 @@ public class BooleanUtilsTest {
@Test @Test
public void testXor_primitive_validInput_2items() { public void testXor_primitive_validInput_2items() {
assertTrue( assertEquals(
"True result for (true, true)", "true ^ true",
! BooleanUtils.xor(new boolean[] { true, true })); true ^ true ,
BooleanUtils.xor(new boolean[] { true, true }));
assertTrue( assertEquals(
"True result for (false, false)", "false ^ false",
! BooleanUtils.xor(new boolean[] { false, false })); false ^ false,
BooleanUtils.xor(new boolean[] { false, false }));
assertTrue( assertEquals(
"False result for (true, false)", "true ^ false",
true ^ false,
BooleanUtils.xor(new boolean[] { true, false })); BooleanUtils.xor(new boolean[] { true, false }));
assertTrue( assertEquals(
"False result for (false, true)", "false ^ true",
false ^ true,
BooleanUtils.xor(new boolean[] { false, true })); BooleanUtils.xor(new boolean[] { false, true }));
} }
@Test @Test
public void testXor_primitive_validInput_3items() { public void testXor_primitive_validInput_3items() {
assertTrue( assertEquals(
"False result for (false, false, true)", "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 })); BooleanUtils.xor(new boolean[] { false, false, true }));
assertTrue( assertEquals(
"False result for (false, true, false)", "false ^ true ^ false",
false ^ true ^ false,
BooleanUtils.xor(new boolean[] { false, true, false })); BooleanUtils.xor(new boolean[] { false, true, false }));
assertTrue( assertEquals(
"False result for (true, false, false)", "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 })); BooleanUtils.xor(new boolean[] { true, false, false }));
assertTrue( assertEquals(
"True result for (true, true, true)", "true ^ false ^ true",
! BooleanUtils.xor(new boolean[] { true, true, true })); true ^ false ^ true,
BooleanUtils.xor(new boolean[] { true, false, true }));
assertTrue( assertEquals(
"True result for (false, false)", "true ^ true ^ false",
! BooleanUtils.xor(new boolean[] { false, false, false })); true ^ true ^ false,
BooleanUtils.xor(new boolean[] { true, true, false }));
assertTrue( assertEquals(
"True result for (true, true, false)", "true ^ true ^ true",
! BooleanUtils.xor(new boolean[] { true, true, false })); true ^ true ^ true,
BooleanUtils.xor(new boolean[] { true, true, true }));
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 }));
} }
@Test(expected = IllegalArgumentException.class) @Test(expected = IllegalArgumentException.class)
@ -515,35 +527,50 @@ public class BooleanUtilsTest {
@Test @Test
public void testXor_object_validInput_2items() { public void testXor_object_validInput_2items() {
assertTrue( assertEquals(
"True result for (true, true)", "false ^ false",
! BooleanUtils false ^ false,
.xor(new Boolean[] { Boolean.TRUE, Boolean.TRUE }) BooleanUtils
.booleanValue());
assertTrue(
"True result for (false, false)",
! BooleanUtils
.xor(new Boolean[] { Boolean.FALSE, Boolean.FALSE }) .xor(new Boolean[] { Boolean.FALSE, Boolean.FALSE })
.booleanValue()); .booleanValue());
assertTrue( assertEquals(
"False result for (true, false)", "false ^ true",
false ^ true,
BooleanUtils
.xor(new Boolean[] { Boolean.FALSE, Boolean.TRUE })
.booleanValue());
assertEquals(
"true ^ false",
true ^ false,
BooleanUtils BooleanUtils
.xor(new Boolean[] { Boolean.TRUE, Boolean.FALSE }) .xor(new Boolean[] { Boolean.TRUE, Boolean.FALSE })
.booleanValue()); .booleanValue());
assertTrue( assertEquals(
"False result for (false, true)", "true ^ true",
true ^ true,
BooleanUtils BooleanUtils
.xor(new Boolean[] { Boolean.FALSE, Boolean.TRUE }) .xor(new Boolean[] { Boolean.TRUE, Boolean.TRUE })
.booleanValue()); .booleanValue());
} }
@Test @Test
public void testXor_object_validInput_3items() { public void testXor_object_validInput_3items() {
assertTrue( assertEquals(
"False result for (false, false, true)", "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 BooleanUtils
.xor( .xor(
new Boolean[] { new Boolean[] {
@ -552,8 +579,9 @@ public class BooleanUtilsTest {
Boolean.TRUE }) Boolean.TRUE })
.booleanValue()); .booleanValue());
assertTrue( assertEquals(
"False result for (false, true, false)", "false ^ true ^ false",
false ^ true ^ false,
BooleanUtils BooleanUtils
.xor( .xor(
new Boolean[] { new Boolean[] {
@ -562,8 +590,9 @@ public class BooleanUtilsTest {
Boolean.FALSE }) Boolean.FALSE })
.booleanValue()); .booleanValue());
assertTrue( assertEquals(
"False result for (true, false, false)", "true ^ false ^ false",
true ^ false ^ false,
BooleanUtils BooleanUtils
.xor( .xor(
new Boolean[] { new Boolean[] {
@ -572,47 +601,42 @@ public class BooleanUtilsTest {
Boolean.FALSE }) Boolean.FALSE })
.booleanValue()); .booleanValue());
assertTrue( assertEquals(
"True result for (true, true, true)", "true ^ false ^ true",
! BooleanUtils 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());
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 }) .xor(new Boolean[] { Boolean.TRUE, Boolean.TRUE, Boolean.TRUE })
.booleanValue()); .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(
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(
new Boolean[] {
Boolean.FALSE,
Boolean.TRUE,
Boolean.TRUE })
.booleanValue());
} }
// testAnd // testAnd