changeset 1022:eecf544bed92

Unit tests for StringBits::splitQuoted
author Chris Cannam
date Mon, 01 Dec 2014 15:42:58 +0000 (2014-12-01)
parents 1888ca033a84
children 1f62a890da58
files base/StringBits.cpp base/test/TestStringBits.h base/test/main.cpp base/test/test.pro
diffstat 4 files changed, 229 insertions(+), 78 deletions(-) [+]
line wrap: on
line diff
--- a/base/StringBits.cpp	Mon Dec 01 10:18:55 2014 +0000
+++ b/base/StringBits.cpp	Mon Dec 01 15:42:58 2014 +0000
@@ -20,6 +20,10 @@
 
 #include "StringBits.h"
 
+#include "Debug.h"
+
+using namespace std;
+
 double
 StringBits::stringToDoubleLocaleFree(QString s, bool *ok)
 {
@@ -73,6 +77,11 @@
     QStringList tokens;
     QString tok;
 
+    // sep -> just seen a field separator (or start of line)
+    // unq -> in an unquoted field
+    // q1  -> in a single-quoted field
+    // q2  -> in a double-quoted field
+
     enum { sep, unq, q1, q2 } mode = sep;
 
     for (int i = 0; i < s.length(); ++i) {
@@ -117,86 +126,19 @@
 	}
     }
 
-    if (tok != "" || mode != sep) tokens << tok;
+    if (tok != "" || mode != sep) {
+        if (mode == q1) {
+            tokens << ("'" + tok);  // turns out it wasn't quoted after all
+        } else if (mode == q2) {
+            tokens << ("\"" + tok);
+        } else {
+            tokens << tok;
+        }
+    }
+
     return tokens;
 }
 
