diff --git a/src/main/java/org/apache/commons/csv/CSVFormat.java b/src/main/java/org/apache/commons/csv/CSVFormat.java
index d190531d..019e7678 100644
--- a/src/main/java/org/apache/commons/csv/CSVFormat.java
+++ b/src/main/java/org/apache/commons/csv/CSVFormat.java
@@ -29,12 +29,13 @@ import java.io.IOException;
import java.io.Reader;
import java.io.Serializable;
import java.io.StringWriter;
+import java.util.Arrays;
/**
* The format specification of a CSV file.
*
* This class is immutable.
- *
+ *
* @version $Id$
*/
public class CSVFormat implements Serializable {
@@ -125,8 +126,8 @@ public class CSVFormat implements Serializable {
/**
* Creates a new CSV format builds.
- *
- * @param delimiter
+ *
+ * @param delimiter
* the char used for value separation, must not be a line break character
* @throws IllegalArgumentException if the delimiter is a line break character
*/
@@ -137,7 +138,7 @@ public class CSVFormat implements Serializable {
public static CSVFormatBuilder newBuilder(final CSVFormat format) {
return new CSVFormatBuilder(format);
}
-
+
/**
* Standard comma separated format, as for {@link #RFC4180} but allowing blank lines.
*
@@ -158,7 +159,7 @@ public class CSVFormat implements Serializable {
* the char used for value separation, must not be a line break character
* @param quoteChar
* the char used as value encapsulation marker
- * @param quotePolicy
+ * @param quotePolicy
* the quote policy
* @param commentStart
* the char used for comment identification
@@ -174,10 +175,12 @@ public class CSVFormat implements Serializable {
* the header
* @throws IllegalArgumentException if the delimiter is a line break character
*/
- private CSVFormat(final char delimiter, final Character quoteChar, final Quote quotePolicy, final Character commentStart, final Character escape, final
- boolean ignoreSurroundingSpaces, final boolean ignoreEmptyLines, final String lineSeparator,
- final String[] header) {
- if (isLineBreak(delimiter)) {
+ private CSVFormat(final char delimiter, final Character quoteChar, final Quote quotePolicy, final Character commentStart, final Character escape, final
+ boolean ignoreSurroundingSpaces, final boolean ignoreEmptyLines, final String lineSeparator,
+ final String[] header)
+ {
+ if (isLineBreak(delimiter))
+ {
throw new IllegalArgumentException("The delimiter cannot be a line break");
}
this.delimiter = delimiter;
@@ -188,7 +191,7 @@ public class CSVFormat implements Serializable {
this.ignoreSurroundingSpaces = ignoreSurroundingSpaces;
this.ignoreEmptyLines = ignoreEmptyLines;
this.recordSeparator = lineSeparator;
- this.header = header;
+ this.header = header == null ? null : header.clone();
}
/**
@@ -373,7 +376,109 @@ public class CSVFormat implements Serializable {
public Quote getQuotePolicy() {
return quotePolicy;
}
-
+
+ @Override
+ public int hashCode()
+ {
+ final int prime = 31;
+ int result = 1;
+
+ result = prime * result + delimiter;
+ result = prime * result + ((quotePolicy == null) ? 0 : quotePolicy.hashCode());
+ result = prime * result + ((quoteChar == null) ? 0 : quoteChar.hashCode());
+ result = prime * result + ((commentStart == null) ? 0 : commentStart.hashCode());
+ result = prime * result + ((escape == null) ? 0 : escape.hashCode());
+ result = prime * result + (ignoreSurroundingSpaces ? 1231 : 1237);
+ result = prime * result + (ignoreEmptyLines ? 1231 : 1237);
+ result = prime * result + ((recordSeparator == null) ? 0 : recordSeparator.hashCode());
+ result = prime * result + Arrays.hashCode(header);
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj)
+ {
+ if (this == obj)
+ {
+ return true;
+ }
+ if (obj == null)
+ {
+ return false;
+ }
+ if (getClass() != obj.getClass())
+ {
+ return false;
+ }
+
+ CSVFormat other = (CSVFormat) obj;
+ if (delimiter != other.delimiter)
+ {
+ return false;
+ }
+ if (quotePolicy != other.quotePolicy)
+ {
+ return false;
+ }
+ if (quoteChar == null)
+ {
+ if (other.quoteChar != null)
+ {
+ return false;
+ }
+ }
+ else if (!quoteChar.equals(other.quoteChar))
+ {
+ return false;
+ }
+ if (commentStart == null)
+ {
+ if (other.commentStart != null)
+ {
+ return false;
+ }
+ }
+ else if (!commentStart.equals(other.commentStart))
+ {
+ return false;
+ }
+ if (escape == null)
+ {
+ if (other.escape != null)
+ {
+ return false;
+ }
+ }
+ else if (!escape.equals(other.escape))
+ {
+ return false;
+ }
+ if (!Arrays.equals(header, other.header))
+ {
+ return false;
+ }
+ if (ignoreSurroundingSpaces != other.ignoreSurroundingSpaces)
+ {
+ return false;
+ }
+ if (ignoreEmptyLines != other.ignoreEmptyLines)
+ {
+ return false;
+ }
+ if (recordSeparator == null)
+ {
+ if (other.recordSeparator != null)
+ {
+ return false;
+ }
+ }
+ else if (!recordSeparator.equals(other.recordSeparator))
+ {
+ return false;
+ }
+ return true;
+ }
+
public static class CSVFormatBuilder {
private char delimiter;
@@ -393,7 +498,7 @@ public class CSVFormat implements Serializable {
* the char used for value separation, must not be a line break character
* @param quoteChar
* the char used as value encapsulation marker
- * @param quotePolicy
+ * @param quotePolicy
* the quote policy
* @param commentStart
* the char used for comment identification
@@ -410,8 +515,8 @@ public class CSVFormat implements Serializable {
* @throws IllegalArgumentException if the delimiter is a line break character
*/
// package protected for use by test code
- CSVFormatBuilder(final char delimiter, final Character quoteChar, final Quote quotePolicy, final Character commentStart, final Character escape, final
- boolean ignoreSurroundingSpaces, final boolean ignoreEmptyLines, final String lineSeparator,
+ CSVFormatBuilder(final char delimiter, final Character quoteChar, final Quote quotePolicy, final Character commentStart, final Character escape, final
+ boolean ignoreSurroundingSpaces, final boolean ignoreEmptyLines, final String lineSeparator,
final String[] header) {
if (isLineBreak(delimiter)) {
throw new IllegalArgumentException("The delimiter cannot be a line break");
@@ -426,11 +531,11 @@ public class CSVFormat implements Serializable {
this.recordSeparator = lineSeparator;
this.header = header;
}
-
+
/**
- *
+ *
* Creates a CSVFormatBuilder, using the values of the given CSVFormat.
- *
+ *
* @param format
* The format to use values from
*/
@@ -443,8 +548,8 @@ public class CSVFormat implements Serializable {
/**
* Creates a basic CSVFormatBuilder.
- *
- * @param delimiter
+ *
+ * @param delimiter
* the char used for value separation, must not be a line break character
* @throws IllegalArgumentException if the delimiter is a line break character
*/
@@ -457,35 +562,35 @@ public class CSVFormat implements Serializable {
return new CSVFormat(delimiter, quoteChar, quotePolicy, commentStart, escape,
ignoreSurroundingSpaces, ignoreEmptyLines, recordSeparator, header);
}
-
+
/**
* Verifies the consistency of the parameters and throws an IllegalStateException if necessary.
- *
+ *
* @throws IllegalStateException
*/
private void validate() throws IllegalStateException {
if (quoteChar != null && delimiter == quoteChar.charValue()) {
throw new IllegalStateException("The quoteChar character and the delimiter cannot be the same ('" + quoteChar + "')");
}
-
+
if (escape != null && delimiter == escape.charValue()) {
throw new IllegalStateException("The escape character and the delimiter cannot be the same ('" + escape + "')");
}
-
+
if (commentStart != null && delimiter == commentStart.charValue()) {
- throw new IllegalStateException("The comment start character and the delimiter cannot be the same ('" + commentStart +
+ throw new IllegalStateException("The comment start character and the delimiter cannot be the same ('" + commentStart +
"')");
}
-
+
if (quoteChar != null && quoteChar.equals(commentStart)) {
- throw new IllegalStateException("The comment start character and the quoteChar cannot be the same ('" + commentStart +
+ throw new IllegalStateException("The comment start character and the quoteChar cannot be the same ('" + commentStart +
"')");
}
-
+
if (escape != null && escape.equals(commentStart)) {
throw new IllegalStateException("The comment start and the escape character cannot be the same ('" + commentStart + "')");
}
-
+
if (escape == null && quotePolicy == Quote.NONE) {
throw new IllegalStateException("No quotes mode set but no escape character is set");
}
@@ -504,7 +609,7 @@ public class CSVFormat implements Serializable {
if (isLineBreak(delimiter)) {
throw new IllegalArgumentException("The delimiter cannot be a line break");
}
- this.delimiter = delimiter;
+ this.delimiter = delimiter;
return this;
}
@@ -625,7 +730,7 @@ public class CSVFormat implements Serializable {
this.header = header;
return this;
}
-
+
/**
* Sets the trimming behavior of the format.
*
diff --git a/src/test/java/org/apache/commons/csv/CSVFormatBuilderTest.java b/src/test/java/org/apache/commons/csv/CSVFormatBuilderTest.java
index a9a68f9e..e2bff4f6 100644
--- a/src/test/java/org/apache/commons/csv/CSVFormatBuilderTest.java
+++ b/src/test/java/org/apache/commons/csv/CSVFormatBuilderTest.java
@@ -21,9 +21,9 @@ import static org.apache.commons.csv.CSVFormat.RFC4180;
import static org.apache.commons.csv.Constants.CR;
import static org.apache.commons.csv.Constants.CRLF;
import static org.apache.commons.csv.Constants.LF;
-import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotSame;
import static org.junit.Assert.assertTrue;
import org.apache.commons.csv.CSVFormat.CSVFormatBuilder;
@@ -159,7 +159,7 @@ public class CSVFormatBuilderTest {
@Test
public void testCopiedFormatIsEqualToOriginal() {
CSVFormat copyOfRCF4180 = CSVFormat.newBuilder(RFC4180).build();
- assertEqualFormats(RFC4180, copyOfRCF4180);
+ assertEquals(RFC4180, copyOfRCF4180);
}
@Test
@@ -168,16 +168,14 @@ public class CSVFormatBuilderTest {
assertTrue(newFormat.getDelimiter() != RFC4180.getDelimiter());
}
- // FIXME implement equals on CSVFormat to allow use of Assert.assertEquals()
- private static void assertEqualFormats(CSVFormat expected, CSVFormat acutal) {
- assertEquals(expected.getCommentStart(), acutal.getCommentStart());
- assertEquals(expected.getDelimiter(), acutal.getDelimiter());
- assertEquals(expected.getEscape(), acutal.getEscape());
- assertArrayEquals(expected.getHeader(), acutal.getHeader());
- assertEquals(expected.getIgnoreEmptyLines(), acutal.getIgnoreEmptyLines());
- assertEquals(expected.getIgnoreSurroundingSpaces(), acutal.getIgnoreSurroundingSpaces());
- assertEquals(expected.getQuoteChar(), acutal.getQuoteChar());
- assertEquals(expected.getQuotePolicy(), acutal.getQuotePolicy());
- assertEquals(expected.getRecordSeparator(), acutal.getRecordSeparator());
+ @Test
+ public void testHeaderReferenceCannotEscape() {
+ String[] header = new String[]{"one", "tow", "three"};
+ builder.withHeader(header);
+
+ CSVFormat firstFormat = builder.build();
+ CSVFormat secondFormat = builder.build();
+ assertNotSame(header, firstFormat.getHeader());
+ assertNotSame(firstFormat, secondFormat.getHeader());
}
}
diff --git a/src/test/java/org/apache/commons/csv/CSVFormatTest.java b/src/test/java/org/apache/commons/csv/CSVFormatTest.java
index 3f7b51c5..b1076f2f 100644
--- a/src/test/java/org/apache/commons/csv/CSVFormatTest.java
+++ b/src/test/java/org/apache/commons/csv/CSVFormatTest.java
@@ -18,6 +18,7 @@
package org.apache.commons.csv;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import java.io.ByteArrayInputStream;
@@ -65,4 +66,153 @@ public class CSVFormatTest {
assertEquals("trim", CSVFormat.DEFAULT.getIgnoreSurroundingSpaces(), format.getIgnoreSurroundingSpaces());
assertEquals("empty lines", CSVFormat.DEFAULT.getIgnoreEmptyLines(), format.getIgnoreEmptyLines());
}
+
+ @Test
+ public void testEquals() {
+ CSVFormat right = CSVFormat.DEFAULT;
+ CSVFormat left = CSVFormat.newBuilder().build();
+
+ assertFalse(right.equals(null));
+ assertFalse(right.equals("A String Instance"));
+
+ assertEquals(right, right);
+ assertEquals(right, left);
+ assertEquals(left, right);
+
+ assertEquals(right.hashCode(), right.hashCode());
+ assertEquals(right.hashCode(), left.hashCode());
+ }
+
+ @Test
+ public void testEqualsDelimiter() {
+ CSVFormat right = CSVFormat.newBuilder('!').build();
+ CSVFormat left = CSVFormat.newBuilder('?').build();
+
+ assertNotEquals(right, left);
+ }
+
+ @Test
+ public void testEqualsQuoteChar() {
+ CSVFormat right = CSVFormat.newBuilder('\'').withQuoteChar('"').build();
+ CSVFormat left = CSVFormat.newBuilder(right).withQuoteChar('!').build();
+
+ assertNotEquals(right, left);
+ }
+
+ @Test
+ public void testEqualsQuotePolicy() {
+ CSVFormat right = CSVFormat.newBuilder('\'')
+ .withQuoteChar('"')
+ .withQuotePolicy(Quote.ALL)
+ .build();
+ CSVFormat left = CSVFormat.newBuilder(right)
+ .withQuotePolicy(Quote.MINIMAL)
+ .build();
+
+ assertNotEquals(right, left);
+ }
+
+ @Test
+ public void testEqualsCommentStart() {
+ CSVFormat right = CSVFormat.newBuilder('\'')
+ .withQuoteChar('"')
+ .withQuotePolicy(Quote.ALL)
+ .withCommentStart('#')
+ .build();
+ CSVFormat left = CSVFormat.newBuilder(right)
+ .withCommentStart('!')
+ .build();
+
+ assertNotEquals(right, left);
+ }
+
+ @Test
+ public void testEqualsEscape() {
+ CSVFormat right = CSVFormat.newBuilder('\'')
+ .withQuoteChar('"')
+ .withQuotePolicy(Quote.ALL)
+ .withCommentStart('#')
+ .withEscape('+')
+ .build();
+ CSVFormat left = CSVFormat.newBuilder(right)
+ .withEscape('!')
+ .build();
+
+ assertNotEquals(right, left);
+ }
+
+ @Test
+ public void testEqualsIgnoreSurroundingSpaces() {
+ CSVFormat right = CSVFormat.newBuilder('\'')
+ .withQuoteChar('"')
+ .withQuotePolicy(Quote.ALL)
+ .withCommentStart('#')
+ .withEscape('+')
+ .withIgnoreSurroundingSpaces(true)
+ .build();
+ CSVFormat left = CSVFormat.newBuilder(right)
+ .withIgnoreSurroundingSpaces(false)
+ .build();
+
+ assertNotEquals(right, left);
+ }
+
+ @Test
+ public void testEqualsIgnoreEmptyLines() {
+ CSVFormat right = CSVFormat.newBuilder('\'')
+ .withQuoteChar('"')
+ .withQuotePolicy(Quote.ALL)
+ .withCommentStart('#')
+ .withEscape('+')
+ .withIgnoreSurroundingSpaces(true)
+ .withIgnoreEmptyLines(true)
+ .build();
+ CSVFormat left = CSVFormat.newBuilder(right)
+ .withIgnoreEmptyLines(false)
+ .build();
+
+ assertNotEquals(right, left);
+ }
+
+ @Test
+ public void testEqualsRecordSeparator() {
+ CSVFormat right = CSVFormat.newBuilder('\'')
+ .withQuoteChar('"')
+ .withQuotePolicy(Quote.ALL)
+ .withCommentStart('#')
+ .withEscape('+')
+ .withIgnoreSurroundingSpaces(true)
+ .withIgnoreEmptyLines(true)
+ .withRecordSeparator('*')
+ .build();
+ CSVFormat left = CSVFormat.newBuilder(right)
+ .withRecordSeparator('!')
+ .build();
+
+ assertNotEquals(right, left);
+ }
+
+ @Test
+ public void testEqualsHeader() {
+ CSVFormat right = CSVFormat.newBuilder('\'')
+ .withQuoteChar('"')
+ .withQuotePolicy(Quote.ALL)
+ .withCommentStart('#')
+ .withEscape('+')
+ .withIgnoreSurroundingSpaces(true)
+ .withIgnoreEmptyLines(true)
+ .withRecordSeparator('*')
+ .withHeader("One", "Two", "Three")
+ .build();
+ CSVFormat left = CSVFormat.newBuilder(right)
+ .withHeader("Three", "Two", "One")
+ .build();
+
+ assertNotEquals(right, left);
+ }
+
+ private static void assertNotEquals(Object right, Object left) {
+ assertFalse(right.equals(left));
+ assertFalse(left.equals(right));
+ }
}