File indexing completed on 2024-04-28 15:11:57

0001 /*
0002     SPDX-FileCopyrightText: 2012 Rishab Arora <ra.rishab@gmail.com>
0003 
0004     SPDX-License-Identifier: GPL-2.0-or-later
0005 */
0006 
0007 /*
0008   * Justification for not testing CombineQuoteParts separately:
0009   * Changing the structure of KSParser would solve this (by removing the
0010   * segments to be tested into separate classes) but would unnecessarily
0011   * complicate things resulting in a large number of small classes.
0012   * This is good from an OOD perspective, but would make the code unmanageable
0013 */
0014 
0015 #include "testcsvparser.h"
0016 
0017 #include <QDir>
0018 #include <QTemporaryFile>
0019 
0020 TestCSVParser::TestCSVParser() : QObject()
0021 {
0022 }
0023 
0024 void TestCSVParser::initTestCase()
0025 {
0026     /*
0027      * Justification for doing this instead of simply creating a file:
0028      * To add/change tests, we'll need to modify 2 places. The file and this class.
0029      * So we write the file from the class.
0030      */
0031     test_cases_.append("\n");
0032     test_cases_.append(QString(","
0033                                "isn't,"
0034                                "it,"
0035                                "\"amusing\","
0036                                "how,"
0037                                "3,"
0038                                "\"isn't, pi\","
0039                                "and,"
0040                                "\"\","
0041                                "-3.141,"
0042                                "isn't,"
0043                                "either\n"));
0044     test_cases_.append(QString(","
0045                                "isn't,"
0046                                "it,"
0047                                "\"amusing\","
0048                                "how,"
0049                                "3,"
0050                                "\"isn't\"(, )\"pi\","
0051                                "and,"
0052                                "\"\","
0053                                "-3.141,"
0054                                "isn't,"
0055                                "either\n"));
0056     test_cases_.append(QString(","
0057                                "isn't,"
0058                                "it,"
0059                                "\"amusing\","
0060                                "how,"
0061                                "3,"
0062                                "\"isn't, pi\","
0063                                "and,"
0064                                "\"\",")); // less than required fields
0065     test_cases_.append(QString(","
0066                                "isn't,"
0067                                "it,"
0068                                "\"amusing\","
0069                                "how,"
0070                                "3,"
0071                                "\"isn't, pi\","
0072                                "and,"
0073                                "\"," // no matching "
0074                                "-3.141,"
0075                                "isn't,"
0076                                "either\n"));
0077     test_cases_.append(",,,,,,,,,,,\n");
0078     test_cases_.append("\n");
0079     QTemporaryFile temp_file;
0080     //temp_file.setPrefix(QDir::tempPath() + QDir::separator());
0081     //temp_file.setSuffix(".txt");
0082     temp_file.setAutoRemove(false);
0083     QVERIFY(temp_file.open());
0084     test_file_name_ = temp_file.fileName();
0085     QTextStream out_stream(&temp_file);
0086     foreach (const QString &test_case, test_cases_)
0087         out_stream << test_case;
0088     temp_file.close();
0089 
0090     //Building the sequence to be used. Includes all available types.
0091     sequence_.clear();
0092     sequence_.append(qMakePair(QString("field1"), KSParser::D_QSTRING));
0093     sequence_.append(qMakePair(QString("field2"), KSParser::D_QSTRING));
0094     sequence_.append(qMakePair(QString("field3"), KSParser::D_QSTRING));
0095     sequence_.append(qMakePair(QString("field4"), KSParser::D_QSTRING));
0096     sequence_.append(qMakePair(QString("field5"), KSParser::D_QSTRING));
0097     sequence_.append(qMakePair(QString("field6"), KSParser::D_INT));
0098     sequence_.append(qMakePair(QString("field7"), KSParser::D_QSTRING));
0099     sequence_.append(qMakePair(QString("field8"), KSParser::D_QSTRING));
0100     sequence_.append(qMakePair(QString("field9"), KSParser::D_QSTRING));
0101     sequence_.append(qMakePair(QString("field10"), KSParser::D_FLOAT));
0102     sequence_.append(qMakePair(QString("field11"), KSParser::D_QSTRING));
0103     sequence_.append(qMakePair(QString("field12"), KSParser::D_QSTRING));
0104 
0105     test_parser_ = new KSParser(test_file_name_, '#', sequence_);
0106 }
0107 
0108 void TestCSVParser::cleanupTestCase()
0109 {
0110     delete test_parser_;
0111 }
0112 
0113 /*
0114  * The following tests checks for the following cases for CSV files
0115  *  1. Mixed inputs (See test case for description)
0116  *  1b. Quoteception
0117  *  2. Empty Row
0118  *  3. No row (only a newline character)
0119  *  4. Truncated row
0120  *  5. Row with no matching quote
0121  *  6. Attempt to read missing file
0122  *
0123 */
0124 
0125 void TestCSVParser::CSVMixedInputs()
0126 {
0127     /*
0128      * Test 1. Includes input of the form:
0129      *
0130      * It starts with a newline char which should be skipped by virtue
0131      * of the design of the parser
0132      *
0133      * Then a row with the following types of inputs:
0134      * 1. empty column
0135      * 2. simple single word
0136      * 3. single word in quotes
0137      * 4. multiple words with , in quotes
0138      * 5. integer
0139      * 6. float
0140     */
0141     QHash<QString, QVariant> row_content = test_parser_->ReadNextRow();
0142     qDebug() << row_content["field1"];
0143     QCOMPARE(row_content["field1"].toString(), QString(""));
0144     QCOMPARE(row_content["field2"].toString(), QString("isn't"));
0145     QCOMPARE(row_content["field3"].toString(), QString("it"));
0146     QCOMPARE(row_content["field4"].toString(), QString("amusing"));
0147     QCOMPARE(row_content["field5"].toString(), QString("how"));
0148     QCOMPARE(row_content["field6"].toInt(), 3);
0149     QCOMPARE(row_content["field7"].toString(), QString("isn't, pi"));
0150     QCOMPARE(row_content["field8"].toString(), QString("and"));
0151     QCOMPARE(row_content["field9"].toString(), QString(""));
0152     QVERIFY(row_content["field10"].toFloat() + 3.141 < 0.1);
0153     QCOMPARE(row_content["field11"].toString(), QString("isn't"));
0154     QCOMPARE(row_content["field12"].toString(), QString("either"));
0155 }
0156 
0157 void TestCSVParser::CSVQuotesInQuotes()
0158 {
0159     /*
0160      * Test 1b. Identical to 1 except quotes in quotes
0161      * in Field 7
0162      *
0163      */
0164     QHash<QString, QVariant> row_content = test_parser_->ReadNextRow();
0165     qDebug() << row_content["field7"];
0166     QCOMPARE(row_content["field1"].toString(), QString(""));
0167     QCOMPARE(row_content["field2"].toString(), QString("isn't"));
0168     QCOMPARE(row_content["field3"].toString(), QString("it"));
0169     QCOMPARE(row_content["field4"].toString(), QString("amusing"));
0170     QCOMPARE(row_content["field5"].toString(), QString("how"));
0171     QCOMPARE(row_content["field6"].toInt(), 3);
0172     QCOMPARE(row_content["field7"].toString(), QString("isn't\"(, )\"pi"));
0173     QCOMPARE(row_content["field8"].toString(), QString("and"));
0174     QCOMPARE(row_content["field9"].toString(), QString(""));
0175     QVERIFY(row_content["field10"].toFloat() + 3.141 < 0.1);
0176     QCOMPARE(row_content["field11"].toString(), QString("isn't"));
0177     QCOMPARE(row_content["field12"].toString(), QString("either"));
0178 }
0179 
0180 void TestCSVParser::CSVEmptyRow()
0181 {
0182     /* Test 2. Row with less rows than required (to be skipped)
0183      * Test 3. Row with truncated \" i.e. no matching "
0184      *         (should be skipped)
0185     */
0186     /*
0187      * Test 4. Attempt to read an empty but valid row
0188      *
0189      * Also includes test for:
0190      * 1. missing integer
0191      * 2. missing float
0192      * 3. missing string
0193     */
0194     QHash<QString, QVariant> row_content = test_parser_->ReadNextRow();
0195     qDebug() << row_content["field1"];
0196     QCOMPARE(row_content["field1"].toString(), QString(""));
0197     QCOMPARE(row_content["field2"].toString(), QString(""));
0198     QCOMPARE(row_content["field3"].toString(), QString(""));
0199     QCOMPARE(row_content["field4"].toString(), QString(""));
0200     QCOMPARE(row_content["field5"].toString(), QString(""));
0201     QCOMPARE(row_content["field6"].toInt(), 0);
0202     QCOMPARE(row_content["field7"].toString(), QString(""));
0203     QCOMPARE(row_content["field8"].toString(), QString(""));
0204     QCOMPARE(row_content["field9"].toString(), QString(""));
0205     QCOMPARE(row_content["field10"].toFloat(), float(0.0));
0206     QCOMPARE(row_content["field11"].toString(), QString(""));
0207     QCOMPARE(row_content["field12"].toString(), QString(""));
0208 }
0209 
0210 void TestCSVParser::CSVNoRow()
0211 {
0212     /*
0213      * Test 3. Attempt to read a newline char instead of a row
0214      * The parser is designed to skip an empty row so we can
0215      * test this for a boundary case. i.e. newline at the end.
0216     */
0217     QHash<QString, QVariant> row_content = test_parser_->ReadNextRow();
0218     qDebug() << row_content["field1"];
0219     QCOMPARE(row_content["field1"].toString(), QString("Null"));
0220     QCOMPARE(row_content["field2"].toString(), QString("Null"));
0221     QCOMPARE(row_content["field3"].toString(), QString("Null"));
0222     QCOMPARE(row_content["field4"].toString(), QString("Null"));
0223     QCOMPARE(row_content["field5"].toString(), QString("Null"));
0224     QCOMPARE(row_content["field6"].toInt(), 0);
0225     QCOMPARE(row_content["field7"].toString(), QString("Null"));
0226     QCOMPARE(row_content["field8"].toString(), QString("Null"));
0227     QCOMPARE(row_content["field9"].toString(), QString("Null"));
0228     QCOMPARE(row_content["field10"].toFloat(), float(0.0));
0229     QCOMPARE(row_content["field11"].toString(), QString("Null"));
0230     QCOMPARE(row_content["field12"].toString(), QString("Null"));
0231 }
0232 
0233 void TestCSVParser::CSVIgnoreHasNextRow()
0234 {
0235     QHash<QString, QVariant> row_content;
0236     for (int times = 0; times < 20; times++)
0237     {
0238         row_content = test_parser_->ReadNextRow();
0239         QCOMPARE(row_content["field1"].toString(), QString("Null"));
0240         QCOMPARE(row_content["field2"].toString(), QString("Null"));
0241         QCOMPARE(row_content["field3"].toString(), QString("Null"));
0242         QCOMPARE(row_content["field4"].toString(), QString("Null"));
0243         QCOMPARE(row_content["field5"].toString(), QString("Null"));
0244         QCOMPARE(row_content["field6"].toInt(), 0);
0245         QCOMPARE(row_content["field7"].toString(), QString("Null"));
0246         QCOMPARE(row_content["field8"].toString(), QString("Null"));
0247         QCOMPARE(row_content["field9"].toString(), QString("Null"));
0248         QCOMPARE(row_content["field10"].toFloat(), float(0.0));
0249         QCOMPARE(row_content["field11"].toString(), QString("Null"));
0250         QCOMPARE(row_content["field12"].toString(), QString("Null"));
0251     }
0252 }
0253 
0254 void TestCSVParser::CSVReadMissingFile()
0255 {
0256     /*
0257      * Test 6. Attempt to read a missing file repeatedly
0258     */
0259     QFile::remove(test_file_name_);
0260 
0261     KSParser missing_parser(test_file_name_, '#', sequence_);
0262     QHash<QString, QVariant> row_content = missing_parser.ReadNextRow();
0263 
0264     for (int times = 0; times < 20; times++)
0265     {
0266         row_content = missing_parser.ReadNextRow();
0267         QCOMPARE(row_content["field1"].toString(), QString("Null"));
0268         QCOMPARE(row_content["field2"].toString(), QString("Null"));
0269         QCOMPARE(row_content["field3"].toString(), QString("Null"));
0270         QCOMPARE(row_content["field4"].toString(), QString("Null"));
0271         QCOMPARE(row_content["field5"].toString(), QString("Null"));
0272         QCOMPARE(row_content["field6"].toInt(), 0);
0273         QCOMPARE(row_content["field7"].toString(), QString("Null"));
0274         QCOMPARE(row_content["field8"].toString(), QString("Null"));
0275         QCOMPARE(row_content["field9"].toString(), QString("Null"));
0276         QCOMPARE(row_content["field10"].toFloat(), float(0.0));
0277         QCOMPARE(row_content["field11"].toString(), QString("Null"));
0278         QCOMPARE(row_content["field12"].toString(), QString("Null"));
0279     }
0280 }
0281 
0282 QTEST_GUILESS_MAIN(TestCSVParser)