-/*
-
-void testSplit()
-{
-    QStringList tests;
-    tests << "a b c d";
-    tests << "a \"b c\" d";
-    tests << "a 'b c' d";
-    tests << "a \"b c\\\" d\"";
-    tests << "a 'b c\\' d'";
-    tests << "a \"b c' d\"";
-    tests << "a 'b c\" d'";
-    tests << "aa 'bb cc\" dd'";
-    tests << "a'a 'bb' \\\"cc\" dd\\\"";
-    tests << "  a'a \\\'	 'bb'	 \'	\\\"cc\" ' dd\\\" '";
-
-    for (int j = 0; j < tests.size(); ++j) {
-	cout << endl;
-	cout << tests[j] << endl;
-	cout << "->" << endl << "(";
-	QStringList l = splitQuoted(tests[j], ' ');
-	for (int i = 0; i < l.size(); ++i) {
-	    if (i > 0) cout << ";";
-	    cout << l[i];
-	}
-	cout << ")" << endl;
-    }
-}
-
-*/
-
-/* 
-   Results:
-
-a b c d
-->     
-(a;b;c;d)
-
-a "b c" d
-->       
-(a;b c;d)
-
-a 'b c' d
-->       
-(a;b c;d)
-
-a "b c\" d"
-->         
-(a;b c" d) 
-
-a 'b c\' d'
-->         
-(a;b c' d) 
-
-a "b c' d"
-->        
-(a;b c' d)
-
-a 'b c" d'
-->        
-(a;b c" d)
-
-aa 'bb cc" dd'
-->            
-(aa;bb cc" dd)
-
-a'a 'bb' \"cc" dd\"
-->                 
-(a'a;bb;"cc";dd")  
-
-  a'a \'         'bb'    '      \"cc" ' dd\" '
-->                                            
-(a'a;';bb;      "cc" ;dd";)
-
-*/
-
 QStringList
 StringBits::split(QString line, QChar separator, bool quoted)
 {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/base/test/TestStringBits.h	Mon Dec 01 15:42:58 2014 +0000
@@ -0,0 +1,203 @@
+/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*-  vi:set ts=8 sts=4 sw=4: */
+
+/*
+    Sonic Visualiser
+    An audio file viewer and annotation editor.
+    Centre for Digital Music, Queen Mary, University of London.
+    
+    This program is free software; you can redistribute it and/or
+    modify it under the terms of the GNU General Public License as
+    published by the Free Software Foundation; either version 2 of the
+    License, or (at your option) any later version.  See the file
+    COPYING included with this distribution for more information.
+*/
+
+#ifndef TEST_STRINGBITS_H
+#define TEST_STRINGBITS_H
+
+#include "../StringBits.h"
+
+#include <QObject>
+#include <QStringList>
+#include <QtTest>
+
+#include <iostream>
+
+using namespace std;
+
+class TestStringBits : public QObject
+{
+    Q_OBJECT
+
+private:
+    void testSplitQuoted(QString in, QStringList out) {
+        // Only suitable where the output strings do not have
+        // consecutive spaces in them
+        QCOMPARE(StringBits::splitQuoted(in, ' '), out);
+        QString in2(in);
+        in2.replace(' ', ',');
+        QStringList out2;
+        foreach (QString o, out) {
+            out2 << o.replace(' ', ',');
+        }
+        QCOMPARE(StringBits::splitQuoted(in2, ','), out2);
+    }
+
+private slots:
+    void simple() {
+        QString in = "a b c d";
+        QStringList out;     
+        out << "a" << "b" << "c" << "d";
+        testSplitQuoted(in, out);
+    }
+
+    void dquoted() {
+        QString in = "a \"b c\" d";
+        QStringList out;       
+        out << "a" << "b c" << "d";
+        testSplitQuoted(in, out);
+    }
+
+    void drunon() {
+        QString in = "a \"b c\"d e";
+        QStringList out;       
+        out << "a" << "b cd" << "e";
+        testSplitQuoted(in, out);
+    }
+
+    void squoted() {
+        QString in = "a 'b c' d";
+        QStringList out;       
+        out << "a" << "b c" << "d";
+        testSplitQuoted(in, out);
+    }
+
+    void srunon() {
+        QString in = "a 'b c'd e";
+        QStringList out;       
+        out << "a" << "b cd" << "e";
+        testSplitQuoted(in, out);
+    }
+
+    void dempty() {
+        QString in = "\"\" \"\" \"\"";
+        QStringList out;       
+        out << "" << "" << "";
+        testSplitQuoted(in, out);
+    }
+
+    void sempty() {
+        QString in = "'' '' ''";
+        QStringList out;       
+        out << "" << "" << "";
+        testSplitQuoted(in, out);
+    }
+
+    void descaped() {
+        QString in = "a \"b c\\\" d\"";
+        QStringList out;         
+        out << "a" << "b c\" d"; 
+        testSplitQuoted(in, out);
+    }
+
+    void sescaped() {
+        QString in = "a 'b c\\' d'";
+        QStringList out;         
+        out << "a" << "b c' d"; 
+        testSplitQuoted(in, out);
+    }
+
+    void dnested() {
+        QString in = "a \"b c' d\"";
+        QStringList out;        
+        out << "a" << "b c' d";
+        testSplitQuoted(in, out);
+    }
+
+    void snested() {
+        QString in = "a 'b c\" d'";
+        QStringList out;        
+        out << "a" << "b c\" d";
+        testSplitQuoted(in, out);
+    }
+
+    void snested2() {
+        QString in = "aa 'bb cc\" dd'";
+        QStringList out;            
+        out << "aa" << "bb cc\" dd";
+        testSplitQuoted(in, out);
+    }
+
+    void qquoted() {
+        QString in = "a'a 'bb' \\\"cc\" dd\\\"";
+        QStringList out;                 
+        out << "a'a" << "bb" << "\"cc\"" << "dd\"";  
+        testSplitQuoted(in, out);
+    }
+
+    void multispace() {
+        QString in = "  a'a \\'         'bb'    '      \\\"cc\" ' dd\\\" '";
+        QStringList out;                                            
+        out << "a'a" << "'" << "bb" << "      \"cc\" " << "dd\"" << "'";
+        QCOMPARE(StringBits::splitQuoted(in, ' '), out);
+
+        QString in2 = ",,a'a,\\',,,,,,,,,'bb',,,,',,,,,,\\\"cc\",',dd\\\",'";
+        QStringList out2;
+        out2 << "" << "" << "a'a" << "'" << "" << "" << "" << "" << "" << ""
+             << "" << "" << "bb" << "" << "" << "" << ",,,,,,\"cc\","
+             << "dd\"" << "'";
+        QCOMPARE(StringBits::splitQuoted(in2, ','), out2);
+    }
+};
+
+#endif
+
+/* r928
+Config: Using QtTest library 5.3.2, Qt 5.3.2
+PASS   : TestStringBits::initTestCase()
+PASS   : TestStringBits::simple()
+PASS   : TestStringBits::dquoted()
+PASS   : TestStringBits::squoted()
+PASS   : TestStringBits::descaped()
+FAIL!  : TestStringBits::sescaped() Compared lists have different sizes.
+   Actual   (StringBits::splitQuoted(in, ' ')) size: 3
+   Expected (out) size: 2
+   Loc: [o/../TestStringBits.h(65)]
+PASS   : TestStringBits::dnested()
+PASS   : TestStringBits::snested()
+PASS   : TestStringBits::snested2()
+PASS   : TestStringBits::qquoted()
+FAIL!  : TestStringBits::multispace() Compared lists differ at index 1.
+   Actual   (StringBits::splitQuoted(in, ' ')): "         "
+   Expected (out): "'"
+   Loc: [o/../TestStringBits.h(100)]
+FAIL!  : TestStringBits::qcommas() Compared lists have different sizes.
+   Actual   (StringBits::splitQuoted(in, ',')) size: 4
+   Expected (out) size: 3
+   Loc: [o/../TestStringBits.h(107)]
+PASS   : TestStringBits::cleanupTestCase()
+Totals: 10 passed, 3 failed, 0 skipped
+*/
+
+/*curr
+PASS   : TestStringBits::initTestCase()
+PASS   : TestStringBits::simple()
+PASS   : TestStringBits::dquoted()
+PASS   : TestStringBits::squoted()
+PASS   : TestStringBits::descaped()
+FAIL!  : TestStringBits::sescaped() Compared lists have different sizes.
+   Actual   (StringBits::splitQuoted(in, ' ')) size: 3
+   Expected (out) size: 2
+   Loc: [o/../TestStringBits.h(65)]
+PASS   : TestStringBits::dnested()
+PASS   : TestStringBits::snested()
+PASS   : TestStringBits::snested2()
+PASS   : TestStringBits::qquoted()
+FAIL!  : TestStringBits::multispace() Compared lists have different sizes.
+   Actual   (StringBits::splitQuoted(in, ' ')) size: 5
+   Expected (out) size: 6
+   Loc: [o/../TestStringBits.h(100)]
+PASS   : TestStringBits::qcommas()
+PASS   : TestStringBits::cleanupTestCase()
+Totals: 11 passed, 2 failed, 0 skipped
+*/
--- a/base/test/main.cpp	Mon Dec 01 10:18:55 2014 +0000
+++ b/base/test/main.cpp	Mon Dec 01 15:42:58 2014 +0000
@@ -14,6 +14,7 @@
 #include "TestRangeMapper.h"
 #include "TestPitch.h"
 #include "TestRealTime.h"
+#include "TestStringBits.h"
 
 #include <QtTest>
 
@@ -42,6 +43,11 @@
 	if (QTest::qExec(&t, argc, argv) == 0) ++good;
 	else ++bad;
     }
+    {
+	TestStringBits t;
+	if (QTest::qExec(&t, argc, argv) == 0) ++good;
+	else ++bad;
+    }
 
     if (bad > 0) {
 	cerr << "\n********* " << bad << " test suite(s) failed!\n" << endl;
--- a/base/test/test.pro	Mon Dec 01 10:18:55 2014 +0000
+++ b/base/test/test.pro	Mon Dec 01 15:42:58 2014 +0000
@@ -49,7 +49,7 @@
 OBJECTS_DIR = o
 MOC_DIR = o
 
-HEADERS += TestRangeMapper.h TestPitch.h TestRealTime.h
+HEADERS += TestRangeMapper.h TestPitch.h TestRealTime.h TestStringBits.h
 SOURCES += main.cpp
 
 win* {