Warning, file /education/labplot/tests/spreadsheet/SpreadsheetTest.cpp was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).
0001 /* 0002 File : SpreadsheetTest.cpp 0003 Project : LabPlot 0004 Description : Tests for the Spreadsheet 0005 -------------------------------------------------------------------- 0006 SPDX-FileCopyrightText: 2020-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 "SpreadsheetTest.h" 0013 #include "backend/core/Project.h" 0014 #include "backend/core/datatypes/DateTime2StringFilter.h" 0015 #include "backend/datasources/filters/VectorBLFFilter.h" 0016 #include "backend/spreadsheet/Spreadsheet.h" 0017 #include "backend/spreadsheet/SpreadsheetModel.h" 0018 #include "backend/spreadsheet/StatisticsSpreadsheet.h" 0019 #include "commonfrontend/ProjectExplorer.h" 0020 #include "commonfrontend/spreadsheet/SpreadsheetView.h" 0021 #include "kdefrontend/dockwidgets/SpreadsheetDock.h" 0022 #include "kdefrontend/spreadsheet/FlattenColumnsDialog.h" 0023 #include "kdefrontend/spreadsheet/SearchReplaceWidget.h" 0024 0025 #ifdef HAVE_VECTOR_BLF 0026 #include <Vector/BLF.h> 0027 #endif 0028 0029 #include <QClipboard> 0030 #include <QModelIndex> 0031 #include <QUndoStack> 0032 #if (QT_VERSION >= QT_VERSION_CHECK(5, 10, 0)) 0033 #include <QRandomGenerator> 0034 #endif 0035 0036 #include <gsl/gsl_math.h> 0037 0038 //********************************************************** 0039 //****************** Copy&Paste tests ********************** 0040 //********************************************************** 0041 0042 //********************************************************** 0043 //********** Handling of different columns modes *********** 0044 //********************************************************** 0045 /*! 0046 insert two columns with float values into an empty spreadsheet 0047 */ 0048 void SpreadsheetTest::testCopyPasteColumnMode00() { 0049 QLocale::setDefault(QLocale::C); // . as decimal separator 0050 Spreadsheet sheet(QStringLiteral("test"), false); 0051 sheet.setColumnCount(2); 0052 sheet.setRowCount(100); 0053 0054 const QString str = QStringLiteral("10.0 100.0\n20.0 200.0"); 0055 QApplication::clipboard()->setText(str); 0056 0057 SpreadsheetView view(&sheet, false); 0058 view.pasteIntoSelection(); 0059 0060 // spreadsheet size 0061 QCOMPARE(sheet.columnCount(), 2); 0062 QCOMPARE(sheet.rowCount(), 100); 0063 0064 // column modes 0065 QCOMPARE(sheet.column(0)->columnMode(), AbstractColumn::ColumnMode::Double); 0066 QCOMPARE(sheet.column(1)->columnMode(), AbstractColumn::ColumnMode::Double); 0067 0068 // values 0069 QCOMPARE(sheet.column(0)->valueAt(0), 10.0); 0070 QCOMPARE(sheet.column(1)->valueAt(0), 100.0); 0071 QCOMPARE(sheet.column(0)->valueAt(1), 20.0); 0072 QCOMPARE(sheet.column(1)->valueAt(1), 200.0); 0073 } 0074 0075 /*! 0076 insert one column with integer and one column with big integer values into an empty spreadsheet. 0077 the first column has to be converted to integer column, the second to big integer. 0078 */ 0079 void SpreadsheetTest::testCopyPasteColumnMode01() { 0080 Spreadsheet sheet(QStringLiteral("test"), false); 0081 sheet.setColumnCount(2); 0082 sheet.setRowCount(100); 0083 0084 const QString str = QStringLiteral("10 ") + QString::number(std::numeric_limits<long long>::min()) + QStringLiteral("\n20 ") 0085 + QString::number(std::numeric_limits<long long>::max()); 0086 QApplication::clipboard()->setText(str); 0087 0088 SpreadsheetView view(&sheet, false); 0089 view.pasteIntoSelection(); 0090 0091 // spreadsheet size 0092 QCOMPARE(sheet.columnCount(), 2); 0093 QCOMPARE(sheet.rowCount(), 100); 0094 0095 // column modes 0096 QCOMPARE(sheet.column(0)->columnMode(), AbstractColumn::ColumnMode::Integer); 0097 QCOMPARE(sheet.column(1)->columnMode(), AbstractColumn::ColumnMode::BigInt); 0098 0099 // values 0100 QCOMPARE(sheet.column(0)->integerAt(0), 10); 0101 QCOMPARE(sheet.column(1)->bigIntAt(0), std::numeric_limits<long long>::min()); 0102 QCOMPARE(sheet.column(0)->integerAt(1), 20); 0103 QCOMPARE(sheet.column(1)->bigIntAt(1), std::numeric_limits<long long>::max()); 0104 } 0105 0106 /*! 0107 insert one column with integer values and one column with float numbers into an empty spreadsheet. 0108 the first column has to be converted to integer column, the second to float. 0109 */ 0110 void SpreadsheetTest::testCopyPasteColumnMode02() { 0111 QLocale::setDefault(QLocale::C); // . as decimal separator 0112 Spreadsheet sheet(QStringLiteral("test"), false); 0113 sheet.setColumnCount(2); 0114 sheet.setRowCount(100); 0115 0116 const QString str = QStringLiteral("10 100.0\n20 200.0"); 0117 QApplication::clipboard()->setText(str); 0118 0119 SpreadsheetView view(&sheet, false); 0120 view.pasteIntoSelection(); 0121 0122 // spreadsheet size 0123 QCOMPARE(sheet.columnCount(), 2); 0124 QCOMPARE(sheet.rowCount(), 100); 0125 0126 // column modes 0127 QCOMPARE(sheet.column(0)->columnMode(), AbstractColumn::ColumnMode::Integer); 0128 QCOMPARE(sheet.column(1)->columnMode(), AbstractColumn::ColumnMode::Double); 0129 0130 // values 0131 QCOMPARE(sheet.column(0)->integerAt(0), 10); 0132 QCOMPARE(sheet.column(1)->valueAt(0), 100.0); 0133 QCOMPARE(sheet.column(0)->integerAt(1), 20); 0134 QCOMPARE(sheet.column(1)->valueAt(1), 200.0); 0135 } 0136 0137 /*! 0138 Properly handle empty values in the tab separated data. 0139 */ 0140 void SpreadsheetTest::testCopyPasteColumnMode03() { 0141 QLocale::setDefault(QLocale::C); // . as decimal separator 0142 Spreadsheet sheet(QStringLiteral("test"), false); 0143 sheet.setColumnCount(2); 0144 sheet.setRowCount(100); 0145 0146 const QString str = QStringLiteral( 0147 "1000 1000 1000\n" 0148 "985 985 985\n" 0149 "970 -7.06562 970 970\n" 0150 "955 -5.93881 955 955\n" 0151 "940 -4.97594 940 -4.97594 940"); 0152 0153 QApplication::clipboard()->setText(str); 0154 0155 SpreadsheetView view(&sheet, false); 0156 view.pasteIntoSelection(); 0157 0158 // spreadsheet size 0159 QCOMPARE(sheet.columnCount(), 5); 0160 QCOMPARE(sheet.rowCount(), 100); 0161 0162 // column modes 0163 QCOMPARE(sheet.column(0)->columnMode(), AbstractColumn::ColumnMode::Integer); 0164 QCOMPARE(sheet.column(1)->columnMode(), AbstractColumn::ColumnMode::Double); 0165 QCOMPARE(sheet.column(2)->columnMode(), AbstractColumn::ColumnMode::Integer); 0166 QCOMPARE(sheet.column(3)->columnMode(), AbstractColumn::ColumnMode::Double); 0167 QCOMPARE(sheet.column(4)->columnMode(), AbstractColumn::ColumnMode::Integer); 0168 0169 // values 0170 QCOMPARE(sheet.column(0)->integerAt(0), 1000); 0171 QCOMPARE((bool)std::isnan(sheet.column(1)->valueAt(0)), true); 0172 QCOMPARE(sheet.column(2)->integerAt(0), 1000); 0173 QCOMPARE((bool)std::isnan(sheet.column(3)->valueAt(0)), true); 0174 QCOMPARE(sheet.column(4)->integerAt(0), 1000); 0175 0176 QCOMPARE(sheet.column(0)->integerAt(1), 985); 0177 QCOMPARE((bool)std::isnan(sheet.column(1)->valueAt(1)), true); 0178 QCOMPARE(sheet.column(2)->integerAt(1), 985); 0179 QCOMPARE((bool)std::isnan(sheet.column(3)->valueAt(1)), true); 0180 QCOMPARE(sheet.column(4)->integerAt(1), 985); 0181 0182 QCOMPARE(sheet.column(0)->integerAt(2), 970); 0183 QCOMPARE(sheet.column(1)->valueAt(2), -7.06562); 0184 QCOMPARE(sheet.column(2)->integerAt(2), 970); 0185 QCOMPARE((bool)std::isnan(sheet.column(3)->valueAt(2)), true); 0186 QCOMPARE(sheet.column(4)->integerAt(2), 970); 0187 0188 QCOMPARE(sheet.column(0)->integerAt(3), 955); 0189 QCOMPARE(sheet.column(1)->valueAt(3), -5.93881); 0190 QCOMPARE(sheet.column(2)->integerAt(3), 955); 0191 QCOMPARE((bool)std::isnan(sheet.column(3)->valueAt(3)), true); 0192 QCOMPARE(sheet.column(4)->integerAt(3), 955); 0193 0194 QCOMPARE(sheet.column(0)->integerAt(4), 940); 0195 QCOMPARE(sheet.column(1)->valueAt(4), -4.97594); 0196 QCOMPARE(sheet.column(2)->integerAt(4), 940); 0197 QCOMPARE(sheet.column(1)->valueAt(4), -4.97594); 0198 QCOMPARE(sheet.column(4)->integerAt(4), 940); 0199 } 0200 0201 /*! 0202 automatically detect the proper format for the datetime columns 0203 */ 0204 void SpreadsheetTest::testCopyPasteColumnMode04() { 0205 QLocale::setDefault(QLocale::C); // . as decimal separator 0206 Spreadsheet sheet(QStringLiteral("test"), false); 0207 sheet.setColumnCount(2); 0208 sheet.setRowCount(100); 0209 0210 const QString str = QStringLiteral( 0211 "2020-09-20 11:21:40:849 7.7\n" 0212 "2020-09-20 11:21:41:830 4.2"); 0213 0214 QApplication::clipboard()->setText(str); 0215 0216 SpreadsheetView view(&sheet, false); 0217 view.pasteIntoSelection(); 0218 0219 // spreadsheet size 0220 QCOMPARE(sheet.columnCount(), 2); 0221 QCOMPARE(sheet.rowCount(), 100); 0222 0223 // column modes 0224 QCOMPARE(sheet.column(0)->columnMode(), AbstractColumn::ColumnMode::DateTime); 0225 QCOMPARE(sheet.column(1)->columnMode(), AbstractColumn::ColumnMode::Double); 0226 0227 // values 0228 auto* filter = static_cast<DateTime2StringFilter*>(sheet.column(0)->outputFilter()); 0229 const QString& format = filter->format(); 0230 0231 QCOMPARE(sheet.column(0)->dateTimeAt(0).toString(format), QLatin1String("2020-09-20 11:21:40:849")); 0232 QCOMPARE(sheet.column(1)->valueAt(0), 7.7); 0233 0234 QCOMPARE(sheet.column(0)->dateTimeAt(1).toString(format), QLatin1String("2020-09-20 11:21:41:830")); 0235 QCOMPARE(sheet.column(1)->valueAt(1), 4.2); 0236 } 0237 0238 /*! 0239 automatically detect the proper format for the datetime columns, time part only 0240 */ 0241 void SpreadsheetTest::testCopyPasteColumnMode05() { 0242 QLocale::setDefault(QLocale::C); // . as decimal separator 0243 Spreadsheet sheet(QStringLiteral("test"), false); 0244 sheet.setColumnCount(2); 0245 sheet.setRowCount(100); 0246 0247 const QString str = QStringLiteral( 0248 "11:21:40 7.7\n" 0249 "11:21:41 4.2"); 0250 0251 QApplication::clipboard()->setText(str); 0252 0253 SpreadsheetView view(&sheet, false); 0254 view.pasteIntoSelection(); 0255 0256 // spreadsheet size 0257 QCOMPARE(sheet.columnCount(), 2); 0258 QCOMPARE(sheet.rowCount(), 100); 0259 0260 // column modes 0261 QCOMPARE(sheet.column(0)->columnMode(), AbstractColumn::ColumnMode::DateTime); 0262 QCOMPARE(sheet.column(1)->columnMode(), AbstractColumn::ColumnMode::Double); 0263 0264 // values 0265 auto* filter = static_cast<DateTime2StringFilter*>(sheet.column(0)->outputFilter()); 0266 const QString& format = filter->format(); 0267 0268 QCOMPARE(sheet.column(0)->dateTimeAt(0).toString(format), QLatin1String("11:21:40")); 0269 QCOMPARE(sheet.column(1)->valueAt(0), 7.7); 0270 0271 QCOMPARE(sheet.column(0)->dateTimeAt(1).toString(format), QLatin1String("11:21:41")); 0272 QCOMPARE(sheet.column(1)->valueAt(1), 4.2); 0273 } 0274 0275 /*! 0276 automatically detect the proper format for the datetime columns having the format "yyyy-MM-dd hh:mm:ss" 0277 */ 0278 void SpreadsheetTest::testCopyPasteColumnMode06() { 0279 Spreadsheet sheet(QStringLiteral("test"), false); 0280 sheet.setColumnCount(2); 0281 sheet.setRowCount(100); 0282 0283 const QString str = QStringLiteral( 0284 "2018-03-21 10:00:00 1\n" 0285 "2018-03-21 10:30:00 2"); 0286 0287 QApplication::clipboard()->setText(str); 0288 0289 SpreadsheetView view(&sheet, false); 0290 view.pasteIntoSelection(); 0291 0292 // spreadsheet size 0293 QCOMPARE(sheet.columnCount(), 2); 0294 QCOMPARE(sheet.rowCount(), 100); 0295 0296 // column modes 0297 QCOMPARE(sheet.column(0)->columnMode(), AbstractColumn::ColumnMode::DateTime); 0298 QCOMPARE(sheet.column(1)->columnMode(), AbstractColumn::ColumnMode::Integer); 0299 0300 // values 0301 auto* filter = static_cast<DateTime2StringFilter*>(sheet.column(0)->outputFilter()); 0302 const QString& format = filter->format(); 0303 0304 QCOMPARE(sheet.column(0)->dateTimeAt(0).toString(format), QLatin1String("2018-03-21 10:00:00")); 0305 QCOMPARE(sheet.column(1)->integerAt(0), 1); 0306 0307 QCOMPARE(sheet.column(0)->dateTimeAt(1).toString(format), QLatin1String("2018-03-21 10:30:00")); 0308 QCOMPARE(sheet.column(1)->integerAt(1), 2); 0309 } 0310 0311 //********************************************************** 0312 //********* Handling of spreadsheet size changes *********** 0313 //********************************************************** 0314 /*! 0315 insert irregular data, new columns should be added appropriately. 0316 */ 0317 void SpreadsheetTest::testCopyPasteSizeChange00() { 0318 Project project; 0319 Spreadsheet* sheet = new Spreadsheet(QStringLiteral("test"), false); 0320 project.addChild(sheet); 0321 sheet->setColumnCount(2); 0322 sheet->setRowCount(100); 0323 0324 const QString str = QStringLiteral( 0325 "0\n" 0326 "10 20\n" 0327 "11 21 31\n" 0328 "12 22 32 42\n" 0329 "13 23\n" 0330 "14"); 0331 QApplication::clipboard()->setText(str); 0332 0333 SpreadsheetView view(sheet, false); 0334 view.pasteIntoSelection(); 0335 0336 // spreadsheet size 0337 QCOMPARE(sheet->columnCount(), 4); 0338 QCOMPARE(sheet->rowCount(), 100); 0339 0340 // column modes 0341 QCOMPARE(sheet->column(0)->columnMode(), AbstractColumn::ColumnMode::Integer); 0342 QCOMPARE(sheet->column(1)->columnMode(), AbstractColumn::ColumnMode::Integer); 0343 QCOMPARE(sheet->column(2)->columnMode(), AbstractColumn::ColumnMode::Integer); 0344 QCOMPARE(sheet->column(3)->columnMode(), AbstractColumn::ColumnMode::Integer); 0345 0346 // values 0347 QCOMPARE(sheet->column(0)->integerAt(0), 0); 0348 QCOMPARE(sheet->column(1)->integerAt(0), 0); 0349 QCOMPARE(sheet->column(2)->integerAt(0), 0); 0350 QCOMPARE(sheet->column(3)->integerAt(0), 0); 0351 0352 QCOMPARE(sheet->column(0)->integerAt(1), 10); 0353 QCOMPARE(sheet->column(1)->integerAt(1), 20); 0354 QCOMPARE(sheet->column(2)->integerAt(1), 0); 0355 QCOMPARE(sheet->column(3)->integerAt(1), 0); 0356 0357 QCOMPARE(sheet->column(0)->integerAt(2), 11); 0358 QCOMPARE(sheet->column(1)->integerAt(2), 21); 0359 QCOMPARE(sheet->column(2)->integerAt(2), 31); 0360 QCOMPARE(sheet->column(3)->integerAt(2), 0); 0361 0362 QCOMPARE(sheet->column(0)->integerAt(3), 12); 0363 QCOMPARE(sheet->column(1)->integerAt(3), 22); 0364 QCOMPARE(sheet->column(2)->integerAt(3), 32); 0365 QCOMPARE(sheet->column(3)->integerAt(3), 42); 0366 0367 QCOMPARE(sheet->column(0)->integerAt(4), 13); 0368 QCOMPARE(sheet->column(1)->integerAt(4), 23); 0369 QCOMPARE(sheet->column(2)->integerAt(4), 0); 0370 QCOMPARE(sheet->column(3)->integerAt(4), 0); 0371 0372 QCOMPARE(sheet->column(0)->integerAt(5), 14); 0373 QCOMPARE(sheet->column(1)->integerAt(5), 0); 0374 QCOMPARE(sheet->column(2)->integerAt(5), 0); 0375 QCOMPARE(sheet->column(3)->integerAt(5), 0); 0376 0377 // undo the changes and check the results again 0378 project.undoStack()->undo(); 0379 0380 // spreadsheet size 0381 QCOMPARE(sheet->columnCount(), 2); 0382 QCOMPARE(sheet->rowCount(), 100); 0383 0384 // column modes 0385 QCOMPARE(sheet->column(0)->columnMode(), AbstractColumn::ColumnMode::Double); 0386 QCOMPARE(sheet->column(1)->columnMode(), AbstractColumn::ColumnMode::Double); 0387 0388 // values 0389 QCOMPARE((bool)std::isnan(sheet->column(0)->valueAt(0)), true); 0390 QCOMPARE((bool)std::isnan(sheet->column(1)->valueAt(0)), true); 0391 0392 QCOMPARE((bool)std::isnan(sheet->column(0)->valueAt(1)), true); 0393 QCOMPARE((bool)std::isnan(sheet->column(1)->valueAt(1)), true); 0394 0395 QCOMPARE((bool)std::isnan(sheet->column(0)->valueAt(2)), true); 0396 QCOMPARE((bool)std::isnan(sheet->column(1)->valueAt(2)), true); 0397 0398 QCOMPARE((bool)std::isnan(sheet->column(0)->valueAt(3)), true); 0399 QCOMPARE((bool)std::isnan(sheet->column(1)->valueAt(3)), true); 0400 0401 QCOMPARE((bool)std::isnan(sheet->column(0)->valueAt(4)), true); 0402 QCOMPARE((bool)std::isnan(sheet->column(1)->valueAt(4)), true); 0403 0404 QCOMPARE((bool)std::isnan(sheet->column(0)->valueAt(5)), true); 0405 QCOMPARE((bool)std::isnan(sheet->column(1)->valueAt(5)), true); 0406 } 0407 0408 void SpreadsheetTest::testCopyPasteUtf8() { 0409 Spreadsheet sheet(QStringLiteral("test"), false); 0410 sheet.setColumnCount(2); 0411 sheet.setRowCount(100); 0412 0413 const QString str = QString::fromUtf8("тест1 1\nтест2 2"); 0414 0415 QApplication::clipboard()->setText(str); 0416 0417 SpreadsheetView view(&sheet, false); 0418 view.pasteIntoSelection(); 0419 0420 // data types 0421 QCOMPARE(sheet.column(0)->columnMode(), AbstractColumn::ColumnMode::Text); 0422 QCOMPARE(sheet.column(1)->columnMode(), AbstractColumn::ColumnMode::Integer); 0423 0424 // values 0425 QCOMPARE(sheet.column(0)->textAt(0), QString::fromUtf8("тест1")); 0426 QCOMPARE(sheet.column(1)->integerAt(0), 1); 0427 0428 QCOMPARE(sheet.column(0)->textAt(1), QString::fromUtf8("тест2")); 0429 QCOMPARE(sheet.column(1)->integerAt(1), 2); 0430 } 0431 /*! 0432 insert the data at the edge of the spreadsheet and paste the data. 0433 the spreadsheet has to be extended accordingly 0434 */ 0435 void SpreadsheetTest::testCopyPasteSizeChange01() { 0436 QLocale::setDefault(QLocale::C); // . as decimal separator 0437 Spreadsheet sheet(QStringLiteral("test"), false); 0438 sheet.setColumnCount(2); 0439 sheet.setRowCount(100); 0440 0441 const QString str = QStringLiteral( 0442 "1.1 2.2\n" 0443 "3.3 4.4"); 0444 QApplication::clipboard()->setText(str); 0445 0446 SpreadsheetView view(&sheet, false); 0447 view.goToCell(1, 1); // havigate to the edge of the spreadsheet 0448 view.pasteIntoSelection(); 0449 0450 // spreadsheet size 0451 QCOMPARE(sheet.columnCount(), 3); 0452 QCOMPARE(sheet.rowCount(), 100); 0453 0454 // column modes 0455 QCOMPARE(sheet.column(0)->columnMode(), AbstractColumn::ColumnMode::Double); 0456 QCOMPARE(sheet.column(1)->columnMode(), AbstractColumn::ColumnMode::Double); 0457 QCOMPARE(sheet.column(2)->columnMode(), AbstractColumn::ColumnMode::Double); 0458 0459 // values 0460 QCOMPARE((bool)std::isnan(sheet.column(0)->valueAt(0)), true); 0461 QCOMPARE((bool)std::isnan(sheet.column(1)->valueAt(0)), true); 0462 QCOMPARE((bool)std::isnan(sheet.column(2)->valueAt(0)), true); 0463 0464 QCOMPARE((bool)std::isnan(sheet.column(0)->valueAt(1)), true); 0465 QCOMPARE(sheet.column(1)->valueAt(1), 1.1); 0466 QCOMPARE(sheet.column(2)->valueAt(1), 2.2); 0467 0468 QCOMPARE((bool)std::isnan(sheet.column(0)->valueAt(2)), true); 0469 QCOMPARE(sheet.column(1)->valueAt(2), 3.3); 0470 QCOMPARE(sheet.column(2)->valueAt(2), 4.4); 0471 } 0472 0473 // ********************************************************** 0474 // *********************** sorting ************************* 0475 // ********************************************************** 0476 // single column 0477 0478 /* 0479 * check sorting single column of double values with NaN ascending 0480 */ 0481 void SpreadsheetTest::testSortSingleNumeric1() { 0482 const QVector<double> xData{0.5, -0.2, GSL_NAN, 2.0, -1.0}; 0483 0484 Spreadsheet sheet(QStringLiteral("test"), false); 0485 sheet.setColumnCount(1); 0486 sheet.setRowCount(7); 0487 auto* col = sheet.column(0); 0488 col->replaceValues(0, xData); 0489 0490 // sort 0491 sheet.sortColumns(nullptr, {col}, true); 0492 0493 // values 0494 QCOMPARE(col->valueAt(0), -1.0); 0495 QCOMPARE(col->valueAt(1), -0.2); 0496 QCOMPARE(col->valueAt(2), 0.5); 0497 QCOMPARE(col->valueAt(3), 2.0); 0498 } 0499 0500 /* 0501 * check sorting single column of double values with NaN descending 0502 */ 0503 void SpreadsheetTest::testSortSingleNumeric2() { 0504 const QVector<double> xData{0.5, -0.2, GSL_NAN, 2.0, -1.0}; 0505 0506 Spreadsheet sheet(QStringLiteral("test"), false); 0507 sheet.setColumnCount(1); 0508 sheet.setRowCount(7); 0509 auto* col = sheet.column(0); 0510 col->replaceValues(0, xData); 0511 0512 // sort 0513 sheet.sortColumns(nullptr, {col}, false); 0514 0515 // values 0516 QCOMPARE(col->valueAt(0), 2.0); 0517 QCOMPARE(col->valueAt(1), 0.5); 0518 QCOMPARE(col->valueAt(2), -0.2); 0519 QCOMPARE(col->valueAt(3), -1.0); 0520 } 0521 0522 /* 0523 * check sorting single column of integer values with empty entries ascending 0524 */ 0525 void SpreadsheetTest::testSortSingleInteger1() { 0526 const QVector<int> xData1{4, 5, 2}; 0527 const QVector<int> xData2{3, 6, -1}; 0528 0529 Spreadsheet sheet(QStringLiteral("test"), false); 0530 sheet.setColumnCount(1); 0531 sheet.setRowCount(7); 0532 auto* col = sheet.column(0); 0533 col->setColumnMode(AbstractColumn::ColumnMode::Integer); 0534 col->replaceInteger(0, xData1); 0535 col->replaceInteger(4, xData2); 0536 0537 // sort 0538 sheet.sortColumns(nullptr, {col}, true); 0539 0540 // values 0541 QCOMPARE(col->integerAt(0), -1); 0542 QCOMPARE(col->integerAt(1), 0); 0543 QCOMPARE(col->integerAt(2), 2); 0544 QCOMPARE(col->integerAt(3), 3); 0545 QCOMPARE(col->integerAt(4), 4); 0546 QCOMPARE(col->integerAt(5), 5); 0547 QCOMPARE(col->integerAt(6), 6); 0548 } 0549 0550 /* 0551 * check sorting single column of integer values with empty entries ascending 0552 */ 0553 void SpreadsheetTest::testSortSingleInteger2() { 0554 const QVector<int> xData1{4, 5, 2}; 0555 const QVector<int> xData2{3, 6, -1}; 0556 0557 Spreadsheet sheet(QStringLiteral("test"), false); 0558 sheet.setColumnCount(1); 0559 sheet.setRowCount(7); 0560 auto* col = sheet.column(0); 0561 col->setColumnMode(AbstractColumn::ColumnMode::Integer); 0562 col->replaceInteger(0, xData1); 0563 col->replaceInteger(4, xData2); 0564 0565 // sort 0566 sheet.sortColumns(nullptr, {col}, false); 0567 0568 // values 0569 QCOMPARE(col->integerAt(6), -1); 0570 QCOMPARE(col->integerAt(5), 0); 0571 QCOMPARE(col->integerAt(4), 2); 0572 QCOMPARE(col->integerAt(3), 3); 0573 QCOMPARE(col->integerAt(2), 4); 0574 QCOMPARE(col->integerAt(1), 5); 0575 QCOMPARE(col->integerAt(0), 6); 0576 } 0577 0578 /* 0579 * check sorting single column of big int values with empty entries ascending 0580 */ 0581 void SpreadsheetTest::testSortSingleBigInt1() { 0582 const QVector<qint64> xData1{40000000000, 50000000000, 20000000000}; 0583 const QVector<qint64> xData2{30000000000, 60000000000, -10000000000}; 0584 0585 Spreadsheet sheet(QStringLiteral("test"), false); 0586 sheet.setColumnCount(1); 0587 sheet.setRowCount(7); 0588 auto* col = sheet.column(0); 0589 col->setColumnMode(AbstractColumn::ColumnMode::BigInt); 0590 col->replaceBigInt(0, xData1); 0591 col->replaceBigInt(4, xData2); 0592 0593 // sort 0594 sheet.sortColumns(nullptr, {col}, true); 0595 0596 // values 0597 QCOMPARE(col->bigIntAt(0), -10000000000ll); 0598 QCOMPARE(col->bigIntAt(1), 0); 0599 QCOMPARE(col->bigIntAt(2), 20000000000ll); 0600 QCOMPARE(col->bigIntAt(3), 30000000000ll); 0601 QCOMPARE(col->bigIntAt(4), 40000000000ll); 0602 QCOMPARE(col->bigIntAt(5), 50000000000ll); 0603 QCOMPARE(col->bigIntAt(6), 60000000000ll); 0604 } 0605 0606 /* 0607 * check sorting single column of big int values with empty entries descending 0608 */ 0609 void SpreadsheetTest::testSortSingleBigInt2() { 0610 const QVector<qint64> xData1{40000000000, 50000000000, 20000000000}; 0611 const QVector<qint64> xData2{30000000000, 60000000000, -10000000000}; 0612 0613 Spreadsheet sheet(QStringLiteral("test"), false); 0614 sheet.setColumnCount(1); 0615 sheet.setRowCount(7); 0616 auto* col = sheet.column(0); 0617 col->setColumnMode(AbstractColumn::ColumnMode::BigInt); 0618 col->replaceBigInt(0, xData1); 0619 col->replaceBigInt(4, xData2); 0620 0621 // sort 0622 sheet.sortColumns(nullptr, {col}, false); 0623 0624 // values 0625 QCOMPARE(col->bigIntAt(6), -10000000000ll); 0626 QCOMPARE(col->bigIntAt(5), 0); 0627 QCOMPARE(col->bigIntAt(4), 20000000000ll); 0628 QCOMPARE(col->bigIntAt(3), 30000000000ll); 0629 QCOMPARE(col->bigIntAt(2), 40000000000ll); 0630 QCOMPARE(col->bigIntAt(1), 50000000000ll); 0631 QCOMPARE(col->bigIntAt(0), 60000000000ll); 0632 } 0633 0634 /* 0635 * check sorting single column of text with empty entries ascending 0636 */ 0637 void SpreadsheetTest::testSortSingleText1() { 0638 const QVector<QString> xData{QStringLiteral("ben"), 0639 QStringLiteral("amy"), 0640 QStringLiteral("eddy"), 0641 QString(), 0642 QStringLiteral("carl"), 0643 QStringLiteral("dan")}; 0644 0645 Spreadsheet sheet(QStringLiteral("test"), false); 0646 sheet.setColumnCount(1); 0647 sheet.setRowCount(8); 0648 auto* col = sheet.column(0); 0649 col->setColumnMode(AbstractColumn::ColumnMode::Text); 0650 col->replaceTexts(0, xData); 0651 0652 // sort 0653 sheet.sortColumns(nullptr, {col}, true); 0654 0655 // values 0656 QCOMPARE(col->textAt(0), QLatin1String("amy")); 0657 QCOMPARE(col->textAt(1), QLatin1String("ben")); 0658 QCOMPARE(col->textAt(2), QLatin1String("carl")); 0659 QCOMPARE(col->textAt(3), QLatin1String("dan")); 0660 QCOMPARE(col->textAt(4), QLatin1String("eddy")); 0661 QCOMPARE(col->textAt(5), QString()); 0662 QCOMPARE(col->textAt(6), QString()); 0663 } 0664 0665 /* 0666 * check sorting single column of text with empty entries descending 0667 */ 0668 void SpreadsheetTest::testSortSingleText2() { 0669 const QVector<QString> xData = 0670 {QStringLiteral("ben"), QStringLiteral("amy"), QStringLiteral("eddy"), QString(), QStringLiteral("carl"), QStringLiteral("dan")}; 0671 0672 Spreadsheet sheet(QStringLiteral("test"), false); 0673 sheet.setColumnCount(1); 0674 sheet.setRowCount(8); 0675 auto* col = sheet.column(0); 0676 col->setColumnMode(AbstractColumn::ColumnMode::Text); 0677 col->replaceTexts(0, xData); 0678 0679 // sort 0680 sheet.sortColumns(nullptr, {col}, false); 0681 0682 // values 0683 QCOMPARE(col->textAt(0), QLatin1String("eddy")); 0684 QCOMPARE(col->textAt(1), QLatin1String("dan")); 0685 QCOMPARE(col->textAt(2), QLatin1String("carl")); 0686 QCOMPARE(col->textAt(3), QLatin1String("ben")); 0687 QCOMPARE(col->textAt(4), QLatin1String("amy")); 0688 QCOMPARE(col->textAt(5), QString()); 0689 QCOMPARE(col->textAt(6), QString()); 0690 } 0691 0692 /* 0693 * check sorting single column of datetimes with invalid entries ascending 0694 */ 0695 void SpreadsheetTest::testSortSingleDateTime1() { 0696 const QVector<QDateTime> xData{ 0697 QDateTime(QDate(2020, 02, 29), QTime(12, 12, 12)), 0698 QDateTime(QDate(2020, 02, 28), QTime(12, 12, 12)), 0699 QDateTime(QDate(2019, 02, 28), QTime(12, 12, 12)), 0700 QDateTime(QDate(2019, 02, 29), QTime(12, 12, 12)), // invalid 0701 QDateTime(QDate(2020, 02, 29), QTime(12, 12, 13)), 0702 QDateTime(QDate(2020, 02, 29), QTime(11, 12, 12)), 0703 }; 0704 0705 Spreadsheet sheet(QStringLiteral("test"), false); 0706 sheet.setColumnCount(1); 0707 sheet.setRowCount(8); 0708 auto* col{sheet.column(0)}; 0709 col->setColumnMode(AbstractColumn::ColumnMode::DateTime); 0710 col->replaceDateTimes(0, xData); 0711 0712 // sort 0713 sheet.sortColumns(nullptr, {col}, true); 0714 0715 // values 0716 QCOMPARE(col->dateTimeAt(0), QDateTime(QDate(2019, 02, 28), QTime(12, 12, 12))); 0717 QCOMPARE(col->dateTimeAt(1), QDateTime(QDate(2020, 02, 28), QTime(12, 12, 12))); 0718 QCOMPARE(col->dateTimeAt(2), QDateTime(QDate(2020, 02, 29), QTime(11, 12, 12))); 0719 QCOMPARE(col->dateTimeAt(3), QDateTime(QDate(2020, 02, 29), QTime(12, 12, 12))); 0720 QCOMPARE(col->dateTimeAt(4), QDateTime(QDate(2020, 02, 29), QTime(12, 12, 13))); 0721 } 0722 0723 /* 0724 * check sorting single column of datetimes with invalid entries descending 0725 */ 0726 void SpreadsheetTest::testSortSingleDateTime2() { 0727 const QVector<QDateTime> xData{ 0728 QDateTime(QDate(2020, 02, 29), QTime(12, 12, 12)), 0729 QDateTime(QDate(2020, 02, 28), QTime(12, 12, 12)), 0730 QDateTime(QDate(2019, 02, 28), QTime(12, 12, 12)), 0731 QDateTime(QDate(2019, 02, 29), QTime(12, 12, 12)), // invalid 0732 QDateTime(QDate(2020, 02, 29), QTime(12, 12, 13)), 0733 QDateTime(QDate(2020, 02, 29), QTime(11, 12, 12)), 0734 }; 0735 0736 Spreadsheet sheet(QStringLiteral("test"), false); 0737 sheet.setColumnCount(1); 0738 sheet.setRowCount(8); 0739 auto* col = sheet.column(0); 0740 col->setColumnMode(AbstractColumn::ColumnMode::DateTime); 0741 col->replaceDateTimes(0, xData); 0742 0743 // sort 0744 sheet.sortColumns(nullptr, {col}, false); 0745 0746 // values 0747 QCOMPARE(col->dateTimeAt(4), QDateTime(QDate(2019, 02, 28), QTime(12, 12, 12))); 0748 QCOMPARE(col->dateTimeAt(3), QDateTime(QDate(2020, 02, 28), QTime(12, 12, 12))); 0749 QCOMPARE(col->dateTimeAt(2), QDateTime(QDate(2020, 02, 29), QTime(11, 12, 12))); 0750 QCOMPARE(col->dateTimeAt(1), QDateTime(QDate(2020, 02, 29), QTime(12, 12, 12))); 0751 QCOMPARE(col->dateTimeAt(0), QDateTime(QDate(2020, 02, 29), QTime(12, 12, 13))); 0752 } 0753 0754 // multiple column 0755 /* 0756 * check sorting double values with NaN ascending as leading column 0757 */ 0758 void SpreadsheetTest::testSortNumeric1() { 0759 const QVector<double> xData{0.5, -0.2, GSL_NAN, 2.0, -1.0}; 0760 const QVector<int> yData{1, 2, 3, 4, 5, 6}; 0761 0762 Spreadsheet sheet(QStringLiteral("test"), false); 0763 sheet.setColumnCount(2); 0764 sheet.setRowCount(10); 0765 auto* col0{sheet.column(0)}; 0766 auto* col1{sheet.column(1)}; 0767 col0->replaceValues(0, xData); 0768 col1->setColumnMode(AbstractColumn::ColumnMode::Integer); 0769 col1->replaceInteger(0, yData); 0770 0771 // sort 0772 sheet.sortColumns(col0, {col0, col1}, true); 0773 0774 // values 0775 QCOMPARE(col0->valueAt(0), -1.0); 0776 QCOMPARE(col0->valueAt(1), -0.2); 0777 QCOMPARE(col0->valueAt(2), 0.5); 0778 QCOMPARE(col0->valueAt(3), 2.0); 0779 // QCOMPARE(col0->valueAt(4), GSL_NAN); 0780 QCOMPARE(col1->integerAt(0), 5); 0781 QCOMPARE(col1->integerAt(1), 2); 0782 QCOMPARE(col1->integerAt(2), 1); 0783 QCOMPARE(col1->integerAt(3), 4); 0784 QCOMPARE(col1->integerAt(4), 3); 0785 QCOMPARE(col1->integerAt(5), 6); 0786 } 0787 0788 /* 0789 * check sorting double values with NaN descending as leading column 0790 */ 0791 void SpreadsheetTest::testSortNumeric2() { 0792 const QVector<double> xData{0.5, -0.2, GSL_NAN, 2.0, -1.0}; 0793 const QVector<int> yData{1, 2, 3, 4, 5, 6, 7}; 0794 0795 Spreadsheet sheet(QStringLiteral("test"), false); 0796 sheet.setColumnCount(2); 0797 sheet.setRowCount(10); 0798 auto* col0{sheet.column(0)}; 0799 auto* col1{sheet.column(1)}; 0800 col0->replaceValues(0, xData); 0801 col1->setColumnMode(AbstractColumn::ColumnMode::Integer); 0802 col1->replaceInteger(0, yData); 0803 0804 // sort 0805 sheet.sortColumns(col0, {col0, col1}, false); 0806 0807 // values 0808 QCOMPARE(col0->valueAt(0), 2.0); 0809 QCOMPARE(col0->valueAt(1), 0.5); 0810 QCOMPARE(col0->valueAt(2), -0.2); 0811 QCOMPARE(col0->valueAt(3), -1.0); 0812 QCOMPARE(col1->integerAt(0), 4); 0813 QCOMPARE(col1->integerAt(1), 1); 0814 QCOMPARE(col1->integerAt(2), 2); 0815 QCOMPARE(col1->integerAt(3), 5); 0816 QCOMPARE(col1->integerAt(4), 3); 0817 QCOMPARE(col1->integerAt(5), 6); 0818 QCOMPARE(col1->integerAt(6), 7); 0819 } 0820 0821 /* 0822 * check sorting integer values with empty entries ascending as leading column 0823 */ 0824 void SpreadsheetTest::testSortInteger1() { 0825 const QVector<int> xData1{4, 5, 2}; 0826 const QVector<int> xData2{3, 6, -1}; 0827 const QVector<int> yData{1, 2, 3, 4, 5, 6, 7}; 0828 0829 Spreadsheet sheet(QStringLiteral("test"), false); 0830 sheet.setColumnCount(2); 0831 sheet.setRowCount(7); 0832 auto* col0{sheet.column(0)}; 0833 auto* col1{sheet.column(1)}; 0834 col0->setColumnMode(AbstractColumn::ColumnMode::Integer); 0835 col0->replaceInteger(0, xData1); 0836 col0->replaceInteger(4, xData2); 0837 col1->setColumnMode(AbstractColumn::ColumnMode::Integer); 0838 col1->replaceInteger(0, yData); 0839 0840 // sort 0841 sheet.sortColumns(col0, {col0, col1}, true); 0842 0843 // values 0844 QCOMPARE(col0->integerAt(0), -1); 0845 QCOMPARE(col0->integerAt(1), 0); 0846 QCOMPARE(col0->integerAt(2), 2); 0847 QCOMPARE(col0->integerAt(3), 3); 0848 QCOMPARE(col0->integerAt(4), 4); 0849 QCOMPARE(col0->integerAt(5), 5); 0850 QCOMPARE(col0->integerAt(6), 6); 0851 QCOMPARE(col1->integerAt(0), 7); 0852 QCOMPARE(col1->integerAt(1), 4); 0853 QCOMPARE(col1->integerAt(2), 3); 0854 QCOMPARE(col1->integerAt(3), 5); 0855 QCOMPARE(col1->integerAt(4), 1); 0856 QCOMPARE(col1->integerAt(5), 2); 0857 QCOMPARE(col1->integerAt(6), 6); 0858 } 0859 0860 /* 0861 * check sorting integer values with empty entries descending as leading column 0862 */ 0863 void SpreadsheetTest::testSortInteger2() { 0864 const QVector<int> xData1{4, 5, 2}; 0865 const QVector<int> xData2{3, 6, -1}; 0866 const QVector<int> yData{1, 2, 3, 4, 5, 6, 7}; 0867 0868 Spreadsheet sheet(QStringLiteral("test"), false); 0869 sheet.setColumnCount(2); 0870 sheet.setRowCount(7); 0871 auto* col0{sheet.column(0)}; 0872 auto* col1{sheet.column(1)}; 0873 col0->setColumnMode(AbstractColumn::ColumnMode::Integer); 0874 col0->replaceInteger(0, xData1); 0875 col0->replaceInteger(4, xData2); 0876 col1->setColumnMode(AbstractColumn::ColumnMode::Integer); 0877 col1->replaceInteger(0, yData); 0878 0879 // sort 0880 sheet.sortColumns(col0, {col0, col1}, false); 0881 0882 // values 0883 QCOMPARE(col0->integerAt(6), -1); 0884 QCOMPARE(col0->integerAt(5), 0); 0885 QCOMPARE(col0->integerAt(4), 2); 0886 QCOMPARE(col0->integerAt(3), 3); 0887 QCOMPARE(col0->integerAt(2), 4); 0888 QCOMPARE(col0->integerAt(1), 5); 0889 QCOMPARE(col0->integerAt(0), 6); 0890 QCOMPARE(col1->integerAt(6), 7); 0891 QCOMPARE(col1->integerAt(5), 4); 0892 QCOMPARE(col1->integerAt(4), 3); 0893 QCOMPARE(col1->integerAt(3), 5); 0894 QCOMPARE(col1->integerAt(2), 1); 0895 QCOMPARE(col1->integerAt(1), 2); 0896 QCOMPARE(col1->integerAt(0), 6); 0897 } 0898 0899 /* 0900 * check sorting big int values with empty entries ascending as leading column 0901 */ 0902 void SpreadsheetTest::testSortBigInt1() { 0903 Spreadsheet sheet(QStringLiteral("test"), false); 0904 sheet.setColumnCount(2); 0905 sheet.setRowCount(7); 0906 0907 QVector<qint64> xData1{40000000000, 50000000000, 20000000000}; 0908 QVector<qint64> xData2{30000000000, 60000000000, -10000000000}; 0909 QVector<qint64> yData{1, 2, 3, 4, 5, 6, 7}; 0910 0911 auto* col0{sheet.column(0)}; 0912 auto* col1{sheet.column(1)}; 0913 col0->setColumnMode(AbstractColumn::ColumnMode::BigInt); 0914 col0->replaceBigInt(0, xData1); 0915 col0->replaceBigInt(4, xData2); 0916 col1->setColumnMode(AbstractColumn::ColumnMode::BigInt); 0917 col1->replaceBigInt(0, yData); 0918 0919 // sort 0920 sheet.sortColumns(col0, {col0, col1}, true); 0921 0922 // values 0923 QCOMPARE(col0->bigIntAt(0), -10000000000ll); 0924 QCOMPARE(col0->bigIntAt(1), 0); 0925 QCOMPARE(col0->bigIntAt(2), 20000000000ll); 0926 QCOMPARE(col0->bigIntAt(3), 30000000000ll); 0927 QCOMPARE(col0->bigIntAt(4), 40000000000ll); 0928 QCOMPARE(col0->bigIntAt(5), 50000000000ll); 0929 QCOMPARE(col0->bigIntAt(6), 60000000000ll); 0930 QCOMPARE(col1->bigIntAt(0), 7); 0931 QCOMPARE(col1->bigIntAt(1), 4); 0932 QCOMPARE(col1->bigIntAt(2), 3); 0933 QCOMPARE(col1->bigIntAt(3), 5); 0934 QCOMPARE(col1->bigIntAt(4), 1); 0935 QCOMPARE(col1->bigIntAt(5), 2); 0936 QCOMPARE(col1->bigIntAt(6), 6); 0937 } 0938 0939 /* 0940 * check sorting big int values with empty entries descending as leading column 0941 */ 0942 void SpreadsheetTest::testSortBigInt2() { 0943 Spreadsheet sheet(QStringLiteral("test"), false); 0944 sheet.setColumnCount(2); 0945 sheet.setRowCount(7); 0946 0947 QVector<qint64> xData1{40000000000, 50000000000, 20000000000}; 0948 QVector<qint64> xData2{30000000000, 60000000000, -10000000000}; 0949 QVector<qint64> yData{1, 2, 3, 4, 5, 6, 7}; 0950 0951 auto* col0{sheet.column(0)}; 0952 auto* col1{sheet.column(1)}; 0953 col0->setColumnMode(AbstractColumn::ColumnMode::BigInt); 0954 col0->replaceBigInt(0, xData1); 0955 col0->replaceBigInt(4, xData2); 0956 col1->setColumnMode(AbstractColumn::ColumnMode::BigInt); 0957 col1->replaceBigInt(0, yData); 0958 0959 // sort 0960 sheet.sortColumns(col0, {col0, col1}, false); 0961 0962 // values 0963 QCOMPARE(col0->bigIntAt(6), -10000000000ll); 0964 QCOMPARE(col0->bigIntAt(5), 0); 0965 QCOMPARE(col0->bigIntAt(4), 20000000000ll); 0966 QCOMPARE(col0->bigIntAt(3), 30000000000ll); 0967 QCOMPARE(col0->bigIntAt(2), 40000000000ll); 0968 QCOMPARE(col0->bigIntAt(1), 50000000000ll); 0969 QCOMPARE(col0->bigIntAt(0), 60000000000ll); 0970 QCOMPARE(col1->bigIntAt(6), 7); 0971 QCOMPARE(col1->bigIntAt(5), 4); 0972 QCOMPARE(col1->bigIntAt(4), 3); 0973 QCOMPARE(col1->bigIntAt(3), 5); 0974 QCOMPARE(col1->bigIntAt(2), 1); 0975 QCOMPARE(col1->bigIntAt(1), 2); 0976 QCOMPARE(col1->bigIntAt(0), 6); 0977 } 0978 0979 /* 0980 * check sorting text with empty entries ascending as leading column 0981 */ 0982 void SpreadsheetTest::testSortText1() { 0983 Spreadsheet sheet(QStringLiteral("test"), false); 0984 sheet.setColumnCount(2); 0985 sheet.setRowCount(8); 0986 0987 QVector<QString> xData{QStringLiteral("ben"), QStringLiteral("amy"), QStringLiteral("eddy"), QString(), QStringLiteral("carl"), QStringLiteral("dan")}; 0988 QVector<int> yData{1, 2, 3, 4, 5, 6, 7}; 0989 0990 auto* col0{sheet.column(0)}; 0991 auto* col1{sheet.column(1)}; 0992 col0->setColumnMode(AbstractColumn::ColumnMode::Text); 0993 col0->replaceTexts(0, xData); 0994 col1->setColumnMode(AbstractColumn::ColumnMode::Integer); 0995 col1->replaceInteger(0, yData); 0996 0997 // sort 0998 sheet.sortColumns(col0, {col0, col1}, true); 0999 1000 // values 1001 QCOMPARE(col0->textAt(0), QLatin1String("amy")); 1002 QCOMPARE(col0->textAt(1), QLatin1String("ben")); 1003 QCOMPARE(col0->textAt(2), QLatin1String("carl")); 1004 QCOMPARE(col0->textAt(3), QLatin1String("dan")); 1005 QCOMPARE(col0->textAt(4), QLatin1String("eddy")); 1006 QCOMPARE(col0->textAt(5), QString()); 1007 QCOMPARE(col0->textAt(6), QString()); 1008 QCOMPARE(col1->integerAt(0), 2); 1009 QCOMPARE(col1->integerAt(1), 1); 1010 QCOMPARE(col1->integerAt(2), 5); 1011 QCOMPARE(col1->integerAt(3), 6); 1012 QCOMPARE(col1->integerAt(4), 3); 1013 QCOMPARE(col1->integerAt(5), 4); 1014 QCOMPARE(col1->integerAt(6), 7); 1015 } 1016 1017 /* 1018 * check sorting text with empty entries descending as leading column 1019 */ 1020 void SpreadsheetTest::testSortText2() { 1021 Spreadsheet sheet(QStringLiteral("test"), false); 1022 sheet.setColumnCount(2); 1023 sheet.setRowCount(8); 1024 1025 QVector<QString> xData{QStringLiteral("ben"), QStringLiteral("amy"), QStringLiteral("eddy"), QString(), QStringLiteral("carl"), QStringLiteral("dan")}; 1026 QVector<int> yData{1, 2, 3, 4, 5, 6, 7}; 1027 1028 auto* col0{sheet.column(0)}; 1029 auto* col1{sheet.column(1)}; 1030 col0->setColumnMode(AbstractColumn::ColumnMode::Text); 1031 col0->replaceTexts(0, xData); 1032 col1->setColumnMode(AbstractColumn::ColumnMode::Integer); 1033 col1->replaceInteger(0, yData); 1034 1035 // sort 1036 sheet.sortColumns(col0, {col0, col1}, false); 1037 1038 // values 1039 QCOMPARE(col0->textAt(4), QLatin1String("amy")); 1040 QCOMPARE(col0->textAt(3), QLatin1String("ben")); 1041 QCOMPARE(col0->textAt(2), QLatin1String("carl")); 1042 QCOMPARE(col0->textAt(1), QLatin1String("dan")); 1043 QCOMPARE(col0->textAt(0), QLatin1String("eddy")); 1044 QCOMPARE(col0->textAt(5), QString()); 1045 QCOMPARE(col0->textAt(6), QString()); 1046 QCOMPARE(col1->integerAt(4), 2); 1047 QCOMPARE(col1->integerAt(3), 1); 1048 QCOMPARE(col1->integerAt(2), 5); 1049 QCOMPARE(col1->integerAt(1), 6); 1050 QCOMPARE(col1->integerAt(0), 3); 1051 QCOMPARE(col1->integerAt(5), 4); 1052 QCOMPARE(col1->integerAt(6), 7); 1053 } 1054 1055 /* 1056 * check sorting datetimes with invalid entries ascending as leading column 1057 */ 1058 void SpreadsheetTest::testSortDateTime1() { 1059 Spreadsheet sheet(QStringLiteral("test"), false); 1060 sheet.setColumnCount(2); 1061 sheet.setRowCount(8); 1062 1063 QVector<QDateTime> xData{ 1064 QDateTime(QDate(2020, 02, 29), QTime(12, 12, 12)), 1065 QDateTime(QDate(2020, 02, 28), QTime(12, 12, 12)), 1066 QDateTime(QDate(2019, 02, 28), QTime(12, 12, 12)), 1067 QDateTime(QDate(2019, 02, 29), QTime(12, 12, 12)), // invalid 1068 QDateTime(QDate(2020, 02, 29), QTime(12, 12, 13)), 1069 QDateTime(QDate(2020, 02, 29), QTime(11, 12, 12)), 1070 }; 1071 QVector<int> yData = {1, 2, 3, 4, 5, 6, 7}; 1072 1073 auto* col0{sheet.column(0)}; 1074 auto* col1{sheet.column(1)}; 1075 col0->setColumnMode(AbstractColumn::ColumnMode::DateTime); 1076 col0->replaceDateTimes(0, xData); 1077 col1->setColumnMode(AbstractColumn::ColumnMode::Integer); 1078 col1->replaceInteger(0, yData); 1079 1080 // sort 1081 sheet.sortColumns(col0, {col0, col1}, true); 1082 1083 // values 1084 QCOMPARE(col0->dateTimeAt(0), QDateTime(QDate(2019, 02, 28), QTime(12, 12, 12))); 1085 QCOMPARE(col0->dateTimeAt(1), QDateTime(QDate(2020, 02, 28), QTime(12, 12, 12))); 1086 QCOMPARE(col0->dateTimeAt(2), QDateTime(QDate(2020, 02, 29), QTime(11, 12, 12))); 1087 QCOMPARE(col0->dateTimeAt(3), QDateTime(QDate(2020, 02, 29), QTime(12, 12, 12))); 1088 QCOMPARE(col0->dateTimeAt(4), QDateTime(QDate(2020, 02, 29), QTime(12, 12, 13))); 1089 QCOMPARE(col1->integerAt(0), 3); 1090 QCOMPARE(col1->integerAt(1), 2); 1091 QCOMPARE(col1->integerAt(2), 6); 1092 QCOMPARE(col1->integerAt(3), 1); 1093 QCOMPARE(col1->integerAt(4), 5); 1094 QCOMPARE(col1->integerAt(5), 4); 1095 QCOMPARE(col1->integerAt(6), 7); 1096 } 1097 1098 /* 1099 * check sorting datetimes with invalid entries descending as leading column 1100 */ 1101 void SpreadsheetTest::testSortDateTime2() { 1102 const QVector<QDateTime> xData{ 1103 QDateTime(QDate(2020, 02, 29), QTime(12, 12, 12)), 1104 QDateTime(QDate(2020, 02, 28), QTime(12, 12, 12)), 1105 QDateTime(QDate(2019, 02, 28), QTime(12, 12, 12)), 1106 QDateTime(QDate(2019, 02, 29), QTime(12, 12, 12)), // invalid 1107 QDateTime(QDate(2020, 02, 29), QTime(12, 12, 13)), 1108 QDateTime(QDate(2020, 02, 29), QTime(11, 12, 12)), 1109 }; 1110 const QVector<int> yData = {1, 2, 3, 4, 5, 6, 7}; 1111 1112 Spreadsheet sheet(QStringLiteral("test"), false); 1113 sheet.setColumnCount(2); 1114 sheet.setRowCount(8); 1115 auto* col0{sheet.column(0)}; 1116 auto* col1{sheet.column(1)}; 1117 col0->setColumnMode(AbstractColumn::ColumnMode::DateTime); 1118 col0->replaceDateTimes(0, xData); 1119 col1->setColumnMode(AbstractColumn::ColumnMode::Integer); 1120 col1->replaceInteger(0, yData); 1121 1122 // sort 1123 sheet.sortColumns(col0, {col0, col1}, false); 1124 1125 // values 1126 QCOMPARE(col0->dateTimeAt(4), QDateTime(QDate(2019, 02, 28), QTime(12, 12, 12))); 1127 QCOMPARE(col0->dateTimeAt(3), QDateTime(QDate(2020, 02, 28), QTime(12, 12, 12))); 1128 QCOMPARE(col0->dateTimeAt(2), QDateTime(QDate(2020, 02, 29), QTime(11, 12, 12))); 1129 QCOMPARE(col0->dateTimeAt(1), QDateTime(QDate(2020, 02, 29), QTime(12, 12, 12))); 1130 QCOMPARE(col0->dateTimeAt(0), QDateTime(QDate(2020, 02, 29), QTime(12, 12, 13))); 1131 QCOMPARE(col1->integerAt(4), 3); 1132 QCOMPARE(col1->integerAt(3), 2); 1133 QCOMPARE(col1->integerAt(2), 6); 1134 QCOMPARE(col1->integerAt(1), 1); 1135 QCOMPARE(col1->integerAt(0), 5); 1136 QCOMPARE(col1->integerAt(5), 4); 1137 QCOMPARE(col1->integerAt(6), 7); 1138 } 1139 1140 // performance 1141 1142 /* 1143 * check performance of sorting double values in single column 1144 */ 1145 void SpreadsheetTest::testSortPerformanceNumeric1() { 1146 Spreadsheet sheet(QStringLiteral("test"), false); 1147 sheet.setColumnCount(1); 1148 sheet.setRowCount(10000); 1149 1150 QVector<double> xData; 1151 WARN("CREATE DATA") 1152 for (int i = 0; i < sheet.rowCount(); i++) 1153 #if (QT_VERSION >= QT_VERSION_CHECK(5, 10, 0)) 1154 xData << QRandomGenerator::global()->generateDouble(); 1155 #else 1156 xData << (double)(qrand()) / RAND_MAX; 1157 #endif 1158 1159 auto* col = sheet.column(0); 1160 col->replaceValues(0, xData); 1161 1162 // sort 1163 QBENCHMARK { sheet.sortColumns(nullptr, {col}, true); } 1164 } 1165 1166 /* 1167 * check performance of sorting double values with two columns 1168 */ 1169 void SpreadsheetTest::testSortPerformanceNumeric2() { 1170 Spreadsheet sheet(QStringLiteral("test"), false); 1171 sheet.setColumnCount(2); 1172 sheet.setRowCount(10000); 1173 1174 QVector<double> xData; 1175 QVector<int> yData; 1176 WARN("CREATE DATA") 1177 for (int i = 0; i < sheet.rowCount(); i++) { 1178 #if (QT_VERSION >= QT_VERSION_CHECK(5, 10, 0)) 1179 xData << QRandomGenerator::global()->generateDouble(); 1180 #else 1181 xData << (double)(qrand()) / RAND_MAX; 1182 #endif 1183 yData << i + 1; 1184 } 1185 1186 auto* col0{sheet.column(0)}; 1187 auto* col1{sheet.column(1)}; 1188 col0->replaceValues(0, xData); 1189 col1->setColumnMode(AbstractColumn::ColumnMode::Integer); 1190 col1->replaceInteger(0, yData); 1191 1192 // sort 1193 QBENCHMARK { sheet.sortColumns(col0, {col0, col1}, true); } 1194 } 1195 1196 // ********************************************************** 1197 // ********************* drop/mask ************************* 1198 // ********************************************************** 1199 void SpreadsheetTest::testRemoveRowsWithMissingValues() { 1200 // prepare the spreadsheet 1201 Spreadsheet sheet(QStringLiteral("test"), false); 1202 sheet.setColumnCount(2); 1203 sheet.setRowCount(5); 1204 1205 auto* col0{sheet.column(0)}; 1206 col0->setColumnMode(AbstractColumn::ColumnMode::Double); 1207 col0->setValueAt(0, 0.); 1208 // missing value for row = 1 1209 col0->setValueAt(2, 2.); 1210 col0->setValueAt(3, 3.); 1211 1212 auto* col1{sheet.column(1)}; 1213 col1->setColumnMode(AbstractColumn::ColumnMode::Double); 1214 col1->setValueAt(0, 0.); 1215 col1->setValueAt(1, 1.); 1216 // missing value for row = 2 1217 col1->setValueAt(3, 3.); 1218 1219 // remove rows with empty values and check the results 1220 sheet.removeEmptyRows(); 1221 QCOMPARE(sheet.rowCount(), 2); 1222 QCOMPARE(col0->valueAt(0), 0.); 1223 QCOMPARE(col0->valueAt(1), 3.); 1224 QCOMPARE(col1->valueAt(0), 0.); 1225 QCOMPARE(col1->valueAt(1), 3.); 1226 } 1227 1228 void SpreadsheetTest::testMaskRowsWithMissingValues() { 1229 // prepare the spreadsheet 1230 Spreadsheet sheet(QStringLiteral("test"), false); 1231 sheet.setColumnCount(2); 1232 sheet.setRowCount(5); 1233 1234 auto* col0{sheet.column(0)}; 1235 col0->setColumnMode(AbstractColumn::ColumnMode::Double); 1236 col0->setValueAt(0, 0.); 1237 // missing value for row = 1 1238 col0->setValueAt(2, 2.); 1239 col0->setValueAt(3, 3.); 1240 1241 auto* col1{sheet.column(1)}; 1242 col1->setColumnMode(AbstractColumn::ColumnMode::Double); 1243 col1->setValueAt(0, 0.); 1244 col1->setValueAt(1, 1.); 1245 // missing value for row = 2 1246 col1->setValueAt(3, 3.); 1247 1248 // mask rows with empty values and check the results 1249 sheet.maskEmptyRows(); 1250 QCOMPARE(sheet.rowCount(), 5); 1251 QCOMPARE(col0->isMasked(0), false); 1252 QCOMPARE(col0->isMasked(1), true); 1253 QCOMPARE(col0->isMasked(2), true); 1254 QCOMPARE(col0->isMasked(3), false); 1255 QCOMPARE(col0->isMasked(4), true); 1256 QCOMPARE(col1->isMasked(0), false); 1257 QCOMPARE(col1->isMasked(1), true); 1258 QCOMPARE(col1->isMasked(2), true); 1259 QCOMPARE(col1->isMasked(3), false); 1260 QCOMPARE(col1->isMasked(4), true); 1261 } 1262 1263 // ********************************************************** 1264 // ********************* flattening ************************ 1265 // ********************************************************** 1266 void SpreadsheetTest::testFlatten00() { 1267 Project project; 1268 auto* sheet = new Spreadsheet(QStringLiteral("test"), false); 1269 project.addChild(sheet); 1270 sheet->setColumnCount(5); 1271 sheet->setRowCount(4); 1272 1273 // "Year" 1274 auto* col1 = sheet->column(0); 1275 col1->setName(QStringLiteral("Year")); 1276 col1->setColumnMode(AbstractColumn::ColumnMode::Text); 1277 col1->setTextAt(0, QStringLiteral("2021")); 1278 col1->setTextAt(1, QStringLiteral("2022")); 1279 col1->setTextAt(2, QStringLiteral("2021")); 1280 col1->setTextAt(3, QStringLiteral("2022")); 1281 1282 // "Country" 1283 auto* col2 = sheet->column(1); 1284 col2->setName(QStringLiteral("Country")); 1285 col2->setColumnMode(AbstractColumn::ColumnMode::Text); 1286 col2->setTextAt(0, QStringLiteral("Germany")); 1287 col2->setTextAt(1, QStringLiteral("Germany")); 1288 col2->setTextAt(2, QStringLiteral("Poland")); 1289 col2->setTextAt(3, QStringLiteral("Poland")); 1290 1291 // "Sales for Product 1" 1292 auto* col3 = sheet->column(2); 1293 col3->setName(QStringLiteral("Product 1")); 1294 col3->setColumnMode(AbstractColumn::ColumnMode::Integer); 1295 col3->setIntegerAt(0, 1); 1296 col3->setIntegerAt(1, 10); 1297 col3->setIntegerAt(2, 4); 1298 col3->setIntegerAt(3, 40); 1299 1300 // "Sales for Product 2" 1301 auto* col4 = sheet->column(3); 1302 col4->setName(QStringLiteral("Product 2")); 1303 col4->setColumnMode(AbstractColumn::ColumnMode::Integer); 1304 col4->setIntegerAt(0, 2); 1305 col4->setIntegerAt(1, 20); 1306 col4->setIntegerAt(2, 5); 1307 col4->setIntegerAt(3, 50); 1308 1309 // "Sales for Product 3" 1310 auto* col5 = sheet->column(4); 1311 col5->setName(QStringLiteral("Product 3")); 1312 col5->setColumnMode(AbstractColumn::ColumnMode::Integer); 1313 col5->setIntegerAt(0, 3); 1314 col5->setIntegerAt(1, 30); 1315 col5->setIntegerAt(2, 6); 1316 col5->setIntegerAt(3, 60); 1317 1318 // flatten the product columns relatively to year and country 1319 FlattenColumnsDialog dlg(sheet); 1320 QVector<Column*> referenceColumns; 1321 referenceColumns << col1; 1322 referenceColumns << col2; 1323 1324 QVector<Column*> valueColumns; 1325 valueColumns << col3; 1326 valueColumns << col4; 1327 valueColumns << col5; 1328 1329 dlg.flatten(sheet, valueColumns, referenceColumns); 1330 1331 // checks 1332 // make sure a new target spreadsheet with the flattened data was created 1333 const auto& sheets = project.children<Spreadsheet>(); 1334 QCOMPARE(sheets.count(), 2); 1335 auto* targetSheet = sheets.at(1); 1336 QCOMPARE(targetSheet->columnCount(), 4); // two reference columns, column "Category" and column "Value" 1337 QCOMPARE(targetSheet->rowCount(), 12); 1338 1339 // check values 1340 col1 = targetSheet->column(0); 1341 QCOMPARE(col1->textAt(0), QStringLiteral("2021")); 1342 QCOMPARE(col1->textAt(1), QStringLiteral("2021")); 1343 QCOMPARE(col1->textAt(2), QStringLiteral("2021")); 1344 QCOMPARE(col1->textAt(3), QStringLiteral("2022")); 1345 QCOMPARE(col1->textAt(4), QStringLiteral("2022")); 1346 QCOMPARE(col1->textAt(5), QStringLiteral("2022")); 1347 QCOMPARE(col1->textAt(6), QStringLiteral("2021")); 1348 QCOMPARE(col1->textAt(7), QStringLiteral("2021")); 1349 QCOMPARE(col1->textAt(8), QStringLiteral("2021")); 1350 QCOMPARE(col1->textAt(9), QStringLiteral("2022")); 1351 QCOMPARE(col1->textAt(10), QStringLiteral("2022")); 1352 QCOMPARE(col1->textAt(11), QStringLiteral("2022")); 1353 1354 col4 = targetSheet->column(3); 1355 QCOMPARE(col4->integerAt(0), 1); 1356 QCOMPARE(col4->integerAt(1), 2); 1357 QCOMPARE(col4->integerAt(2), 3); 1358 QCOMPARE(col4->integerAt(3), 10); 1359 QCOMPARE(col4->integerAt(4), 20); 1360 QCOMPARE(col4->integerAt(5), 30); 1361 QCOMPARE(col4->integerAt(6), 4); 1362 QCOMPARE(col4->integerAt(7), 5); 1363 QCOMPARE(col4->integerAt(8), 6); 1364 QCOMPARE(col4->integerAt(9), 40); 1365 QCOMPARE(col4->integerAt(10), 50); 1366 QCOMPARE(col4->integerAt(11), 60); 1367 } 1368 1369 // test with a missing value in one of the reference columns 1370 void SpreadsheetTest::testFlatten01() { 1371 Project project; 1372 auto* sheet = new Spreadsheet(QStringLiteral("test"), false); 1373 project.addChild(sheet); 1374 sheet->setColumnCount(5); 1375 sheet->setRowCount(2); 1376 1377 // "Year" 1378 auto* col1 = sheet->column(0); 1379 col1->setName(QStringLiteral("Year")); 1380 col1->setColumnMode(AbstractColumn::ColumnMode::Text); 1381 col1->setTextAt(0, QStringLiteral("2021")); 1382 col1->setTextAt(1, QStringLiteral("2022")); 1383 1384 // "Country" 1385 auto* col2 = sheet->column(1); 1386 col2->setName(QStringLiteral("Country")); 1387 col2->setColumnMode(AbstractColumn::ColumnMode::Text); 1388 col2->setTextAt(0, QStringLiteral("Germany")); 1389 // missing value in the second row 1390 1391 // "Sales for Product 1" 1392 auto* col3 = sheet->column(2); 1393 col3->setName(QStringLiteral("Product 1")); 1394 col3->setColumnMode(AbstractColumn::ColumnMode::Integer); 1395 col3->setIntegerAt(0, 1); 1396 col3->setIntegerAt(1, 10); 1397 1398 // "Sales for Product 2" 1399 auto* col4 = sheet->column(3); 1400 col4->setName(QStringLiteral("Product 2")); 1401 col4->setColumnMode(AbstractColumn::ColumnMode::Integer); 1402 col4->setIntegerAt(0, 2); 1403 col4->setIntegerAt(1, 20); 1404 1405 // "Sales for Product 3" 1406 auto* col5 = sheet->column(4); 1407 col5->setName(QStringLiteral("Product 3")); 1408 col5->setColumnMode(AbstractColumn::ColumnMode::Integer); 1409 col5->setIntegerAt(0, 3); 1410 col5->setIntegerAt(1, 30); 1411 1412 // flatten the product columns relatively to year and country 1413 FlattenColumnsDialog dlg(sheet); 1414 QVector<Column*> referenceColumns; 1415 referenceColumns << col1; 1416 referenceColumns << col2; 1417 1418 QVector<Column*> valueColumns; 1419 valueColumns << col3; 1420 valueColumns << col4; 1421 valueColumns << col5; 1422 1423 dlg.flatten(sheet, valueColumns, referenceColumns); 1424 1425 // checks 1426 // make sure a new target spreadsheet with the flattened data was created 1427 const auto& sheets = project.children<Spreadsheet>(); 1428 QCOMPARE(sheets.count(), 2); 1429 auto* targetSheet = sheets.at(1); 1430 QCOMPARE(targetSheet->columnCount(), 4); // two reference columns, column "Category" and column "Value" 1431 QCOMPARE(targetSheet->rowCount(), 6); 1432 1433 // check values 1434 col1 = targetSheet->column(0); 1435 QCOMPARE(col1->textAt(0), QStringLiteral("2021")); 1436 QCOMPARE(col1->textAt(1), QStringLiteral("2021")); 1437 QCOMPARE(col1->textAt(2), QStringLiteral("2021")); 1438 QCOMPARE(col1->textAt(3), QStringLiteral("2022")); 1439 QCOMPARE(col1->textAt(4), QStringLiteral("2022")); 1440 QCOMPARE(col1->textAt(5), QStringLiteral("2022")); 1441 1442 col1 = targetSheet->column(1); 1443 QCOMPARE(col1->textAt(0), QStringLiteral("Germany")); 1444 QCOMPARE(col1->textAt(1), QStringLiteral("Germany")); 1445 QCOMPARE(col1->textAt(2), QStringLiteral("Germany")); 1446 QCOMPARE(col1->textAt(3), QString()); 1447 QCOMPARE(col1->textAt(4), QString()); 1448 QCOMPARE(col1->textAt(5), QString()); 1449 1450 col4 = targetSheet->column(3); 1451 QCOMPARE(col4->integerAt(0), 1); 1452 QCOMPARE(col4->integerAt(1), 2); 1453 QCOMPARE(col4->integerAt(2), 3); 1454 QCOMPARE(col4->integerAt(3), 10); 1455 QCOMPARE(col4->integerAt(4), 20); 1456 QCOMPARE(col4->integerAt(5), 30); 1457 } 1458 1459 // test with missing values in the reference columns - no result should be produced for these rows 1460 void SpreadsheetTest::testFlatten02() { 1461 Project project; 1462 auto* sheet = new Spreadsheet(QStringLiteral("test"), false); 1463 project.addChild(sheet); 1464 sheet->setColumnCount(5); 1465 sheet->setRowCount(2); 1466 1467 // "Year" 1468 auto* col1 = sheet->column(0); 1469 col1->setName(QStringLiteral("Year")); 1470 col1->setColumnMode(AbstractColumn::ColumnMode::Text); 1471 col1->setTextAt(0, QStringLiteral("2021")); 1472 // missing value in the second row 1473 1474 // "Country" 1475 auto* col2 = sheet->column(1); 1476 col2->setName(QStringLiteral("Country")); 1477 col2->setColumnMode(AbstractColumn::ColumnMode::Text); 1478 col2->setTextAt(0, QStringLiteral("Germany")); 1479 // missing value in the second rows 1480 1481 // "Sales for Product 1" 1482 auto* col3 = sheet->column(2); 1483 col3->setName(QStringLiteral("Product 1")); 1484 col3->setColumnMode(AbstractColumn::ColumnMode::Integer); 1485 col3->setIntegerAt(0, 1); 1486 col3->setIntegerAt(1, 10); 1487 1488 // "Sales for Product 2" 1489 auto* col4 = sheet->column(3); 1490 col4->setName(QStringLiteral("Product 2")); 1491 col4->setColumnMode(AbstractColumn::ColumnMode::Integer); 1492 col4->setIntegerAt(0, 2); 1493 col4->setIntegerAt(1, 20); 1494 1495 // "Sales for Product 3" 1496 auto* col5 = sheet->column(4); 1497 col5->setName(QStringLiteral("Product 3")); 1498 col5->setColumnMode(AbstractColumn::ColumnMode::Integer); 1499 col5->setIntegerAt(0, 3); 1500 col5->setIntegerAt(1, 30); 1501 1502 // flatten the product columns relatively to year and country 1503 FlattenColumnsDialog dlg(sheet); 1504 QVector<Column*> referenceColumns; 1505 referenceColumns << col1; 1506 referenceColumns << col2; 1507 1508 QVector<Column*> valueColumns; 1509 valueColumns << col3; 1510 valueColumns << col4; 1511 valueColumns << col5; 1512 1513 dlg.flatten(sheet, valueColumns, referenceColumns); 1514 1515 // checks 1516 // make sure a new target spreadsheet with the flattened data was created 1517 const auto& sheets = project.children<Spreadsheet>(); 1518 QCOMPARE(sheets.count(), 2); 1519 auto* targetSheet = sheets.at(1); 1520 QCOMPARE(targetSheet->columnCount(), 4); // two reference columns, column "Category" and column "Value" 1521 QCOMPARE(targetSheet->rowCount(), 3); 1522 1523 // check values 1524 col1 = targetSheet->column(0); 1525 QCOMPARE(col1->textAt(0), QStringLiteral("2021")); 1526 QCOMPARE(col1->textAt(1), QStringLiteral("2021")); 1527 QCOMPARE(col1->textAt(2), QStringLiteral("2021")); 1528 1529 col1 = targetSheet->column(1); 1530 QCOMPARE(col1->textAt(0), QStringLiteral("Germany")); 1531 QCOMPARE(col1->textAt(1), QStringLiteral("Germany")); 1532 QCOMPARE(col1->textAt(2), QStringLiteral("Germany")); 1533 1534 col4 = targetSheet->column(3); 1535 QCOMPARE(col4->integerAt(0), 1); 1536 QCOMPARE(col4->integerAt(1), 2); 1537 QCOMPARE(col4->integerAt(2), 3); 1538 } 1539 1540 // test with missing no reference columns 1541 void SpreadsheetTest::testFlatten03() { 1542 Project project; 1543 auto* sheet = new Spreadsheet(QStringLiteral("test"), false); 1544 project.addChild(sheet); 1545 sheet->setColumnCount(3); 1546 sheet->setRowCount(2); 1547 1548 // "Sales for Product 1" 1549 auto* col1 = sheet->column(0); 1550 col1->setName(QStringLiteral("Product 1")); 1551 col1->setColumnMode(AbstractColumn::ColumnMode::Integer); 1552 col1->setIntegerAt(0, 1); 1553 col1->setIntegerAt(1, 10); 1554 1555 // "Sales for Product 2" 1556 auto* col2 = sheet->column(1); 1557 col2->setName(QStringLiteral("Product 2")); 1558 col2->setColumnMode(AbstractColumn::ColumnMode::Integer); 1559 col2->setIntegerAt(0, 2); 1560 col2->setIntegerAt(1, 20); 1561 1562 // "Sales for Product 3" 1563 auto* col3 = sheet->column(2); 1564 col3->setName(QStringLiteral("Product 3")); 1565 col3->setColumnMode(AbstractColumn::ColumnMode::Integer); 1566 col3->setIntegerAt(0, 3); 1567 col3->setIntegerAt(1, 30); 1568 1569 // flatten the product columns without any reference columns 1570 QVector<Column*> valueColumns; 1571 valueColumns << col1; 1572 valueColumns << col2; 1573 valueColumns << col3; 1574 1575 FlattenColumnsDialog dlg(sheet); 1576 dlg.flatten(sheet, valueColumns, QVector<Column*>()); 1577 1578 // checks 1579 // make sure a new target spreadsheet with the flattened data was created 1580 const auto& sheets = project.children<Spreadsheet>(); 1581 QCOMPARE(sheets.count(), 2); 1582 auto* targetSheet = sheets.at(1); 1583 QCOMPARE(targetSheet->columnCount(), 2); // no reference columns, only column "Category" and column "Value" 1584 QCOMPARE(targetSheet->rowCount(), 6); 1585 1586 // check values 1587 col1 = targetSheet->column(0); 1588 QCOMPARE(col1->textAt(0), QStringLiteral("Product 1")); 1589 QCOMPARE(col1->textAt(1), QStringLiteral("Product 2")); 1590 QCOMPARE(col1->textAt(2), QStringLiteral("Product 3")); 1591 QCOMPARE(col1->textAt(3), QStringLiteral("Product 1")); 1592 QCOMPARE(col1->textAt(4), QStringLiteral("Product 2")); 1593 QCOMPARE(col1->textAt(5), QStringLiteral("Product 3")); 1594 1595 col2 = targetSheet->column(1); 1596 QCOMPARE(col2->integerAt(0), 1); 1597 QCOMPARE(col2->integerAt(1), 2); 1598 QCOMPARE(col2->integerAt(2), 3); 1599 QCOMPARE(col2->integerAt(3), 10); 1600 QCOMPARE(col2->integerAt(4), 20); 1601 QCOMPARE(col2->integerAt(5), 30); 1602 } 1603 1604 // ********************************************************** 1605 // ******************** search&replace ********************* 1606 // ********************************************************** 1607 Spreadsheet* SpreadsheetTest::createSearchReplaceSpreadsheet() { 1608 auto* sheet = new Spreadsheet(QStringLiteral("test"), false); 1609 1610 sheet->setColumnCount(4); 1611 sheet->setRowCount(4); 1612 1613 // first text column 1614 auto* col1 = sheet->column(0); 1615 col1->setName(QStringLiteral("text")); 1616 col1->setColumnMode(AbstractColumn::ColumnMode::Text); 1617 col1->setTextAt(0, QStringLiteral("A")); 1618 col1->setTextAt(1, QStringLiteral("B")); 1619 col1->setTextAt(2, QStringLiteral("A")); 1620 col1->setTextAt(3, QStringLiteral("C")); 1621 1622 // first numeric (integer) column 1623 auto* col2 = sheet->column(1); 1624 col2->setName(QStringLiteral("integer")); 1625 col2->setColumnMode(AbstractColumn::ColumnMode::Integer); 1626 col2->setIntegerAt(0, 1); 1627 col2->setIntegerAt(1, 2); 1628 col2->setIntegerAt(2, 4); 1629 col2->setIntegerAt(3, 2); 1630 1631 // second text column 1632 auto* col3 = sheet->column(2); 1633 col3->setName(QStringLiteral("text2")); 1634 col3->setColumnMode(AbstractColumn::ColumnMode::Text); 1635 col3->setTextAt(0, QStringLiteral("B1")); 1636 col3->setTextAt(1, QStringLiteral("A")); 1637 col3->setTextAt(2, QStringLiteral("C2")); 1638 col3->setTextAt(3, QStringLiteral("A2")); 1639 1640 // second numeric (double) column 1641 auto* col4 = sheet->column(3); 1642 col4->setName(QStringLiteral("double")); 1643 col4->setColumnMode(AbstractColumn::ColumnMode::Double); 1644 col4->setValueAt(0, 4); 1645 col4->setValueAt(1, 3); 1646 col4->setValueAt(2, 2); 1647 col4->setValueAt(3, 1); 1648 1649 return sheet; 1650 } 1651 1652 /*! 1653 * simple search ignoring data types, column-major order 1654 */ 1655 void SpreadsheetTest::testSearchSimple00() { 1656 Project project; 1657 auto* sheet = createSearchReplaceSpreadsheet(); 1658 project.addChild(sheet); 1659 1660 // navigate to the (0,0) cell having the text value "A" 1661 auto* view = static_cast<SpreadsheetView*>(sheet->view()); 1662 view->goToCell(0, 0); 1663 1664 // initialize the search&replace widget 1665 auto* searchReplaceWidget = new SearchReplaceWidget(sheet, view); 1666 searchReplaceWidget->setReplaceEnabled(false); 1667 1668 auto indexes = view->selectionModel()->selectedIndexes(); 1669 if (!indexes.isEmpty()) { 1670 const auto& firstIndex = indexes.constFirst(); 1671 const auto* column = sheet->column(firstIndex.column()); 1672 const int row = firstIndex.row(); 1673 searchReplaceWidget->setInitialPattern(column->columnMode(), column->asStringColumn()->textAt(row)); 1674 } 1675 1676 // checks: the initial cell text is "A", we navigate with 'next' 1677 // and then back with 'prev' in the column-major order looking for "A" 1678 1679 // initial 1680 indexes = view->selectionModel()->selectedIndexes(); 1681 QCOMPARE(indexes.count(), 1); 1682 auto curIndex = indexes.constFirst(); 1683 QCOMPARE(curIndex.row(), 0); 1684 QCOMPARE(curIndex.column(), 0); 1685 1686 // next 1687 searchReplaceWidget->findNextSimple(true); 1688 indexes = view->selectionModel()->selectedIndexes(); 1689 QCOMPARE(indexes.count(), 1); 1690 curIndex = indexes.constFirst(); 1691 QCOMPARE(curIndex.row(), 2); 1692 QCOMPARE(curIndex.column(), 0); 1693 1694 // next 1695 searchReplaceWidget->findNextSimple(true); 1696 indexes = view->selectionModel()->selectedIndexes(); 1697 QCOMPARE(indexes.count(), 1); 1698 curIndex = indexes.constFirst(); 1699 QCOMPARE(curIndex.row(), 1); 1700 QCOMPARE(curIndex.column(), 2); 1701 1702 // next 1703 searchReplaceWidget->findNextSimple(true); 1704 indexes = view->selectionModel()->selectedIndexes(); 1705 QCOMPARE(indexes.count(), 1); 1706 curIndex = indexes.constFirst(); 1707 QCOMPARE(curIndex.row(), 3); 1708 QCOMPARE(curIndex.column(), 2); 1709 1710 // next, last matching cell reached 1711 searchReplaceWidget->findNextSimple(true); 1712 indexes = view->selectionModel()->selectedIndexes(); 1713 QCOMPARE(indexes.count(), 1); 1714 curIndex = indexes.constFirst(); 1715 QCOMPARE(curIndex.row(), 3); 1716 QCOMPARE(curIndex.column(), 2); 1717 1718 // previous 1719 searchReplaceWidget->findPreviousSimple(true); 1720 indexes = view->selectionModel()->selectedIndexes(); 1721 QCOMPARE(indexes.count(), 1); 1722 curIndex = indexes.constFirst(); 1723 QCOMPARE(curIndex.row(), 1); 1724 QCOMPARE(curIndex.column(), 2); 1725 1726 // previous 1727 searchReplaceWidget->findPreviousSimple(true); 1728 indexes = view->selectionModel()->selectedIndexes(); 1729 QCOMPARE(indexes.count(), 1); 1730 curIndex = indexes.constFirst(); 1731 QCOMPARE(curIndex.row(), 2); 1732 QCOMPARE(curIndex.column(), 0); 1733 1734 // previous 1735 searchReplaceWidget->findPreviousSimple(true); 1736 indexes = view->selectionModel()->selectedIndexes(); 1737 QCOMPARE(indexes.count(), 1); 1738 curIndex = indexes.constFirst(); 1739 QCOMPARE(curIndex.row(), 0); 1740 QCOMPARE(curIndex.column(), 0); 1741 1742 // previous, last matching cell reached 1743 searchReplaceWidget->findPreviousSimple(true); 1744 indexes = view->selectionModel()->selectedIndexes(); 1745 QCOMPARE(indexes.count(), 1); 1746 curIndex = indexes.constFirst(); 1747 QCOMPARE(curIndex.row(), 0); 1748 QCOMPARE(curIndex.column(), 0); 1749 } 1750 1751 /*! 1752 * extended search for Text, column-major order 1753 */ 1754 void SpreadsheetTest::testSearchExtended00() { 1755 Project project; 1756 auto* sheet = createSearchReplaceSpreadsheet(); 1757 project.addChild(sheet); 1758 1759 // navigate to the (0,0) cell having the text value "A" 1760 auto* view = static_cast<SpreadsheetView*>(sheet->view()); 1761 view->goToCell(0, 0); 1762 1763 // initialize the search&replace widget 1764 auto* searchReplaceWidget = new SearchReplaceWidget(sheet, view); 1765 searchReplaceWidget->setReplaceEnabled(true); 1766 searchReplaceWidget->setDataType(SearchReplaceWidget::DataType::Text); 1767 searchReplaceWidget->setOrder(SearchReplaceWidget::Order::ColumnMajor); 1768 1769 auto indexes = view->selectionModel()->selectedIndexes(); 1770 if (!indexes.isEmpty()) { 1771 const auto& firstIndex = indexes.constFirst(); 1772 const auto* column = sheet->column(firstIndex.column()); 1773 const int row = firstIndex.row(); 1774 searchReplaceWidget->setInitialPattern(column->columnMode(), column->asStringColumn()->textAt(row)); 1775 } 1776 1777 // checks: the initial cell text is "A", we navigate with 'next' 1778 // and then back with 'prev' in the column-major order looking for "A" 1779 1780 // initial 1781 indexes = view->selectionModel()->selectedIndexes(); 1782 QCOMPARE(indexes.count(), 1); 1783 auto curIndex = indexes.constFirst(); 1784 QCOMPARE(curIndex.row(), 0); 1785 QCOMPARE(curIndex.column(), 0); 1786 1787 // next 1788 searchReplaceWidget->findNext(true); 1789 indexes = view->selectionModel()->selectedIndexes(); 1790 QCOMPARE(indexes.count(), 1); 1791 curIndex = indexes.constFirst(); 1792 QCOMPARE(curIndex.row(), 2); 1793 QCOMPARE(curIndex.column(), 0); 1794 1795 // next 1796 searchReplaceWidget->findNext(true); 1797 indexes = view->selectionModel()->selectedIndexes(); 1798 QCOMPARE(indexes.count(), 1); 1799 curIndex = indexes.constFirst(); 1800 QCOMPARE(curIndex.row(), 1); 1801 QCOMPARE(curIndex.column(), 2); 1802 1803 // next, last matching cell reached 1804 searchReplaceWidget->findNext(true); 1805 indexes = view->selectionModel()->selectedIndexes(); 1806 QCOMPARE(indexes.count(), 1); 1807 curIndex = indexes.constFirst(); 1808 QCOMPARE(curIndex.row(), 1); 1809 QCOMPARE(curIndex.column(), 2); 1810 1811 // previous 1812 searchReplaceWidget->findPrevious(true); 1813 indexes = view->selectionModel()->selectedIndexes(); 1814 QCOMPARE(indexes.count(), 1); 1815 curIndex = indexes.constFirst(); 1816 QCOMPARE(curIndex.row(), 2); 1817 QCOMPARE(curIndex.column(), 0); 1818 1819 // previous 1820 searchReplaceWidget->findPrevious(true); 1821 indexes = view->selectionModel()->selectedIndexes(); 1822 QCOMPARE(indexes.count(), 1); 1823 curIndex = indexes.constFirst(); 1824 QCOMPARE(curIndex.row(), 0); 1825 QCOMPARE(curIndex.column(), 0); 1826 1827 // previous, last matching cell reached 1828 searchReplaceWidget->findPrevious(true); 1829 indexes = view->selectionModel()->selectedIndexes(); 1830 QCOMPARE(indexes.count(), 1); 1831 curIndex = indexes.constFirst(); 1832 QCOMPARE(curIndex.row(), 0); 1833 QCOMPARE(curIndex.column(), 0); 1834 } 1835 1836 /*! 1837 * extended search for Text, row-major order 1838 */ 1839 void SpreadsheetTest::testSearchExtended01() { 1840 Project project; 1841 auto* sheet = createSearchReplaceSpreadsheet(); 1842 project.addChild(sheet); 1843 1844 // navigate to the (0,0) cell having the text value "A" 1845 auto* view = static_cast<SpreadsheetView*>(sheet->view()); 1846 view->goToCell(0, 0); 1847 1848 // initialize the search&replace widget 1849 auto* searchReplaceWidget = new SearchReplaceWidget(sheet, view); 1850 searchReplaceWidget->setReplaceEnabled(true); 1851 searchReplaceWidget->setDataType(SearchReplaceWidget::DataType::Text); 1852 searchReplaceWidget->setOrder(SearchReplaceWidget::Order::RowMajor); 1853 1854 auto indexes = view->selectionModel()->selectedIndexes(); 1855 if (!indexes.isEmpty()) { 1856 const auto& firstIndex = indexes.constFirst(); 1857 const auto* column = sheet->column(firstIndex.column()); 1858 const int row = firstIndex.row(); 1859 searchReplaceWidget->setInitialPattern(column->columnMode(), column->asStringColumn()->textAt(row)); 1860 } 1861 1862 // checks: the initial cell text is "A", we navigate with 'next' 1863 // and then back with 'prev' in the row-major order looking for "A" 1864 1865 // initial 1866 indexes = view->selectionModel()->selectedIndexes(); 1867 QCOMPARE(indexes.count(), 1); 1868 auto curIndex = indexes.constFirst(); 1869 QCOMPARE(curIndex.row(), 0); 1870 QCOMPARE(curIndex.column(), 0); 1871 1872 // next 1873 searchReplaceWidget->findNext(true); 1874 indexes = view->selectionModel()->selectedIndexes(); 1875 QCOMPARE(indexes.count(), 1); 1876 curIndex = indexes.constFirst(); 1877 QCOMPARE(curIndex.row(), 1); 1878 QCOMPARE(curIndex.column(), 2); 1879 1880 // next 1881 searchReplaceWidget->findNext(true); 1882 indexes = view->selectionModel()->selectedIndexes(); 1883 QCOMPARE(indexes.count(), 1); 1884 curIndex = indexes.constFirst(); 1885 QCOMPARE(curIndex.row(), 2); 1886 QCOMPARE(curIndex.column(), 0); 1887 1888 // next, last matching cell reached 1889 searchReplaceWidget->findNext(true); 1890 indexes = view->selectionModel()->selectedIndexes(); 1891 QCOMPARE(indexes.count(), 1); 1892 curIndex = indexes.constFirst(); 1893 QCOMPARE(curIndex.row(), 2); 1894 QCOMPARE(curIndex.column(), 0); 1895 1896 // previous 1897 searchReplaceWidget->findPrevious(true); 1898 indexes = view->selectionModel()->selectedIndexes(); 1899 QCOMPARE(indexes.count(), 1); 1900 curIndex = indexes.constFirst(); 1901 QCOMPARE(curIndex.row(), 1); 1902 QCOMPARE(curIndex.column(), 2); 1903 1904 // previous 1905 searchReplaceWidget->findPrevious(true); 1906 indexes = view->selectionModel()->selectedIndexes(); 1907 QCOMPARE(indexes.count(), 1); 1908 curIndex = indexes.constFirst(); 1909 QCOMPARE(curIndex.row(), 0); 1910 QCOMPARE(curIndex.column(), 0); 1911 1912 // previous, last matching cell reached 1913 searchReplaceWidget->findPrevious(true); 1914 indexes = view->selectionModel()->selectedIndexes(); 1915 QCOMPARE(indexes.count(), 1); 1916 curIndex = indexes.constFirst(); 1917 QCOMPARE(curIndex.row(), 0); 1918 QCOMPARE(curIndex.column(), 0); 1919 } 1920 1921 /*! 1922 * search for Numeric, column-major order 1923 */ 1924 void SpreadsheetTest::testSearchExtended02() { 1925 Project project; 1926 auto* sheet = createSearchReplaceSpreadsheet(); 1927 project.addChild(sheet); 1928 1929 // navigate to the (1,1) cell having the numeric value "2" 1930 auto* view = static_cast<SpreadsheetView*>(sheet->view()); 1931 view->goToCell(1, 1); 1932 1933 // initialize the search&replace widget 1934 auto* searchReplaceWidget = new SearchReplaceWidget(sheet, view); 1935 searchReplaceWidget->setReplaceEnabled(true); 1936 searchReplaceWidget->setDataType(SearchReplaceWidget::DataType::Numeric); 1937 searchReplaceWidget->setOrder(SearchReplaceWidget::Order::ColumnMajor); 1938 1939 auto indexes = view->selectionModel()->selectedIndexes(); 1940 if (!indexes.isEmpty()) { 1941 const auto& firstIndex = indexes.constFirst(); 1942 const auto* column = sheet->column(firstIndex.column()); 1943 const int row = firstIndex.row(); 1944 searchReplaceWidget->setInitialPattern(column->columnMode(), column->asStringColumn()->textAt(row)); 1945 } 1946 1947 // checks: the initial cell text is "2", we navigate with 'next' 1948 // and then back with 'prev' in the column-major order looking for "2" 1949 1950 // initial 1951 indexes = view->selectionModel()->selectedIndexes(); 1952 QCOMPARE(indexes.count(), 1); 1953 auto curIndex = indexes.constFirst(); 1954 QCOMPARE(curIndex.row(), 1); 1955 QCOMPARE(curIndex.column(), 1); 1956 1957 // next 1958 searchReplaceWidget->findNext(true); 1959 indexes = view->selectionModel()->selectedIndexes(); 1960 QCOMPARE(indexes.count(), 1); 1961 curIndex = indexes.constFirst(); 1962 QCOMPARE(curIndex.row(), 3); 1963 QCOMPARE(curIndex.column(), 1); 1964 1965 // next 1966 searchReplaceWidget->findNext(true); 1967 indexes = view->selectionModel()->selectedIndexes(); 1968 QCOMPARE(indexes.count(), 1); 1969 curIndex = indexes.constFirst(); 1970 QCOMPARE(curIndex.row(), 2); 1971 QCOMPARE(curIndex.column(), 3); 1972 1973 // next, last matching cell reached 1974 searchReplaceWidget->findNext(true); 1975 indexes = view->selectionModel()->selectedIndexes(); 1976 QCOMPARE(indexes.count(), 1); 1977 curIndex = indexes.constFirst(); 1978 QCOMPARE(curIndex.row(), 2); 1979 QCOMPARE(curIndex.column(), 3); 1980 1981 // previous 1982 searchReplaceWidget->findPrevious(true); 1983 indexes = view->selectionModel()->selectedIndexes(); 1984 QCOMPARE(indexes.count(), 1); 1985 curIndex = indexes.constFirst(); 1986 QCOMPARE(curIndex.row(), 3); 1987 QCOMPARE(curIndex.column(), 1); 1988 1989 // previous 1990 searchReplaceWidget->findPrevious(true); 1991 indexes = view->selectionModel()->selectedIndexes(); 1992 QCOMPARE(indexes.count(), 1); 1993 curIndex = indexes.constFirst(); 1994 QCOMPARE(curIndex.row(), 1); 1995 QCOMPARE(curIndex.column(), 1); 1996 1997 // previous, last matching cell reached 1998 searchReplaceWidget->findPrevious(true); 1999 indexes = view->selectionModel()->selectedIndexes(); 2000 QCOMPARE(indexes.count(), 1); 2001 curIndex = indexes.constFirst(); 2002 QCOMPARE(curIndex.row(), 1); 2003 QCOMPARE(curIndex.column(), 1); 2004 } 2005 2006 /*! 2007 * search for Numeric, row major 2008 */ 2009 void SpreadsheetTest::testSearchExtended03() { 2010 Project project; 2011 auto* sheet = createSearchReplaceSpreadsheet(); 2012 project.addChild(sheet); 2013 2014 // navigate to the (1,1) cell having the numeric value "2" 2015 auto* view = static_cast<SpreadsheetView*>(sheet->view()); 2016 view->goToCell(1, 1); 2017 2018 // initialize the search&replace widget 2019 auto* searchReplaceWidget = new SearchReplaceWidget(sheet, view); 2020 searchReplaceWidget->setReplaceEnabled(true); 2021 searchReplaceWidget->setDataType(SearchReplaceWidget::DataType::Numeric); 2022 searchReplaceWidget->setOrder(SearchReplaceWidget::Order::RowMajor); 2023 2024 auto indexes = view->selectionModel()->selectedIndexes(); 2025 if (!indexes.isEmpty()) { 2026 const auto& firstIndex = indexes.constFirst(); 2027 const auto* column = sheet->column(firstIndex.column()); 2028 const int row = firstIndex.row(); 2029 searchReplaceWidget->setInitialPattern(column->columnMode(), column->asStringColumn()->textAt(row)); 2030 } 2031 2032 // checks: the initial cell text is "2", we navigate with 'next' 2033 // and then back with 'prev' in the column-major order looking for "2" 2034 2035 // initial 2036 indexes = view->selectionModel()->selectedIndexes(); 2037 QCOMPARE(indexes.count(), 1); 2038 auto curIndex = indexes.constFirst(); 2039 QCOMPARE(curIndex.row(), 1); 2040 QCOMPARE(curIndex.column(), 1); 2041 2042 // next 2043 searchReplaceWidget->findNext(true); 2044 indexes = view->selectionModel()->selectedIndexes(); 2045 QCOMPARE(indexes.count(), 1); 2046 curIndex = indexes.constFirst(); 2047 QCOMPARE(curIndex.row(), 2); 2048 QCOMPARE(curIndex.column(), 3); 2049 2050 // next 2051 searchReplaceWidget->findNext(true); 2052 indexes = view->selectionModel()->selectedIndexes(); 2053 QCOMPARE(indexes.count(), 1); 2054 curIndex = indexes.constFirst(); 2055 QCOMPARE(curIndex.row(), 3); 2056 QCOMPARE(curIndex.column(), 1); 2057 2058 // next, last matching cell reached 2059 searchReplaceWidget->findNext(true); 2060 indexes = view->selectionModel()->selectedIndexes(); 2061 QCOMPARE(indexes.count(), 1); 2062 curIndex = indexes.constFirst(); 2063 QCOMPARE(curIndex.row(), 3); 2064 QCOMPARE(curIndex.column(), 1); 2065 2066 // previous 2067 searchReplaceWidget->findPrevious(true); 2068 indexes = view->selectionModel()->selectedIndexes(); 2069 QCOMPARE(indexes.count(), 1); 2070 curIndex = indexes.constFirst(); 2071 QCOMPARE(curIndex.row(), 2); 2072 QCOMPARE(curIndex.column(), 3); 2073 2074 // previous 2075 searchReplaceWidget->findPrevious(true); 2076 indexes = view->selectionModel()->selectedIndexes(); 2077 QCOMPARE(indexes.count(), 1); 2078 curIndex = indexes.constFirst(); 2079 QCOMPARE(curIndex.row(), 1); 2080 QCOMPARE(curIndex.column(), 1); 2081 2082 // previous, last matching cell reached 2083 searchReplaceWidget->findPrevious(true); 2084 indexes = view->selectionModel()->selectedIndexes(); 2085 QCOMPARE(indexes.count(), 1); 2086 curIndex = indexes.constFirst(); 2087 QCOMPARE(curIndex.row(), 1); 2088 QCOMPARE(curIndex.column(), 1); 2089 } 2090 2091 void SpreadsheetTest::testSearchFindAll() { 2092 Project project; 2093 auto* sheet = createSearchReplaceSpreadsheet(); 2094 project.addChild(sheet); 2095 2096 // initialize the search&replace widget 2097 auto* searchReplaceWidget = new SearchReplaceWidget(sheet, nullptr); 2098 searchReplaceWidget->setReplaceEnabled(true); 2099 searchReplaceWidget->setDataType(SearchReplaceWidget::DataType::Text); 2100 searchReplaceWidget->setOrder(SearchReplaceWidget::Order::ColumnMajor); 2101 searchReplaceWidget->setTextOperator(SearchReplaceWidget::OperatorText::StartsWith); 2102 2103 // search for cells starting with "B" and highlight them ("find") 2104 searchReplaceWidget->setInitialPattern(AbstractColumn::ColumnMode::Text, QLatin1String("B")); 2105 searchReplaceWidget->findAll(); 2106 2107 // checks 2108 auto* view = static_cast<SpreadsheetView*>(sheet->view()); 2109 auto indexes = view->selectionModel()->selectedIndexes(); 2110 QCOMPARE(indexes.size(), 2); 2111 QCOMPARE(indexes.at(0).row(), 1); 2112 QCOMPARE(indexes.at(0).column(), 0); 2113 QCOMPARE(indexes.at(1).row(), 0); 2114 QCOMPARE(indexes.at(1).column(), 2); 2115 } 2116 2117 void SpreadsheetTest::testSearchReplaceAll() { 2118 Project project; 2119 auto* sheet = createSearchReplaceSpreadsheet(); 2120 project.addChild(sheet); 2121 2122 // initialize the search&replace widget 2123 auto* searchReplaceWidget = new SearchReplaceWidget(sheet, nullptr); 2124 searchReplaceWidget->setReplaceEnabled(true); 2125 searchReplaceWidget->setDataType(SearchReplaceWidget::DataType::Text); 2126 searchReplaceWidget->setOrder(SearchReplaceWidget::Order::ColumnMajor); 2127 searchReplaceWidget->setTextOperator(SearchReplaceWidget::OperatorText::RegEx); 2128 2129 // search for "A" or "C" and replace with "test" 2130 searchReplaceWidget->setInitialPattern(AbstractColumn::ColumnMode::Text, QLatin1String("[A.C]")); 2131 searchReplaceWidget->setReplaceText(QLatin1String("test")); 2132 searchReplaceWidget->replaceAll(); 2133 2134 // checks 2135 const auto& columns = sheet->children<Column>(); 2136 QCOMPARE(columns.at(0)->textAt(0), QLatin1String("test")); 2137 QCOMPARE(columns.at(0)->textAt(2), QLatin1String("test")); 2138 QCOMPARE(columns.at(2)->textAt(1), QLatin1String("test")); 2139 QCOMPARE(columns.at(2)->textAt(2), QLatin1String("test")); 2140 } 2141 2142 // ********************************************************** 2143 // ********************** size changes ********************* 2144 // ********************************************************** 2145 void SpreadsheetTest::testInsertRows() { 2146 Project project; 2147 auto* sheet = new Spreadsheet(QStringLiteral("test"), false); 2148 project.addChild(sheet); 2149 2150 auto* model = new SpreadsheetModel(sheet); 2151 int rowsAboutToBeInsertedCounter = 0; 2152 connect(model, &SpreadsheetModel::rowsAboutToBeInserted, [&rowsAboutToBeInsertedCounter]() { 2153 rowsAboutToBeInsertedCounter++; 2154 }); 2155 int rowsInsertedCounter = 0; 2156 connect(model, &SpreadsheetModel::rowsInserted, [&rowsInsertedCounter]() { 2157 rowsInsertedCounter++; 2158 }); 2159 int rowsAboutToBeRemovedCounter = 0; 2160 connect(model, &SpreadsheetModel::rowsAboutToBeRemoved, [&rowsAboutToBeRemovedCounter]() { 2161 rowsAboutToBeRemovedCounter++; 2162 }); 2163 int rowsRemovedCounter = 0; 2164 connect(model, &SpreadsheetModel::rowsRemoved, [&rowsRemovedCounter]() { 2165 rowsRemovedCounter++; 2166 }); 2167 2168 QCOMPARE(sheet->rowCount(), 100); 2169 QCOMPARE(model->rowCount(), 100); 2170 sheet->setRowCount(101); // No crash shall happen 2171 QCOMPARE(sheet->rowCount(), 101); 2172 QCOMPARE(model->rowCount(), 101); 2173 2174 sheet->undoStack()->undo(); 2175 QCOMPARE(sheet->rowCount(), 100); 2176 QCOMPARE(model->rowCount(), 100); 2177 sheet->undoStack()->redo(); 2178 QCOMPARE(sheet->rowCount(), 101); 2179 QCOMPARE(model->rowCount(), 101); 2180 2181 QCOMPARE(rowsAboutToBeInsertedCounter, 2); // set and redo() 2182 QCOMPARE(rowsInsertedCounter, 2); // set and redo() 2183 QCOMPARE(rowsAboutToBeRemovedCounter, 1); // undo() 2184 QCOMPARE(rowsRemovedCounter, 1); // undo() 2185 } 2186 2187 void SpreadsheetTest::testRemoveRows() { 2188 Project project; 2189 auto* sheet = new Spreadsheet(QStringLiteral("test"), false); 2190 project.addChild(sheet); 2191 2192 auto* model = new SpreadsheetModel(sheet); 2193 int rowsAboutToBeInsertedCounter = 0; 2194 connect(model, &SpreadsheetModel::rowsAboutToBeInserted, [&rowsAboutToBeInsertedCounter]() { 2195 rowsAboutToBeInsertedCounter++; 2196 }); 2197 int rowsInsertedCounter = 0; 2198 connect(model, &SpreadsheetModel::rowsInserted, [&rowsInsertedCounter]() { 2199 rowsInsertedCounter++; 2200 }); 2201 int rowsAboutToBeRemovedCounter = 0; 2202 connect(model, &SpreadsheetModel::rowsAboutToBeRemoved, [&rowsAboutToBeRemovedCounter]() { 2203 rowsAboutToBeRemovedCounter++; 2204 }); 2205 int rowsRemovedCounter = 0; 2206 connect(model, &SpreadsheetModel::rowsRemoved, [&rowsRemovedCounter]() { 2207 rowsRemovedCounter++; 2208 }); 2209 2210 QCOMPARE(sheet->rowCount(), 100); 2211 QCOMPARE(model->rowCount(), 100); 2212 sheet->setRowCount(10); // No crash shall happen 2213 QCOMPARE(sheet->rowCount(), 10); 2214 QCOMPARE(model->rowCount(), 10); 2215 2216 sheet->undoStack()->undo(); 2217 QCOMPARE(sheet->rowCount(), 100); 2218 QCOMPARE(model->rowCount(), 100); 2219 sheet->undoStack()->redo(); 2220 QCOMPARE(sheet->rowCount(), 10); 2221 QCOMPARE(model->rowCount(), 10); 2222 2223 QCOMPARE(rowsAboutToBeInsertedCounter, 1); // undo 2224 QCOMPARE(rowsInsertedCounter, 1); // undo 2225 QCOMPARE(rowsAboutToBeRemovedCounter, 2); // set and redo() 2226 QCOMPARE(rowsRemovedCounter, 2); // set and redo() 2227 } 2228 2229 void SpreadsheetTest::testInsertRowsBegin() { 2230 Project project; 2231 auto* sheet = new Spreadsheet(QStringLiteral("test"), false); 2232 project.addChild(sheet); 2233 2234 auto* model = new SpreadsheetModel(sheet); 2235 int rowsAboutToBeInsertedCounter = 0; 2236 connect(model, &SpreadsheetModel::rowsAboutToBeInserted, [&rowsAboutToBeInsertedCounter]() { 2237 rowsAboutToBeInsertedCounter++; 2238 }); 2239 int rowsInsertedCounter = 0; 2240 connect(model, &SpreadsheetModel::rowsInserted, [&rowsInsertedCounter]() { 2241 rowsInsertedCounter++; 2242 }); 2243 int rowsAboutToBeRemovedCounter = 0; 2244 connect(model, &SpreadsheetModel::rowsAboutToBeRemoved, [&rowsAboutToBeRemovedCounter]() { 2245 rowsAboutToBeRemovedCounter++; 2246 }); 2247 int rowsRemovedCounter = 0; 2248 connect(model, &SpreadsheetModel::rowsRemoved, [&rowsRemovedCounter]() { 2249 rowsRemovedCounter++; 2250 }); 2251 2252 QCOMPARE(sheet->rowCount(), 100); 2253 QCOMPARE(model->rowCount(), 100); 2254 sheet->insertRows(0, 1); // No crash shall happen 2255 QCOMPARE(sheet->rowCount(), 101); 2256 QCOMPARE(model->rowCount(), 101); 2257 2258 sheet->undoStack()->undo(); 2259 QCOMPARE(sheet->rowCount(), 100); 2260 QCOMPARE(model->rowCount(), 100); 2261 sheet->undoStack()->redo(); 2262 QCOMPARE(sheet->rowCount(), 101); 2263 QCOMPARE(model->rowCount(), 101); 2264 2265 QCOMPARE(rowsAboutToBeInsertedCounter, 2); // set and redo() 2266 QCOMPARE(rowsInsertedCounter, 2); // set and redo() 2267 QCOMPARE(rowsAboutToBeRemovedCounter, 1); // undo() 2268 QCOMPARE(rowsRemovedCounter, 1); // undo() 2269 } 2270 void SpreadsheetTest::testRemoveRowsBegin() { 2271 Project project; 2272 auto* sheet = new Spreadsheet(QStringLiteral("test"), false); 2273 project.addChild(sheet); 2274 2275 auto* model = new SpreadsheetModel(sheet); 2276 int rowsAboutToBeInsertedCounter = 0; 2277 connect(model, &SpreadsheetModel::rowsAboutToBeInserted, [&rowsAboutToBeInsertedCounter]() { 2278 rowsAboutToBeInsertedCounter++; 2279 }); 2280 int rowsInsertedCounter = 0; 2281 connect(model, &SpreadsheetModel::rowsInserted, [&rowsInsertedCounter]() { 2282 rowsInsertedCounter++; 2283 }); 2284 int rowsAboutToBeRemovedCounter = 0; 2285 connect(model, &SpreadsheetModel::rowsAboutToBeRemoved, [&rowsAboutToBeRemovedCounter]() { 2286 rowsAboutToBeRemovedCounter++; 2287 }); 2288 int rowsRemovedCounter = 0; 2289 connect(model, &SpreadsheetModel::rowsRemoved, [&rowsRemovedCounter]() { 2290 rowsRemovedCounter++; 2291 }); 2292 2293 QCOMPARE(sheet->rowCount(), 100); 2294 QCOMPARE(model->rowCount(), 100); 2295 sheet->removeRows(0, 1); 2296 QCOMPARE(sheet->rowCount(), 99); 2297 QCOMPARE(model->rowCount(), 99); 2298 2299 sheet->undoStack()->undo(); 2300 QCOMPARE(sheet->rowCount(), 100); 2301 QCOMPARE(model->rowCount(), 100); 2302 sheet->undoStack()->redo(); 2303 QCOMPARE(sheet->rowCount(), 99); 2304 QCOMPARE(model->rowCount(), 99); 2305 2306 QCOMPARE(rowsAboutToBeInsertedCounter, 1); // undo 2307 QCOMPARE(rowsInsertedCounter, 1); // undo 2308 QCOMPARE(rowsAboutToBeRemovedCounter, 2); // set and redo() 2309 QCOMPARE(rowsRemovedCounter, 2); // set and redo() 2310 } 2311 2312 void SpreadsheetTest::testInsertColumns() { 2313 Project project; 2314 auto* sheet = new Spreadsheet(QStringLiteral("test"), false); 2315 project.addChild(sheet); 2316 2317 auto* model = new SpreadsheetModel(sheet); 2318 2319 int columnsAboutToBeInsertedCounter = 0; 2320 connect(model, &SpreadsheetModel::columnsAboutToBeInserted, [&columnsAboutToBeInsertedCounter]() { 2321 columnsAboutToBeInsertedCounter++; 2322 }); 2323 int columnsInsertedCounter = 0; 2324 connect(model, &SpreadsheetModel::columnsInserted, [&columnsInsertedCounter]() { 2325 columnsInsertedCounter++; 2326 }); 2327 int columnsAboutToBeRemovedCounter = 0; 2328 connect(model, &SpreadsheetModel::columnsAboutToBeRemoved, [&columnsAboutToBeRemovedCounter]() { 2329 columnsAboutToBeRemovedCounter++; 2330 }); 2331 int columnsRemovedCounter = 0; 2332 connect(model, &SpreadsheetModel::columnsRemoved, [&columnsRemovedCounter]() { 2333 columnsRemovedCounter++; 2334 }); 2335 2336 QCOMPARE(sheet->columnCount(), 2); 2337 QCOMPARE(model->columnCount(), 2); 2338 sheet->setColumnCount(5); // No crash shall happen 2339 QCOMPARE(sheet->columnCount(), 5); 2340 QCOMPARE(model->columnCount(), 5); 2341 2342 sheet->undoStack()->undo(); 2343 QCOMPARE(sheet->columnCount(), 2); 2344 QCOMPARE(model->columnCount(), 2); 2345 sheet->undoStack()->redo(); 2346 QCOMPARE(sheet->columnCount(), 5); 2347 QCOMPARE(model->columnCount(), 5); 2348 2349 QCOMPARE(columnsAboutToBeInsertedCounter, 2); // set and redo() 2350 QCOMPARE(columnsInsertedCounter, 2); // set and redo() 2351 QCOMPARE(columnsRemovedCounter, 1); // undo() 2352 QCOMPARE(columnsAboutToBeRemovedCounter, 1); // undo() 2353 } 2354 2355 void SpreadsheetTest::testRemoveColumns() { 2356 Project project; 2357 auto* sheet = new Spreadsheet(QStringLiteral("test"), false); 2358 project.addChild(sheet); 2359 2360 auto* model = new SpreadsheetModel(sheet); 2361 2362 int columnsAboutToBeInsertedCounter = 0; 2363 connect(model, &SpreadsheetModel::columnsAboutToBeInserted, [&columnsAboutToBeInsertedCounter]() { 2364 columnsAboutToBeInsertedCounter++; 2365 }); 2366 int columnsInsertedCounter = 0; 2367 connect(model, &SpreadsheetModel::columnsInserted, [&columnsInsertedCounter]() { 2368 columnsInsertedCounter++; 2369 }); 2370 int columnsAboutToBeRemovedCounter = 0; 2371 connect(model, &SpreadsheetModel::columnsAboutToBeRemoved, [&columnsAboutToBeRemovedCounter]() { 2372 columnsAboutToBeRemovedCounter++; 2373 }); 2374 int columnsRemovedCounter = 0; 2375 connect(model, &SpreadsheetModel::columnsRemoved, [&columnsRemovedCounter]() { 2376 columnsRemovedCounter++; 2377 }); 2378 2379 QCOMPARE(sheet->columnCount(), 2); 2380 QCOMPARE(model->columnCount(), 2); 2381 sheet->setColumnCount(1); // No crash shall happen 2382 QCOMPARE(sheet->columnCount(), 1); 2383 QCOMPARE(model->columnCount(), 1); 2384 2385 sheet->undoStack()->undo(); 2386 QCOMPARE(sheet->columnCount(), 2); 2387 QCOMPARE(model->columnCount(), 2); 2388 sheet->undoStack()->redo(); 2389 QCOMPARE(sheet->columnCount(), 1); 2390 QCOMPARE(model->columnCount(), 1); 2391 2392 QCOMPARE(columnsAboutToBeInsertedCounter, 1); // undo() 2393 QCOMPARE(columnsInsertedCounter, 1); // undo() 2394 QCOMPARE(columnsRemovedCounter, 2); // set and redo() 2395 QCOMPARE(columnsAboutToBeRemovedCounter, 2); // set and redo() 2396 } 2397 2398 /*! 2399 * \brief testInsertRowsSuppressUpdate 2400 * It shall not crash 2401 * Testing if in the model begin and end are used properly 2402 */ 2403 void SpreadsheetTest::testInsertRowsSuppressUpdate() { 2404 Project project; 2405 auto* sheet = new Spreadsheet(QStringLiteral("test"), false); 2406 project.addChild(sheet); 2407 2408 auto* model = new SpreadsheetModel(sheet); 2409 2410 int rowsAboutToBeInsertedCounter = 0; 2411 connect(model, &SpreadsheetModel::rowsAboutToBeInserted, [&rowsAboutToBeInsertedCounter]() { 2412 rowsAboutToBeInsertedCounter++; 2413 }); 2414 int rowsInsertedCounter = 0; 2415 connect(model, &SpreadsheetModel::rowsInserted, [&rowsInsertedCounter]() { 2416 rowsInsertedCounter++; 2417 }); 2418 int rowsAboutToBeRemovedCounter = 0; 2419 connect(model, &SpreadsheetModel::rowsAboutToBeRemoved, [&rowsAboutToBeRemovedCounter]() { 2420 rowsAboutToBeRemovedCounter++; 2421 }); 2422 int rowsRemovedCounter = 0; 2423 connect(model, &SpreadsheetModel::rowsRemoved, [&rowsRemovedCounter]() { 2424 rowsRemovedCounter++; 2425 }); 2426 2427 int modelResetCounter = 0; 2428 connect(model, &SpreadsheetModel::modelReset, [&modelResetCounter]() { 2429 modelResetCounter++; 2430 }); 2431 int modelAboutToResetCounter = 0; 2432 connect(model, &SpreadsheetModel::modelAboutToBeReset, [&modelAboutToResetCounter]() { 2433 modelAboutToResetCounter++; 2434 }); 2435 2436 model->suppressSignals(true); 2437 2438 QCOMPARE(sheet->rowCount(), 100); 2439 sheet->setRowCount(101); // No crash shall happen 2440 QCOMPARE(sheet->rowCount(), 101); 2441 2442 sheet->undoStack()->undo(); 2443 QCOMPARE(sheet->rowCount(), 100); 2444 sheet->undoStack()->redo(); 2445 QCOMPARE(sheet->rowCount(), 101); 2446 2447 model->suppressSignals(false); 2448 2449 QCOMPARE(rowsAboutToBeInsertedCounter, 0); 2450 QCOMPARE(rowsInsertedCounter, 0); 2451 QCOMPARE(rowsAboutToBeRemovedCounter, 0); 2452 QCOMPARE(rowsRemovedCounter, 0); 2453 QCOMPARE(modelResetCounter, 1); 2454 QCOMPARE(modelAboutToResetCounter, 1); 2455 } 2456 2457 /*! 2458 * \brief testInsertColumnsSuppressUpdate 2459 * It shall not crash 2460 * Testing if in the model begin and end are used properly 2461 */ 2462 void SpreadsheetTest::testInsertColumnsSuppressUpdate() { 2463 Project project; 2464 auto* sheet = new Spreadsheet(QStringLiteral("test"), false); 2465 project.addChild(sheet); 2466 2467 auto* model = new SpreadsheetModel(sheet); 2468 2469 int columnsAboutToBeInsertedCounter = 0; 2470 connect(model, &SpreadsheetModel::columnsAboutToBeInserted, [&columnsAboutToBeInsertedCounter]() { 2471 columnsAboutToBeInsertedCounter++; 2472 }); 2473 int columnsInsertedCounter = 0; 2474 connect(model, &SpreadsheetModel::columnsInserted, [&columnsInsertedCounter]() { 2475 columnsInsertedCounter++; 2476 }); 2477 int columnsAboutToBeRemovedCounter = 0; 2478 connect(model, &SpreadsheetModel::columnsAboutToBeRemoved, [&columnsAboutToBeRemovedCounter]() { 2479 columnsAboutToBeRemovedCounter++; 2480 }); 2481 int columnsRemovedCounter = 0; 2482 connect(model, &SpreadsheetModel::columnsRemoved, [&columnsRemovedCounter]() { 2483 columnsRemovedCounter++; 2484 }); 2485 2486 int modelResetCounter = 0; 2487 connect(model, &SpreadsheetModel::modelReset, [&modelResetCounter]() { 2488 modelResetCounter++; 2489 }); 2490 int modelAboutToResetCounter = 0; 2491 connect(model, &SpreadsheetModel::modelAboutToBeReset, [&modelAboutToResetCounter]() { 2492 modelAboutToResetCounter++; 2493 }); 2494 2495 model->suppressSignals(true); 2496 2497 QCOMPARE(sheet->columnCount(), 2); 2498 sheet->setColumnCount(5); // No crash shall happen 2499 QCOMPARE(sheet->columnCount(), 5); 2500 2501 sheet->undoStack()->undo(); 2502 QCOMPARE(sheet->columnCount(), 2); 2503 sheet->undoStack()->redo(); 2504 QCOMPARE(sheet->columnCount(), 5); 2505 2506 model->suppressSignals(false); 2507 2508 QCOMPARE(columnsAboutToBeInsertedCounter, 0); 2509 QCOMPARE(columnsInsertedCounter, 0); 2510 QCOMPARE(columnsRemovedCounter, 0); 2511 QCOMPARE(columnsAboutToBeRemovedCounter, 0); 2512 QCOMPARE(modelResetCounter, 1); 2513 QCOMPARE(modelAboutToResetCounter, 1); 2514 } 2515 2516 void SpreadsheetTest::testLinkSpreadsheetsUndoRedo() { 2517 #ifdef __FreeBSD__ 2518 return; 2519 #endif 2520 Project project; 2521 auto* sheetData = new Spreadsheet(QStringLiteral("data"), false); 2522 project.addChild(sheetData); 2523 sheetData->setColumnCount(3); 2524 sheetData->setRowCount(10); 2525 2526 auto* sheetData2 = new Spreadsheet(QStringLiteral("data2"), false); 2527 project.addChild(sheetData2); 2528 sheetData2->setColumnCount(3); 2529 sheetData2->setRowCount(100); 2530 2531 auto* sheetCalculations = new Spreadsheet(QStringLiteral("calculations"), false); 2532 project.addChild(sheetCalculations); 2533 sheetCalculations->setColumnCount(3); 2534 sheetCalculations->setRowCount(2); 2535 2536 SpreadsheetDock dock(nullptr); 2537 dock.setSpreadsheets({sheetCalculations}); 2538 2539 QCOMPARE(dock.ui.cbLinkingEnabled->isChecked(), false); 2540 QCOMPARE(dock.ui.cbLinkedSpreadsheet->isVisible(), false); 2541 QCOMPARE(dock.ui.sbRowCount->isEnabled(), true); 2542 QCOMPARE(dock.m_spreadsheet->linking(), false); 2543 2544 dock.ui.cbLinkingEnabled->toggled(true); 2545 2546 // QCOMPARE(dock.ui.cbLinkingEnabled->isChecked(), true); // does not work here. Don't know why 2547 // QCOMPARE(dock.ui.cbLinkedSpreadsheet->isVisible(), true); 2548 // QCOMPARE(dock.ui.sbRowCount->isEnabled(), false); 2549 QCOMPARE(sheetCalculations->linking(), true); 2550 QCOMPARE(sheetCalculations->linkedSpreadsheet(), nullptr); 2551 QCOMPARE(sheetCalculations->linkedSpreadsheetPath(), QLatin1String()); 2552 QCOMPARE(sheetCalculations->rowCount(), 2); 2553 2554 const auto index = dock.m_aspectTreeModel->modelIndexOfAspect(sheetData); 2555 QCOMPARE(index.isValid(), true); 2556 // dock.ui.cbLinkedSpreadsheet->setCurrentModelIndex(index); // Does not trigger the slot 2557 sheetCalculations->setLinkedSpreadsheet(sheetData); 2558 2559 QCOMPARE(sheetCalculations->linkedSpreadsheet(), sheetData); 2560 QCOMPARE(sheetCalculations->linkedSpreadsheetPath(), sheetData->path()); 2561 QCOMPARE(sheetCalculations->rowCount(), 10); 2562 2563 sheetCalculations->setLinkedSpreadsheet(sheetData2); 2564 2565 QCOMPARE(sheetCalculations->linking(), true); 2566 QCOMPARE(sheetCalculations->linkedSpreadsheet(), sheetData2); 2567 QCOMPARE(sheetCalculations->linkedSpreadsheetPath(), sheetData2->path()); 2568 QCOMPARE(sheetCalculations->rowCount(), 100); 2569 2570 sheetCalculations->undoStack()->undo(); 2571 2572 QCOMPARE(sheetCalculations->linking(), true); 2573 QCOMPARE(sheetCalculations->linkedSpreadsheet(), sheetData); 2574 QCOMPARE(sheetCalculations->linkedSpreadsheetPath(), sheetData->path()); 2575 QCOMPARE(sheetCalculations->rowCount(), 10); 2576 2577 sheetCalculations->undoStack()->redo(); 2578 2579 QCOMPARE(sheetCalculations->linking(), true); 2580 QCOMPARE(sheetCalculations->linkedSpreadsheet(), sheetData2); 2581 QCOMPARE(sheetCalculations->linkedSpreadsheetPath(), sheetData2->path()); 2582 QCOMPARE(sheetCalculations->rowCount(), 100); 2583 2584 sheetCalculations->undoStack()->undo(); // first undo 2585 QCOMPARE(sheetCalculations->linking(), true); 2586 QCOMPARE(sheetCalculations->linkedSpreadsheet(), sheetData); 2587 QCOMPARE(sheetCalculations->linkedSpreadsheetPath(), sheetData->path()); 2588 QCOMPARE(sheetCalculations->rowCount(), 10); 2589 2590 sheetCalculations->undoStack()->undo(); 2591 2592 QCOMPARE(sheetCalculations->linking(), true); 2593 QCOMPARE(sheetCalculations->linkedSpreadsheet(), nullptr); // No linked spreadsheet anymore 2594 QCOMPARE(sheetCalculations->linkedSpreadsheetPath(), QLatin1String()); 2595 QCOMPARE(sheetCalculations->rowCount(), 2); // Go back to original row count 2596 2597 sheetCalculations->undoStack()->undo(); 2598 QCOMPARE(sheetCalculations->linking(), false); 2599 QCOMPARE(sheetCalculations->linkedSpreadsheet(), nullptr); 2600 QCOMPARE(sheetCalculations->linkedSpreadsheetPath(), QLatin1String()); 2601 QCOMPARE(sheetCalculations->rowCount(), 2); 2602 } 2603 2604 void SpreadsheetTest::testLinkSpreadsheetDeleteAdd() { 2605 #ifdef __FreeBSD__ 2606 return; 2607 #endif 2608 Project project; 2609 auto* sheetData = new Spreadsheet(QStringLiteral("data"), false); 2610 project.addChild(sheetData); 2611 sheetData->setColumnCount(3); 2612 sheetData->setRowCount(10); 2613 2614 auto* sheetCalculations = new Spreadsheet(QStringLiteral("calculations"), false); 2615 project.addChild(sheetCalculations); 2616 sheetCalculations->setColumnCount(3); 2617 sheetCalculations->setRowCount(2); 2618 2619 SpreadsheetDock dock(nullptr); 2620 dock.setSpreadsheets({sheetCalculations}); 2621 2622 QCOMPARE(dock.ui.cbLinkingEnabled->isChecked(), false); 2623 QCOMPARE(dock.ui.cbLinkedSpreadsheet->isVisible(), false); 2624 QCOMPARE(dock.ui.sbRowCount->isEnabled(), true); 2625 QCOMPARE(sheetCalculations->linking(), false); 2626 2627 Q_EMIT dock.ui.cbLinkingEnabled->toggled(true); 2628 2629 sheetCalculations->setLinkedSpreadsheet(sheetData); 2630 2631 QCOMPARE(sheetCalculations->linking(), true); 2632 QCOMPARE(sheetCalculations->linkedSpreadsheet(), sheetData); 2633 QCOMPARE(sheetCalculations->linkedSpreadsheetPath(), sheetData->path()); 2634 QCOMPARE(sheetCalculations->rowCount(), 10); 2635 2636 sheetData->remove(); 2637 sheetData->setRowCount(100); 2638 2639 QCOMPARE(sheetCalculations->linking(), true); 2640 QCOMPARE(sheetCalculations->linkedSpreadsheet(), nullptr); 2641 QCOMPARE(sheetCalculations->linkedSpreadsheetPath(), QStringLiteral("Project/data")); 2642 QCOMPARE(sheetCalculations->rowCount(), 10); // does not change 2643 2644 auto* sheetDataNew = new Spreadsheet(QStringLiteral("data"), false); 2645 sheetDataNew->setColumnCount(3); 2646 sheetDataNew->setRowCount(12); 2647 project.addChild(sheetDataNew); 2648 2649 QCOMPARE(sheetCalculations->linking(), true); 2650 QCOMPARE(sheetCalculations->linkedSpreadsheet(), sheetDataNew); 2651 QCOMPARE(sheetCalculations->linkedSpreadsheetPath(), sheetDataNew->path()); 2652 QCOMPARE(sheetCalculations->rowCount(), 12); 2653 } 2654 2655 void SpreadsheetTest::testLinkSpreadsheetAddRow() { 2656 #ifdef __FreeBSD__ 2657 return; 2658 #endif 2659 Project project; 2660 auto* sheetData = new Spreadsheet(QStringLiteral("data"), false); 2661 project.addChild(sheetData); 2662 sheetData->setColumnCount(3); 2663 sheetData->setRowCount(10); 2664 2665 auto* sheetCalculations = new Spreadsheet(QStringLiteral("calculations"), false); 2666 project.addChild(sheetCalculations); 2667 sheetCalculations->setColumnCount(3); 2668 sheetCalculations->setRowCount(2); 2669 2670 SpreadsheetDock dock(nullptr); 2671 dock.setSpreadsheets({sheetCalculations}); 2672 2673 QCOMPARE(dock.ui.cbLinkingEnabled->isChecked(), false); 2674 QCOMPARE(dock.ui.cbLinkedSpreadsheet->isVisible(), false); 2675 QCOMPARE(dock.ui.sbRowCount->isEnabled(), true); 2676 QCOMPARE(sheetCalculations->linking(), false); 2677 2678 Q_EMIT dock.ui.cbLinkingEnabled->toggled(true); 2679 2680 sheetCalculations->setLinkedSpreadsheet(sheetData); 2681 2682 QCOMPARE(sheetCalculations->linking(), true); 2683 QCOMPARE(sheetCalculations->linkedSpreadsheet(), sheetData); 2684 QCOMPARE(sheetCalculations->linkedSpreadsheetPath(), sheetData->path()); 2685 QCOMPARE(sheetCalculations->rowCount(), 10); 2686 2687 new SpreadsheetModel(sheetData); // otherwise emitRowCountChanged will not be called 2688 sheetData->setRowCount(13); 2689 2690 QCOMPARE(sheetCalculations->linking(), true); 2691 QCOMPARE(sheetCalculations->linkedSpreadsheet(), sheetData); 2692 QCOMPARE(sheetCalculations->linkedSpreadsheetPath(), sheetData->path()); 2693 QCOMPARE(sheetCalculations->rowCount(), 13); 2694 } 2695 2696 void SpreadsheetTest::testLinkSpreadsheetRemoveRow() { 2697 #ifdef __FreeBSD__ 2698 return; 2699 #endif 2700 Project project; 2701 auto* sheetData = new Spreadsheet(QStringLiteral("data"), false); 2702 project.addChild(sheetData); 2703 sheetData->setColumnCount(3); 2704 sheetData->setRowCount(10); 2705 2706 auto* sheetCalculations = new Spreadsheet(QStringLiteral("calculations"), false); 2707 project.addChild(sheetCalculations); 2708 sheetCalculations->setColumnCount(3); 2709 sheetCalculations->setRowCount(2); 2710 2711 SpreadsheetDock dock(nullptr); 2712 dock.setSpreadsheets({sheetCalculations}); 2713 2714 QCOMPARE(dock.ui.cbLinkingEnabled->isChecked(), false); 2715 QCOMPARE(dock.ui.cbLinkedSpreadsheet->isVisible(), false); 2716 QCOMPARE(dock.ui.sbRowCount->isEnabled(), true); 2717 QCOMPARE(sheetCalculations->linking(), false); 2718 2719 dock.ui.cbLinkingEnabled->toggled(true); 2720 2721 sheetCalculations->setLinkedSpreadsheet(sheetData); 2722 2723 QCOMPARE(sheetCalculations->linking(), true); 2724 QCOMPARE(sheetCalculations->linkedSpreadsheet(), sheetData); 2725 QCOMPARE(sheetCalculations->linkedSpreadsheetPath(), sheetData->path()); 2726 QCOMPARE(sheetCalculations->rowCount(), 10); 2727 2728 new SpreadsheetModel(sheetData); // otherwise emitRowCountChanged will not be called 2729 sheetData->setRowCount(7); 2730 2731 QCOMPARE(sheetCalculations->linking(), true); 2732 QCOMPARE(sheetCalculations->linkedSpreadsheet(), sheetData); 2733 QCOMPARE(sheetCalculations->linkedSpreadsheetPath(), sheetData->path()); 2734 QCOMPARE(sheetCalculations->rowCount(), 7); 2735 } 2736 2737 void SpreadsheetTest::testLinkSpreadsheetRecalculate() { 2738 #ifdef __FreeBSD__ 2739 return; 2740 #endif 2741 Project project; 2742 auto* sheetData = new Spreadsheet(QStringLiteral("data"), false); 2743 project.addChild(sheetData); 2744 sheetData->setColumnCount(2); 2745 sheetData->setRowCount(10); 2746 auto* sheetDataColumn0 = sheetData->child<Column>(0); 2747 sheetDataColumn0->replaceValues(0, {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}); 2748 QVERIFY(sheetDataColumn0); 2749 auto* sheetDataColumn1 = sheetData->child<Column>(1); 2750 QVERIFY(sheetDataColumn1); 2751 sheetDataColumn1->replaceValues(0, {1, 2, 1, 2, 1, 2, 1, 2, 1, 3}); 2752 2753 auto* sheetCalculations = new Spreadsheet(QStringLiteral("calculations"), false); 2754 project.addChild(sheetCalculations); 2755 sheetCalculations->setColumnCount(1); 2756 sheetCalculations->setRowCount(2); 2757 auto* sheetCalculationsColumn0 = sheetCalculations->child<Column>(0); 2758 QVERIFY(sheetCalculationsColumn0); 2759 sheetCalculationsColumn0->setFormula(QStringLiteral("x + y"), {QStringLiteral("x"), QStringLiteral("y")}, {sheetDataColumn0, sheetDataColumn1}, true); 2760 sheetCalculationsColumn0->updateFormula(); 2761 2762 { 2763 QVector<double> ref{2, 4, 4, 6, 6, 8, 8, 10, 10, 13}; 2764 QCOMPARE(sheetCalculationsColumn0->rowCount(), 10); // currently the update() triggers a resize 2765 for (int i = 0; i < 10; i++) 2766 VALUES_EQUAL(sheetCalculationsColumn0->doubleAt(i), ref.at(i)); 2767 } 2768 sheetCalculations->setLinking(true); 2769 sheetCalculations->setLinkedSpreadsheet(sheetData); 2770 2771 QCOMPARE(sheetCalculations->linking(), true); 2772 QCOMPARE(sheetCalculations->linkedSpreadsheet(), sheetData); 2773 QCOMPARE(sheetCalculations->linkedSpreadsheetPath(), sheetData->path()); 2774 QCOMPARE(sheetCalculations->rowCount(), 10); 2775 2776 new SpreadsheetModel(sheetData); // otherwise emitRowCountChanged will not be called 2777 sheetData->setRowCount(7); 2778 sheetDataColumn0->replaceValues(0, {3, 4, 6, 2, 1, 8, 5}); 2779 QCOMPARE(sheetDataColumn0->rowCount(), 7); 2780 2781 { 2782 QVector<double> ref{4, 6, 7, 4, 2, 10, 6}; 2783 QCOMPARE(sheetCalculationsColumn0->rowCount(), ref.count()); 2784 for (int i = 0; i < ref.count(); i++) { 2785 qDebug() << i; 2786 VALUES_EQUAL(sheetCalculationsColumn0->doubleAt(i), ref.at(i)); 2787 } 2788 } 2789 } 2790 2791 void SpreadsheetTest::testLinkSpreadsheetSaveLoad() { 2792 #ifdef __FreeBSD__ 2793 return; 2794 #endif 2795 QString savePath; 2796 { 2797 Project project; 2798 auto model = new AspectTreeModel(&project, this); 2799 ProjectExplorer pe; // Needed otherwise the state key is missing in the file and then no restorePointers will be called 2800 pe.setProject(&project); 2801 pe.setModel(model); 2802 auto* sheetData = new Spreadsheet(QStringLiteral("data"), false); 2803 project.addChild(sheetData); 2804 sheetData->setColumnCount(3); 2805 sheetData->setRowCount(10); 2806 2807 auto* sheetCalculations = new Spreadsheet(QStringLiteral("calculations"), false); 2808 project.addChild(sheetCalculations); 2809 sheetCalculations->setColumnCount(3); 2810 sheetCalculations->setRowCount(2); 2811 2812 SpreadsheetDock dock(nullptr); 2813 dock.setSpreadsheets({sheetCalculations}); 2814 2815 QCOMPARE(dock.ui.cbLinkingEnabled->isChecked(), false); 2816 QCOMPARE(dock.ui.cbLinkedSpreadsheet->isVisible(), false); 2817 QCOMPARE(dock.ui.sbRowCount->isEnabled(), true); 2818 QCOMPARE(sheetCalculations->linking(), false); 2819 2820 Q_EMIT dock.ui.cbLinkingEnabled->toggled(true); 2821 2822 sheetCalculations->setLinkedSpreadsheet(sheetData); 2823 2824 QCOMPARE(sheetCalculations->linking(), true); 2825 QCOMPARE(sheetCalculations->linkedSpreadsheet(), sheetData); 2826 QCOMPARE(sheetCalculations->linkedSpreadsheetPath(), sheetData->path()); 2827 QCOMPARE(sheetCalculations->rowCount(), 10); 2828 2829 SAVE_PROJECT("testLinkSpreadsheetSaveLoad") 2830 } 2831 2832 { 2833 Project project; 2834 QCOMPARE(project.load(savePath), true); 2835 2836 auto sheetData = project.child<Spreadsheet>(0); 2837 QVERIFY(sheetData); 2838 auto sheetCalculations = project.child<Spreadsheet>(1); 2839 QVERIFY(sheetCalculations); 2840 2841 QCOMPARE(sheetCalculations->linking(), true); 2842 QCOMPARE(sheetCalculations->linkedSpreadsheetPath(), sheetData->path()); 2843 QCOMPARE(sheetCalculations->linkedSpreadsheet(), sheetData); 2844 QCOMPARE(sheetCalculations->rowCount(), 10); 2845 2846 new SpreadsheetModel(sheetData); // otherwise emitRowCountChanged will not be called 2847 sheetData->setRowCount(11); // Changing shall also update sheetCalculations also after loading 2848 2849 QCOMPARE(sheetCalculations->linking(), true); 2850 QCOMPARE(sheetCalculations->linkedSpreadsheet(), sheetData); 2851 QCOMPARE(sheetCalculations->linkedSpreadsheetPath(), sheetData->path()); 2852 QCOMPARE(sheetCalculations->rowCount(), 11); 2853 } 2854 } 2855 2856 // ********************************************************** 2857 // **************** statistics spreadsheet ***************** 2858 // ********************************************************** 2859 /*! 2860 * toggle on and off the statistics spreadsheet and check its presence 2861 */ 2862 void SpreadsheetTest::testStatisticsSpreadsheetToggle() { 2863 Project project; 2864 auto* sheet = new Spreadsheet(QStringLiteral("test"), false); 2865 project.addChild(sheet); 2866 2867 // initial 2868 auto children = sheet->children<StatisticsSpreadsheet>(); 2869 QCOMPARE(children.size(), 0); 2870 2871 // toggle on 2872 sheet->toggleStatisticsSpreadsheet(true); 2873 children = sheet->children<StatisticsSpreadsheet>(); 2874 QCOMPARE(children.size(), 1); 2875 2876 // toggle off 2877 sheet->toggleStatisticsSpreadsheet(false); 2878 children = sheet->children<StatisticsSpreadsheet>(); 2879 QCOMPARE(children.size(), 0); 2880 } 2881 2882 /*! 2883 * change the statistics metrics and check the presense of the corresponding columns 2884 */ 2885 void SpreadsheetTest::testStatisticsSpreadsheetChangeMetrics() { 2886 Project project; 2887 auto* sheet = new Spreadsheet(QStringLiteral("test"), false); 2888 project.addChild(sheet); 2889 2890 new SpreadsheetModel(sheet); 2891 2892 // toggle on the statistics spreadsheet and count the available columns 2893 sheet->toggleStatisticsSpreadsheet(true); 2894 auto* statisticsSpreadsheet = sheet->children<StatisticsSpreadsheet>().constFirst(); 2895 auto metrics = statisticsSpreadsheet->metrics(); 2896 int colCount = 1; // column "Column Name" is always available 2897 auto it = statisticsSpreadsheet->m_metricNames.constBegin(); 2898 while (it != statisticsSpreadsheet->m_metricNames.constEnd()) { 2899 if (metrics.testFlag(it.key())) 2900 ++colCount; 2901 ++it; 2902 } 2903 QCOMPARE(statisticsSpreadsheet->children<Column>().size(), colCount); 2904 2905 // deactivate Count and check the available columns again 2906 metrics.setFlag(StatisticsSpreadsheet::Metric::Count, false); 2907 statisticsSpreadsheet->setMetrics(metrics); 2908 QCOMPARE(statisticsSpreadsheet->children<Column>().size(), colCount - 1); 2909 } 2910 2911 /*! 2912 * check the position of the statistics spreadsheet in the list of children of the parent 2913 * spreadsheet, it should always be put at the last position. 2914 */ 2915 void SpreadsheetTest::testStatisticsSpreadsheetChildIndex() { 2916 Project project; 2917 auto* sheet = new Spreadsheet(QStringLiteral("test"), false); 2918 project.addChild(sheet); 2919 2920 // toggle on the statistics spreadsheet and count the available columns 2921 sheet->toggleStatisticsSpreadsheet(true); 2922 auto* statisticsSpreadsheet = sheet->children<StatisticsSpreadsheet>().constFirst(); 2923 2924 // set the column count and check the position of the statistics spreadsheet 2925 sheet->setColumnCount(2); 2926 QCOMPARE(sheet->indexOfChild<AbstractAspect>(statisticsSpreadsheet), 2); 2927 2928 // change the column count and check the position again 2929 sheet->setColumnCount(3); 2930 QCOMPARE(sheet->indexOfChild<AbstractAspect>(statisticsSpreadsheet), 3); 2931 2932 // append one more column and check the position again 2933 sheet->appendColumn(); 2934 QCOMPARE(sheet->indexOfChild<AbstractAspect>(statisticsSpreadsheet), 4); 2935 2936 // check also the position when adding new columns via the actions in the view that also 2937 // take the current selected column into account and have more logic for "append left to" 2938 // and "append right to" - ensure no columns are added after the statistics spreadhseet 2939 auto* view = static_cast<SpreadsheetView*>(sheet->view()); 2940 2941 // insert a new column right to the last selected column, it should be placed in front of the statistics spreadsheet 2942 view->selectColumn(3); // select the last 4th column 2943 view->insertColumnsRight(1); 2944 QCOMPARE(sheet->indexOfChild<AbstractAspect>(statisticsSpreadsheet), 5); 2945 } 2946 2947 /*! 2948 * check the position of the statistics spreadsheet in the list of children of the parent 2949 * spreadsheet after an undo and redo of a column appen, it should always be put at the last position, 2950 * and also check the handling of added and removed childrend in the model in the presense of the 2951 * statistics spreadsheet. 2952 */ 2953 void SpreadsheetTest::testStatisticsSpreadsheetChildIndexAfterUndoRedo() { 2954 Project project; 2955 auto* sheet = new Spreadsheet(QStringLiteral("test"), false); 2956 project.addChild(sheet); 2957 2958 new SpreadsheetModel(sheet); 2959 2960 // toggle on the statistics spreadsheet and count the available columns 2961 sheet->toggleStatisticsSpreadsheet(true); 2962 auto* statisticsSpreadsheet = sheet->children<StatisticsSpreadsheet>().constFirst(); 2963 2964 // set the column count , append a column, undo and redo this change and check the position of the statistics spreadsheet 2965 sheet->setColumnCount(2); 2966 sheet->appendColumn(); 2967 QCOMPARE(sheet->model()->columnCount(), 3); 2968 QCOMPARE(sheet->indexOfChild<AbstractAspect>(statisticsSpreadsheet), 3); 2969 2970 project.undoStack()->undo(); 2971 QCOMPARE(sheet->model()->columnCount(), 2); 2972 QCOMPARE(sheet->indexOfChild<AbstractAspect>(statisticsSpreadsheet), 2); 2973 2974 project.undoStack()->redo(); 2975 QCOMPARE(sheet->model()->columnCount(), 3); 2976 QCOMPARE(sheet->indexOfChild<AbstractAspect>(statisticsSpreadsheet), 3); 2977 } 2978 2979 #ifdef HAVE_VECTOR_BLF 2980 // Copied from BLFFilterTest.cpp 2981 namespace { 2982 static const std::string PRIMITIVE_DBC = 2983 R"(VERSION "1.0.0" 2984 2985 NS_ : 2986 2987 BS_: 2988 2989 BU_: DBG DRIVER IO MOTOR SENSOR 2990 2991 )"; 2992 2993 void createDBCFile(const QString& filename, const std::string& content) { 2994 auto* file = std::fopen(filename.toStdString().c_str(), "w"); 2995 QVERIFY(file); 2996 std::fputs(PRIMITIVE_DBC.c_str(), file); 2997 std::fputs(content.c_str(), file); 2998 std::fclose(file); 2999 } 3000 3001 Vector::BLF::CanMessage2* createCANMessage(uint32_t id, uint64_t timestamp, const std::vector<uint8_t>& data) { 3002 auto* canMessage = new Vector::BLF::CanMessage2(); 3003 canMessage->channel = 1; 3004 canMessage->flags = 1; // TX 3005 canMessage->dlc = std::min<uint8_t>(data.size(), 8); 3006 canMessage->id = id; 3007 canMessage->objectTimeStamp = timestamp; 3008 canMessage->objectFlags = Vector::BLF::ObjectHeader::ObjectFlags::TimeOneNans; 3009 if (canMessage->data.size() < canMessage->dlc) 3010 canMessage->data.resize(canMessage->dlc); 3011 3012 for (int i = 0; i < canMessage->dlc; i++) { 3013 canMessage->data[i] = data.at(i); 3014 } 3015 return canMessage; 3016 } 3017 3018 void createBLFFile(const QString& filename, QVector<Vector::BLF::CanMessage2*> messages) { 3019 Vector::BLF::File blfFile; 3020 blfFile.open(filename.toStdString().c_str(), std::ios_base::out); 3021 QVERIFY(blfFile.is_open()); 3022 3023 for (auto msg : messages) { 3024 blfFile.write(msg); 3025 } 3026 // Finish creating files 3027 blfFile.close(); 3028 } 3029 } 3030 3031 void SpreadsheetTest::testLinkSpreadSheetImportBLF() { 3032 QTemporaryFile blfFileName(QStringLiteral("XXXXXX.blf")); 3033 QVERIFY(blfFileName.open()); 3034 QVector<Vector::BLF::CanMessage2*> messages{ 3035 createCANMessage(337, 5, {0, 4, 252, 19, 0, 0, 0, 0}), 3036 createCANMessage(541, 10, {7, 39, 118, 33, 250, 30, 76, 24}), // 99.91, 85.66, 79.3, 22.2 3037 createCANMessage(337, 15, {47, 4, 60, 29, 0, 0, 0, 0}), 3038 createCANMessage(337, 20, {57, 4, 250, 29, 0, 0, 0, 0}), 3039 createCANMessage(541, 25, {7, 39, 118, 33, 250, 30, 76, 24}), // 99.91, 85.66, 79.3, 22.2 3040 }; // time is in nanoseconds 3041 createBLFFile(blfFileName.fileName(), messages); 3042 3043 QTemporaryFile dbcFile(QStringLiteral("XXXXXX.dbc")); 3044 QVERIFY(dbcFile.open()); 3045 const auto dbcContent = R"(BO_ 337 STATUS: 8 Vector__XXX 3046 SG_ Value6 : 27|3@1+ (1,0) [0|7] "" Vector__XXX 3047 SG_ Value5 : 16|11@1+ (0.1,-102) [-102|102] "%" Vector__XXX 3048 SG_ Value2 : 8|2@1+ (1,0) [0|2] "" Vector__XXX 3049 SG_ Value3 : 10|1@1+ (1,0) [0|1] "" Vector__XXX 3050 SG_ Value7 : 30|2@1+ (1,0) [0|3] "" Vector__XXX 3051 SG_ Value4 : 11|4@1+ (1,0) [0|3] "" Vector__XXX 3052 SG_ Value1 : 0|8@1+ (1,0) [0|204] "Km/h" Vector__XXX" 3053 BO_ 541 MSG2: 8 Vector__XXX 3054 SG_ MSG2Value4 : 48|16@1+ (0.01,-40) [-40|125] "C" Vector__XXX 3055 SG_ MSG2Value1 : 0|16@1+ (0.01,0) [0|100] "%" Vector__XXX 3056 SG_ MSG2Value3 : 32|16@1+ (0.01,0) [0|100] "%" Vector__XXX 3057 SG_ MSG2Value2 : 16|16@1+ (0.01,0) [0|100] "%" Vector__XXX 3058 )"; 3059 createDBCFile(dbcFile.fileName(), dbcContent); 3060 3061 //------------------------------------------------------------------------------------------ 3062 Project project; 3063 const auto spreadsheetName = blfFileName.fileName().replace(QStringLiteral(".blf"), QStringLiteral("")); 3064 auto* sheetData = new Spreadsheet(spreadsheetName, false); 3065 project.addChild(sheetData); 3066 sheetData->setColumnCount(2); 3067 sheetData->setRowCount(10); 3068 auto* sheetDataColumn0 = sheetData->child<Column>(0); 3069 sheetDataColumn0->setName(QStringLiteral("Value6_")); 3070 sheetDataColumn0->replaceValues(0, {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}); 3071 QVERIFY(sheetDataColumn0); 3072 auto* sheetDataColumn1 = sheetData->child<Column>(1); 3073 sheetDataColumn1->setName(QStringLiteral("Value5_%")); 3074 QVERIFY(sheetDataColumn1); 3075 sheetDataColumn1->replaceValues(0, {1, 2, 1, 2, 1, 2, 1, 2, 1, 3}); 3076 3077 auto* sheetCalculations = new Spreadsheet(QStringLiteral("calculations"), false); 3078 project.addChild(sheetCalculations); 3079 sheetCalculations->setColumnCount(2); 3080 sheetCalculations->setRowCount(2); 3081 3082 auto* sheetCalculationsColumn0 = sheetCalculations->child<Column>(0); 3083 QVERIFY(sheetCalculationsColumn0); 3084 sheetCalculationsColumn0->setFormula(QStringLiteral("2*x"), {QStringLiteral("x")}, {sheetDataColumn0}, true); 3085 sheetCalculationsColumn0->updateFormula(); 3086 3087 auto* sheetCalculationsColumn1 = sheetCalculations->child<Column>(1); 3088 QVERIFY(sheetCalculationsColumn1); 3089 sheetCalculationsColumn1->setFormula(QStringLiteral("2*x"), {QStringLiteral("x")}, {sheetDataColumn1}, true); 3090 sheetCalculationsColumn1->updateFormula(); 3091 3092 { 3093 QVector<double> ref{2, 4, 6, 8, 10, 12, 14, 16, 18, 20}; 3094 QCOMPARE(sheetCalculationsColumn0->rowCount(), 10); 3095 for (int i = 0; i < 10; i++) 3096 VALUES_EQUAL(sheetCalculationsColumn0->doubleAt(i), ref.at(i)); 3097 } 3098 3099 { 3100 QVector<double> ref{2, 4, 2, 4, 2, 4, 2, 4, 2, 6}; 3101 QCOMPARE(sheetCalculationsColumn1->rowCount(), 10); 3102 for (int i = 0; i < 10; i++) 3103 VALUES_EQUAL(sheetCalculationsColumn1->doubleAt(i), ref.at(i)); 3104 } 3105 3106 sheetCalculations->setLinking(true); 3107 sheetCalculations->setLinkedSpreadsheet(sheetData); 3108 3109 QCOMPARE(sheetCalculations->linking(), true); 3110 QCOMPARE(sheetCalculations->linkedSpreadsheet(), sheetData); 3111 QCOMPARE(sheetCalculations->linkedSpreadsheetPath(), sheetData->path()); 3112 QCOMPARE(sheetCalculations->rowCount(), 10); 3113 3114 new SpreadsheetModel(sheetData); // otherwise emitRowCountChanged will not be called 3115 3116 VectorBLFFilter filter; 3117 filter.setConvertTimeToSeconds(true); 3118 filter.setTimeHandlingMode(CANFilter::TimeHandling::ConcatPrevious); 3119 QCOMPARE(filter.isValid(blfFileName.fileName()), true); 3120 3121 // Valid blf and valid dbc 3122 filter.setDBCFile(dbcFile.fileName()); 3123 filter.readDataFromFile(blfFileName.fileName(), sheetData); 3124 QCOMPARE(sheetData->columnCount(), 12); 3125 3126 QCOMPARE(sheetData->rowCount(), 5); 3127 QCOMPARE(sheetDataColumn0->rowCount(), 5); 3128 QCOMPARE(sheetDataColumn1->rowCount(), 5); 3129 3130 const auto* sheetDataColumn6 = sheetData->child<Column>(1); 3131 QCOMPARE(sheetDataColumn6->name(), QStringLiteral("Value6_")); 3132 const auto* sheetDataColumn5 = sheetData->child<Column>(2); 3133 QCOMPARE(sheetDataColumn5->name(), QStringLiteral("Value5_%")); 3134 3135 { 3136 QVector<double> ref{4., 4., 6., 6., 6.}; 3137 const auto* sheetCalculationsColumn = sheetCalculations->child<Column>(0); 3138 QCOMPARE(sheetCalculationsColumn->formulaData().at(0).column(), sheetDataColumn6); 3139 QCOMPARE(sheetCalculationsColumn->rowCount(), ref.count()); 3140 for (int i = 0; i < ref.count(); i++) { 3141 qDebug() << i; 3142 VALUES_EQUAL(sheetCalculationsColumn->doubleAt(i), ref.at(i)); 3143 } 3144 } 3145 3146 { 3147 QVector<double> ref{0., 0., 64., 102., 102.}; 3148 const auto* sheetCalculationsColumn = sheetCalculations->child<Column>(1); 3149 QCOMPARE(sheetCalculationsColumn->formulaData().at(0).column(), sheetDataColumn5); 3150 QCOMPARE(sheetCalculationsColumn->rowCount(), ref.count()); 3151 for (int i = 0; i < ref.count(); i++) { 3152 qDebug() << i; 3153 VALUES_EQUAL(sheetCalculationsColumn->doubleAt(i), ref.at(i)); 3154 } 3155 } 3156 } 3157 #endif // HAVE_VECTOR_BLF 3158 3159 /*! 3160 * Columns are named in the correct number order 3161 */ 3162 void SpreadsheetTest::testNaming() { 3163 Project project; 3164 auto* sheet = new Spreadsheet(QStringLiteral("test"), false); 3165 project.addChild(sheet); 3166 3167 new SpreadsheetModel(sheet); 3168 3169 QCOMPARE(sheet->columnCount(), 2); 3170 QCOMPARE(sheet->column(0)->name(), QStringLiteral("1")); 3171 QCOMPARE(sheet->column(1)->name(), QStringLiteral("2")); 3172 3173 sheet->setColumnCount(10); 3174 QCOMPARE(sheet->columnCount(), 10); 3175 for (int i = 0; i < 10; i++) { 3176 QCOMPARE(sheet->column(i)->name(), QString::number(i + 1)); 3177 } 3178 } 3179 3180 QTEST_MAIN(SpreadsheetTest)