2017-01-08 19:33:21 -05:00
|
|
|
/*
|
|
|
|
* Copyright (C) 2015 Enrico Mariotti <enricomariotti@yahoo.it>
|
2017-06-09 17:40:36 -04:00
|
|
|
* Copyright (C) 2017 KeePassXC Team <team@keepassxc.org>
|
2017-01-08 19:33:21 -05:00
|
|
|
*
|
|
|
|
* 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 or (at your option)
|
|
|
|
* version 3 of the License.
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "TestCsvParser.h"
|
2017-02-21 19:03:22 -05:00
|
|
|
|
2017-01-08 19:33:21 -05:00
|
|
|
#include <QTest>
|
|
|
|
|
|
|
|
QTEST_GUILESS_MAIN(TestCsvParser)
|
|
|
|
|
|
|
|
void TestCsvParser::initTestCase()
|
|
|
|
{
|
2017-11-27 15:41:58 -05:00
|
|
|
parser.reset(new CsvParser());
|
2017-01-08 19:33:21 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
void TestCsvParser::init()
|
|
|
|
{
|
2017-11-27 15:41:58 -05:00
|
|
|
file.reset(new QTemporaryFile());
|
2017-02-21 19:03:22 -05:00
|
|
|
if (not file->open())
|
2017-01-08 19:33:21 -05:00
|
|
|
QFAIL("Cannot open file!");
|
|
|
|
parser->setBackslashSyntax(false);
|
|
|
|
parser->setComment('#');
|
|
|
|
parser->setFieldSeparator(',');
|
|
|
|
parser->setTextQualifier(QChar('"'));
|
|
|
|
}
|
|
|
|
|
|
|
|
void TestCsvParser::cleanup()
|
|
|
|
{
|
2017-02-21 19:03:22 -05:00
|
|
|
file->remove();
|
2017-01-08 19:33:21 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
/****************** TEST CASES ******************/
|
2018-03-31 16:01:30 -04:00
|
|
|
void TestCsvParser::testMissingQuote()
|
|
|
|
{
|
2017-01-08 19:33:21 -05:00
|
|
|
parser->setTextQualifier(':');
|
2017-11-27 15:41:58 -05:00
|
|
|
QTextStream out(file.data());
|
2017-01-08 19:33:21 -05:00
|
|
|
out << "A,B\n:BM,1";
|
|
|
|
QEXPECT_FAIL("", "Bad format", Continue);
|
2017-11-27 15:41:58 -05:00
|
|
|
QVERIFY(parser->parse(file.data()));
|
2017-01-08 19:33:21 -05:00
|
|
|
t = parser->getCsvTable();
|
|
|
|
QWARN(parser->getStatus().toLatin1());
|
|
|
|
}
|
|
|
|
|
2018-03-31 16:01:30 -04:00
|
|
|
void TestCsvParser::testMalformed()
|
|
|
|
{
|
2017-01-08 19:33:21 -05:00
|
|
|
parser->setTextQualifier(':');
|
2017-11-27 15:41:58 -05:00
|
|
|
QTextStream out(file.data());
|
2017-01-08 19:33:21 -05:00
|
|
|
out << "A,B,C\n:BM::,1,:2:";
|
|
|
|
QEXPECT_FAIL("", "Bad format", Continue);
|
2017-11-27 15:41:58 -05:00
|
|
|
QVERIFY(parser->parse(file.data()));
|
2017-01-08 19:33:21 -05:00
|
|
|
t = parser->getCsvTable();
|
|
|
|
QWARN(parser->getStatus().toLatin1());
|
|
|
|
}
|
|
|
|
|
2018-03-31 16:01:30 -04:00
|
|
|
void TestCsvParser::testBackslashSyntax()
|
|
|
|
{
|
2017-01-08 19:33:21 -05:00
|
|
|
parser->setBackslashSyntax(true);
|
|
|
|
parser->setTextQualifier(QChar('X'));
|
2017-11-27 15:41:58 -05:00
|
|
|
QTextStream out(file.data());
|
2018-03-31 16:01:30 -04:00
|
|
|
// attended result: one"\t\"wo
|
2017-01-08 19:33:21 -05:00
|
|
|
out << "Xone\\\"\\\\t\\\\\\\"w\noX\n"
|
|
|
|
<< "X13X,X2\\X,X,\"\"3\"X\r"
|
|
|
|
<< "3,X\"4\"X,,\n"
|
|
|
|
<< "XX\n"
|
|
|
|
<< "\\";
|
2017-11-27 15:41:58 -05:00
|
|
|
QVERIFY(parser->parse(file.data()));
|
2017-01-08 19:33:21 -05:00
|
|
|
t = parser->getCsvTable();
|
|
|
|
QVERIFY(t.at(0).at(0) == "one\"\\t\\\"w\no");
|
|
|
|
QVERIFY(t.at(1).at(0) == "13");
|
|
|
|
QVERIFY(t.at(1).at(1) == "2X,");
|
|
|
|
QVERIFY(t.at(1).at(2) == "\"\"3\"X");
|
|
|
|
QVERIFY(t.at(2).at(0) == "3");
|
|
|
|
QVERIFY(t.at(2).at(1) == "\"4\"");
|
|
|
|
QVERIFY(t.at(2).at(2) == "");
|
|
|
|
QVERIFY(t.at(2).at(3) == "");
|
|
|
|
QVERIFY(t.at(3).at(0) == "\\");
|
|
|
|
QVERIFY(t.size() == 4);
|
|
|
|
}
|
|
|
|
|
2018-03-31 16:01:30 -04:00
|
|
|
void TestCsvParser::testQuoted()
|
|
|
|
{
|
2017-11-27 15:41:58 -05:00
|
|
|
QTextStream out(file.data());
|
2017-01-08 19:33:21 -05:00
|
|
|
out << "ro,w,\"end, of \"\"\"\"\"\"row\"\"\"\"\"\n"
|
|
|
|
<< "2\n";
|
2017-11-27 15:41:58 -05:00
|
|
|
QVERIFY(parser->parse(file.data()));
|
2017-01-08 19:33:21 -05:00
|
|
|
t = parser->getCsvTable();
|
|
|
|
QVERIFY(t.at(0).at(0) == "ro");
|
|
|
|
QVERIFY(t.at(0).at(1) == "w");
|
|
|
|
QVERIFY(t.at(0).at(2) == "end, of \"\"\"row\"\"");
|
|
|
|
QVERIFY(t.at(1).at(0) == "2");
|
|
|
|
QVERIFY(t.size() == 2);
|
|
|
|
}
|
|
|
|
|
2018-03-31 16:01:30 -04:00
|
|
|
void TestCsvParser::testEmptySimple()
|
|
|
|
{
|
2017-11-27 15:41:58 -05:00
|
|
|
QTextStream out(file.data());
|
2018-03-31 16:01:30 -04:00
|
|
|
out << "";
|
2017-11-27 15:41:58 -05:00
|
|
|
QVERIFY(parser->parse(file.data()));
|
2017-01-08 19:33:21 -05:00
|
|
|
t = parser->getCsvTable();
|
2019-10-31 16:44:40 -04:00
|
|
|
QVERIFY(t.isEmpty());
|
2017-01-08 19:33:21 -05:00
|
|
|
}
|
|
|
|
|
2018-03-31 16:01:30 -04:00
|
|
|
void TestCsvParser::testEmptyQuoted()
|
|
|
|
{
|
2017-11-27 15:41:58 -05:00
|
|
|
QTextStream out(file.data());
|
2018-03-31 16:01:30 -04:00
|
|
|
out << "\"\"";
|
2017-11-27 15:41:58 -05:00
|
|
|
QVERIFY(parser->parse(file.data()));
|
2017-01-08 19:33:21 -05:00
|
|
|
t = parser->getCsvTable();
|
2019-10-31 16:44:40 -04:00
|
|
|
QVERIFY(t.isEmpty());
|
2017-01-08 19:33:21 -05:00
|
|
|
}
|
|
|
|
|
2018-03-31 16:01:30 -04:00
|
|
|
void TestCsvParser::testEmptyNewline()
|
|
|
|
{
|
2017-11-27 15:41:58 -05:00
|
|
|
QTextStream out(file.data());
|
2018-03-31 16:01:30 -04:00
|
|
|
out << "\"\n\"";
|
2017-11-27 15:41:58 -05:00
|
|
|
QVERIFY(parser->parse(file.data()));
|
2017-01-08 19:33:21 -05:00
|
|
|
t = parser->getCsvTable();
|
2019-10-31 16:44:40 -04:00
|
|
|
QVERIFY(t.isEmpty());
|
2017-01-08 19:33:21 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
void TestCsvParser::testEmptyFile()
|
|
|
|
{
|
2017-11-27 15:41:58 -05:00
|
|
|
QVERIFY(parser->parse(file.data()));
|
2017-01-08 19:33:21 -05:00
|
|
|
t = parser->getCsvTable();
|
2019-10-31 16:44:40 -04:00
|
|
|
QVERIFY(t.isEmpty());
|
2017-01-08 19:33:21 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
void TestCsvParser::testNewline()
|
|
|
|
{
|
2017-11-27 15:41:58 -05:00
|
|
|
QTextStream out(file.data());
|
2017-01-08 19:33:21 -05:00
|
|
|
out << "1,2\n\n\n";
|
2017-11-27 15:41:58 -05:00
|
|
|
QVERIFY(parser->parse(file.data()));
|
2017-01-08 19:33:21 -05:00
|
|
|
t = parser->getCsvTable();
|
|
|
|
QVERIFY(t.size() == 1);
|
|
|
|
QVERIFY(t.at(0).at(0) == "1");
|
|
|
|
QVERIFY(t.at(0).at(1) == "2");
|
|
|
|
}
|
|
|
|
|
|
|
|
void TestCsvParser::testCR()
|
|
|
|
{
|
2017-11-27 15:41:58 -05:00
|
|
|
QTextStream out(file.data());
|
2017-01-08 19:33:21 -05:00
|
|
|
out << "1,2\r3,4";
|
2017-11-27 15:41:58 -05:00
|
|
|
QVERIFY(parser->parse(file.data()));
|
2017-01-08 19:33:21 -05:00
|
|
|
t = parser->getCsvTable();
|
|
|
|
QVERIFY(t.size() == 2);
|
|
|
|
QVERIFY(t.at(0).at(0) == "1");
|
|
|
|
QVERIFY(t.at(0).at(1) == "2");
|
|
|
|
QVERIFY(t.at(1).at(0) == "3");
|
|
|
|
QVERIFY(t.at(1).at(1) == "4");
|
|
|
|
}
|
|
|
|
|
|
|
|
void TestCsvParser::testLF()
|
|
|
|
{
|
2017-11-27 15:41:58 -05:00
|
|
|
QTextStream out(file.data());
|
2017-01-08 19:33:21 -05:00
|
|
|
out << "1,2\n3,4";
|
2017-11-27 15:41:58 -05:00
|
|
|
QVERIFY(parser->parse(file.data()));
|
2017-01-08 19:33:21 -05:00
|
|
|
t = parser->getCsvTable();
|
|
|
|
QVERIFY(t.size() == 2);
|
|
|
|
QVERIFY(t.at(0).at(0) == "1");
|
|
|
|
QVERIFY(t.at(0).at(1) == "2");
|
|
|
|
QVERIFY(t.at(1).at(0) == "3");
|
|
|
|
QVERIFY(t.at(1).at(1) == "4");
|
|
|
|
}
|
|
|
|
|
|
|
|
void TestCsvParser::testCRLF()
|
|
|
|
{
|
2017-11-27 15:41:58 -05:00
|
|
|
QTextStream out(file.data());
|
2017-01-08 19:33:21 -05:00
|
|
|
out << "1,2\r\n3,4";
|
2017-11-27 15:41:58 -05:00
|
|
|
QVERIFY(parser->parse(file.data()));
|
2017-01-08 19:33:21 -05:00
|
|
|
t = parser->getCsvTable();
|
|
|
|
QVERIFY(t.size() == 2);
|
|
|
|
QVERIFY(t.at(0).at(0) == "1");
|
|
|
|
QVERIFY(t.at(0).at(1) == "2");
|
|
|
|
QVERIFY(t.at(1).at(0) == "3");
|
|
|
|
QVERIFY(t.at(1).at(1) == "4");
|
|
|
|
}
|
|
|
|
|
|
|
|
void TestCsvParser::testComments()
|
|
|
|
{
|
2017-11-27 15:41:58 -05:00
|
|
|
QTextStream out(file.data());
|
2017-01-08 19:33:21 -05:00
|
|
|
out << " #one\n"
|
|
|
|
<< " \t # two, three \r\n"
|
|
|
|
<< " #, sing\t with\r"
|
|
|
|
<< " #\t me!\n"
|
|
|
|
<< "useful,text #1!";
|
2017-11-27 15:41:58 -05:00
|
|
|
QVERIFY(parser->parse(file.data()));
|
2017-01-08 19:33:21 -05:00
|
|
|
t = parser->getCsvTable();
|
|
|
|
QVERIFY(t.size() == 1);
|
|
|
|
QVERIFY(t.at(0).at(0) == "useful");
|
|
|
|
QVERIFY(t.at(0).at(1) == "text #1!");
|
|
|
|
}
|
|
|
|
|
2018-03-31 16:01:30 -04:00
|
|
|
void TestCsvParser::testColumns()
|
|
|
|
{
|
2017-11-27 15:41:58 -05:00
|
|
|
QTextStream out(file.data());
|
2017-01-08 19:33:21 -05:00
|
|
|
out << "1,2\n"
|
|
|
|
<< ",,,,,,,,,a\n"
|
|
|
|
<< "a,b,c,d\n";
|
2017-11-27 15:41:58 -05:00
|
|
|
QVERIFY(parser->parse(file.data()));
|
2017-01-08 19:33:21 -05:00
|
|
|
t = parser->getCsvTable();
|
|
|
|
QVERIFY(parser->getCsvCols() == 10);
|
|
|
|
}
|
|
|
|
|
2018-03-31 16:01:30 -04:00
|
|
|
void TestCsvParser::testSimple()
|
|
|
|
{
|
2017-11-27 15:41:58 -05:00
|
|
|
QTextStream out(file.data());
|
2017-01-08 19:33:21 -05:00
|
|
|
out << ",,2\r,2,3\n"
|
|
|
|
<< "A,,B\"\n"
|
|
|
|
<< " ,,\n";
|
2017-11-27 15:41:58 -05:00
|
|
|
QVERIFY(parser->parse(file.data()));
|
2017-01-08 19:33:21 -05:00
|
|
|
t = parser->getCsvTable();
|
|
|
|
QVERIFY(t.size() == 4);
|
|
|
|
QVERIFY(t.at(0).at(0) == "");
|
|
|
|
QVERIFY(t.at(0).at(1) == "");
|
|
|
|
QVERIFY(t.at(0).at(2) == "2");
|
|
|
|
QVERIFY(t.at(1).at(0) == "");
|
|
|
|
QVERIFY(t.at(1).at(1) == "2");
|
|
|
|
QVERIFY(t.at(1).at(2) == "3");
|
|
|
|
QVERIFY(t.at(2).at(0) == "A");
|
|
|
|
QVERIFY(t.at(2).at(1) == "");
|
|
|
|
QVERIFY(t.at(2).at(2) == "B\"");
|
|
|
|
QVERIFY(t.at(3).at(0) == " ");
|
|
|
|
QVERIFY(t.at(3).at(1) == "");
|
|
|
|
QVERIFY(t.at(3).at(2) == "");
|
|
|
|
}
|
|
|
|
|
2018-03-31 16:01:30 -04:00
|
|
|
void TestCsvParser::testSeparator()
|
|
|
|
{
|
2017-01-08 19:33:21 -05:00
|
|
|
parser->setFieldSeparator('\t');
|
2017-11-27 15:41:58 -05:00
|
|
|
QTextStream out(file.data());
|
2017-01-08 19:33:21 -05:00
|
|
|
out << "\t\t2\r\t2\t3\n"
|
|
|
|
<< "A\t\tB\"\n"
|
|
|
|
<< " \t\t\n";
|
2017-11-27 15:41:58 -05:00
|
|
|
QVERIFY(parser->parse(file.data()));
|
2017-01-08 19:33:21 -05:00
|
|
|
t = parser->getCsvTable();
|
|
|
|
QVERIFY(t.size() == 4);
|
|
|
|
QVERIFY(t.at(0).at(0) == "");
|
|
|
|
QVERIFY(t.at(0).at(1) == "");
|
|
|
|
QVERIFY(t.at(0).at(2) == "2");
|
|
|
|
QVERIFY(t.at(1).at(0) == "");
|
|
|
|
QVERIFY(t.at(1).at(1) == "2");
|
|
|
|
QVERIFY(t.at(1).at(2) == "3");
|
|
|
|
QVERIFY(t.at(2).at(0) == "A");
|
|
|
|
QVERIFY(t.at(2).at(1) == "");
|
|
|
|
QVERIFY(t.at(2).at(2) == "B\"");
|
|
|
|
QVERIFY(t.at(3).at(0) == " ");
|
|
|
|
QVERIFY(t.at(3).at(1) == "");
|
|
|
|
QVERIFY(t.at(3).at(2) == "");
|
|
|
|
}
|
|
|
|
|
|
|
|
void TestCsvParser::testMultiline()
|
|
|
|
{
|
|
|
|
parser->setTextQualifier(QChar(':'));
|
2017-11-27 15:41:58 -05:00
|
|
|
QTextStream out(file.data());
|
2017-01-08 19:33:21 -05:00
|
|
|
out << ":1\r\n2a::b:,:3\r4:\n"
|
|
|
|
<< "2\n";
|
2017-11-27 15:41:58 -05:00
|
|
|
QVERIFY(parser->parse(file.data()));
|
2017-01-08 19:33:21 -05:00
|
|
|
t = parser->getCsvTable();
|
|
|
|
QVERIFY(t.at(0).at(0) == "1\n2a:b");
|
|
|
|
QVERIFY(t.at(0).at(1) == "3\n4");
|
|
|
|
QVERIFY(t.at(1).at(0) == "2");
|
|
|
|
QVERIFY(t.size() == 2);
|
|
|
|
}
|
|
|
|
|
|
|
|
void TestCsvParser::testEmptyReparsing()
|
|
|
|
{
|
|
|
|
parser->parse(nullptr);
|
|
|
|
QVERIFY(parser->reparse());
|
|
|
|
t = parser->getCsvTable();
|
2019-10-31 16:44:40 -04:00
|
|
|
QVERIFY(t.isEmpty());
|
2017-01-08 19:33:21 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
void TestCsvParser::testReparsing()
|
|
|
|
{
|
2017-11-27 15:41:58 -05:00
|
|
|
QTextStream out(file.data());
|
2017-01-08 19:33:21 -05:00
|
|
|
out << ":te\r\nxt1:,:te\rxt2:,:end of \"this\n string\":\n"
|
|
|
|
<< "2\n";
|
2017-11-27 15:41:58 -05:00
|
|
|
QVERIFY(parser->parse(file.data()));
|
2017-01-08 19:33:21 -05:00
|
|
|
t = parser->getCsvTable();
|
|
|
|
|
|
|
|
QEXPECT_FAIL("", "Wrong qualifier", Continue);
|
|
|
|
QVERIFY(t.at(0).at(0) == "te\nxt1");
|
|
|
|
|
|
|
|
parser->setTextQualifier(QChar(':'));
|
|
|
|
|
|
|
|
QVERIFY(parser->reparse());
|
|
|
|
t = parser->getCsvTable();
|
|
|
|
QVERIFY(t.at(0).at(0) == "te\nxt1");
|
|
|
|
QVERIFY(t.at(0).at(1) == "te\nxt2");
|
|
|
|
QVERIFY(t.at(0).at(2) == "end of \"this\n string\"");
|
|
|
|
QVERIFY(t.at(1).at(0) == "2");
|
|
|
|
QVERIFY(t.size() == 2);
|
|
|
|
}
|
|
|
|
|
2018-03-31 16:01:30 -04:00
|
|
|
void TestCsvParser::testQualifier()
|
|
|
|
{
|
2017-01-08 19:33:21 -05:00
|
|
|
parser->setTextQualifier(QChar('X'));
|
2017-11-27 15:41:58 -05:00
|
|
|
QTextStream out(file.data());
|
2017-01-08 19:33:21 -05:00
|
|
|
out << "X1X,X2XX,X,\"\"3\"\"\"X\r"
|
|
|
|
<< "3,X\"4\"X,,\n";
|
2017-11-27 15:41:58 -05:00
|
|
|
QVERIFY(parser->parse(file.data()));
|
2017-01-08 19:33:21 -05:00
|
|
|
t = parser->getCsvTable();
|
|
|
|
QVERIFY(t.size() == 2);
|
|
|
|
QVERIFY(t.at(0).at(0) == "1");
|
|
|
|
QVERIFY(t.at(0).at(1) == "2X,");
|
|
|
|
QVERIFY(t.at(0).at(2) == "\"\"3\"\"\"X");
|
|
|
|
QVERIFY(t.at(1).at(0) == "3");
|
|
|
|
QVERIFY(t.at(1).at(1) == "\"4\"");
|
|
|
|
QVERIFY(t.at(1).at(2) == "");
|
|
|
|
QVERIFY(t.at(1).at(3) == "");
|
|
|
|
}
|
|
|
|
|
2018-03-31 16:01:30 -04:00
|
|
|
void TestCsvParser::testUnicode()
|
|
|
|
{
|
|
|
|
// QString m("Texte en fran\u00e7ais");
|
|
|
|
// CORRECT QString g("\u20AC");
|
|
|
|
// CORRECT QChar g(0x20AC);
|
|
|
|
// ERROR QChar g("\u20AC");
|
2017-01-08 19:33:21 -05:00
|
|
|
parser->setFieldSeparator(QChar('A'));
|
2017-11-27 15:41:58 -05:00
|
|
|
QTextStream out(file.data());
|
2017-12-25 11:10:30 -05:00
|
|
|
out.setCodec("UTF-8");
|
2017-01-08 19:33:21 -05:00
|
|
|
out << QString("€1A2śA\"3śAż\"Ażac");
|
|
|
|
|
2017-11-27 15:41:58 -05:00
|
|
|
QVERIFY(parser->parse(file.data()));
|
2017-01-08 19:33:21 -05:00
|
|
|
t = parser->getCsvTable();
|
|
|
|
QVERIFY(t.size() == 1);
|
|
|
|
QVERIFY(t.at(0).at(0) == "€1");
|
|
|
|
QVERIFY(t.at(0).at(1) == "2ś");
|
|
|
|
QVERIFY(t.at(0).at(2) == "3śAż");
|
|
|
|
QVERIFY(t.at(0).at(3) == "żac");
|
|
|
|
}
|