diff --git a/src/main/java/org/apache/commons/validator/GenericValidator.java b/src/main/java/org/apache/commons/validator/GenericValidator.java index d212aa06e..fcf49a58e 100644 --- a/src/main/java/org/apache/commons/validator/GenericValidator.java +++ b/src/main/java/org/apache/commons/validator/GenericValidator.java @@ -53,7 +53,10 @@ private static int adjustForLineEnding(final String value, final int lineEndLeng } } final int rnCount = rCount + nCount; - return nCount * lineEndLength - rnCount; + // A carriage return that is not paired with a line feed is still a line ending, so the number of line + // endings is at least the number of carriage returns as well as the number of line feeds. Counting only + // the line feeds discounts every character of a CR-only value, leaving its adjusted length at zero. + return Math.max(nCount, rCount) * lineEndLength - rnCount; } /** diff --git a/src/test/java/org/apache/commons/validator/GenericValidatorTest.java b/src/test/java/org/apache/commons/validator/GenericValidatorTest.java index 88a873104..e796f8f8f 100644 --- a/src/test/java/org/apache/commons/validator/GenericValidatorTest.java +++ b/src/test/java/org/apache/commons/validator/GenericValidatorTest.java @@ -34,6 +34,29 @@ void testIsDate() { assertFalse(GenericValidator.isDate("2/12/1999", "MM/dd/yyyy", true), "abbreviated month"); } + /** + * A carriage return with no line feed next to it is a line ending in its own right, so it must not be + * discounted to zero characters. + */ + @Test + void testLengthUnpairedCarriageReturn() { + // Use 0 for line end length + assertTrue(GenericValidator.maxLength("12345\r", 5, 0), "Max=5 End=0"); + // Use 1 for line end length + assertFalse(GenericValidator.maxLength("12345\r", 5, 1), "Max=5 End=1"); + assertTrue(GenericValidator.maxLength("12345\r", 6, 1), "Max=6 End=1"); + // Use 2 for line end length + assertFalse(GenericValidator.maxLength("12345\r", 6, 2), "Max=6 End=2"); + assertTrue(GenericValidator.maxLength("12345\r", 7, 2), "Max=7 End=2"); + assertTrue(GenericValidator.minLength("12345\r", 7, 2), "Min=7 End=2"); + assertFalse(GenericValidator.minLength("12345\r", 8, 2), "Min=8 End=2"); + // Carriage returns alone used to leave the adjusted length at zero whatever the value's length + assertFalse(GenericValidator.maxLength("\r\r\r\r\r", 1, 2), "Max=1 End=2"); + // The paired form is unchanged + assertFalse(GenericValidator.maxLength("12345\r\n", 6, 2), "Max=6 End=2 paired"); + assertTrue(GenericValidator.maxLength("12345\r\n", 7, 2), "Max=7 End=2 paired"); + } + @Test void testMaxLength() {