Bug 46491 - Incorrect value for the last variable in "CSV Data Set Config" (error in processing quoted strings)

git-svn-id: https://svn.apache.org/repos/asf/jakarta/jmeter/trunk@740183 13f79535-47bb-0310-9956-ffa450edef68

Former-commit-id: bb1dc0669c
This commit is contained in:
Sebastian Bazley 2009-02-03 01:33:53 +00:00
parent b364ae6ad0
commit 1ba2f2419e
3 changed files with 125 additions and 7 deletions

View File

@ -58,6 +58,7 @@ import org.apache.oro.text.regex.Perl5Matcher;
/** /**
* This class provides a means for saving/reading test results as CSV files. * This class provides a means for saving/reading test results as CSV files.
*/ */
// For unit tests, @see TestCSVSaveService
public final class CSVSaveService { public final class CSVSaveService {
private static final Logger log = LoggingManager.getLoggerForClass(); private static final Logger log = LoggingManager.getLoggerForClass();
@ -137,7 +138,11 @@ public final class CSVSaveService {
lineNumber = 0; lineNumber = 0;
} }
String [] parts; String [] parts;
while ((parts = csvReadFile(dataReader, saveConfig.getDelimiter().charAt(0))).length != 0) { 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
// If so, then need to check whether the reader is at EOF
while ((parts = csvReadFile(dataReader, delim)).length != 0) {
lineNumber++; lineNumber++;
SampleEvent event = CSVSaveService.makeResultFromDelimitedString(parts,saveConfig,lineNumber); SampleEvent event = CSVSaveService.makeResultFromDelimitedString(parts,saveConfig,lineNumber);
if (event != null){ if (event != null){
@ -208,6 +213,8 @@ public final class CSVSaveService {
timeStamp = Long.parseLong(text); timeStamp = Long.parseLong(text);
} catch (NumberFormatException e) {// see if this works } catch (NumberFormatException e) {// see if this works
log.warn(e.toString()); log.warn(e.toString());
// method is only ever called from one thread at a time
// so it's OK to use a static DateFormat
Date stamp = DEFAULT_DATE_FORMAT.parse(text); Date stamp = DEFAULT_DATE_FORMAT.parse(text);
timeStamp = stamp.getTime(); timeStamp = stamp.getTime();
log.warn("Setting date format to: "+DEFAULT_DATE_FORMAT_STRING); log.warn("Setting date format to: "+DEFAULT_DATE_FORMAT_STRING);
@ -911,9 +918,11 @@ public final class CSVSaveService {
/** /**
* Reads from file and splits input into strings according to the delimiter, * Reads from file and splits input into strings according to the delimiter,
* taking note of quoted strings. * taking note of quoted strings.
* * <p>
* Handles DOS (CRLF), Unix (LF), and Mac (CR) line-endings equally. * 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 infile input file - must support mark(1)
* @param delim delimiter (e.g. comma) * @param delim delimiter (e.g. comma)
* @return array of strings * @return array of strings
@ -924,8 +933,9 @@ public final class CSVSaveService {
int state = INITIAL; int state = INITIAL;
List list = new ArrayList(); List list = new ArrayList();
ByteArrayOutputStream baos = new ByteArrayOutputStream(200); ByteArrayOutputStream baos = new ByteArrayOutputStream(200);
while(-1 != (ch=infile.read())){
boolean push = false; boolean push = false;
while(-1 != (ch=infile.read())){
push = false;
switch(state){ switch(state){
case INITIAL: case INITIAL:
if (ch == QUOTING_CHAR){ if (ch == QUOTING_CHAR){
@ -983,15 +993,19 @@ public final class CSVSaveService {
break; break;
} }
} // while not EOF } // while not EOF
if (ch == -1){ if (ch == -1){// EOF (or end of string) so collect any remaining data
if (state == QUOTED){ if (state == QUOTED){
throw new IOException(state+" Missing trailing quote-char in quoted field:[\""+baos.toString()+"]"); throw new IOException(state+" Missing trailing quote-char in quoted field:[\""+baos.toString()+"]");
} }
if (baos.size() > 0) { // Do we have some data, or a trailing empty field?
if (baos.size() > 0 // we have some data
|| push // we've started a field
|| state == EMBEDDEDQUOTE // Just seen ""
) {
list.add(baos.toString()); list.add(baos.toString());
} }
} }
return (String[]) list.toArray(new String[]{}); return (String[]) list.toArray(new String[list.size()]);
} }
private static boolean isDelimOrEOL(char delim, int ch) { private static boolean isDelimOrEOL(char delim, int ch) {

View File

@ -0,0 +1,103 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package org.apache.jmeter.save;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.StringReader;
import org.apache.jmeter.junit.JMeterTestCase;
public class TestCSVSaveService extends JMeterTestCase {
public TestCSVSaveService(String name) {
super(name);
}
private void checkSplitString(String input, char delim, String []expected) throws Exception {
String out[] = CSVSaveService.csvSplitString(input, delim);
checkStrings(expected, out);
}
private void checkStrings(String[] expected, String[] out) {
assertEquals("Incorrect number of strings returned",expected.length, out.length);
for(int i = 0; i < out.length; i++){
assertEquals("Incorrect entry returned",expected[i], out[i]);
}
}
// This is what JOrphanUtils.split() does
public void testSplitEmpty() throws Exception {
checkSplitString("", ',', new String[]{});
}
// These tests should agree with those for JOrphanUtils.split() as far as possible
public void testSplitUnquoted() throws Exception {
checkSplitString("a", ',', new String[]{"a"});
checkSplitString("a,bc,d,e", ',', new String[]{"a","bc","d","e"});
checkSplitString(",bc,d,e", ',', new String[]{"","bc","d","e"});
checkSplitString("a,,d,e", ',', new String[]{"a","","d","e"});
checkSplitString("a,bc, ,e", ',', new String[]{"a","bc"," ","e"});
checkSplitString("a,bc,d, ", ',', new String[]{"a","bc","d"," "});
checkSplitString("a,bc,d,", ',', new String[]{"a","bc","d",""});
checkSplitString("a,bc,,", ',', new String[]{"a","bc","",""});
checkSplitString("a,,,", ',', new String[]{"a","","",""});
checkSplitString("a,bc,d,\n",',', new String[]{"a","bc","d",""});
}
public void testSplitQuoted() throws Exception {
checkSplitString("a,bc,d,e", ',', new String[]{"a","bc","d","e"});
checkSplitString(",bc,d,e", ',', new String[]{"","bc","d","e"});
checkSplitString("\"\",bc,d,e", ',', new String[]{"","bc","d","e"});
checkSplitString("a,,d,e", ',', new String[]{"a","","d","e"});
checkSplitString("a,\"\",d,e", ',', new String[]{"a","","d","e"});
checkSplitString("a,bc, ,e", ',', new String[]{"a","bc"," ","e"});
checkSplitString("a,bc,\" \",e", ',', new String[]{"a","bc"," ","e"});
checkSplitString("a,bc,d, ", ',', new String[]{"a","bc","d"," "});
checkSplitString("a,bc,d,\" \"", ',', new String[]{"a","bc","d"," "});
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",""});
}
public void testSplitBadQuote() throws Exception {
try {
checkSplitString("a\"b",',',null);
fail("Should have generated IOException");
} catch (IOException e) {
}
}
public void testSplitMultiLine() throws Exception {
String line="a,,\"c\nd\",e\n,,f,g,";
String[] out;
BufferedReader br = new BufferedReader(new StringReader(line));
out = CSVSaveService.csvReadFile(br, ',');
checkStrings(new String[]{"a","","c\nd","e"}, out);
out = CSVSaveService.csvReadFile(br, ',');
checkStrings(new String[]{"","","f","g",""}, out);
assertEquals("Expected to be at EOF",-1,br.read());
// Empty strings at EOF
out = CSVSaveService.csvReadFile(br, ',');
checkStrings(new String[]{}, out);
out = CSVSaveService.csvReadFile(br, ',');
checkStrings(new String[]{}, out);
}
}

View File

@ -185,6 +185,7 @@ These are implemented in the AbstractTestElement class which all elements should
<li>Fix potential thread safety issue in JMeterThread class</li> <li>Fix potential thread safety issue in JMeterThread class</li>
<li>Mailer Visualiser - fix parsing of multiple e-mail address when using Test button</li> <li>Mailer Visualiser - fix parsing of multiple e-mail address when using Test button</li>
<li>Bug 46435 - More verbose error msg for error 501 (Proxy Server)</li> <li>Bug 46435 - More verbose error msg for error 501 (Proxy Server)</li>
<li>Bug 46491 - Incorrect value for the last variable in "CSV Data Set Config" (error in processing quoted strings)</li>
</ul> </ul>
<h3>Improvements</h3> <h3>Improvements</h3>