File indexing completed on 2024-10-06 06:35:10
0001 /* 0002 File : AsciiFilterTest.cpp 0003 Project : LabPlot 0004 Description : Tests for the ascii filter 0005 -------------------------------------------------------------------- 0006 SPDX-FileCopyrightText: 2017-2023 Alexander Semke <alexander.semke@web.de> 0007 SPDX-FileCopyrightText: 2022 Stefan Gerlach <stefan.gerlach@uni.kn> 0008 0009 SPDX-License-Identifier: GPL-2.0-or-later 0010 */ 0011 0012 #include "AsciiFilterTest.h" 0013 #include "backend/core/Project.h" 0014 #include "backend/datasources/filters/AsciiFilter.h" 0015 #include "backend/lib/macros.h" 0016 #include "backend/matrix/Matrix.h" 0017 #include "backend/spreadsheet/Spreadsheet.h" 0018 #include "backend/worksheet/plots/cartesian/CartesianPlot.h" 0019 #include "backend/worksheet/plots/cartesian/XYCurve.h" 0020 0021 #include <gsl/gsl_randist.h> 0022 #include <gsl/gsl_rng.h> 0023 0024 void AsciiFilterTest::initTestCase() { 0025 // needed in order to have the signals triggered by SignallingUndoCommand, see LabPlot.cpp 0026 // TODO: redesign/remove this 0027 qRegisterMetaType<const AbstractAspect*>("const AbstractAspect*"); 0028 qRegisterMetaType<const AbstractColumn*>("const AbstractColumn*"); 0029 } 0030 0031 // ############################################################################## 0032 // ################# handling of empty and sparse files ######################## 0033 // ############################################################################## 0034 void AsciiFilterTest::testEmptyFileAppend() { 0035 Spreadsheet spreadsheet(QStringLiteral("test"), false); 0036 AsciiFilter filter; 0037 0038 const int rowCount = spreadsheet.rowCount(); 0039 const int colCount = spreadsheet.columnCount(); 0040 const QString& fileName = QFINDTESTDATA(QLatin1String("data/empty_file.txt")); 0041 0042 filter.readDataFromFile(fileName, &spreadsheet, AbstractFileFilter::ImportMode::Append); 0043 0044 QCOMPARE(spreadsheet.rowCount(), rowCount); 0045 QCOMPARE(spreadsheet.columnCount(), colCount); 0046 } 0047 0048 void AsciiFilterTest::testEmptyFilePrepend() { 0049 Spreadsheet spreadsheet(QStringLiteral("test"), false); 0050 AsciiFilter filter; 0051 0052 const int rowCount = spreadsheet.rowCount(); 0053 const int colCount = spreadsheet.columnCount(); 0054 const QString& fileName = QFINDTESTDATA(QLatin1String("data/empty_file.txt")); 0055 0056 filter.readDataFromFile(fileName, &spreadsheet, AbstractFileFilter::ImportMode::Prepend); 0057 0058 QCOMPARE(spreadsheet.rowCount(), rowCount); 0059 QCOMPARE(spreadsheet.columnCount(), colCount); 0060 } 0061 0062 void AsciiFilterTest::testEmptyFileReplace() { 0063 Spreadsheet spreadsheet(QStringLiteral("test"), false); 0064 AsciiFilter filter; 0065 0066 const int rowCount = spreadsheet.rowCount(); 0067 const int colCount = spreadsheet.columnCount(); 0068 const QString& fileName = QFINDTESTDATA(QLatin1String("data/empty_file.txt")); 0069 filter.readDataFromFile(fileName, &spreadsheet, AbstractFileFilter::ImportMode::Replace); 0070 0071 QCOMPARE(spreadsheet.rowCount(), rowCount); 0072 QCOMPARE(spreadsheet.columnCount(), colCount); 0073 } 0074 0075 void AsciiFilterTest::testEmptyLines01() { 0076 Spreadsheet spreadsheet(QStringLiteral("test"), false); 0077 AsciiFilter filter; 0078 const QString& fileName = QFINDTESTDATA(QLatin1String("data/empty_lines_01.txt")); 0079 0080 filter.setSeparatingCharacter(QStringLiteral("auto")); 0081 filter.setHeaderEnabled(true); 0082 filter.setHeaderLine(1); 0083 filter.readDataFromFile(fileName, &spreadsheet, AbstractFileFilter::ImportMode::Replace); 0084 0085 QCOMPARE(spreadsheet.rowCount(), 3); 0086 QCOMPARE(spreadsheet.columnCount(), 3); 0087 0088 QCOMPARE(spreadsheet.column(0)->name(), QLatin1String("x")); 0089 QCOMPARE(spreadsheet.column(1)->name(), QLatin1String("y")); 0090 QCOMPARE(spreadsheet.column(2)->name(), QLatin1String("values")); 0091 0092 QCOMPARE(spreadsheet.column(0)->columnMode(), AbstractColumn::ColumnMode::Integer); 0093 QCOMPARE(spreadsheet.column(1)->columnMode(), AbstractColumn::ColumnMode::Integer); 0094 QCOMPARE(spreadsheet.column(2)->columnMode(), AbstractColumn::ColumnMode::Integer); 0095 0096 QCOMPARE(spreadsheet.column(0)->integerAt(0), 1); 0097 QCOMPARE(spreadsheet.column(0)->integerAt(1), 2); 0098 QCOMPARE(spreadsheet.column(0)->integerAt(2), 3); 0099 QCOMPARE(spreadsheet.column(1)->integerAt(0), 2); 0100 QCOMPARE(spreadsheet.column(1)->integerAt(1), 4); 0101 QCOMPARE(spreadsheet.column(1)->integerAt(2), 9); 0102 QCOMPARE(spreadsheet.column(2)->integerAt(0), 10); 0103 QCOMPARE(spreadsheet.column(2)->integerAt(1), 40); 0104 QCOMPARE(spreadsheet.column(2)->integerAt(2), 90); 0105 } 0106 0107 void AsciiFilterTest::testSparseFile01() { 0108 Spreadsheet spreadsheet(QStringLiteral("test"), false); 0109 AsciiFilter filter; 0110 const QString& fileName = QFINDTESTDATA(QLatin1String("data/sparse_file_01.txt")); 0111 0112 filter.setSeparatingCharacter(QStringLiteral(",")); 0113 filter.setHeaderEnabled(true); 0114 filter.setHeaderLine(1); 0115 filter.setSimplifyWhitespacesEnabled(true); 0116 filter.readDataFromFile(fileName, &spreadsheet, AbstractFileFilter::ImportMode::Replace); 0117 0118 QCOMPARE(spreadsheet.rowCount(), 3); 0119 QCOMPARE(spreadsheet.columnCount(), 3); 0120 0121 QCOMPARE(spreadsheet.column(0)->name(), QLatin1String("N")); 0122 QCOMPARE(spreadsheet.column(1)->name(), QLatin1String("Col1")); 0123 QCOMPARE(spreadsheet.column(2)->name(), QLatin1String("Col2")); 0124 0125 QCOMPARE(spreadsheet.column(0)->columnMode(), AbstractColumn::ColumnMode::Integer); 0126 QCOMPARE(spreadsheet.column(1)->columnMode(), AbstractColumn::ColumnMode::Integer); 0127 QCOMPARE(spreadsheet.column(2)->columnMode(), AbstractColumn::ColumnMode::Integer); 0128 0129 QCOMPARE(spreadsheet.column(0)->integerAt(0), 1); 0130 QCOMPARE(spreadsheet.column(0)->integerAt(1), 2); 0131 QCOMPARE(spreadsheet.column(0)->integerAt(2), 3); 0132 0133 QCOMPARE(spreadsheet.column(1)->integerAt(0), 1); 0134 QCOMPARE(spreadsheet.column(1)->integerAt(1), 0); 0135 QCOMPARE(spreadsheet.column(1)->integerAt(2), 1); 0136 0137 QCOMPARE(spreadsheet.column(2)->integerAt(0), 2); 0138 QCOMPARE(spreadsheet.column(2)->integerAt(1), 2); 0139 QCOMPARE(spreadsheet.column(2)->integerAt(2), 0); 0140 } 0141 0142 void AsciiFilterTest::testSparseFile02() { 0143 Spreadsheet spreadsheet(QStringLiteral("test"), false); 0144 AsciiFilter filter; 0145 const QString& fileName = QFINDTESTDATA(QLatin1String("data/sparse_file_02.txt")); 0146 0147 filter.setSeparatingCharacter(QStringLiteral(",")); 0148 filter.setNaNValueToZero(false); 0149 filter.setSimplifyWhitespacesEnabled(true); 0150 filter.setSkipEmptyParts(false); 0151 filter.setHeaderEnabled(true); 0152 filter.setHeaderLine(1); 0153 filter.readDataFromFile(fileName, &spreadsheet, AbstractFileFilter::ImportMode::Replace); 0154 0155 QCOMPARE(spreadsheet.rowCount(), 3); 0156 QCOMPARE(spreadsheet.columnCount(), 3); 0157 0158 QCOMPARE(spreadsheet.column(0)->name(), QLatin1String("N")); 0159 QCOMPARE(spreadsheet.column(1)->name(), QLatin1String("Col1")); 0160 QCOMPARE(spreadsheet.column(2)->name(), QLatin1String("Col2")); 0161 0162 QCOMPARE(spreadsheet.column(0)->columnMode(), AbstractColumn::ColumnMode::Integer); 0163 QCOMPARE(spreadsheet.column(1)->columnMode(), AbstractColumn::ColumnMode::Double); 0164 QCOMPARE(spreadsheet.column(2)->columnMode(), AbstractColumn::ColumnMode::Double); 0165 0166 QCOMPARE(spreadsheet.column(0)->integerAt(0), 1); 0167 QCOMPARE(spreadsheet.column(0)->integerAt(1), 2); 0168 QCOMPARE(spreadsheet.column(0)->integerAt(2), 3); 0169 0170 QCOMPARE(spreadsheet.column(1)->valueAt(0), 1.); 0171 QCOMPARE((bool)std::isnan(spreadsheet.column(1)->valueAt(1)), true); 0172 QCOMPARE(spreadsheet.column(1)->valueAt(2), 1.); 0173 0174 QCOMPARE(spreadsheet.column(2)->valueAt(0), 2.); 0175 QCOMPARE(spreadsheet.column(2)->valueAt(1), 2.); 0176 QCOMPARE((bool)std::isnan(spreadsheet.column(2)->valueAt(2)), true); 0177 } 0178 0179 void AsciiFilterTest::testSparseFile03() { 0180 Spreadsheet spreadsheet(QStringLiteral("test"), false); 0181 AsciiFilter filter; 0182 const QString& fileName = QFINDTESTDATA(QLatin1String("data/sparse_file_03.txt")); 0183 0184 filter.setSeparatingCharacter(QStringLiteral(",")); 0185 filter.setNaNValueToZero(true); 0186 filter.setSimplifyWhitespacesEnabled(true); 0187 filter.setSkipEmptyParts(false); 0188 filter.setHeaderEnabled(true); 0189 filter.setHeaderLine(1); 0190 filter.readDataFromFile(fileName, &spreadsheet, AbstractFileFilter::ImportMode::Replace); 0191 0192 QCOMPARE(spreadsheet.rowCount(), 4); 0193 QCOMPARE(spreadsheet.columnCount(), 3); 0194 0195 QCOMPARE(spreadsheet.column(0)->name(), QLatin1String("N")); 0196 QCOMPARE(spreadsheet.column(1)->name(), QLatin1String("Col1")); 0197 QCOMPARE(spreadsheet.column(2)->name(), QLatin1String("Col2")); 0198 0199 QCOMPARE(spreadsheet.column(0)->columnMode(), AbstractColumn::ColumnMode::Integer); 0200 QCOMPARE(spreadsheet.column(1)->columnMode(), AbstractColumn::ColumnMode::Double); 0201 QCOMPARE(spreadsheet.column(2)->columnMode(), AbstractColumn::ColumnMode::Double); 0202 0203 QCOMPARE(spreadsheet.column(0)->integerAt(0), 1); 0204 QCOMPARE(spreadsheet.column(0)->integerAt(1), 2); 0205 QCOMPARE(spreadsheet.column(0)->integerAt(2), 3); 0206 QCOMPARE(spreadsheet.column(0)->integerAt(3), 0); 0207 0208 QCOMPARE(spreadsheet.column(1)->valueAt(0), 1.); 0209 QCOMPARE(spreadsheet.column(1)->valueAt(1), 0.); 0210 QCOMPARE(spreadsheet.column(1)->valueAt(2), 1.); 0211 QCOMPARE(spreadsheet.column(1)->valueAt(3), 0.); 0212 0213 QCOMPARE(spreadsheet.column(2)->valueAt(0), 2.); 0214 QCOMPARE(spreadsheet.column(2)->valueAt(1), 2.); 0215 QCOMPARE(spreadsheet.column(2)->valueAt(2), 0.); 0216 QCOMPARE(spreadsheet.column(2)->valueAt(3), 3.); 0217 } 0218 0219 // ############################################################################## 0220 // ################################ header handling ############################ 0221 // ############################################################################## 0222 void AsciiFilterTest::testHeader01() { 0223 Spreadsheet spreadsheet(QStringLiteral("test"), false); 0224 AsciiFilter filter; 0225 const QString& fileName = QFINDTESTDATA(QLatin1String("data/separator_semicolon.txt")); 0226 0227 filter.setSeparatingCharacter(QStringLiteral(";")); 0228 filter.setHeaderEnabled(false); 0229 filter.setVectorNames(QString()); 0230 filter.readDataFromFile(fileName, &spreadsheet, AbstractFileFilter::ImportMode::Replace); 0231 0232 QCOMPARE(spreadsheet.rowCount(), 3); 0233 QCOMPARE(spreadsheet.columnCount(), 2); 0234 } 0235 0236 void AsciiFilterTest::testHeader02() { 0237 Spreadsheet spreadsheet(QStringLiteral("test"), false); 0238 AsciiFilter filter; 0239 const QString& fileName = QFINDTESTDATA(QLatin1String("data/separator_semicolon.txt")); 0240 0241 filter.setSeparatingCharacter(QStringLiteral(";")); 0242 filter.setHeaderEnabled(true); 0243 filter.setHeaderLine(1); 0244 filter.setVectorNames(QString()); 0245 filter.readDataFromFile(fileName, &spreadsheet, AbstractFileFilter::ImportMode::Replace); 0246 0247 QCOMPARE(spreadsheet.rowCount(), 2); // out of 3 rows one row is used for the column names (header) 0248 QCOMPARE(spreadsheet.columnCount(), 2); 0249 QCOMPARE(spreadsheet.column(0)->name(), QLatin1String("1")); 0250 QCOMPARE(spreadsheet.column(1)->name(), QLatin1String("2")); 0251 } 0252 0253 void AsciiFilterTest::testHeader03() { 0254 Spreadsheet spreadsheet(QStringLiteral("test"), false); 0255 AsciiFilter filter; 0256 const QString& fileName = QFINDTESTDATA(QLatin1String("data/separator_semicolon.txt")); 0257 0258 filter.setSeparatingCharacter(QStringLiteral(";")); 0259 filter.setHeaderEnabled(false); 0260 filter.setVectorNames(QStringLiteral("x")); 0261 filter.readDataFromFile(fileName, &spreadsheet, AbstractFileFilter::ImportMode::Replace); 0262 0263 QCOMPARE(spreadsheet.rowCount(), 3); 0264 QCOMPARE(spreadsheet.columnCount(), 1); // one column name was specified, we import only one column 0265 QCOMPARE(spreadsheet.column(0)->name(), QLatin1String("x")); 0266 } 0267 0268 void AsciiFilterTest::testHeader04() { 0269 Spreadsheet spreadsheet(QStringLiteral("test"), false); 0270 AsciiFilter filter; 0271 const QString& fileName = QFINDTESTDATA(QLatin1String("data/separator_semicolon.txt")); 0272 0273 filter.setSeparatingCharacter(QStringLiteral(";")); 0274 filter.setHeaderEnabled(false); 0275 filter.setVectorNames(QStringLiteral("x")); 0276 filter.readDataFromFile(fileName, &spreadsheet, AbstractFileFilter::ImportMode::Replace); 0277 0278 QCOMPARE(spreadsheet.rowCount(), 3); 0279 QCOMPARE(spreadsheet.columnCount(), 1); // one column name was specified -> we import only one column 0280 QCOMPARE(spreadsheet.column(0)->name(), QLatin1String("x")); 0281 } 0282 0283 void AsciiFilterTest::testHeader05() { 0284 Spreadsheet spreadsheet(QStringLiteral("test"), false); 0285 AsciiFilter filter; 0286 const QString& fileName = QFINDTESTDATA(QLatin1String("data/separator_semicolon.txt")); 0287 0288 filter.setSeparatingCharacter(QStringLiteral(";")); 0289 filter.setHeaderEnabled(false); 0290 filter.setVectorNames(QStringLiteral("x y")); 0291 filter.readDataFromFile(fileName, &spreadsheet, AbstractFileFilter::ImportMode::Replace); 0292 0293 QCOMPARE(spreadsheet.rowCount(), 3); 0294 QCOMPARE(spreadsheet.columnCount(), 2); // two names were specified -> we import two columns 0295 QCOMPARE(spreadsheet.column(0)->name(), QLatin1String("x")); 0296 QCOMPARE(spreadsheet.column(1)->name(), QLatin1String("y")); 0297 } 0298 0299 void AsciiFilterTest::testHeader06() { 0300 Spreadsheet spreadsheet(QStringLiteral("test"), false); 0301 AsciiFilter filter; 0302 const QString& fileName = QFINDTESTDATA(QLatin1String("data/separator_semicolon.txt")); 0303 0304 filter.setSeparatingCharacter(QStringLiteral(";")); 0305 filter.setHeaderEnabled(false); 0306 filter.setVectorNames(QStringLiteral("x y z")); 0307 filter.readDataFromFile(fileName, &spreadsheet, AbstractFileFilter::ImportMode::Replace); 0308 0309 QCOMPARE(spreadsheet.rowCount(), 3); 0310 QCOMPARE(spreadsheet.columnCount(), 2); // three names were specified, but there're only two columns in the file -> we import only two columns 0311 QCOMPARE(spreadsheet.column(0)->name(), QLatin1String("x")); 0312 QCOMPARE(spreadsheet.column(1)->name(), QLatin1String("y")); 0313 } 0314 0315 /*! 0316 * test with a file containing the header in the second line 0317 * with a subsequent comment line without any comment character. 0318 * this line shouldn't disturb the detection of numeric column modes. 0319 */ 0320 void AsciiFilterTest::testHeader07() { 0321 Spreadsheet spreadsheet(QStringLiteral("test"), false); 0322 AsciiFilter filter; 0323 const QString& fileName = QFINDTESTDATA(QLatin1String("data/comment_header_comment.txt")); 0324 0325 filter.setSeparatingCharacter(QStringLiteral("TAB")); 0326 filter.setHeaderEnabled(true); 0327 filter.setHeaderLine(2); 0328 filter.setDateTimeFormat(QLatin1String("yyyy-MM-dd hh:mm:ss.zzz")); 0329 filter.readDataFromFile(fileName, &spreadsheet, AbstractFileFilter::ImportMode::Replace); 0330 0331 // spreadsheet size 0332 QCOMPARE(spreadsheet.columnCount(), 3); 0333 QCOMPARE(spreadsheet.rowCount(), 4); 0334 0335 // column names 0336 QCOMPARE(spreadsheet.column(0)->name(), QLatin1String("counter")); 0337 QCOMPARE(spreadsheet.column(1)->name(), QLatin1String("t[min]")); 0338 QCOMPARE(spreadsheet.column(2)->name(), QLatin1String("#1ch1")); 0339 0340 // data types 0341 QCOMPARE(spreadsheet.column(0)->columnMode(), AbstractColumn::ColumnMode::Integer); 0342 QCOMPARE(spreadsheet.column(1)->columnMode(), AbstractColumn::ColumnMode::Double); 0343 QCOMPARE(spreadsheet.column(2)->columnMode(), AbstractColumn::ColumnMode::Double); 0344 0345 // values 0346 QCOMPARE(spreadsheet.column(0)->integerAt(0), 0); 0347 QCOMPARE((bool)std::isnan(spreadsheet.column(1)->valueAt(0)), true); 0348 QCOMPARE((bool)std::isnan(spreadsheet.column(2)->valueAt(0)), true); 0349 0350 QCOMPARE(spreadsheet.column(0)->integerAt(1), 1); 0351 QCOMPARE(spreadsheet.column(1)->valueAt(1), 0.0513); 0352 QCOMPARE(spreadsheet.column(2)->valueAt(1), 0.3448); 0353 0354 QCOMPARE(spreadsheet.column(0)->integerAt(2), 2); 0355 QCOMPARE(spreadsheet.column(1)->valueAt(2), 0.1005); 0356 QCOMPARE(spreadsheet.column(2)->valueAt(2), 0.3418); 0357 0358 QCOMPARE(spreadsheet.column(0)->integerAt(3), 3); 0359 QCOMPARE(spreadsheet.column(1)->valueAt(3), 0.1516); 0360 QCOMPARE(spreadsheet.column(2)->valueAt(3), 0.3433); 0361 } 0362 0363 /*! 0364 * test with a file containing the header in the second line 0365 * with a subsequent comment line ignored by using startRow. 0366 */ 0367 void AsciiFilterTest::testHeader07a() { 0368 Spreadsheet spreadsheet(QStringLiteral("test"), false); 0369 AsciiFilter filter; 0370 const QString& fileName = QFINDTESTDATA(QLatin1String("data/comment_header_comment.txt")); 0371 0372 filter.setSeparatingCharacter(QStringLiteral("TAB")); 0373 filter.setHeaderLine(2); 0374 filter.setHeaderEnabled(true); 0375 filter.setStartRow(4); 0376 filter.setDateTimeFormat(QLatin1String("yyyy-MM-dd hh:mm:ss.zzz")); 0377 filter.readDataFromFile(fileName, &spreadsheet, AbstractFileFilter::ImportMode::Replace); 0378 0379 // spreadsheet size 0380 QCOMPARE(spreadsheet.columnCount(), 3); 0381 QCOMPARE(spreadsheet.rowCount(), 3); 0382 0383 // column names 0384 QCOMPARE(spreadsheet.column(0)->name(), QLatin1String("counter")); 0385 QCOMPARE(spreadsheet.column(1)->name(), QLatin1String("t[min]")); 0386 QCOMPARE(spreadsheet.column(2)->name(), QLatin1String("#1ch1")); 0387 0388 // data types 0389 QCOMPARE(spreadsheet.column(0)->columnMode(), AbstractColumn::ColumnMode::Integer); 0390 QCOMPARE(spreadsheet.column(1)->columnMode(), AbstractColumn::ColumnMode::Double); 0391 QCOMPARE(spreadsheet.column(2)->columnMode(), AbstractColumn::ColumnMode::Double); 0392 0393 // values 0394 QCOMPARE(spreadsheet.column(0)->integerAt(0), 1); 0395 QCOMPARE(spreadsheet.column(1)->valueAt(0), 0.0513); 0396 QCOMPARE(spreadsheet.column(2)->valueAt(0), 0.3448); 0397 0398 QCOMPARE(spreadsheet.column(0)->integerAt(1), 2); 0399 QCOMPARE(spreadsheet.column(1)->valueAt(1), 0.1005); 0400 QCOMPARE(spreadsheet.column(2)->valueAt(1), 0.3418); 0401 0402 QCOMPARE(spreadsheet.column(0)->integerAt(2), 3); 0403 QCOMPARE(spreadsheet.column(1)->valueAt(2), 0.1516); 0404 QCOMPARE(spreadsheet.column(2)->valueAt(2), 0.3433); 0405 } 0406 0407 /*! 0408 * the header contains spaces in the column names, values are tab separated. 0409 * when using "auto" for the separator characters, the tab character has to 0410 * be properly recognized and used. 0411 */ 0412 void AsciiFilterTest::testHeader08() { 0413 Spreadsheet spreadsheet(QStringLiteral("test"), false); 0414 AsciiFilter filter; 0415 const QString& fileName = QFINDTESTDATA(QLatin1String("data/separator_tab_with_header_with_spaces.txt")); 0416 0417 filter.setHeaderEnabled(true); 0418 filter.setHeaderLine(1); 0419 filter.readDataFromFile(fileName, &spreadsheet, AbstractFileFilter::ImportMode::Replace); 0420 0421 // spreadsheet size 0422 QCOMPARE(spreadsheet.columnCount(), 2); 0423 QCOMPARE(spreadsheet.rowCount(), 2); 0424 0425 // column names 0426 QCOMPARE(spreadsheet.column(0)->name(), QLatin1String("first column")); 0427 QCOMPARE(spreadsheet.column(1)->name(), QLatin1String("second column")); 0428 0429 // data types 0430 QCOMPARE(spreadsheet.column(0)->columnMode(), AbstractColumn::ColumnMode::Integer); 0431 QCOMPARE(spreadsheet.column(1)->columnMode(), AbstractColumn::ColumnMode::Integer); 0432 0433 // values 0434 QCOMPARE(spreadsheet.column(0)->integerAt(0), 1); 0435 QCOMPARE(spreadsheet.column(1)->integerAt(0), 2); 0436 0437 QCOMPARE(spreadsheet.column(0)->integerAt(1), 3); 0438 QCOMPARE(spreadsheet.column(1)->integerAt(1), 4); 0439 } 0440 0441 /*! 0442 * test the handling of duplicated columns names provided by the user. 0443 */ 0444 void AsciiFilterTest::testHeader09() { 0445 Spreadsheet spreadsheet(QStringLiteral("test"), false); 0446 AsciiFilter filter; 0447 const QString& fileName = QFINDTESTDATA(QLatin1String("data/separator_semicolon.txt")); 0448 0449 filter.setSeparatingCharacter(QStringLiteral(";")); 0450 filter.setHeaderEnabled(false); 0451 filter.setVectorNames(QStringList{QStringLiteral("x"), QStringLiteral("x")}); 0452 filter.readDataFromFile(fileName, &spreadsheet, AbstractFileFilter::ImportMode::Replace); 0453 0454 QCOMPARE(spreadsheet.rowCount(), 3); 0455 QCOMPARE(spreadsheet.columnCount(), 2); 0456 QCOMPARE(spreadsheet.column(0)->name(), QLatin1String("x")); 0457 QCOMPARE(spreadsheet.column(1)->name(), QLatin1String("x 1")); // the duplicated name was renamed 0458 } 0459 0460 /*! 0461 * test the handling of duplicated columns in the file to be imported. 0462 */ 0463 void AsciiFilterTest::testHeader10() { 0464 Spreadsheet spreadsheet(QStringLiteral("test"), false); 0465 AsciiFilter filter; 0466 const QString& fileName = QFINDTESTDATA(QLatin1String("data/separator_semicolon_with_header_duplicated_names.txt")); 0467 0468 filter.setSeparatingCharacter(QStringLiteral(";")); 0469 filter.setHeaderEnabled(true); 0470 filter.setHeaderLine(1); 0471 filter.readDataFromFile(fileName, &spreadsheet, AbstractFileFilter::ImportMode::Replace); 0472 0473 QCOMPARE(spreadsheet.rowCount(), 3); 0474 QCOMPARE(spreadsheet.columnCount(), 2); 0475 QCOMPARE(spreadsheet.column(0)->name(), QLatin1String("x")); 0476 QCOMPARE(spreadsheet.column(1)->name(), QLatin1String("x 1")); // the duplicated name was renamed 0477 } 0478 0479 /*! 0480 * test the handling of duplicated columns in the file to be imported. 0481 */ 0482 void AsciiFilterTest::testHeader11() { 0483 Spreadsheet spreadsheet(QStringLiteral("test"), false); 0484 AsciiFilter filter; 0485 const QString& fileName = QFINDTESTDATA(QLatin1String("data/column_names.txt")); 0486 0487 filter.setSeparatingCharacter(QStringLiteral(" ")); 0488 filter.setHeaderEnabled(true); 0489 filter.setHeaderLine(1); 0490 filter.readDataFromFile(fileName, &spreadsheet, AbstractFileFilter::ImportMode::Replace); 0491 0492 QCOMPARE(spreadsheet.rowCount(), 1); 0493 QCOMPARE(spreadsheet.columnCount(), 2); 0494 QCOMPARE(spreadsheet.column(0)->name(), QLatin1String("A")); 0495 QCOMPARE(spreadsheet.column(1)->name(), QLatin1String("B")); 0496 0497 // import the second file with reversed column names into the same spreadsheet 0498 AsciiFilter filter2; // create a new filter so we go through the prepare logic from scratch for the 2nd file 0499 const QString& fileName2 = QFINDTESTDATA(QLatin1String("data/column_names_reversed.txt")); 0500 filter2.setSeparatingCharacter(QStringLiteral(" ")); 0501 filter.setHeaderEnabled(true); 0502 filter2.setHeaderLine(1); 0503 filter2.readDataFromFile(fileName2, &spreadsheet, AbstractFileFilter::ImportMode::Replace); 0504 0505 QCOMPARE(spreadsheet.rowCount(), 1); 0506 QCOMPARE(spreadsheet.columnCount(), 2); 0507 QCOMPARE(spreadsheet.column(0)->name(), QLatin1String("B")); 0508 QCOMPARE(spreadsheet.column(1)->name(), QLatin1String("A")); 0509 } 0510 0511 /*! 0512 * test the handling of column names with and without header 0513 */ 0514 void AsciiFilterTest::testHeader11a() { 0515 Spreadsheet spreadsheet(QStringLiteral("test"), false); 0516 AsciiFilter filter; 0517 const QString& fileName = QFINDTESTDATA(QLatin1String("data/column_names.txt")); 0518 0519 filter.setSeparatingCharacter(QStringLiteral(" ")); 0520 filter.setHeaderEnabled(true); 0521 filter.setHeaderLine(1); 0522 filter.readDataFromFile(fileName, &spreadsheet, AbstractFileFilter::ImportMode::Replace); 0523 0524 QCOMPARE(spreadsheet.rowCount(), 1); 0525 QCOMPARE(spreadsheet.columnCount(), 2); 0526 QCOMPARE(spreadsheet.column(0)->name(), QLatin1String("A")); 0527 QCOMPARE(spreadsheet.column(1)->name(), QLatin1String("B")); 0528 0529 AsciiFilter filter2; 0530 filter2.setHeaderEnabled(false); 0531 filter2.setSeparatingCharacter(QStringLiteral(" ")); 0532 filter2.readDataFromFile(fileName, &spreadsheet, AbstractFileFilter::ImportMode::Replace); 0533 0534 QCOMPARE(spreadsheet.rowCount(), 2); 0535 QCOMPARE(spreadsheet.columnCount(), 2); 0536 QCOMPARE(spreadsheet.column(0)->name(), QLatin1String("Column 1")); 0537 QCOMPARE(spreadsheet.column(1)->name(), QLatin1String("Column 2")); 0538 } 0539 0540 // ############################################################################## 0541 // ##################### handling of different read ranges ##################### 0542 // ############################################################################## 0543 void AsciiFilterTest::testColumnRange00() { 0544 Spreadsheet spreadsheet(QStringLiteral("test"), false); 0545 AsciiFilter filter; 0546 const QString& fileName = QFINDTESTDATA(QLatin1String("data/numeric_data.txt")); 0547 0548 filter.setSeparatingCharacter(QStringLiteral("auto")); 0549 filter.setHeaderEnabled(false); 0550 filter.readDataFromFile(fileName, &spreadsheet, AbstractFileFilter::ImportMode::Replace); 0551 0552 // no ranges specified, all rows and columns have to be read 0553 QCOMPARE(spreadsheet.rowCount(), 5); 0554 QCOMPARE(spreadsheet.columnCount(), 3); 0555 0556 QCOMPARE(spreadsheet.column(0)->columnMode(), AbstractColumn::ColumnMode::Double); 0557 QCOMPARE(spreadsheet.column(1)->columnMode(), AbstractColumn::ColumnMode::Double); 0558 QCOMPARE(spreadsheet.column(2)->columnMode(), AbstractColumn::ColumnMode::Double); 0559 0560 // check the values for the first line 0561 QCOMPARE(spreadsheet.column(0)->valueAt(0), 1.716299); 0562 QCOMPARE(spreadsheet.column(1)->valueAt(0), -0.485527); 0563 QCOMPARE(spreadsheet.column(2)->valueAt(0), -0.288690); 0564 } 0565 0566 void AsciiFilterTest::testColumnRange01() { 0567 Spreadsheet spreadsheet(QStringLiteral("test"), false); 0568 AsciiFilter filter; 0569 const QString& fileName = QFINDTESTDATA(QLatin1String("data/numeric_data.txt")); 0570 0571 filter.setSeparatingCharacter(QStringLiteral("auto")); 0572 filter.setHeaderEnabled(false); 0573 filter.setCreateIndexEnabled(true); 0574 filter.readDataFromFile(fileName, &spreadsheet, AbstractFileFilter::ImportMode::Replace); 0575 0576 // no ranges specified, all rows and columns have to be read plus the additional column for the index 0577 QCOMPARE(spreadsheet.rowCount(), 5); 0578 QCOMPARE(spreadsheet.columnCount(), 4); 0579 0580 QCOMPARE(spreadsheet.column(0)->columnMode(), AbstractColumn::ColumnMode::Integer); 0581 QCOMPARE(spreadsheet.column(1)->columnMode(), AbstractColumn::ColumnMode::Double); 0582 QCOMPARE(spreadsheet.column(2)->columnMode(), AbstractColumn::ColumnMode::Double); 0583 QCOMPARE(spreadsheet.column(3)->columnMode(), AbstractColumn::ColumnMode::Double); 0584 0585 // check the values for the first line 0586 QCOMPARE(spreadsheet.column(0)->integerAt(0), 1); 0587 QCOMPARE(spreadsheet.column(1)->valueAt(0), 1.716299); 0588 QCOMPARE(spreadsheet.column(2)->valueAt(0), -0.485527); 0589 QCOMPARE(spreadsheet.column(3)->valueAt(0), -0.288690); 0590 } 0591 0592 void AsciiFilterTest::testColumnRange02() { 0593 Spreadsheet spreadsheet(QStringLiteral("test"), false); 0594 AsciiFilter filter; 0595 const QString& fileName = QFINDTESTDATA(QLatin1String("data/numeric_data.txt")); 0596 0597 filter.setSeparatingCharacter(QStringLiteral("auto")); 0598 filter.setHeaderEnabled(false); 0599 filter.setStartColumn(2); 0600 filter.setEndColumn(3); 0601 filter.readDataFromFile(fileName, &spreadsheet, AbstractFileFilter::ImportMode::Replace); 0602 0603 // read all rows and the last two columns only 0604 QCOMPARE(spreadsheet.rowCount(), 5); 0605 QCOMPARE(spreadsheet.columnCount(), 2); 0606 0607 QCOMPARE(spreadsheet.column(0)->columnMode(), AbstractColumn::ColumnMode::Double); 0608 QCOMPARE(spreadsheet.column(1)->columnMode(), AbstractColumn::ColumnMode::Double); 0609 0610 // check the values for the first line 0611 QCOMPARE(spreadsheet.column(0)->valueAt(0), -0.485527); 0612 QCOMPARE(spreadsheet.column(1)->valueAt(0), -0.288690); 0613 } 0614 0615 void AsciiFilterTest::testColumnRange03() { 0616 Spreadsheet spreadsheet(QStringLiteral("test"), false); 0617 AsciiFilter filter; 0618 const QString& fileName = QFINDTESTDATA(QLatin1String("data/numeric_data.txt")); 0619 0620 filter.setSeparatingCharacter(QStringLiteral("auto")); 0621 filter.setHeaderEnabled(false); 0622 filter.setCreateIndexEnabled(true); 0623 filter.setStartColumn(2); 0624 filter.setEndColumn(3); 0625 filter.readDataFromFile(fileName, &spreadsheet, AbstractFileFilter::ImportMode::Replace); 0626 0627 // read all rows and the last two columns only plus the additional column for the index 0628 QCOMPARE(spreadsheet.rowCount(), 5); 0629 QCOMPARE(spreadsheet.columnCount(), 3); 0630 0631 QCOMPARE(spreadsheet.column(0)->columnMode(), AbstractColumn::ColumnMode::Integer); 0632 QCOMPARE(spreadsheet.column(1)->columnMode(), AbstractColumn::ColumnMode::Double); 0633 QCOMPARE(spreadsheet.column(2)->columnMode(), AbstractColumn::ColumnMode::Double); 0634 0635 // check the values for the first line 0636 QCOMPARE(spreadsheet.column(0)->integerAt(0), 1); 0637 QCOMPARE(spreadsheet.column(1)->valueAt(0), -0.485527); 0638 QCOMPARE(spreadsheet.column(2)->valueAt(0), -0.288690); 0639 } 0640 0641 void AsciiFilterTest::testColumnRange04() { 0642 Spreadsheet spreadsheet(QStringLiteral("test"), false); 0643 AsciiFilter filter; 0644 const QString& fileName = QFINDTESTDATA(QLatin1String("data/numeric_data.txt")); 0645 0646 filter.setSeparatingCharacter(QStringLiteral("auto")); 0647 filter.setHeaderEnabled(false); 0648 filter.setStartColumn(3); 0649 filter.setEndColumn(3); 0650 filter.readDataFromFile(fileName, &spreadsheet, AbstractFileFilter::ImportMode::Replace); 0651 0652 // read all rows and the last column only 0653 QCOMPARE(spreadsheet.rowCount(), 5); 0654 QCOMPARE(spreadsheet.columnCount(), 1); 0655 0656 QCOMPARE(spreadsheet.column(0)->columnMode(), AbstractColumn::ColumnMode::Double); 0657 0658 // check the values for the first line 0659 QCOMPARE(spreadsheet.column(0)->valueAt(0), -0.288690); 0660 } 0661 0662 void AsciiFilterTest::testColumnRange05() { 0663 Spreadsheet spreadsheet(QStringLiteral("test"), false); 0664 AsciiFilter filter; 0665 const QString& fileName = QFINDTESTDATA(QLatin1String("data/numeric_data.txt")); 0666 0667 filter.setSeparatingCharacter(QStringLiteral("auto")); 0668 filter.setHeaderEnabled(false); 0669 filter.setStartColumn(3); 0670 filter.setEndColumn(2); 0671 filter.readDataFromFile(fileName, &spreadsheet, AbstractFileFilter::ImportMode::Replace); 0672 0673 // wrong column range specified (start>end), nothing to read, 0674 // empty spreadsheet because of the replace mode 0675 QCOMPARE(spreadsheet.rowCount(), 0); 0676 QCOMPARE(spreadsheet.columnCount(), 0); 0677 } 0678 0679 void AsciiFilterTest::testColumnRange06() { 0680 Spreadsheet spreadsheet(QStringLiteral("test"), false); 0681 AsciiFilter filter; 0682 const QString& fileName = QFINDTESTDATA(QLatin1String("data/numeric_data.txt")); 0683 0684 filter.setSeparatingCharacter(QStringLiteral("auto")); 0685 filter.setHeaderEnabled(false); 0686 filter.setCreateIndexEnabled(true); 0687 filter.setStartColumn(3); 0688 filter.setEndColumn(2); 0689 filter.readDataFromFile(fileName, &spreadsheet, AbstractFileFilter::ImportMode::Replace); 0690 0691 // wrong column range specified (start>end), only the index column is created 0692 QCOMPARE(spreadsheet.rowCount(), 5); 0693 QCOMPARE(spreadsheet.columnCount(), 1); 0694 0695 QCOMPARE(spreadsheet.column(0)->columnMode(), AbstractColumn::ColumnMode::Integer); 0696 QCOMPARE(spreadsheet.column(0)->integerAt(0), 1); 0697 } 0698 0699 void AsciiFilterTest::testRowRange00() { 0700 Spreadsheet spreadsheet(QStringLiteral("test"), false); 0701 AsciiFilter filter; 0702 const QString& fileName = QFINDTESTDATA(QLatin1String("data/numeric_data.txt")); 0703 0704 filter.setSeparatingCharacter(QStringLiteral("auto")); 0705 filter.setStartRow(3); 0706 filter.setEndRow(5); 0707 filter.readDataFromFile(fileName, &spreadsheet, AbstractFileFilter::ImportMode::Replace); 0708 0709 // three rows to read 0710 QCOMPARE(spreadsheet.rowCount(), 3); 0711 QCOMPARE(spreadsheet.columnCount(), 3); 0712 0713 QCOMPARE(spreadsheet.column(0)->columnMode(), AbstractColumn::ColumnMode::Double); 0714 QCOMPARE(spreadsheet.column(1)->columnMode(), AbstractColumn::ColumnMode::Double); 0715 QCOMPARE(spreadsheet.column(2)->columnMode(), AbstractColumn::ColumnMode::Double); 0716 0717 // check the values for the first and for the last lines 0718 QCOMPARE(spreadsheet.column(0)->valueAt(0), 1.711721); 0719 QCOMPARE(spreadsheet.column(1)->valueAt(0), -0.485527); 0720 QCOMPARE(spreadsheet.column(2)->valueAt(0), -0.293267); 0721 0722 QCOMPARE(spreadsheet.column(0)->valueAt(2), 1.716299); 0723 QCOMPARE(spreadsheet.column(1)->valueAt(2), -0.494682); 0724 QCOMPARE(spreadsheet.column(2)->valueAt(2), -0.284112); 0725 } 0726 0727 void AsciiFilterTest::testRowRange01() { 0728 Spreadsheet spreadsheet(QStringLiteral("test"), false); 0729 AsciiFilter filter; 0730 const QString& fileName = QFINDTESTDATA(QLatin1String("data/numeric_data.txt")); 0731 0732 filter.setSeparatingCharacter(QStringLiteral("auto")); 0733 filter.setHeaderEnabled(false); 0734 filter.setStartRow(3); 0735 filter.setEndRow(10); 0736 filter.readDataFromFile(fileName, &spreadsheet, AbstractFileFilter::ImportMode::Replace); 0737 0738 // end row larger than the number of available rows, three rows to read 0739 QCOMPARE(spreadsheet.rowCount(), 3); 0740 QCOMPARE(spreadsheet.columnCount(), 3); 0741 0742 QCOMPARE(spreadsheet.column(0)->columnMode(), AbstractColumn::ColumnMode::Double); 0743 QCOMPARE(spreadsheet.column(1)->columnMode(), AbstractColumn::ColumnMode::Double); 0744 QCOMPARE(spreadsheet.column(2)->columnMode(), AbstractColumn::ColumnMode::Double); 0745 0746 // check the values for the first and for the last lines 0747 QCOMPARE(spreadsheet.column(0)->valueAt(0), 1.711721); 0748 QCOMPARE(spreadsheet.column(1)->valueAt(0), -0.485527); 0749 QCOMPARE(spreadsheet.column(2)->valueAt(0), -0.293267); 0750 0751 QCOMPARE(spreadsheet.column(0)->valueAt(2), 1.716299); 0752 QCOMPARE(spreadsheet.column(1)->valueAt(2), -0.494682); 0753 QCOMPARE(spreadsheet.column(2)->valueAt(2), -0.284112); 0754 } 0755 0756 void AsciiFilterTest::testRowRange02() { 0757 Spreadsheet spreadsheet(QStringLiteral("test"), false); 0758 AsciiFilter filter; 0759 const QString& fileName = QFINDTESTDATA(QLatin1String("data/numeric_data.txt")); 0760 0761 filter.setSeparatingCharacter(QStringLiteral("auto")); 0762 filter.setHeaderEnabled(false); 0763 filter.setStartRow(3); 0764 filter.setEndRow(1); 0765 filter.readDataFromFile(fileName, &spreadsheet, AbstractFileFilter::ImportMode::Replace); 0766 0767 // start bigger than end, no rows to read 0768 // wrong row range specified (start>end), nothing to read, 0769 // spreadsheet is not touched, default number of rows and columns 0770 // TODO: this is inconsistent with the handling for columns, see testColumnRange05() 0771 QCOMPARE(spreadsheet.rowCount(), 100); 0772 QCOMPARE(spreadsheet.columnCount(), 2); 0773 } 0774 0775 void AsciiFilterTest::testRowColumnRange00() { 0776 Spreadsheet spreadsheet(QStringLiteral("test"), false); 0777 AsciiFilter filter; 0778 const QString& fileName = QFINDTESTDATA(QLatin1String("data/numeric_data.txt")); 0779 0780 filter.setSeparatingCharacter(QStringLiteral("auto")); 0781 filter.setHeaderEnabled(false); 0782 filter.setStartRow(3); 0783 filter.setEndRow(5); 0784 filter.setStartColumn(2); 0785 filter.setEndColumn(3); 0786 filter.readDataFromFile(fileName, &spreadsheet, AbstractFileFilter::ImportMode::Replace); 0787 0788 // three rows and two columns to read 0789 QCOMPARE(spreadsheet.rowCount(), 3); 0790 QCOMPARE(spreadsheet.columnCount(), 2); 0791 0792 QCOMPARE(spreadsheet.column(0)->columnMode(), AbstractColumn::ColumnMode::Double); 0793 QCOMPARE(spreadsheet.column(1)->columnMode(), AbstractColumn::ColumnMode::Double); 0794 0795 // check the values for the first and for the last lines 0796 QCOMPARE(spreadsheet.column(0)->valueAt(0), -0.485527); 0797 QCOMPARE(spreadsheet.column(1)->valueAt(0), -0.293267); 0798 0799 QCOMPARE(spreadsheet.column(0)->valueAt(2), -0.494682); 0800 QCOMPARE(spreadsheet.column(1)->valueAt(2), -0.284112); 0801 } 0802 0803 // ############################################################################## 0804 // ##################### handling of different separators ###################### 0805 // ############################################################################## 0806 0807 // ############################################################################## 0808 // ##################################### quoted strings ######################## 0809 // ############################################################################## 0810 void AsciiFilterTest::testQuotedStrings00() { 0811 Spreadsheet spreadsheet(QStringLiteral("test"), false); 0812 AsciiFilter filter; 0813 const QString& fileName = QFINDTESTDATA(QLatin1String("data/quoted_strings.txt")); 0814 0815 filter.setSeparatingCharacter(QStringLiteral(",")); 0816 filter.setHeaderEnabled(false); 0817 filter.setRemoveQuotesEnabled(true); 0818 filter.readDataFromFile(fileName, &spreadsheet, AbstractFileFilter::ImportMode::Replace); 0819 0820 // three rows and two columns to read 0821 QCOMPARE(spreadsheet.rowCount(), 3); 0822 QCOMPARE(spreadsheet.columnCount(), 4); 0823 0824 QCOMPARE(spreadsheet.column(0)->columnMode(), AbstractColumn::ColumnMode::Text); 0825 QCOMPARE(spreadsheet.column(1)->columnMode(), AbstractColumn::ColumnMode::Integer); 0826 QCOMPARE(spreadsheet.column(2)->columnMode(), AbstractColumn::ColumnMode::Integer); 0827 QCOMPARE(spreadsheet.column(3)->columnMode(), AbstractColumn::ColumnMode::Double); 0828 0829 QCOMPARE(spreadsheet.column(0)->textAt(0), QLatin1String("a")); 0830 QCOMPARE(spreadsheet.column(1)->integerAt(0), 1000); 0831 QCOMPARE(spreadsheet.column(2)->integerAt(0), 201811); 0832 QCOMPARE(spreadsheet.column(3)->valueAt(0), 1.1); 0833 0834 QCOMPARE(spreadsheet.column(0)->textAt(1), QLatin1String("ab")); 0835 QCOMPARE(spreadsheet.column(1)->integerAt(1), 2000); 0836 QCOMPARE(spreadsheet.column(2)->integerAt(1), 201812); 0837 QCOMPARE(spreadsheet.column(3)->valueAt(1), 1.2); 0838 0839 QCOMPARE(spreadsheet.column(0)->textAt(2), QLatin1String("abc")); 0840 QCOMPARE(spreadsheet.column(1)->integerAt(2), 3000); 0841 QCOMPARE(spreadsheet.column(2)->integerAt(2), 201901); 0842 QCOMPARE(spreadsheet.column(3)->valueAt(2), 1.3); 0843 } 0844 0845 void AsciiFilterTest::testQuotedStrings01() { 0846 Spreadsheet spreadsheet(QStringLiteral("test"), false); 0847 AsciiFilter filter; 0848 const QString& fileName = QFINDTESTDATA(QLatin1String("data/quoted_strings_with_header.txt")); 0849 0850 filter.setSeparatingCharacter(QStringLiteral(",")); 0851 filter.setHeaderEnabled(true); 0852 filter.setHeaderLine(1); 0853 filter.setSimplifyWhitespacesEnabled(true); 0854 filter.setRemoveQuotesEnabled(true); 0855 filter.readDataFromFile(fileName, &spreadsheet, AbstractFileFilter::ImportMode::Replace); 0856 0857 // three rows and two columns to read 0858 QCOMPARE(spreadsheet.rowCount(), 3); 0859 QCOMPARE(spreadsheet.columnCount(), 4); 0860 0861 // column names 0862 QCOMPARE(spreadsheet.column(0)->name(), QLatin1String("col1")); 0863 QCOMPARE(spreadsheet.column(1)->name(), QLatin1String("col2")); 0864 QCOMPARE(spreadsheet.column(2)->name(), QLatin1String("col3")); 0865 QCOMPARE(spreadsheet.column(3)->name(), QLatin1String("col4")); 0866 0867 // data types 0868 QCOMPARE(spreadsheet.column(0)->columnMode(), AbstractColumn::ColumnMode::Text); 0869 QCOMPARE(spreadsheet.column(1)->columnMode(), AbstractColumn::ColumnMode::Integer); 0870 QCOMPARE(spreadsheet.column(2)->columnMode(), AbstractColumn::ColumnMode::Integer); 0871 QCOMPARE(spreadsheet.column(3)->columnMode(), AbstractColumn::ColumnMode::Double); 0872 0873 // values 0874 QCOMPARE(spreadsheet.column(0)->textAt(0), QLatin1String("a")); 0875 QCOMPARE(spreadsheet.column(1)->integerAt(0), 1000); 0876 QCOMPARE(spreadsheet.column(2)->integerAt(0), 201811); 0877 QCOMPARE(spreadsheet.column(3)->valueAt(0), 1.1); 0878 0879 QCOMPARE(spreadsheet.column(0)->textAt(1), QLatin1String("ab")); 0880 QCOMPARE(spreadsheet.column(1)->integerAt(1), 2000); 0881 QCOMPARE(spreadsheet.column(2)->integerAt(1), 201812); 0882 QCOMPARE(spreadsheet.column(3)->valueAt(1), 1.2); 0883 0884 QCOMPARE(spreadsheet.column(0)->textAt(2), QLatin1String("abc")); 0885 QCOMPARE(spreadsheet.column(1)->integerAt(2), 3000); 0886 QCOMPARE(spreadsheet.column(2)->integerAt(2), 201901); 0887 QCOMPARE(spreadsheet.column(3)->valueAt(2), 1.3); 0888 } 0889 0890 void AsciiFilterTest::testQuotedStrings02() { 0891 Spreadsheet spreadsheet(QStringLiteral("test"), false); 0892 AsciiFilter filter; 0893 const QString& fileName = QFINDTESTDATA(QLatin1String("data/quoted_strings_one_line.txt")); 0894 0895 QCOMPARE(QFile::exists(fileName), true); 0896 0897 filter.setSeparatingCharacter(QStringLiteral(",")); 0898 // filter.setHeaderEnabled(false); 0899 filter.setRemoveQuotesEnabled(true); 0900 filter.readDataFromFile(fileName, &spreadsheet, AbstractFileFilter::ImportMode::Replace); 0901 0902 // three rows and two columns to read 0903 // QCOMPARE(spreadsheet.rowCount(), 1); 0904 // QCOMPARE(spreadsheet.columnCount(), 4); 0905 0906 QCOMPARE(spreadsheet.column(0)->columnMode(), AbstractColumn::ColumnMode::Text); 0907 QCOMPARE(spreadsheet.column(1)->columnMode(), AbstractColumn::ColumnMode::Integer); 0908 QCOMPARE(spreadsheet.column(2)->columnMode(), AbstractColumn::ColumnMode::Integer); 0909 QCOMPARE(spreadsheet.column(3)->columnMode(), AbstractColumn::ColumnMode::Double); 0910 0911 QCOMPARE(spreadsheet.column(0)->textAt(0), QLatin1String("a")); 0912 QCOMPARE(spreadsheet.column(1)->integerAt(0), 1000); 0913 QCOMPARE(spreadsheet.column(2)->integerAt(0), 201811); 0914 QCOMPARE(spreadsheet.column(3)->valueAt(0), 1.1); 0915 } 0916 0917 void AsciiFilterTest::testQuotedStrings03() { 0918 Spreadsheet spreadsheet(QStringLiteral("test"), false); 0919 AsciiFilter filter; 0920 const QString& fileName = QFINDTESTDATA(QLatin1String("data/quoted_strings_one_line_with_header.txt")); 0921 0922 filter.setSeparatingCharacter(QStringLiteral(",")); 0923 filter.setHeaderEnabled(true); 0924 filter.setHeaderLine(1); 0925 filter.setSimplifyWhitespacesEnabled(true); 0926 filter.setRemoveQuotesEnabled(true); 0927 filter.readDataFromFile(fileName, &spreadsheet, AbstractFileFilter::ImportMode::Replace); 0928 0929 // three rows and two columns to read 0930 // QCOMPARE(spreadsheet.rowCount(), 1); 0931 // QCOMPARE(spreadsheet.columnCount(), 4); 0932 0933 // column names 0934 QCOMPARE(spreadsheet.column(0)->name(), QLatin1String("col1")); 0935 QCOMPARE(spreadsheet.column(1)->name(), QLatin1String("col2")); 0936 QCOMPARE(spreadsheet.column(2)->name(), QLatin1String("col3")); 0937 QCOMPARE(spreadsheet.column(3)->name(), QLatin1String("col4")); 0938 0939 // data types 0940 QCOMPARE(spreadsheet.column(0)->columnMode(), AbstractColumn::ColumnMode::Text); 0941 QCOMPARE(spreadsheet.column(1)->columnMode(), AbstractColumn::ColumnMode::Integer); 0942 QCOMPARE(spreadsheet.column(2)->columnMode(), AbstractColumn::ColumnMode::Integer); 0943 QCOMPARE(spreadsheet.column(3)->columnMode(), AbstractColumn::ColumnMode::Double); 0944 0945 // values 0946 QCOMPARE(spreadsheet.column(0)->textAt(0), QLatin1String("a")); 0947 QCOMPARE(spreadsheet.column(1)->integerAt(0), 1000); 0948 QCOMPARE(spreadsheet.column(2)->integerAt(0), 201811); 0949 QCOMPARE(spreadsheet.column(3)->valueAt(0), 1.1); 0950 } 0951 0952 /*! 0953 * test quoted text having separators inside - the text between quotes shouldn't be splitted into separate columns. 0954 */ 0955 void AsciiFilterTest::testQuotedStrings04() { 0956 Spreadsheet spreadsheet(QStringLiteral("test"), false); 0957 AsciiFilter filter; 0958 const QString& fileName = QFINDTESTDATA(QLatin1String("data/quoted_strings_with_separator_inside.csv")); 0959 0960 filter.setHeaderLine(1); 0961 filter.setSimplifyWhitespacesEnabled(true); // TODO: this shouldn't be required, but QString::split() seems to introduce blanks... 0962 filter.setRemoveQuotesEnabled(true); 0963 filter.readDataFromFile(fileName, &spreadsheet, AbstractFileFilter::ImportMode::Replace); 0964 0965 // three rows and two columns to read 0966 // QCOMPARE(spreadsheet.rowCount(), 2); 0967 // QCOMPARE(spreadsheet.columnCount(), 3); 0968 0969 // column names 0970 QCOMPARE(spreadsheet.column(0)->name(), QLatin1String("id")); 0971 QCOMPARE(spreadsheet.column(1)->name(), QLatin1String("text")); 0972 QCOMPARE(spreadsheet.column(2)->name(), QLatin1String("value")); 0973 0974 // data types 0975 QCOMPARE(spreadsheet.column(0)->columnMode(), AbstractColumn::ColumnMode::Integer); 0976 QCOMPARE(spreadsheet.column(1)->columnMode(), AbstractColumn::ColumnMode::Text); 0977 QCOMPARE(spreadsheet.column(2)->columnMode(), AbstractColumn::ColumnMode::Double); 0978 0979 // values 0980 QCOMPARE(spreadsheet.column(0)->integerAt(0), 1); 0981 QCOMPARE(spreadsheet.column(1)->textAt(0), QLatin1String("some text, having a comma, and yet another comma")); 0982 QCOMPARE(spreadsheet.column(2)->valueAt(0), 1.0); 0983 0984 QCOMPARE(spreadsheet.column(0)->integerAt(1), 2); 0985 QCOMPARE(spreadsheet.column(1)->textAt(1), QLatin1String("more text")); 0986 QCOMPARE(spreadsheet.column(2)->valueAt(1), 2.0); 0987 } 0988 0989 /*! 0990 * test quoted text having separators inside - a JSON file has a similar structure and we should't crash because of this "wrong" data. 0991 */ 0992 void AsciiFilterTest::testQuotedStrings05() { 0993 Spreadsheet spreadsheet(QStringLiteral("test"), false); 0994 AsciiFilter filter; 0995 const QString& fileName = QFINDTESTDATA(QLatin1String("data/object.json")); 0996 0997 filter.setSimplifyWhitespacesEnabled(true); // TODO: this shouldn't be required, but QString::split() seems to introduce blanks... 0998 filter.setRemoveQuotesEnabled(true); 0999 filter.readDataFromFile(fileName, &spreadsheet, AbstractFileFilter::ImportMode::Replace); 1000 1001 // everything should be read into one single text column. 1002 // the actuall content is irrelevant, we just need to make sure we don't crash because of such wrong content 1003 QCOMPARE(spreadsheet.columnCount(), 1); 1004 QCOMPARE(spreadsheet.column(0)->columnMode(), AbstractColumn::ColumnMode::Text); 1005 } 1006 1007 // ############################################################################## 1008 // ################################## locales ################################### 1009 // ############################################################################## 1010 void AsciiFilterTest::testUtf8Cyrillic() { 1011 Spreadsheet spreadsheet(QStringLiteral("test"), false); 1012 AsciiFilter filter; 1013 const QString& fileName = QFINDTESTDATA(QLatin1String("data/utf8_cyrillic.txt")); 1014 1015 filter.setSeparatingCharacter(QStringLiteral("auto")); 1016 filter.setHeaderLine(1); 1017 filter.readDataFromFile(fileName, &spreadsheet, AbstractFileFilter::ImportMode::Replace); 1018 1019 // column names 1020 QCOMPARE(spreadsheet.column(0)->name(), QString::fromUtf8("перший_стовпець")); 1021 QCOMPARE(spreadsheet.column(1)->name(), QString::fromUtf8("другий_стовпець")); 1022 1023 // data types 1024 QCOMPARE(spreadsheet.column(0)->columnMode(), AbstractColumn::ColumnMode::Text); 1025 QCOMPARE(spreadsheet.column(1)->columnMode(), AbstractColumn::ColumnMode::Integer); 1026 1027 // values 1028 QCOMPARE(spreadsheet.column(0)->textAt(0), QString::fromUtf8("тест1")); 1029 QCOMPARE(spreadsheet.column(1)->integerAt(0), 1); 1030 1031 QCOMPARE(spreadsheet.column(0)->textAt(1), QString::fromUtf8("тест2")); 1032 QCOMPARE(spreadsheet.column(1)->integerAt(1), 2); 1033 } 1034 1035 // ############################################################################## 1036 // ############################### skip comments ############################### 1037 // ############################################################################## 1038 void AsciiFilterTest::testComments00() { 1039 Spreadsheet spreadsheet(QStringLiteral("test"), false); 1040 AsciiFilter filter; 1041 const QString& fileName = QFINDTESTDATA(QLatin1String("data/multi_line_comment.txt")); 1042 1043 filter.setHeaderEnabled(false); 1044 filter.setSeparatingCharacter(QStringLiteral(",")); 1045 filter.readDataFromFile(fileName, &spreadsheet, AbstractFileFilter::ImportMode::Replace); 1046 1047 QCOMPARE(spreadsheet.columnCount(), 2); 1048 1049 // data types 1050 QCOMPARE(spreadsheet.column(0)->columnMode(), AbstractColumn::ColumnMode::Integer); 1051 QCOMPARE(spreadsheet.column(1)->columnMode(), AbstractColumn::ColumnMode::Double); 1052 1053 // values 1054 QCOMPARE(spreadsheet.column(0)->integerAt(0), 1); 1055 QCOMPARE(spreadsheet.column(1)->valueAt(0), 1.1); 1056 1057 QCOMPARE(spreadsheet.column(0)->integerAt(1), 2); 1058 QCOMPARE(spreadsheet.column(1)->valueAt(1), 2.2); 1059 } 1060 1061 void AsciiFilterTest::testComments01() { 1062 Spreadsheet spreadsheet(QStringLiteral("test"), false); 1063 AsciiFilter filter; 1064 const QString& fileName = QFINDTESTDATA(QLatin1String("data/multi_line_comment_with_empty_lines.txt")); 1065 1066 filter.setHeaderEnabled(false); 1067 filter.setSeparatingCharacter(QStringLiteral(",")); 1068 filter.readDataFromFile(fileName, &spreadsheet, AbstractFileFilter::ImportMode::Replace); 1069 1070 QCOMPARE(spreadsheet.columnCount(), 2); 1071 1072 // data types 1073 QCOMPARE(spreadsheet.column(0)->columnMode(), AbstractColumn::ColumnMode::Integer); 1074 QCOMPARE(spreadsheet.column(1)->columnMode(), AbstractColumn::ColumnMode::Double); 1075 1076 // values 1077 QCOMPARE(spreadsheet.column(0)->integerAt(0), 1); 1078 QCOMPARE(spreadsheet.column(1)->valueAt(0), 1.1); 1079 1080 QCOMPARE(spreadsheet.column(0)->integerAt(1), 2); 1081 QCOMPARE(spreadsheet.column(1)->valueAt(1), 2.2); 1082 } 1083 1084 /*! 1085 * test with an empty comment character 1086 */ 1087 void AsciiFilterTest::testComments02() { 1088 Spreadsheet spreadsheet(QStringLiteral("test"), false); 1089 AsciiFilter filter; 1090 const QString& fileName = QFINDTESTDATA(QLatin1String("data/separator_semicolon_with_header.txt")); 1091 1092 filter.setCommentCharacter(QString()); 1093 filter.setSeparatingCharacter(QStringLiteral(";")); 1094 filter.setHeaderEnabled(true); 1095 filter.setHeaderLine(1); 1096 filter.readDataFromFile(fileName, &spreadsheet, AbstractFileFilter::ImportMode::Replace); 1097 1098 // spreadsheet size 1099 QCOMPARE(spreadsheet.columnCount(), 2); 1100 QCOMPARE(spreadsheet.rowCount(), 3); 1101 1102 // column names 1103 QCOMPARE(spreadsheet.column(0)->name(), QLatin1String("c1")); 1104 QCOMPARE(spreadsheet.column(1)->name(), QLatin1String("c2")); 1105 1106 // data types 1107 QCOMPARE(spreadsheet.column(0)->columnMode(), AbstractColumn::ColumnMode::Integer); 1108 QCOMPARE(spreadsheet.column(1)->columnMode(), AbstractColumn::ColumnMode::Integer); 1109 1110 // values 1111 QCOMPARE(spreadsheet.column(0)->integerAt(0), 1); 1112 QCOMPARE(spreadsheet.column(1)->integerAt(0), 1); 1113 1114 QCOMPARE(spreadsheet.column(0)->integerAt(1), 2); 1115 QCOMPARE(spreadsheet.column(1)->integerAt(1), 2); 1116 1117 QCOMPARE(spreadsheet.column(0)->integerAt(2), 3); 1118 QCOMPARE(spreadsheet.column(1)->integerAt(2), 3); 1119 } 1120 1121 // ############################################################################## 1122 // ######################### handling of datetime data ######################### 1123 // ############################################################################## 1124 /*! 1125 * read data containing only two characters for the year - 'yy'. The default year in 1126 * QDateTime is 1900 . When reading such two-characters DateTime values we want 1127 * to have the current centure after the import. 1128 */ 1129 void AsciiFilterTest::testDateTime00() { 1130 Spreadsheet spreadsheet(QStringLiteral("test"), false); 1131 AsciiFilter filter; 1132 const QString& fileName = QFINDTESTDATA(QLatin1String("data/datetime_01.csv")); 1133 1134 filter.setSeparatingCharacter(QStringLiteral(",")); 1135 filter.setHeaderEnabled(true); 1136 filter.setHeaderLine(1); 1137 filter.setDateTimeFormat(QLatin1String("dd/MM/yy hh:mm:ss")); 1138 filter.readDataFromFile(fileName, &spreadsheet, AbstractFileFilter::ImportMode::Replace); 1139 1140 // spreadsheet size 1141 QCOMPARE(spreadsheet.columnCount(), 2); 1142 QCOMPARE(spreadsheet.rowCount(), 2); 1143 1144 // column names 1145 QCOMPARE(spreadsheet.column(0)->name(), QLatin1String("Date")); 1146 QCOMPARE(spreadsheet.column(1)->name(), QLatin1String("Water Pressure")); 1147 1148 // data types 1149 QCOMPARE(spreadsheet.column(0)->columnMode(), AbstractColumn::ColumnMode::DateTime); 1150 QCOMPARE(spreadsheet.column(1)->columnMode(), AbstractColumn::ColumnMode::Double); 1151 1152 // values 1153 auto value = QDateTime::fromString(QLatin1String("01/01/2019 00:00:00"), QLatin1String("dd/MM/yyyy hh:mm:ss")); 1154 value.setTimeSpec(Qt::UTC); 1155 QCOMPARE(spreadsheet.column(0)->dateTimeAt(0), value); 1156 QCOMPARE(spreadsheet.column(1)->valueAt(0), 14.7982); 1157 1158 value = QDateTime::fromString(QLatin1String("01/01/2019 00:30:00"), QLatin1String("dd/MM/yyyy hh:mm:ss")); 1159 value.setTimeSpec(Qt::UTC); 1160 QCOMPARE(spreadsheet.column(0)->dateTimeAt(1), value); 1161 QCOMPARE(spreadsheet.column(1)->valueAt(1), 14.8026); 1162 } 1163 1164 /*! 1165 * same as in the previous test, but with the auto-detection of the datetime format 1166 */ 1167 void AsciiFilterTest::testDateTime01() { 1168 Spreadsheet spreadsheet(QStringLiteral("test"), false); 1169 AsciiFilter filter; 1170 const QString& fileName = QFINDTESTDATA(QLatin1String("data/datetime_01.csv")); 1171 1172 filter.setSeparatingCharacter(QStringLiteral(",")); 1173 filter.setHeaderEnabled(true); 1174 filter.setHeaderLine(1); 1175 filter.setDateTimeFormat(QLatin1String()); // auto detect the format 1176 filter.readDataFromFile(fileName, &spreadsheet, AbstractFileFilter::ImportMode::Replace); 1177 1178 // spreadsheet size 1179 QCOMPARE(spreadsheet.columnCount(), 2); 1180 QCOMPARE(spreadsheet.rowCount(), 2); 1181 1182 // column names 1183 QCOMPARE(spreadsheet.column(0)->name(), QLatin1String("Date")); 1184 QCOMPARE(spreadsheet.column(1)->name(), QLatin1String("Water Pressure")); 1185 1186 // data types 1187 QCOMPARE(spreadsheet.column(0)->columnMode(), AbstractColumn::ColumnMode::DateTime); 1188 QCOMPARE(spreadsheet.column(1)->columnMode(), AbstractColumn::ColumnMode::Double); 1189 1190 // values 1191 auto value = QDateTime::fromString(QLatin1String("01/01/2019 00:00:00"), QLatin1String("dd/MM/yyyy hh:mm:ss")); 1192 value.setTimeSpec(Qt::UTC); 1193 QCOMPARE(spreadsheet.column(0)->dateTimeAt(0), value); 1194 QCOMPARE(spreadsheet.column(1)->valueAt(0), 14.7982); 1195 1196 value = QDateTime::fromString(QLatin1String("01/01/2019 00:30:00"), QLatin1String("dd/MM/yyyy hh:mm:ss")); 1197 value.setTimeSpec(Qt::UTC); 1198 QCOMPARE(spreadsheet.column(0)->dateTimeAt(1), value); 1199 QCOMPARE(spreadsheet.column(1)->valueAt(1), 14.8026); 1200 } 1201 1202 /* read datetime data before big int 1203 * TODO: handle hex value 1204 */ 1205 void AsciiFilterTest::testDateTimeHex() { 1206 Spreadsheet spreadsheet(QStringLiteral("test"), false); 1207 AsciiFilter filter; 1208 const QString& fileName = QFINDTESTDATA(QLatin1String("data/datetime-hex.dat")); 1209 1210 filter.setHeaderEnabled(false); 1211 filter.setSeparatingCharacter(QStringLiteral("|")); 1212 filter.setDateTimeFormat(QLatin1String("yyyyMMddhhmmss")); 1213 filter.readDataFromFile(fileName, &spreadsheet, AbstractFileFilter::ImportMode::Replace); 1214 1215 // spreadsheet size 1216 QCOMPARE(spreadsheet.columnCount(), 17); 1217 QCOMPARE(spreadsheet.rowCount(), 1); 1218 1219 // data types 1220 QCOMPARE(spreadsheet.column(0)->columnMode(), AbstractColumn::ColumnMode::DateTime); 1221 QCOMPARE(spreadsheet.column(1)->columnMode(), AbstractColumn::ColumnMode::Text); 1222 QCOMPARE(spreadsheet.column(2)->columnMode(), AbstractColumn::ColumnMode::Integer); 1223 QCOMPARE(spreadsheet.column(3)->columnMode(), AbstractColumn::ColumnMode::Integer); 1224 QCOMPARE(spreadsheet.column(4)->columnMode(), AbstractColumn::ColumnMode::Integer); 1225 QCOMPARE(spreadsheet.column(5)->columnMode(), AbstractColumn::ColumnMode::Integer); 1226 QCOMPARE(spreadsheet.column(6)->columnMode(), AbstractColumn::ColumnMode::Integer); 1227 QCOMPARE(spreadsheet.column(7)->columnMode(), AbstractColumn::ColumnMode::Integer); 1228 QCOMPARE(spreadsheet.column(8)->columnMode(), AbstractColumn::ColumnMode::Integer); 1229 QCOMPARE(spreadsheet.column(9)->columnMode(), AbstractColumn::ColumnMode::Integer); 1230 QCOMPARE(spreadsheet.column(10)->columnMode(), AbstractColumn::ColumnMode::Double); 1231 QCOMPARE(spreadsheet.column(11)->columnMode(), AbstractColumn::ColumnMode::Integer); 1232 QCOMPARE(spreadsheet.column(12)->columnMode(), AbstractColumn::ColumnMode::Integer); 1233 QCOMPARE(spreadsheet.column(13)->columnMode(), AbstractColumn::ColumnMode::Text); 1234 QCOMPARE(spreadsheet.column(14)->columnMode(), AbstractColumn::ColumnMode::Double); 1235 QCOMPARE(spreadsheet.column(15)->columnMode(), AbstractColumn::ColumnMode::Integer); 1236 QCOMPARE(spreadsheet.column(16)->columnMode(), AbstractColumn::ColumnMode::Text); 1237 1238 auto value = QDateTime::fromString(QLatin1String("18/12/2019 02:36:08"), QLatin1String("dd/MM/yyyy hh:mm:ss")); 1239 value.setTimeSpec(Qt::UTC); 1240 QCOMPARE(spreadsheet.column(0)->dateTimeAt(0), value); 1241 QCOMPARE(spreadsheet.column(1)->textAt(0), QLatin1String("F")); 1242 QCOMPARE(spreadsheet.column(2)->integerAt(0), 1000); 1243 QCOMPARE(spreadsheet.column(3)->integerAt(0), 0); 1244 QCOMPARE(spreadsheet.column(4)->integerAt(0), 0); 1245 QCOMPARE(spreadsheet.column(5)->integerAt(0), 3190); 1246 QCOMPARE(spreadsheet.column(6)->integerAt(0), 528); 1247 QCOMPARE(spreadsheet.column(7)->integerAt(0), 3269); 1248 QCOMPARE(spreadsheet.column(8)->integerAt(0), 15); 1249 QCOMPARE(spreadsheet.column(9)->integerAt(0), 9); 1250 QCOMPARE(spreadsheet.column(10)->valueAt(0), 1.29); 1251 QCOMPARE(spreadsheet.column(11)->integerAt(0), 934); 1252 QCOMPARE(spreadsheet.column(12)->integerAt(0), -105); 1253 QCOMPARE(spreadsheet.column(13)->textAt(0), QLatin1String("G 03935")); 1254 QCOMPARE(spreadsheet.column(14)->valueAt(0), 94.09); 1255 QCOMPARE(spreadsheet.column(15)->integerAt(0), 9680); 1256 QCOMPARE(spreadsheet.column(16)->textAt(0), QLatin1String("5AD17")); 1257 } 1258 1259 void AsciiFilterTest::testMatrixHeader() { 1260 Matrix matrix(QStringLiteral("test"), false); 1261 AsciiFilter filter; 1262 const QString& fileName = QFINDTESTDATA(QLatin1String("data/numeric_data.txt")); 1263 1264 filter.setSeparatingCharacter(QStringLiteral("auto")); 1265 filter.readDataFromFile(fileName, &matrix, AbstractFileFilter::ImportMode::Replace); 1266 1267 QCOMPARE(matrix.rowCount(), 5); 1268 QCOMPARE(matrix.columnCount(), 3); 1269 1270 QCOMPARE(matrix.mode(), AbstractColumn::ColumnMode::Double); 1271 1272 // check all values 1273 QCOMPARE(matrix.cell<double>(0, 0), 1.716299); 1274 QCOMPARE(matrix.cell<double>(0, 1), -0.485527); 1275 QCOMPARE(matrix.cell<double>(0, 2), -0.288690); 1276 QCOMPARE(matrix.cell<double>(1, 0), 1.716299); 1277 QCOMPARE(matrix.cell<double>(1, 1), -0.476371); 1278 QCOMPARE(matrix.cell<double>(1, 2), -0.274957); 1279 QCOMPARE(matrix.cell<double>(2, 0), 1.711721); 1280 QCOMPARE(matrix.cell<double>(2, 1), -0.485527); 1281 QCOMPARE(matrix.cell<double>(2, 2), -0.293267); 1282 QCOMPARE(matrix.cell<double>(3, 0), 1.711721); 1283 QCOMPARE(matrix.cell<double>(3, 1), -0.480949); 1284 QCOMPARE(matrix.cell<double>(3, 2), -0.293267); 1285 QCOMPARE(matrix.cell<double>(4, 0), 1.716299); 1286 QCOMPARE(matrix.cell<double>(4, 1), -0.494682); 1287 QCOMPARE(matrix.cell<double>(4, 2), -0.284112); 1288 } 1289 1290 // ############################################################################## 1291 // ############# updates in the dependent objects after the import ############## 1292 // ############################################################################## 1293 /*! 1294 * test the update of the column values calculated via a formula after the values 1295 * in the source spreadsheet were modified by the import. 1296 */ 1297 void AsciiFilterTest::spreadsheetFormulaUpdateAfterImport() { 1298 // create the first spreadsheet with the source data 1299 Spreadsheet spreadsheet(QStringLiteral("test"), false); 1300 spreadsheet.setColumnCount(2); 1301 spreadsheet.setRowCount(3); 1302 1303 auto* col = spreadsheet.column(0); 1304 col->setColumnMode(AbstractColumn::ColumnMode::Double); 1305 col->setName(QStringLiteral("c1")); 1306 col->setValueAt(0, 10.); 1307 col->setValueAt(1, 20.); 1308 col->setValueAt(2, 30.); 1309 1310 col = spreadsheet.column(1); 1311 col->setColumnMode(AbstractColumn::ColumnMode::Double); 1312 col->setName(QStringLiteral("c2")); 1313 col->setValueAt(0, 10.); 1314 col->setValueAt(1, 20.); 1315 col->setValueAt(2, 30.); 1316 1317 // create the second spreadsheet with one single column calculated via a formula from the first spreadsheet 1318 Spreadsheet spreadsheetFormula(QStringLiteral("formula"), false); 1319 spreadsheetFormula.setColumnCount(1); 1320 spreadsheetFormula.setRowCount(3); 1321 col = spreadsheetFormula.column(0); 1322 col->setColumnMode(AbstractColumn::ColumnMode::Double); 1323 1324 QStringList variableNames{QLatin1String("x"), QLatin1String("y")}; 1325 QVector<Column*> variableColumns{spreadsheet.column(0), spreadsheet.column(1)}; 1326 col->setFormula(QLatin1String("x+y"), variableNames, variableColumns, true); 1327 col->updateFormula(); 1328 1329 // check the results of the calculation first 1330 QCOMPARE(spreadsheetFormula.columnCount(), 1); 1331 QCOMPARE(spreadsheetFormula.rowCount(), 3); 1332 QCOMPARE(col->columnMode(), AbstractColumn::ColumnMode::Double); 1333 QCOMPARE(col->valueAt(0), 20.); 1334 QCOMPARE(col->valueAt(1), 40.); 1335 QCOMPARE(col->valueAt(2), 60.); 1336 1337 // import the data into the source spreadsheet 1338 AsciiFilter filter; 1339 const QString& fileName = QFINDTESTDATA(QLatin1String("data/separator_semicolon_with_header.txt")); 1340 filter.setCommentCharacter(QString()); 1341 filter.setSeparatingCharacter(QStringLiteral(";")); 1342 filter.setHeaderEnabled(true); 1343 filter.setHeaderLine(1); 1344 filter.readDataFromFile(fileName, &spreadsheet, AbstractFileFilter::ImportMode::Replace); 1345 1346 // re-check the results of the calculation 1347 QCOMPARE(spreadsheetFormula.columnCount(), 1); 1348 QCOMPARE(spreadsheetFormula.rowCount(), 3); 1349 QCOMPARE(col->columnMode(), AbstractColumn::ColumnMode::Double); 1350 QCOMPARE(col->valueAt(0), 2.); 1351 QCOMPARE(col->valueAt(1), 4.); 1352 QCOMPARE(col->valueAt(2), 6.); 1353 } 1354 1355 /*! 1356 * test the update of the column values calculated via a formula after one of the source columns 1357 * was deleted first and was restored and the source values were modified by the import. 1358 */ 1359 void AsciiFilterTest::spreadsheetFormulaUpdateAfterImportWithColumnRestore() { 1360 Project project; // need a project object since the column restore logic is in project 1361 1362 // create the first spreadsheet with the source data 1363 auto* spreadsheet = new Spreadsheet(QStringLiteral("test"), false); 1364 project.addChild(spreadsheet); 1365 spreadsheet->setColumnCount(2); 1366 spreadsheet->setRowCount(3); 1367 1368 auto* col = spreadsheet->column(0); 1369 col->setColumnMode(AbstractColumn::ColumnMode::Double); 1370 col->setName(QStringLiteral("c1")); 1371 col->setValueAt(0, 10.); 1372 col->setValueAt(1, 20.); 1373 col->setValueAt(2, 30.); 1374 1375 col = spreadsheet->column(1); 1376 col->setColumnMode(AbstractColumn::ColumnMode::Double); 1377 col->setName(QStringLiteral("c2")); 1378 col->setValueAt(0, 10.); 1379 col->setValueAt(1, 20.); 1380 col->setValueAt(2, 30.); 1381 1382 // create the second spreadsheet with one single column calculated via a formula from the first spreadsheet 1383 auto* spreadsheetFormula = new Spreadsheet(QStringLiteral("formula"), false); 1384 project.addChild(spreadsheetFormula); 1385 spreadsheetFormula->setColumnCount(1); 1386 spreadsheetFormula->setRowCount(3); 1387 col = spreadsheetFormula->column(0); 1388 col->setColumnMode(AbstractColumn::ColumnMode::Double); 1389 1390 QStringList variableNames{QLatin1String("x"), QLatin1String("y")}; 1391 QVector<Column*> variableColumns{spreadsheet->column(0), spreadsheet->column(1)}; 1392 col->setFormula(QLatin1String("x+y"), variableNames, variableColumns, true); 1393 col->updateFormula(); 1394 1395 // delete the first column in the source spreadsheet and check the results of the calculation first, 1396 // the cells should be empty 1397 spreadsheet->removeChild(spreadsheet->column(0)); 1398 QCOMPARE(spreadsheetFormula->columnCount(), 1); 1399 QCOMPARE(spreadsheetFormula->rowCount(), 3); 1400 QCOMPARE(col->columnMode(), AbstractColumn::ColumnMode::Double); 1401 QCOMPARE((bool)std::isnan(col->valueAt(0)), true); 1402 QCOMPARE((bool)std::isnan(col->valueAt(1)), true); 1403 QCOMPARE((bool)std::isnan(col->valueAt(2)), true); 1404 1405 // import the data into the source spreadsheet, the deleted column with the name "c1" is re-created again 1406 AsciiFilter filter; 1407 const QString& fileName = QFINDTESTDATA(QLatin1String("data/separator_semicolon_with_header.txt")); 1408 filter.setCommentCharacter(QString()); 1409 filter.setSeparatingCharacter(QStringLiteral(";")); 1410 filter.setHeaderEnabled(true); 1411 filter.setHeaderLine(1); 1412 filter.readDataFromFile(fileName, spreadsheet, AbstractFileFilter::ImportMode::Replace); 1413 1414 // re-check the results of the calculation after one of the source columns was re-created and the values were changed 1415 QCOMPARE(spreadsheetFormula->columnCount(), 1); 1416 QCOMPARE(spreadsheetFormula->rowCount(), 3); 1417 QCOMPARE(col->columnMode(), AbstractColumn::ColumnMode::Double); 1418 QCOMPARE(col->valueAt(0), 2.); 1419 QCOMPARE(col->valueAt(1), 4.); 1420 QCOMPARE(col->valueAt(2), 6.); 1421 } 1422 1423 /*! 1424 * test the update of the xycurve and plot ranges after the values 1425 * in the source columns were modified by the import. 1426 */ 1427 void AsciiFilterTest::plotUpdateAfterImport() { 1428 // create the spreadsheet with the source data 1429 Spreadsheet spreadsheet(QStringLiteral("test"), false); 1430 spreadsheet.setColumnCount(2); 1431 spreadsheet.setRowCount(3); 1432 1433 auto* col = spreadsheet.column(0); 1434 col->setColumnMode(AbstractColumn::ColumnMode::Double); 1435 col->setName(QStringLiteral("c1")); 1436 col->setValueAt(0, 10.); 1437 col->setValueAt(1, 20.); 1438 col->setValueAt(2, 30.); 1439 1440 col = spreadsheet.column(1); 1441 col->setColumnMode(AbstractColumn::ColumnMode::Double); 1442 col->setName(QStringLiteral("c2")); 1443 col->setValueAt(0, 10.); 1444 col->setValueAt(1, 20.); 1445 col->setValueAt(2, 30.); 1446 1447 // create a xy-curve with the both columns in the source spreadsheet and check the ranges 1448 CartesianPlot p(QStringLiteral("plot")); 1449 auto* curve = new XYCurve(QStringLiteral("curve")); 1450 p.addChild(curve); 1451 curve->setXColumn(spreadsheet.column(0)); 1452 curve->setYColumn(spreadsheet.column(1)); 1453 1454 auto rangeX = p.range(Dimension::X); 1455 QCOMPARE(rangeX.start(), 10); 1456 QCOMPARE(rangeX.end(), 30); 1457 1458 auto rangeY = p.range(Dimension::Y); 1459 QCOMPARE(rangeY.start(), 10); 1460 QCOMPARE(rangeY.end(), 30); 1461 1462 // import the data into the source spreadsheet 1463 AsciiFilter filter; 1464 const QString& fileName = QFINDTESTDATA(QLatin1String("data/separator_semicolon_with_header.txt")); 1465 filter.setCommentCharacter(QString()); 1466 filter.setSeparatingCharacter(QStringLiteral(";")); 1467 filter.setHeaderEnabled(true); 1468 filter.setHeaderLine(1); 1469 filter.readDataFromFile(fileName, &spreadsheet, AbstractFileFilter::ImportMode::Replace); 1470 1471 // re-check the plot ranges with the new data 1472 rangeX = p.range(Dimension::X); 1473 QCOMPARE(rangeX.start(), 1); 1474 QCOMPARE(rangeX.end(), 3); 1475 1476 rangeY = p.range(Dimension::Y); 1477 QCOMPARE(rangeY.start(), 1); 1478 QCOMPARE(rangeY.end(), 3); 1479 } 1480 1481 /*! 1482 * test the update of the xycurve and plot ranges after one of the source columns 1483 * was deleted first and was restored and the source values were modified by the import. 1484 */ 1485 void AsciiFilterTest::plotUpdateAfterImportWithColumnRestore() { 1486 Project project; // need a project object since the column restore logic is in project 1487 1488 // create the spreadsheet with the source data 1489 auto* spreadsheet = new Spreadsheet(QStringLiteral("test"), false); 1490 project.addChild(spreadsheet); 1491 spreadsheet->setColumnCount(2); 1492 spreadsheet->setRowCount(3); 1493 1494 auto* col = spreadsheet->column(0); 1495 col->setColumnMode(AbstractColumn::ColumnMode::Double); 1496 col->setName(QStringLiteral("c1")); 1497 col->setValueAt(0, 10.); 1498 col->setValueAt(1, 20.); 1499 col->setValueAt(2, 30.); 1500 1501 col = spreadsheet->column(1); 1502 col->setColumnMode(AbstractColumn::ColumnMode::Double); 1503 col->setName(QStringLiteral("c2")); 1504 col->setValueAt(0, 10.); 1505 col->setValueAt(1, 20.); 1506 col->setValueAt(2, 30.); 1507 1508 // create a xy-curve with the both columns in the source spreadsheet and check the ranges 1509 auto* p = new CartesianPlot(QStringLiteral("plot")); 1510 project.addChild(p); 1511 auto* curve = new XYCurve(QStringLiteral("curve")); 1512 p->addChild(curve); 1513 curve->setXColumn(spreadsheet->column(0)); 1514 curve->setYColumn(spreadsheet->column(1)); 1515 1516 auto rangeX = p->range(Dimension::X); 1517 QCOMPARE(rangeX.start(), 10); 1518 QCOMPARE(rangeX.end(), 30); 1519 1520 auto rangeY = p->range(Dimension::Y); 1521 QCOMPARE(rangeY.start(), 10); 1522 QCOMPARE(rangeY.end(), 30); 1523 1524 // delete the first source column 1525 spreadsheet->removeChild(spreadsheet->column(0)); 1526 1527 // import the data into the source spreadsheet, the deleted column with the name "c1" is re-created again 1528 AsciiFilter filter; 1529 const QString& fileName = QFINDTESTDATA(QLatin1String("data/separator_semicolon_with_header.txt")); 1530 filter.setCommentCharacter(QString()); 1531 filter.setSeparatingCharacter(QStringLiteral(";")); 1532 filter.setHeaderEnabled(true); 1533 filter.setHeaderLine(1); 1534 filter.readDataFromFile(fileName, spreadsheet, AbstractFileFilter::ImportMode::Replace); 1535 1536 // re-check the plot ranges with the new data 1537 rangeX = p->range(Dimension::X); 1538 QCOMPARE(rangeX.start(), 1); 1539 QCOMPARE(rangeX.end(), 3); 1540 1541 rangeY = p->range(Dimension::Y); 1542 QCOMPARE(rangeY.start(), 1); 1543 QCOMPARE(rangeY.end(), 3); 1544 } 1545 1546 /*! 1547 * test the update of the xycurve and plot ranges after the order or columns (their names) 1548 * was changed during the import. 1549 */ 1550 void AsciiFilterTest::plotUpdateAfterImportWithColumnRenaming() { 1551 Project project; // need a project object since the column restore logic is in project 1552 1553 // create the spreadsheet with the source data 1554 auto* spreadsheet = new Spreadsheet(QStringLiteral("test"), false); 1555 project.addChild(spreadsheet); 1556 spreadsheet->setColumnCount(3); 1557 spreadsheet->setRowCount(3); 1558 1559 auto* col = spreadsheet->column(0); 1560 col->setColumnMode(AbstractColumn::ColumnMode::Double); 1561 col->setName(QStringLiteral("c0")); // dummy column, values not required 1562 1563 col = spreadsheet->column(1); 1564 col->setColumnMode(AbstractColumn::ColumnMode::Double); 1565 col->setName(QStringLiteral("c1")); 1566 col->setValueAt(0, 10.); 1567 col->setValueAt(1, 20.); 1568 col->setValueAt(2, 30.); 1569 1570 col = spreadsheet->column(2); 1571 col->setColumnMode(AbstractColumn::ColumnMode::Double); 1572 col->setName(QStringLiteral("c2")); 1573 col->setValueAt(0, 10.); 1574 col->setValueAt(1, 20.); 1575 col->setValueAt(2, 30.); 1576 1577 // create a xy-curve with the both columns in the source spreadsheet and check the ranges 1578 auto* p = new CartesianPlot(QStringLiteral("plot")); 1579 project.addChild(p); 1580 auto* curve = new XYCurve(QStringLiteral("curve")); 1581 p->addChild(curve); 1582 curve->setXColumn(spreadsheet->column(1)); // use "c1" for x 1583 curve->setYColumn(spreadsheet->column(2)); // use "c2" for y 1584 1585 auto rangeX = p->range(Dimension::X); 1586 QCOMPARE(rangeX.start(), 10); 1587 QCOMPARE(rangeX.end(), 30); 1588 1589 auto rangeY = p->range(Dimension::Y); 1590 QCOMPARE(rangeY.start(), 10); 1591 QCOMPARE(rangeY.end(), 30); 1592 1593 // import the data into the source spreadsheet: 1594 // the columns "c0", "c1" and "c2" are renamed to "c1", "c2" and "c3" and xy-curve should still be using "c1" and "c2" 1595 // event hough their positions in the spreadsheet have changed 1596 AsciiFilter filter; 1597 const QString& fileName = QFINDTESTDATA(QLatin1String("data/separator_semicolon_with_header.txt")); 1598 filter.setCommentCharacter(QString()); 1599 filter.setSeparatingCharacter(QStringLiteral(";")); 1600 filter.setHeaderEnabled(true); 1601 filter.setHeaderLine(1); 1602 filter.readDataFromFile(fileName, spreadsheet, AbstractFileFilter::ImportMode::Replace); 1603 1604 // check the connection to the new columns 1605 QCOMPARE(curve->xColumn(), spreadsheet->column(0)); // "c1" for x 1606 QCOMPARE(curve->yColumn(), spreadsheet->column(1)); // "c2" for y 1607 1608 // re-check the plot ranges with the new data 1609 rangeX = p->range(Dimension::X); 1610 QCOMPARE(rangeX.start(), 1); 1611 QCOMPARE(rangeX.end(), 3); 1612 1613 rangeY = p->range(Dimension::Y); 1614 QCOMPARE(rangeY.start(), 1); 1615 QCOMPARE(rangeY.end(), 3); 1616 } 1617 1618 /*! 1619 * test the update of the xycurve after the source columns were renamed 1620 * during the import, the curve becomes invalid after this. 1621 */ 1622 void AsciiFilterTest::plotUpdateAfterImportWithColumnRemove() { 1623 Project project; // need a project object since the column restore logic is in project 1624 1625 // create the spreadsheet with the source data 1626 auto* spreadsheet = new Spreadsheet(QStringLiteral("test"), false); 1627 project.addChild(spreadsheet); 1628 spreadsheet->setColumnCount(2); 1629 spreadsheet->setRowCount(3); 1630 1631 auto* col = spreadsheet->column(0); 1632 col->setColumnMode(AbstractColumn::ColumnMode::Double); 1633 col->setName(QStringLiteral("1")); 1634 col->setValueAt(0, 10.); 1635 col->setValueAt(1, 20.); 1636 col->setValueAt(2, 30.); 1637 1638 col = spreadsheet->column(1); 1639 col->setColumnMode(AbstractColumn::ColumnMode::Double); 1640 col->setName(QStringLiteral("2")); 1641 col->setValueAt(0, 10.); 1642 col->setValueAt(1, 20.); 1643 col->setValueAt(2, 30.); 1644 1645 // create a xy-curve with the both columns in the source spreadsheet and check the ranges 1646 auto* p = new CartesianPlot(QStringLiteral("plot")); 1647 project.addChild(p); 1648 auto* curve = new XYCurve(QStringLiteral("curve")); 1649 p->addChild(curve); 1650 curve->setXColumn(spreadsheet->column(0)); // use "1" for x 1651 curve->setYColumn(spreadsheet->column(1)); // use "2" for y 1652 1653 auto rangeX = p->range(Dimension::X); 1654 QCOMPARE(rangeX.start(), 10); 1655 QCOMPARE(rangeX.end(), 30); 1656 1657 auto rangeY = p->range(Dimension::Y); 1658 QCOMPARE(rangeY.start(), 10); 1659 QCOMPARE(rangeY.end(), 30); 1660 1661 // import the data into the source spreadsheet, the columns are renamed to "c1" and "c2" 1662 AsciiFilter filter; 1663 const QString& fileName = QFINDTESTDATA(QLatin1String("data/separator_semicolon_with_header.txt")); 1664 filter.setCommentCharacter(QString()); 1665 filter.setSeparatingCharacter(QStringLiteral(";")); 1666 filter.setHeaderEnabled(true); 1667 filter.setHeaderLine(1); 1668 filter.readDataFromFile(fileName, spreadsheet, AbstractFileFilter::ImportMode::Replace); 1669 1670 // the assignment to the data columns got lost since the columns were renamed 1671 QCOMPARE(curve->xColumn(), nullptr); 1672 QCOMPARE(curve->yColumn(), nullptr); 1673 1674 // TODO: further checks to make sure the curve was really and properly invalidated 1675 } 1676 1677 // ############################################################################## 1678 // ################################# Benchmarks ################################# 1679 // ############################################################################## 1680 void AsciiFilterTest::benchDoubleImport_data() { 1681 QTest::addColumn<size_t>("lineCount"); 1682 // can't transfer file name since needed in clean up 1683 1684 QTemporaryFile file; 1685 if (!file.open()) // needed to generate file name 1686 return; 1687 1688 file.setAutoRemove(false); 1689 benchDataFileName = file.fileName(); 1690 1691 QString testName(QString::number(paths) + QLatin1String(" random double paths")); 1692 1693 QTest::newRow(qPrintable(testName)) << lines; 1694 DEBUG("CREATE DATA FILE " << STDSTRING(benchDataFileName) << ", lines = " << lines) 1695 1696 gsl_rng_env_setup(); 1697 gsl_rng* r = gsl_rng_alloc(gsl_rng_default); 1698 gsl_rng_set(r, 12345); 1699 1700 // create file 1701 QTextStream out(&file); 1702 // for higher precision 1703 // out.setRealNumberPrecision(13); 1704 1705 // create data 1706 double path[paths] = {0.0}; 1707 1708 const double delta = 0.25; 1709 const int dt = 1; 1710 const double sigma = delta * delta * dt; 1711 for (size_t i = 0; i < lines; ++i) { 1712 // std::cout << "line " << i+1 << std::endl; 1713 1714 for (int p = 0; p < paths; ++p) { 1715 path[p] += gsl_ran_gaussian_ziggurat(r, sigma); 1716 out << path[p]; 1717 if (p < paths - 1) 1718 out << ' '; 1719 } 1720 out << QStringLiteral("\n"); 1721 } 1722 1723 DEBUG(Q_FUNC_INFO << ", DONE") 1724 } 1725 1726 void AsciiFilterTest::benchDoubleImport() { 1727 Spreadsheet spreadsheet(QStringLiteral("test"), false); 1728 AsciiFilter filter; 1729 filter.setHeaderEnabled(false); 1730 1731 const int p = paths; // need local variable 1732 QBENCHMARK { 1733 filter.readDataFromFile(benchDataFileName, &spreadsheet, AbstractFileFilter::ImportMode::Replace); 1734 1735 QCOMPARE(spreadsheet.columnCount(), p); 1736 QCOMPARE(spreadsheet.rowCount(), lines); 1737 1738 QCOMPARE(spreadsheet.column(0)->valueAt(0), 0.120998); 1739 QCOMPARE(spreadsheet.column(1)->valueAt(0), 0.119301); 1740 QCOMPARE(spreadsheet.column(2)->valueAt(0), -0.0209980); 1741 } 1742 } 1743 1744 void AsciiFilterTest::benchDoubleImport_cleanup() { 1745 DEBUG("REMOVE DATA FILE " << STDSTRING(benchDataFileName)) 1746 QFile::remove(benchDataFileName); 1747 } 1748 1749 QTEST_MAIN(AsciiFilterTest)