Author: sebb
Date: Thu Aug 11 00:28:58 2011
New Revision: 1156416
URL: http://svn.apache.org/viewvc?rev=1156416&view=rev
Log:
Bug 51645 - CSVDataSet does not read UTF-8 files when file.encoding is UTF-8
Added:
jakarta/jmeter/trunk/bin/testfiles/testutf8.csv (with props)
Modified:
jakarta/jmeter/trunk/src/core/org/apache/jmeter/save/CSVSaveService.java
jakarta/jmeter/trunk/test/src/org/apache/jmeter/config/TestCVSDataSet.java
jakarta/jmeter/trunk/test/src/org/apache/jmeter/save/TestCSVSaveService.java
jakarta/jmeter/trunk/xdocs/changes.xml
Added: jakarta/jmeter/trunk/bin/testfiles/testutf8.csv
URL:
http://svn.apache.org/viewvc/jakarta/jmeter/trunk/bin/testfiles/testutf8.csv?rev=1156416&view=auto
==============================================================================
--- jakarta/jmeter/trunk/bin/testfiles/testutf8.csv (added)
+++ jakarta/jmeter/trunk/bin/testfiles/testutf8.csv Thu Aug 11 00:28:58 2011
@@ -0,0 +1,4 @@
+a1,b1,"ç1",d1
+a2,b2,"ç2",d2
+a3,b3,"ç3",d3
+a4,b4,"ç4",d4
\ No newline at end of file
Propchange: jakarta/jmeter/trunk/bin/testfiles/testutf8.csv
------------------------------------------------------------------------------
svn:eol-style = native
Modified:
jakarta/jmeter/trunk/src/core/org/apache/jmeter/save/CSVSaveService.java
URL:
http://svn.apache.org/viewvc/jakarta/jmeter/trunk/src/core/org/apache/jmeter/save/CSVSaveService.java?rev=1156416&r1=1156415&r2=1156416&view=diff
==============================================================================
--- jakarta/jmeter/trunk/src/core/org/apache/jmeter/save/CSVSaveService.java
(original)
+++ jakarta/jmeter/trunk/src/core/org/apache/jmeter/save/CSVSaveService.java
Thu Aug 11 00:28:58 2011
@@ -19,7 +19,7 @@
package org.apache.jmeter.save;
import java.io.BufferedReader;
-import java.io.ByteArrayOutputStream;
+import java.io.CharArrayWriter;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
@@ -80,7 +80,7 @@ public final class CSVSaveService {
// ---------------------------------------------------------------------
private static final String CSV_ELAPSED = "elapsed"; // $NON-NLS-1$
- private static final String CSV_BYTES= "bytes"; // $NON-NLS-1$
+ private static final String CSV_BYTES = "bytes"; // $NON-NLS-1$
private static final String CSV_THREAD_COUNT1 = "grpThreads"; //
$NON-NLS-1$
private static final String CSV_THREAD_COUNT2 = "allThreads"; //
$NON-NLS-1$
private static final String CSV_SAMPLE_COUNT = "SampleCount"; //
$NON-NLS-1$
@@ -92,16 +92,19 @@ public final class CSVSaveService {
private static final String CSV_HOSTNAME = "Hostname"; // $NON-NLS-1$
private static final String CSV_IDLETIME = "IdleTime"; // $NON-NLS-1$
- // Used to enclose variable name labels, to distinguish from any of the
above labels
- private static final String VARIABLE_NAME_QUOTE_CHAR = "\""; //
$NON-NLS-1$
+ // Used to enclose variable name labels, to distinguish from any of the
+ // above labels
+ private static final String VARIABLE_NAME_QUOTE_CHAR = "\""; // $NON-NLS-1$
// Initial config from properties
- static private final SampleSaveConfiguration _saveConfig =
SampleSaveConfiguration.staticConfig();
+ static private final SampleSaveConfiguration _saveConfig =
SampleSaveConfiguration
+ .staticConfig();
// Date format to try if the time format does not parse as milliseconds
// (this is the suggested value in jmeter.properties)
private static final String DEFAULT_DATE_FORMAT_STRING = "MM/dd/yy
HH:mm:ss"; // $NON-NLS-1$
- private static final DateFormat DEFAULT_DATE_FORMAT = new
SimpleDateFormat(DEFAULT_DATE_FORMAT_STRING);
+ private static final DateFormat DEFAULT_DATE_FORMAT = new SimpleDateFormat(
+ DEFAULT_DATE_FORMAT_STRING);
private static final String LINE_SEP =
System.getProperty("line.separator"); // $NON-NLS-1$
@@ -113,10 +116,13 @@ public final class CSVSaveService {
/**
* Read Samples from a file; handles quoted strings.
- *
- * @param filename input file
- * @param visualizer where to send the results
- * @param resultCollector the parent collector
+ *
+ * @param filename
+ * input file
+ * @param visualizer
+ * where to send the results
+ * @param resultCollector
+ * the parent collector
* @throws IOException
*/
public static void processSamples(String filename, Visualizer visualizer,
@@ -129,28 +135,35 @@ public final class CSVSaveService {
dataReader.mark(400);// Enough to read the header column names
// Get the first line, and see if it is the header
String line = dataReader.readLine();
- if (line == null){
- throw new IOException(filename+": unable to read header line");
+ if (line == null) {
+ throw new IOException(filename + ": unable to read header
line");
}
- long lineNumber=1;
- SampleSaveConfiguration saveConfig =
CSVSaveService.getSampleSaveConfiguration(line,filename);
+ long lineNumber = 1;
+ SampleSaveConfiguration saveConfig = CSVSaveService
+ .getSampleSaveConfiguration(line, filename);
if (saveConfig == null) {// not a valid header
- log.info(filename+" does not appear to have a valid header.
Using default configuration.");
- saveConfig = (SampleSaveConfiguration)
resultCollector.getSaveConfig().clone(); // may change the format later
+ log.info(filename
+ + " does not appear to have a valid header. Using
default configuration.");
+ saveConfig = (SampleSaveConfiguration) resultCollector
+ .getSaveConfig().clone(); // may change the format
later
dataReader.reset(); // restart from beginning
lineNumber = 0;
}
- String [] parts;
+ String[] parts;
final char delim = saveConfig.getDelimiter().charAt(0);
// TODO: does it matter that an empty line will terminate the loop?
- // CSV output files should never contain empty lines, so probably
not
+ // CSV output files should never contain empty lines, so probably
+ // not
// If so, then need to check whether the reader is at EOF
while ((parts = csvReadFile(dataReader, delim)).length != 0) {
lineNumber++;
- SampleEvent event =
CSVSaveService.makeResultFromDelimitedString(parts,saveConfig,lineNumber);
- if (event != null){
+ SampleEvent event = CSVSaveService
+ .makeResultFromDelimitedString(parts, saveConfig,
+ lineNumber);
+ if (event != null) {
final SampleResult result = event.getResult();
- if
(ResultCollector.isSampleWanted(result.isSuccessful(),errorsOnly, successOnly))
{
+ if (ResultCollector.isSampleWanted(result.isSuccessful(),
+ errorsOnly, successOnly)) {
visualizer.add(result);
}
}
@@ -162,16 +175,20 @@ public final class CSVSaveService {
/**
* Make a SampleResult given a set of tokens
- * @param parts tokens parsed from the input
- * @param saveConfig the save configuration (may be updated)
+ *
+ * @param parts
+ * tokens parsed from the input
+ * @param saveConfig
+ * the save configuration (may be updated)
* @param lineNumber
* @return the sample result
- *
+ *
* @throws JMeterError
*/
private static SampleEvent makeResultFromDelimitedString(
- final String[] parts,
- final SampleSaveConfiguration saveConfig, // may be updated
+ final String[] parts, final SampleSaveConfiguration saveConfig, //
may
+ //
be
+ //
updated
final long lineNumber) {
SampleResult result = null;
@@ -180,10 +197,10 @@ public final class CSVSaveService {
long elapsed = 0;
String text = null;
String field = null; // Save the name for error reporting
- int i=0;
+ int i = 0;
try {
- if (saveConfig.saveTimestamp()){
+ if (saveConfig.saveTimestamp()) {
field = TIME_STAMP;
text = parts[i++];
if (saveConfig.printMilliseconds()) {
@@ -195,7 +212,8 @@ public final class CSVSaveService {
// so it's OK to use a static DateFormat
Date stamp = DEFAULT_DATE_FORMAT.parse(text);
timeStamp = stamp.getTime();
- log.warn("Setting date format to:
"+DEFAULT_DATE_FORMAT_STRING);
+ log.warn("Setting date format to: "
+ + DEFAULT_DATE_FORMAT_STRING);
saveConfig.setFormatter(DEFAULT_DATE_FORMAT);
}
} else if (saveConfig.formatter() != null) {
@@ -318,26 +336,31 @@ public final class CSVSaveService {
result.setIdleTime(Long.parseLong(text));
}
- if (i + saveConfig.getVarCount() < parts.length){
- log.warn("Line: "+lineNumber+". Found "+parts.length+" fields,
expected "+i+". Extra fields have been ignored.");
+ if (i + saveConfig.getVarCount() < parts.length) {
+ log.warn("Line: " + lineNumber + ". Found " + parts.length
+ + " fields, expected " + i
+ + ". Extra fields have been ignored.");
}
} catch (NumberFormatException e) {
- log.warn("Error parsing field '" + field + "' at line " +
lineNumber + " " + e);
+ log.warn("Error parsing field '" + field + "' at line "
+ + lineNumber + " " + e);
throw new JMeterError(e);
} catch (ParseException e) {
- log.warn("Error parsing field '" + field + "' at line " +
lineNumber + " " + e);
+ log.warn("Error parsing field '" + field + "' at line "
+ + lineNumber + " " + e);
throw new JMeterError(e);
- } catch (ArrayIndexOutOfBoundsException e){
- log.warn("Insufficient columns to parse field '" + field + "' at
line " + lineNumber);
+ } catch (ArrayIndexOutOfBoundsException e) {
+ log.warn("Insufficient columns to parse field '" + field
+ + "' at line " + lineNumber);
throw new JMeterError(e);
}
- return new SampleEvent(result,"",hostname);
+ return new SampleEvent(result, "", hostname);
}
/**
* Generates the field names for the output file
- *
+ *
* @return the field names as a string
*/
public static String printableFieldNamesToString() {
@@ -346,10 +369,11 @@ public final class CSVSaveService {
/**
* Generates the field names for the output file
- *
+ *
* @return the field names as a string
*/
- public static String printableFieldNamesToString(SampleSaveConfiguration
saveConfig) {
+ public static String printableFieldNamesToString(
+ SampleSaveConfiguration saveConfig) {
StringBuilder text = new StringBuilder();
String delim = saveConfig.getDelimiter();
@@ -447,7 +471,7 @@ public final class CSVSaveService {
text.append(delim);
}
- for (int i = 0; i < SampleEvent.getVarCount(); i++){
+ for (int i = 0; i < SampleEvent.getVarCount(); i++) {
text.append(VARIABLE_NAME_QUOTE_CHAR);
text.append(SampleEvent.getVarName(i));
text.append(VARIABLE_NAME_QUOTE_CHAR);
@@ -473,55 +497,68 @@ public final class CSVSaveService {
// These entries must be in the same order as columns are saved/restored.
static {
- headerLabelMethods.put(TIME_STAMP, new Functor("setTimestamp"));
- headerLabelMethods.put(CSV_ELAPSED, new Functor("setTime"));
- headerLabelMethods.put(LABEL, new Functor("setLabel"));
- headerLabelMethods.put(RESPONSE_CODE, new Functor("setCode"));
- headerLabelMethods.put(RESPONSE_MESSAGE, new
Functor("setMessage"));
- headerLabelMethods.put(THREAD_NAME, new Functor("setThreadName"));
- headerLabelMethods.put(DATA_TYPE, new Functor("setDataType"));
- headerLabelMethods.put(SUCCESSFUL, new Functor("setSuccess"));
- headerLabelMethods.put(FAILURE_MESSAGE, new
Functor("setAssertionResultsFailureMessage"));
- headerLabelMethods.put(CSV_BYTES, new Functor("setBytes"));
- // Both these are needed in the list even though they set the same
variable
- headerLabelMethods.put(CSV_THREAD_COUNT1,new
Functor("setThreadCounts"));
- headerLabelMethods.put(CSV_THREAD_COUNT2,new
Functor("setThreadCounts"));
- headerLabelMethods.put(CSV_URL, new Functor("setUrl"));
- headerLabelMethods.put(CSV_FILENAME, new Functor("setFileName"));
- headerLabelMethods.put(CSV_LATENCY, new Functor("setLatency"));
- headerLabelMethods.put(CSV_ENCODING, new Functor("setEncoding"));
- // Both these are needed in the list even though they set the same
variable
- headerLabelMethods.put(CSV_SAMPLE_COUNT, new
Functor("setSampleCount"));
- headerLabelMethods.put(CSV_ERROR_COUNT, new
Functor("setSampleCount"));
- headerLabelMethods.put(CSV_HOSTNAME, new Functor("setHostname"));
- headerLabelMethods.put(CSV_IDLETIME, new Functor("setIdleTime"));
+ headerLabelMethods.put(TIME_STAMP, new Functor("setTimestamp"));
+ headerLabelMethods.put(CSV_ELAPSED, new Functor("setTime"));
+ headerLabelMethods.put(LABEL, new Functor("setLabel"));
+ headerLabelMethods.put(RESPONSE_CODE, new Functor("setCode"));
+ headerLabelMethods.put(RESPONSE_MESSAGE, new Functor("setMessage"));
+ headerLabelMethods.put(THREAD_NAME, new Functor("setThreadName"));
+ headerLabelMethods.put(DATA_TYPE, new Functor("setDataType"));
+ headerLabelMethods.put(SUCCESSFUL, new Functor("setSuccess"));
+ headerLabelMethods.put(FAILURE_MESSAGE, new Functor(
+ "setAssertionResultsFailureMessage"));
+ headerLabelMethods.put(CSV_BYTES, new Functor("setBytes"));
+ // Both these are needed in the list even though they set the same
+ // variable
+ headerLabelMethods.put(CSV_THREAD_COUNT1,
+ new Functor("setThreadCounts"));
+ headerLabelMethods.put(CSV_THREAD_COUNT2,
+ new Functor("setThreadCounts"));
+ headerLabelMethods.put(CSV_URL, new Functor("setUrl"));
+ headerLabelMethods.put(CSV_FILENAME, new Functor("setFileName"));
+ headerLabelMethods.put(CSV_LATENCY, new Functor("setLatency"));
+ headerLabelMethods.put(CSV_ENCODING, new Functor("setEncoding"));
+ // Both these are needed in the list even though they set the same
+ // variable
+ headerLabelMethods.put(CSV_SAMPLE_COUNT, new
Functor("setSampleCount"));
+ headerLabelMethods.put(CSV_ERROR_COUNT, new Functor("setSampleCount"));
+ headerLabelMethods.put(CSV_HOSTNAME, new Functor("setHostname"));
+ headerLabelMethods.put(CSV_IDLETIME, new Functor("setIdleTime"));
}
/**
* Parse a CSV header line
- * @param headerLine from CSV file
- * @param filename name of file (for log message only)
- * @return config corresponding to the header items found or null if not a
header line
+ *
+ * @param headerLine
+ * from CSV file
+ * @param filename
+ * name of file (for log message only)
+ * @return config corresponding to the header items found or null if not a
+ * header line
*/
- public static SampleSaveConfiguration getSampleSaveConfiguration(String
headerLine, String filename){
- String[] parts = splitHeader(headerLine,_saveConfig.getDelimiter());
// Try default delimiter
+ public static SampleSaveConfiguration getSampleSaveConfiguration(
+ String headerLine, String filename) {
+ String[] parts = splitHeader(headerLine, _saveConfig.getDelimiter());
// Try
+
// default
+
// delimiter
String delim = null;
- if (parts == null){
+ if (parts == null) {
Perl5Matcher matcher = JMeterUtils.getMatcher();
PatternMatcherInput input = new PatternMatcherInput(headerLine);
Pattern pattern = JMeterUtils.getPatternCache()
// This assumes the header names are all single words with no
spaces
// word followed by 0 or more repeats of (non-word char + word)
// where the non-word char (\2) is the same
- // e.g. abc|def|ghi but not abd|def~ghi
+ // e.g. abc|def|ghi but not abd|def~ghi
.getPattern("\\w+((\\W)\\w+)?(\\2\\w+)*(\\2\"\\w+\")*", //
$NON-NLS-1$
// last entries may be quoted strings
- Perl5Compiler.READ_ONLY_MASK);
+ Perl5Compiler.READ_ONLY_MASK);
if (matcher.matches(input, pattern)) {
delim = matcher.getMatch().group(2);
- parts = splitHeader(headerLine,delim);// now validate the
result
+ parts = splitHeader(headerLine, delim);// now validate the
+ // result
}
}
@@ -530,21 +567,23 @@ public final class CSVSaveService {
}
// We know the column names all exist, so create the config
- SampleSaveConfiguration saveConfig=new SampleSaveConfiguration(false);
+ SampleSaveConfiguration saveConfig = new
SampleSaveConfiguration(false);
int varCount = 0;
- for(int i=0;i<parts.length;i++){
+ for (int i = 0; i < parts.length; i++) {
String label = parts[i];
- if (isVariableName(label)){
+ if (isVariableName(label)) {
varCount++;
} else {
Functor set = (Functor) headerLabelMethods.get(label);
- set.invoke(saveConfig,new Boolean[]{Boolean.TRUE});
+ set.invoke(saveConfig, new Boolean[] { Boolean.TRUE });
}
}
- if (delim != null){
- log.warn("Default delimiter '"+_saveConfig.getDelimiter()+"' did
not work; using alternate '"+delim+"' for reading "+filename);
+ if (delim != null) {
+ log.warn("Default delimiter '" + _saveConfig.getDelimiter()
+ + "' did not work; using alternate '" + delim
+ + "' for reading " + filename);
saveConfig.setDelimiter(delim);
}
@@ -554,22 +593,23 @@ public final class CSVSaveService {
}
private static String[] splitHeader(String headerLine, String delim) {
- String parts[]=headerLine.split("\\Q"+delim);// $NON-NLS-1$
+ String parts[] = headerLine.split("\\Q" + delim);// $NON-NLS-1$
int previous = -1;
// Check if the line is a header
- for(int i=0;i<parts.length;i++){
+ for (int i = 0; i < parts.length; i++) {
final String label = parts[i];
// Check for Quoted variable names
- if (isVariableName(label)){
- previous=Integer.MAX_VALUE; // they are always last
+ if (isVariableName(label)) {
+ previous = Integer.MAX_VALUE; // they are always last
continue;
}
int current = headerLabelMethods.indexOf(label);
- if (current == -1){
+ if (current == -1) {
return null; // unknown column name
}
- if (current <= previous){
- log.warn("Column header number "+(i+1)+" name "+ label + " is
out of order.");
+ if (current <= previous) {
+ log.warn("Column header number " + (i + 1) + " name " + label
+ + " is out of order.");
return null; // out of order
}
previous = current;
@@ -578,109 +618,126 @@ public final class CSVSaveService {
}
/**
- * Check if the label is a variable name, i.e. is it enclosed in
double-quotes?
- *
- * @param label column name from CSV file
+ * Check if the label is a variable name, i.e. is it enclosed in
+ * double-quotes?
+ *
+ * @param label
+ * column name from CSV file
* @return if the label is enclosed in double-quotes
*/
private static boolean isVariableName(final String label) {
- return label.length() > 2
- && label.startsWith(VARIABLE_NAME_QUOTE_CHAR)
- && label.endsWith(VARIABLE_NAME_QUOTE_CHAR);
+ return label.length() > 2 && label.startsWith(VARIABLE_NAME_QUOTE_CHAR)
+ && label.endsWith(VARIABLE_NAME_QUOTE_CHAR);
}
/**
- * Method will save aggregate statistics as CSV. For now I put it here.
- * Not sure if it should go in the newer SaveService instead of here.
- * if we ever decide to get rid of this class, we'll need to move this
- * method to the new save service.
- * @param data vector of data rows
- * @param writer output file
+ * Method will save aggregate statistics as CSV. For now I put it here. Not
+ * sure if it should go in the newer SaveService instead of here. if we
ever
+ * decide to get rid of this class, we'll need to move this method to the
+ * new save service.
+ *
+ * @param data
+ * vector of data rows
+ * @param writer
+ * output file
* @throws IOException
*/
- public static void saveCSVStats(Vector<?> data, FileWriter writer) throws
IOException {
+ public static void saveCSVStats(Vector<?> data, FileWriter writer)
+ throws IOException {
saveCSVStats(data, writer, null);
}
/**
- * Method will save aggregate statistics as CSV. For now I put it here.
- * Not sure if it should go in the newer SaveService instead of here.
- * if we ever decide to get rid of this class, we'll need to move this
- * method to the new save service.
- * @param data vector of data rows
- * @param writer output file
- * @param headers header names (if non-null)
+ * Method will save aggregate statistics as CSV. For now I put it here. Not
+ * sure if it should go in the newer SaveService instead of here. if we
ever
+ * decide to get rid of this class, we'll need to move this method to the
+ * new save service.
+ *
+ * @param data
+ * vector of data rows
+ * @param writer
+ * output file
+ * @param headers
+ * header names (if non-null)
* @throws IOException
*/
- public static void saveCSVStats(Vector<?> data, FileWriter writer, String
headers[]) throws IOException {
+ public static void saveCSVStats(Vector<?> data, FileWriter writer,
+ String headers[]) throws IOException {
final char DELIM = ',';
- final char SPECIALS[] = new char[] {DELIM, QUOTING_CHAR};
- if (headers != null){
- for (int i=0; i < headers.length; i++){
- if (i>0) {
+ final char SPECIALS[] = new char[] { DELIM, QUOTING_CHAR };
+ if (headers != null) {
+ for (int i = 0; i < headers.length; i++) {
+ if (i > 0) {
writer.write(DELIM);
}
- writer.write(quoteDelimiters(headers[i],SPECIALS));
+ writer.write(quoteDelimiters(headers[i], SPECIALS));
}
writer.write(LINE_SEP);
}
- for (int idx=0; idx < data.size(); idx++) {
- Vector<?> row = (Vector<?>)data.elementAt(idx);
- for (int idy=0; idy < row.size(); idy++) {
+ for (int idx = 0; idx < data.size(); idx++) {
+ Vector<?> row = (Vector<?>) data.elementAt(idx);
+ for (int idy = 0; idy < row.size(); idy++) {
if (idy > 0) {
writer.write(DELIM);
}
Object item = row.elementAt(idy);
- writer.write( quoteDelimiters(String.valueOf(item),SPECIALS));
+ writer.write(quoteDelimiters(String.valueOf(item), SPECIALS));
}
writer.write(LINE_SEP);
}
}
/**
- * Method saves aggregate statistics (with header names) as CSV from a
table model.
- * Same as {@link #saveCSVStats(Vector, FileWriter, String[])} except
+ * Method saves aggregate statistics (with header names) as CSV from a
table
+ * model. Same as {@link #saveCSVStats(Vector, FileWriter, String[])}
except
* that there is no need to create a Vector containing the data.
- *
- * @param model table model containing the data
- * @param writer output file
+ *
+ * @param model
+ * table model containing the data
+ * @param writer
+ * output file
* @throws IOException
*/
- public static void saveCSVStats(DefaultTableModel model, FileWriter
writer) throws IOException {
+ public static void saveCSVStats(DefaultTableModel model, FileWriter writer)
+ throws IOException {
saveCSVStats(model, writer, true);
}
/**
- * Method saves aggregate statistics as CSV from a table model.
- * Same as {@link #saveCSVStats(Vector, FileWriter, String[])} except
- * that there is no need to create a Vector containing the data.
- *
- * @param model table model containing the data
- * @param writer output file
- * @param saveHeaders whether or not to save headers
+ * Method saves aggregate statistics as CSV from a table model. Same as
+ * {@link #saveCSVStats(Vector, FileWriter, String[])} except that there is
+ * no need to create a Vector containing the data.
+ *
+ * @param model
+ * table model containing the data
+ * @param writer
+ * output file
+ * @param saveHeaders
+ * whether or not to save headers
* @throws IOException
*/
- public static void saveCSVStats(DefaultTableModel model, FileWriter
writer, boolean saveHeaders) throws IOException {
+ public static void saveCSVStats(DefaultTableModel model, FileWriter writer,
+ boolean saveHeaders) throws IOException {
final char DELIM = ',';
- final char SPECIALS[] = new char[] {DELIM, QUOTING_CHAR};
+ final char SPECIALS[] = new char[] { DELIM, QUOTING_CHAR };
final int columns = model.getColumnCount();
final int rows = model.getRowCount();
- if (saveHeaders){
- for (int i=0; i < columns; i++){
- if (i>0) {
+ if (saveHeaders) {
+ for (int i = 0; i < columns; i++) {
+ if (i > 0) {
writer.write(DELIM);
}
- writer.write(quoteDelimiters(model.getColumnName(i),SPECIALS));
+ writer.write(quoteDelimiters(model.getColumnName(i),
SPECIALS));
}
writer.write(LINE_SEP);
}
- for (int row=0; row < rows; row++) {
- for (int column=0; column < columns; column++) {
+ for (int row = 0; row < rows; row++) {
+ for (int column = 0; column < columns; column++) {
if (column > 0) {
writer.write(DELIM);
}
Object item = model.getValueAt(row, column);
- writer.write( quoteDelimiters(String.valueOf(item),SPECIALS));
+ writer.write(quoteDelimiters(String.valueOf(item), SPECIALS));
}
writer.write(LINE_SEP);
}
@@ -689,74 +746,83 @@ public final class CSVSaveService {
/**
* Convert a result into a string, where the fields of the result are
* separated by the default delimiter.
- *
+ *
* @param event
* the sample event to be converted
* @return the separated value representation of the result
*/
public static String resultToDelimitedString(SampleEvent event) {
- return resultToDelimitedString(event,
event.getResult().getSaveConfig().getDelimiter());
+ return resultToDelimitedString(event, event.getResult().getSaveConfig()
+ .getDelimiter());
}
/**
* Convert a result into a string, where the fields of the result are
* separated by a specified String.
- *
+ *
* @param event
* the sample event to be converted
* @param delimiter
* the separation string
* @return the separated value representation of the result
*/
- public static String resultToDelimitedString(SampleEvent event, final
String delimiter) {
+ public static String resultToDelimitedString(SampleEvent event,
+ final String delimiter) {
/*
- * Class to handle generating the delimited string.
- * - adds the delimiter if not the first call
- * - quotes any strings that require it
+ * Class to handle generating the delimited string. - adds the
delimiter
+ * if not the first call - quotes any strings that require it
*/
- final class StringQuoter{
+ final class StringQuoter {
final StringBuilder sb = new StringBuilder();
private final char[] specials;
private boolean addDelim;
+
public StringQuoter(char delim) {
- specials = new char[] {delim, QUOTING_CHAR, CharUtils.CR,
CharUtils.LF};
- addDelim=false; // Don't add delimiter first time round
+ specials = new char[] { delim, QUOTING_CHAR, CharUtils.CR,
+ CharUtils.LF };
+ addDelim = false; // Don't add delimiter first time round
}
- private void addDelim(){
- if (addDelim){
+ private void addDelim() {
+ if (addDelim) {
sb.append(specials[0]);
} else {
addDelim = true;
}
}
- // These methods handle parameters that could contain delimiters
or quotes:
- public void append(String s){
+
+ // These methods handle parameters that could contain delimiters or
+ // quotes:
+ public void append(String s) {
addDelim();
- //if (s == null) return;
- sb.append(quoteDelimiters(s,specials));
+ // if (s == null) return;
+ sb.append(quoteDelimiters(s, specials));
}
- public void append(Object obj){
+
+ public void append(Object obj) {
append(String.valueOf(obj));
}
- // These methods handle parameters that cannot contain delimiters
or quotes
- public void append(int i){
+ // These methods handle parameters that cannot contain delimiters
or
+ // quotes
+ public void append(int i) {
addDelim();
sb.append(i);
}
- public void append(long l){
+
+ public void append(long l) {
addDelim();
sb.append(l);
}
- public void append(boolean b){
+
+ public void append(boolean b) {
addDelim();
sb.append(b);
}
@Override
- public String toString(){
+ public String toString() {
return sb.toString();
}
}
@@ -767,10 +833,11 @@ public final class CSVSaveService {
SampleSaveConfiguration saveConfig = sample.getSaveConfig();
if (saveConfig.saveTimestamp()) {
- if (saveConfig.printMilliseconds()){
+ if (saveConfig.printMilliseconds()) {
text.append(sample.getTimeStamp());
} else if (saveConfig.formatter() != null) {
- String stamp = saveConfig.formatter().format(new
Date(sample.getTimeStamp()));
+ String stamp = saveConfig.formatter().format(
+ new Date(sample.getTimeStamp()));
text.append(stamp);
}
}
@@ -809,7 +876,7 @@ public final class CSVSaveService {
if (results != null) {
// Find the first non-null message
- for (int i = 0; i < results.length; i++){
+ for (int i = 0; i < results.length; i++) {
message = results[i].getFailureMessage();
if (message != null) {
break;
@@ -820,7 +887,8 @@ public final class CSVSaveService {
if (message != null) {
text.append(message);
} else {
- text.append(""); // Need to append something so delimiter is
added
+ text.append(""); // Need to append something so delimiter is
+ // added
}
}
@@ -848,7 +916,8 @@ public final class CSVSaveService {
text.append(sample.getDataEncodingWithDefault());
}
- if (saveConfig.saveSampleCount()) {// Need both sample and error count
to be any use
+ if (saveConfig.saveSampleCount()) {// Need both sample and error count
+ // to be any use
text.append(sample.getSampleCount());
text.append(sample.getErrorCount());
}
@@ -857,47 +926,44 @@ public final class CSVSaveService {
text.append(event.getHostname());
}
- for (int i=0; i < SampleEvent.getVarCount(); i++){
+ for (int i = 0; i < SampleEvent.getVarCount(); i++) {
text.append(event.getVarValue(i));
}
return text.toString();
}
- // =================================== CSV quote/unquote handling
==============================
+ // =================================== CSV quote/unquote handling
+ // ==============================
/*
- * Private versions of what might eventually be part of Commons-CSV or
Commons-Lang/Io...
+ * Private versions of what might eventually be part of Commons-CSV or
+ * Commons-Lang/Io...
*/
/*
- * <p>
- * Returns a <code>String</code> value for a character-delimited column
value
- * enclosed in the quote character, if required.
- * </p>
- *
- * <p>
- * If the value contains a special character,
- * then the String value is returned enclosed in the quote character.
+ * <p> Returns a <code>String</code> value for a character-delimited column
+ * value enclosed in the quote character, if required. </p>
+ *
+ * <p> If the value contains a special character, then the String value is
+ * returned enclosed in the quote character. </p>
+ *
+ * <p> Any quote characters in the value are doubled up. </p>
+ *
+ * <p> If the value does not contain any special characters, then the
String
+ * value is returned unchanged. </p>
+ *
+ * <p> N.B. The list of special characters includes the quote character.
* </p>
- *
- * <p>
- * Any quote characters in the value are doubled up.
- * </p>
- *
- * <p>
- * If the value does not contain any special characters,
- * then the String value is returned unchanged.
- * </p>
- *
- * <p>
- * N.B. The list of special characters includes the quote character.
- * </p>
- *
- * @param input the input column String, may be null (without enclosing
delimiters)
- * @param specialChars special characters; second one must be the quote
character
- * @return the input String, enclosed in quote characters if the value
contains a special character,
- * <code>null</code> for null string input
+ *
+ * @param input the input column String, may be null (without enclosing
+ * delimiters)
+ *
+ * @param specialChars special characters; second one must be the quote
+ * character
+ *
+ * @return the input String, enclosed in quote characters if the value
+ * contains a special character, <code>null</code> for null string input
*/
private static String quoteDelimiters(String input, char[] specialChars) {
if (StringUtils.containsNone(input, specialChars)) {
@@ -918,32 +984,39 @@ public final class CSVSaveService {
}
// State of the parser
- private static final int INITIAL=0, PLAIN = 1, QUOTED = 2, EMBEDDEDQUOTE =
3;
+ private static final int INITIAL = 0, PLAIN = 1, QUOTED = 2,
+ EMBEDDEDQUOTE = 3;
public static final char QUOTING_CHAR = '"';
+
/**
* Reads from file and splits input into strings according to the
delimiter,
* taking note of quoted strings.
* <p>
* Handles DOS (CRLF), Unix (LF), and Mac (CR) line-endings equally.
* <p>
- * N.B. a blank line is returned as a zero length array, whereas "" is
returned
- * as an empty string. This is inconsistent.
- * @param infile input file - must support mark(1)
- * @param delim delimiter (e.g. comma)
+ * N.B. a blank line is returned as a zero length array, whereas "" is
+ * returned as an empty string. This is inconsistent.
+ *
+ * @param infile
+ * input file - must support mark(1)
+ * @param delim
+ * delimiter (e.g. comma)
* @return array of strings
- * @throws IOException also for unexpected quote characters
+ * @throws IOException
+ * also for unexpected quote characters
*/
- public static String[] csvReadFile(BufferedReader infile, char delim)
throws IOException {
+ public static String[] csvReadFile(BufferedReader infile, char delim)
+ throws IOException {
int ch;
int state = INITIAL;
List<String> list = new ArrayList<String>();
- ByteArrayOutputStream baos = new ByteArrayOutputStream(200);
+ CharArrayWriter baos = new CharArrayWriter(200);
boolean push = false;
- while(-1 != (ch=infile.read())){
+ while (-1 != (ch = infile.read())) {
push = false;
- switch(state){
+ switch (state) {
case INITIAL:
- if (ch == QUOTING_CHAR){
+ if (ch == QUOTING_CHAR) {
state = QUOTED;
} else if (isDelimOrEOL(delim, ch)) {
push = true;
@@ -953,9 +1026,11 @@ public final class CSVSaveService {
}
break;
case PLAIN:
- if (ch == QUOTING_CHAR){
+ if (ch == QUOTING_CHAR) {
baos.write(ch);
- throw new IOException("Cannot have quote-char in plain
field:["+baos.toString()+"]");
+ throw new IOException(
+ "Cannot have quote-char in plain field:["
+ + baos.toString() + "]");
} else if (isDelimOrEOL(delim, ch)) {
push = true;
state = INITIAL;
@@ -964,14 +1039,14 @@ public final class CSVSaveService {
}
break;
case QUOTED:
- if (ch == QUOTING_CHAR){
- state=EMBEDDEDQUOTE;
+ if (ch == QUOTING_CHAR) {
+ state = EMBEDDEDQUOTE;
} else {
baos.write(ch);
}
break;
case EMBEDDEDQUOTE:
- if (ch == QUOTING_CHAR){
+ if (ch == QUOTING_CHAR) {
baos.write(QUOTING_CHAR); // doubled quote => quote
state = QUOTED;
} else if (isDelimOrEOL(delim, ch)) {
@@ -979,15 +1054,18 @@ public final class CSVSaveService {
state = INITIAL;
} else {
baos.write(QUOTING_CHAR);
- throw new IOException("Cannot have single quote-char in
quoted field:["+baos.toString()+"]");
+ throw new IOException(
+ "Cannot have single quote-char in quoted field:["
+ + baos.toString() + "]");
}
break;
} // switch(state)
if (push) {
if (ch == '\r') {// Remove following \n if present
infile.mark(1);
- if (infile.read() != '\n'){
- infile.reset(); // did not find \n, put the character
back
+ if (infile.read() != '\n') {
+ infile.reset(); // did not find \n, put the character
+ // back
}
}
String s = baos.toString();
@@ -998,15 +1076,17 @@ public final class CSVSaveService {
break;
}
} // while not EOF
- if (ch == -1){// EOF (or end of string) so collect any remaining data
- if (state == QUOTED){
- throw new IOException(state+" Missing trailing quote-char in
quoted field:[\""+baos.toString()+"]");
+ if (ch == -1) {// EOF (or end of string) so collect any remaining data
+ if (state == QUOTED) {
+ throw new IOException(state
+ + " Missing trailing quote-char in quoted field:[\""
+ + baos.toString() + "]");
}
// Do we have some data, or a trailing empty field?
if (baos.size() > 0 // we have some data
- || push // we've started a field
+ || push // we've started a field
|| state == EMBEDDEDQUOTE // Just seen ""
- ) {
+ ) {
list.add(baos.toString());
}
}
@@ -1020,15 +1100,19 @@ public final class CSVSaveService {
/**
* Reads from String and splits into strings according to the delimiter,
* taking note of quoted strings.
- *
+ *
* Handles DOS (CRLF), Unix (LF), and Mac (CR) line-endings equally.
- *
- * @param line input line
- * @param delim delimiter (e.g. comma)
+ *
+ * @param line
+ * input line
+ * @param delim
+ * delimiter (e.g. comma)
* @return array of strings
- * @throws IOException also for unexpected quote characters
+ * @throws IOException
+ * also for unexpected quote characters
*/
- public static String[] csvSplitString(String line, char delim) throws
IOException {
+ public static String[] csvSplitString(String line, char delim)
+ throws IOException {
return csvReadFile(new BufferedReader(new StringReader(line)), delim);
}
}
Modified:
jakarta/jmeter/trunk/test/src/org/apache/jmeter/config/TestCVSDataSet.java
URL:
http://svn.apache.org/viewvc/jakarta/jmeter/trunk/test/src/org/apache/jmeter/config/TestCVSDataSet.java?rev=1156416&r1=1156415&r2=1156416&view=diff
==============================================================================
--- jakarta/jmeter/trunk/test/src/org/apache/jmeter/config/TestCVSDataSet.java
(original)
+++ jakarta/jmeter/trunk/test/src/org/apache/jmeter/config/TestCVSDataSet.java
Thu Aug 11 00:28:58 2011
@@ -92,6 +92,40 @@ public class TestCVSDataSet extends JMet
assertEquals("b1",threadVars.get("b"));
assertEquals("c1",threadVars.get("c"));
}
+
+ public void testutf8() throws Exception {
+
+ CSVDataSet csv = new CSVDataSet();
+ csv.setFilename(findTestPath("testfiles/testutf8.csv"));
+ csv.setVariableNames("a,b,c,d");
+ csv.setDelimiter(",");
+ csv.setQuotedData( true );
+ csv.setFileEncoding( "UTF-8" );
+
+ csv.iterationStart(null);
+ assertEquals("a1",threadVars.get("a"));
+ assertEquals("b1",threadVars.get("b"));
+ assertEquals("\u00e71",threadVars.get("c"));
+ assertEquals("d1",threadVars.get("d"));
+
+ csv.iterationStart(null);
+ assertEquals("a2",threadVars.get("a"));
+ assertEquals("b2",threadVars.get("b"));
+ assertEquals("\u00e72",threadVars.get("c"));
+ assertEquals("d2",threadVars.get("d"));
+
+ csv.iterationStart(null);
+ assertEquals("a3",threadVars.get("a"));
+ assertEquals("b3",threadVars.get("b"));
+ assertEquals("\u00e73",threadVars.get("c"));
+ assertEquals("d3",threadVars.get("d"));
+
+ csv.iterationStart(null);
+ assertEquals("a4",threadVars.get("a"));
+ assertEquals("b4",threadVars.get("b"));
+ assertEquals("\u00e74",threadVars.get("c"));
+ assertEquals("d4",threadVars.get("d"));
+ }
// Test CSV file with a header line
public void testHeaderOpen(){
Modified:
jakarta/jmeter/trunk/test/src/org/apache/jmeter/save/TestCSVSaveService.java
URL:
http://svn.apache.org/viewvc/jakarta/jmeter/trunk/test/src/org/apache/jmeter/save/TestCSVSaveService.java?rev=1156416&r1=1156415&r2=1156416&view=diff
==============================================================================
---
jakarta/jmeter/trunk/test/src/org/apache/jmeter/save/TestCSVSaveService.java
(original)
+++
jakarta/jmeter/trunk/test/src/org/apache/jmeter/save/TestCSVSaveService.java
Thu Aug 11 00:28:58 2011
@@ -60,6 +60,10 @@ public class TestCSVSaveService extends
checkSplitString("a,bc,,", ',', new String[]{"a","bc","",""});
checkSplitString("a,,,", ',', new String[]{"a","","",""});
checkSplitString("a,bc,d,\n",',', new String[]{"a","bc","d",""});
+
+ // \u00e7 = LATIN SMALL LETTER C WITH CEDILLA
+ // \u00e9 = LATIN SMALL LETTER E WITH ACUTE
+ checkSplitString("a,b\u00e7,d,\u00e9", ',', new
String[]{"a","b\u00e7","d","\u00e9"});
}
public void testSplitQuoted() throws Exception {
@@ -75,6 +79,10 @@ public class TestCSVSaveService extends
checkSplitString("a,bc,d,", ',', new String[]{"a","bc","d",""});
checkSplitString("a,bc,d,\"\"", ',', new String[]{"a","bc","d",""});
checkSplitString("a,bc,d,\"\"\n",',', new String[]{"a","bc","d",""});
+
+ // \u00e7 = LATIN SMALL LETTER C WITH CEDILLA
+ // \u00e9 = LATIN SMALL LETTER E WITH ACUTE
+ checkSplitString("\"a\",\"b\u00e7\",\"d\",\"\u00e9\"", ',', new
String[]{"a","b\u00e7","d","\u00e9"});
}
public void testSplitBadQuote() throws Exception {
Modified: jakarta/jmeter/trunk/xdocs/changes.xml
URL:
http://svn.apache.org/viewvc/jakarta/jmeter/trunk/xdocs/changes.xml?rev=1156416&r1=1156415&r2=1156416&view=diff
==============================================================================
--- jakarta/jmeter/trunk/xdocs/changes.xml (original)
+++ jakarta/jmeter/trunk/xdocs/changes.xml Thu Aug 11 00:28:58 2011
@@ -163,6 +163,7 @@ Fixed RMI startup to provide location of
<li>Bug 50221 - Renaming elements in the tree does not resize label</li>
<li>Bug 51002 - Stop Thread if CSV file is not available. JMeter now treats
IOError as EOF.</li>
<li>Define sun.net.http.allowRestrictedHeaders=true by default. This fixes Bug
51238.</li>
+<li>Bug 51645 - CSVDataSet does not read UTF-8 files when file.encoding is
UTF-8</li>
</ul>
<!-- ==================================================== -->
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]