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 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 "commonfrontend/ProjectExplorer.h" 0019 #include "commonfrontend/spreadsheet/SpreadsheetView.h" 0020 #include "kdefrontend/dockwidgets/SpreadsheetDock.h" 0021 #include "kdefrontend/spreadsheet/FlattenColumnsDialog.h" 0022 0023 #ifdef HAVE_VECTOR_BLF 0024 #include <Vector/BLF.h> 0025 #endif 0026 0027 #include <QClipboard> 0028 #include <QModelIndex> 0029 #include <QUndoStack> 0030 #if (QT_VERSION >= QT_VERSION_CHECK(5, 10, 0)) 0031 #include <QRandomGenerator> 0032 #endif 0033 0034 extern "C" { 0035 #include <gsl/gsl_math.h> 0036 } 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 /*! 0409 insert the data at the edge of the spreadsheet and paste the data. 0410 the spreadsheet has to be extended accordingly 0411 */ 0412 void SpreadsheetTest::testCopyPasteSizeChange01() { 0413 QLocale::setDefault(QLocale::C); // . as decimal separator 0414 Spreadsheet sheet(QStringLiteral("test"), false); 0415 sheet.setColumnCount(2); 0416 sheet.setRowCount(100); 0417 0418 const QString str = QStringLiteral( 0419 "1.1 2.2\n" 0420 "3.3 4.4"); 0421 QApplication::clipboard()->setText(str); 0422 0423 SpreadsheetView view(&sheet, false); 0424 view.goToCell(1, 1); // havigate to the edge of the spreadsheet 0425 view.pasteIntoSelection(); 0426 0427 // spreadsheet size 0428 QCOMPARE(sheet.columnCount(), 3); 0429 QCOMPARE(sheet.rowCount(), 100); 0430 0431 // column modes 0432 QCOMPARE(sheet.column(0)->columnMode(), AbstractColumn::ColumnMode::Double); 0433 QCOMPARE(sheet.column(1)->columnMode(), AbstractColumn::ColumnMode::Double); 0434 QCOMPARE(sheet.column(2)->columnMode(), AbstractColumn::ColumnMode::Double); 0435 0436 // values 0437 QCOMPARE((bool)std::isnan(sheet.column(0)->valueAt(0)), true); 0438 QCOMPARE((bool)std::isnan(sheet.column(1)->valueAt(0)), true); 0439 QCOMPARE((bool)std::isnan(sheet.column(2)->valueAt(0)), true); 0440 0441 QCOMPARE((bool)std::isnan(sheet.column(0)->valueAt(1)), true); 0442 QCOMPARE(sheet.column(1)->valueAt(1), 1.1); 0443 QCOMPARE(sheet.column(2)->valueAt(1), 2.2); 0444 0445 QCOMPARE((bool)std::isnan(sheet.column(0)->valueAt(2)), true); 0446 QCOMPARE(sheet.column(1)->valueAt(2), 3.3); 0447 QCOMPARE(sheet.column(2)->valueAt(2), 4.4); 0448 } 0449 0450 /////////////////////////////// Sorting tests //////////////////////////// 0451 // single column 0452 0453 /* 0454 * check sorting single column of double values with NaN ascending 0455 */ 0456 void SpreadsheetTest::testSortSingleNumeric1() { 0457 const QVector<double> xData{0.5, -0.2, GSL_NAN, 2.0, -1.0}; 0458 0459 Spreadsheet sheet(QStringLiteral("test"), false); 0460 sheet.setColumnCount(1); 0461 sheet.setRowCount(7); 0462 auto* col = sheet.column(0); 0463 col->replaceValues(0, xData); 0464 0465 // sort 0466 sheet.sortColumns(nullptr, {col}, true); 0467 0468 // values 0469 QCOMPARE(col->valueAt(0), -1.0); 0470 QCOMPARE(col->valueAt(1), -0.2); 0471 QCOMPARE(col->valueAt(2), 0.5); 0472 QCOMPARE(col->valueAt(3), 2.0); 0473 } 0474 0475 /* 0476 * check sorting single column of double values with NaN descending 0477 */ 0478 void SpreadsheetTest::testSortSingleNumeric2() { 0479 const QVector<double> xData{0.5, -0.2, GSL_NAN, 2.0, -1.0}; 0480 0481 Spreadsheet sheet(QStringLiteral("test"), false); 0482 sheet.setColumnCount(1); 0483 sheet.setRowCount(7); 0484 auto* col = sheet.column(0); 0485 col->replaceValues(0, xData); 0486 0487 // sort 0488 sheet.sortColumns(nullptr, {col}, false); 0489 0490 // values 0491 QCOMPARE(col->valueAt(0), 2.0); 0492 QCOMPARE(col->valueAt(1), 0.5); 0493 QCOMPARE(col->valueAt(2), -0.2); 0494 QCOMPARE(col->valueAt(3), -1.0); 0495 } 0496 0497 /* 0498 * check sorting single column of integer values with empty entries ascending 0499 */ 0500 void SpreadsheetTest::testSortSingleInteger1() { 0501 const QVector<int> xData1{4, 5, 2}; 0502 const QVector<int> xData2{3, 6, -1}; 0503 0504 Spreadsheet sheet(QStringLiteral("test"), false); 0505 sheet.setColumnCount(1); 0506 sheet.setRowCount(7); 0507 auto* col = sheet.column(0); 0508 col->setColumnMode(AbstractColumn::ColumnMode::Integer); 0509 col->replaceInteger(0, xData1); 0510 col->replaceInteger(4, xData2); 0511 0512 // sort 0513 sheet.sortColumns(nullptr, {col}, true); 0514 0515 // values 0516 QCOMPARE(col->integerAt(0), -1); 0517 QCOMPARE(col->integerAt(1), 0); 0518 QCOMPARE(col->integerAt(2), 2); 0519 QCOMPARE(col->integerAt(3), 3); 0520 QCOMPARE(col->integerAt(4), 4); 0521 QCOMPARE(col->integerAt(5), 5); 0522 QCOMPARE(col->integerAt(6), 6); 0523 } 0524 0525 /* 0526 * check sorting single column of integer values with empty entries ascending 0527 */ 0528 void SpreadsheetTest::testSortSingleInteger2() { 0529 const QVector<int> xData1{4, 5, 2}; 0530 const QVector<int> xData2{3, 6, -1}; 0531 0532 Spreadsheet sheet(QStringLiteral("test"), false); 0533 sheet.setColumnCount(1); 0534 sheet.setRowCount(7); 0535 auto* col = sheet.column(0); 0536 col->setColumnMode(AbstractColumn::ColumnMode::Integer); 0537 col->replaceInteger(0, xData1); 0538 col->replaceInteger(4, xData2); 0539 0540 // sort 0541 sheet.sortColumns(nullptr, {col}, false); 0542 0543 // values 0544 QCOMPARE(col->integerAt(6), -1); 0545 QCOMPARE(col->integerAt(5), 0); 0546 QCOMPARE(col->integerAt(4), 2); 0547 QCOMPARE(col->integerAt(3), 3); 0548 QCOMPARE(col->integerAt(2), 4); 0549 QCOMPARE(col->integerAt(1), 5); 0550 QCOMPARE(col->integerAt(0), 6); 0551 } 0552 0553 /* 0554 * check sorting single column of big int values with empty entries ascending 0555 */ 0556 void SpreadsheetTest::testSortSingleBigInt1() { 0557 const QVector<qint64> xData1{40000000000, 50000000000, 20000000000}; 0558 const QVector<qint64> xData2{30000000000, 60000000000, -10000000000}; 0559 0560 Spreadsheet sheet(QStringLiteral("test"), false); 0561 sheet.setColumnCount(1); 0562 sheet.setRowCount(7); 0563 auto* col = sheet.column(0); 0564 col->setColumnMode(AbstractColumn::ColumnMode::BigInt); 0565 col->replaceBigInt(0, xData1); 0566 col->replaceBigInt(4, xData2); 0567 0568 // sort 0569 sheet.sortColumns(nullptr, {col}, true); 0570 0571 // values 0572 QCOMPARE(col->bigIntAt(0), -10000000000ll); 0573 QCOMPARE(col->bigIntAt(1), 0); 0574 QCOMPARE(col->bigIntAt(2), 20000000000ll); 0575 QCOMPARE(col->bigIntAt(3), 30000000000ll); 0576 QCOMPARE(col->bigIntAt(4), 40000000000ll); 0577 QCOMPARE(col->bigIntAt(5), 50000000000ll); 0578 QCOMPARE(col->bigIntAt(6), 60000000000ll); 0579 } 0580 0581 /* 0582 * check sorting single column of big int values with empty entries descending 0583 */ 0584 void SpreadsheetTest::testSortSingleBigInt2() { 0585 const QVector<qint64> xData1{40000000000, 50000000000, 20000000000}; 0586 const QVector<qint64> xData2{30000000000, 60000000000, -10000000000}; 0587 0588 Spreadsheet sheet(QStringLiteral("test"), false); 0589 sheet.setColumnCount(1); 0590 sheet.setRowCount(7); 0591 auto* col = sheet.column(0); 0592 col->setColumnMode(AbstractColumn::ColumnMode::BigInt); 0593 col->replaceBigInt(0, xData1); 0594 col->replaceBigInt(4, xData2); 0595 0596 // sort 0597 sheet.sortColumns(nullptr, {col}, false); 0598 0599 // values 0600 QCOMPARE(col->bigIntAt(6), -10000000000ll); 0601 QCOMPARE(col->bigIntAt(5), 0); 0602 QCOMPARE(col->bigIntAt(4), 20000000000ll); 0603 QCOMPARE(col->bigIntAt(3), 30000000000ll); 0604 QCOMPARE(col->bigIntAt(2), 40000000000ll); 0605 QCOMPARE(col->bigIntAt(1), 50000000000ll); 0606 QCOMPARE(col->bigIntAt(0), 60000000000ll); 0607 } 0608 0609 /* 0610 * check sorting single column of text with empty entries ascending 0611 */ 0612 void SpreadsheetTest::testSortSingleText1() { 0613 const QVector<QString> xData{QStringLiteral("ben"), 0614 QStringLiteral("amy"), 0615 QStringLiteral("eddy"), 0616 QString(), 0617 QStringLiteral("carl"), 0618 QStringLiteral("dan")}; 0619 0620 Spreadsheet sheet(QStringLiteral("test"), false); 0621 sheet.setColumnCount(1); 0622 sheet.setRowCount(8); 0623 auto* col = sheet.column(0); 0624 col->setColumnMode(AbstractColumn::ColumnMode::Text); 0625 col->replaceTexts(0, xData); 0626 0627 // sort 0628 sheet.sortColumns(nullptr, {col}, true); 0629 0630 // values 0631 QCOMPARE(col->textAt(0), QLatin1String("amy")); 0632 QCOMPARE(col->textAt(1), QLatin1String("ben")); 0633 QCOMPARE(col->textAt(2), QLatin1String("carl")); 0634 QCOMPARE(col->textAt(3), QLatin1String("dan")); 0635 QCOMPARE(col->textAt(4), QLatin1String("eddy")); 0636 QCOMPARE(col->textAt(5), QString()); 0637 QCOMPARE(col->textAt(6), QString()); 0638 } 0639 0640 /* 0641 * check sorting single column of text with empty entries descending 0642 */ 0643 void SpreadsheetTest::testSortSingleText2() { 0644 const QVector<QString> xData = 0645 {QStringLiteral("ben"), QStringLiteral("amy"), QStringLiteral("eddy"), QString(), QStringLiteral("carl"), QStringLiteral("dan")}; 0646 0647 Spreadsheet sheet(QStringLiteral("test"), false); 0648 sheet.setColumnCount(1); 0649 sheet.setRowCount(8); 0650 auto* col = sheet.column(0); 0651 col->setColumnMode(AbstractColumn::ColumnMode::Text); 0652 col->replaceTexts(0, xData); 0653 0654 // sort 0655 sheet.sortColumns(nullptr, {col}, false); 0656 0657 // values 0658 QCOMPARE(col->textAt(0), QLatin1String("eddy")); 0659 QCOMPARE(col->textAt(1), QLatin1String("dan")); 0660 QCOMPARE(col->textAt(2), QLatin1String("carl")); 0661 QCOMPARE(col->textAt(3), QLatin1String("ben")); 0662 QCOMPARE(col->textAt(4), QLatin1String("amy")); 0663 QCOMPARE(col->textAt(5), QString()); 0664 QCOMPARE(col->textAt(6), QString()); 0665 } 0666 0667 /* 0668 * check sorting single column of datetimes with invalid entries ascending 0669 */ 0670 void SpreadsheetTest::testSortSingleDateTime1() { 0671 const QVector<QDateTime> xData{ 0672 QDateTime(QDate(2020, 02, 29), QTime(12, 12, 12)), 0673 QDateTime(QDate(2020, 02, 28), QTime(12, 12, 12)), 0674 QDateTime(QDate(2019, 02, 28), QTime(12, 12, 12)), 0675 QDateTime(QDate(2019, 02, 29), QTime(12, 12, 12)), // invalid 0676 QDateTime(QDate(2020, 02, 29), QTime(12, 12, 13)), 0677 QDateTime(QDate(2020, 02, 29), QTime(11, 12, 12)), 0678 }; 0679 0680 Spreadsheet sheet(QStringLiteral("test"), false); 0681 sheet.setColumnCount(1); 0682 sheet.setRowCount(8); 0683 auto* col{sheet.column(0)}; 0684 col->setColumnMode(AbstractColumn::ColumnMode::DateTime); 0685 col->replaceDateTimes(0, xData); 0686 0687 // sort 0688 sheet.sortColumns(nullptr, {col}, true); 0689 0690 // values 0691 QCOMPARE(col->dateTimeAt(0), QDateTime(QDate(2019, 02, 28), QTime(12, 12, 12))); 0692 QCOMPARE(col->dateTimeAt(1), QDateTime(QDate(2020, 02, 28), QTime(12, 12, 12))); 0693 QCOMPARE(col->dateTimeAt(2), QDateTime(QDate(2020, 02, 29), QTime(11, 12, 12))); 0694 QCOMPARE(col->dateTimeAt(3), QDateTime(QDate(2020, 02, 29), QTime(12, 12, 12))); 0695 QCOMPARE(col->dateTimeAt(4), QDateTime(QDate(2020, 02, 29), QTime(12, 12, 13))); 0696 } 0697 0698 /* 0699 * check sorting single column of datetimes with invalid entries descending 0700 */ 0701 void SpreadsheetTest::testSortSingleDateTime2() { 0702 const QVector<QDateTime> xData{ 0703 QDateTime(QDate(2020, 02, 29), QTime(12, 12, 12)), 0704 QDateTime(QDate(2020, 02, 28), QTime(12, 12, 12)), 0705 QDateTime(QDate(2019, 02, 28), QTime(12, 12, 12)), 0706 QDateTime(QDate(2019, 02, 29), QTime(12, 12, 12)), // invalid 0707 QDateTime(QDate(2020, 02, 29), QTime(12, 12, 13)), 0708 QDateTime(QDate(2020, 02, 29), QTime(11, 12, 12)), 0709 }; 0710 0711 Spreadsheet sheet(QStringLiteral("test"), false); 0712 sheet.setColumnCount(1); 0713 sheet.setRowCount(8); 0714 auto* col = sheet.column(0); 0715 col->setColumnMode(AbstractColumn::ColumnMode::DateTime); 0716 col->replaceDateTimes(0, xData); 0717 0718 // sort 0719 sheet.sortColumns(nullptr, {col}, false); 0720 0721 // values 0722 QCOMPARE(col->dateTimeAt(4), QDateTime(QDate(2019, 02, 28), QTime(12, 12, 12))); 0723 QCOMPARE(col->dateTimeAt(3), QDateTime(QDate(2020, 02, 28), QTime(12, 12, 12))); 0724 QCOMPARE(col->dateTimeAt(2), QDateTime(QDate(2020, 02, 29), QTime(11, 12, 12))); 0725 QCOMPARE(col->dateTimeAt(1), QDateTime(QDate(2020, 02, 29), QTime(12, 12, 12))); 0726 QCOMPARE(col->dateTimeAt(0), QDateTime(QDate(2020, 02, 29), QTime(12, 12, 13))); 0727 } 0728 0729 // multiple column 0730 /* 0731 * check sorting double values with NaN ascending as leading column 0732 */ 0733 void SpreadsheetTest::testSortNumeric1() { 0734 const QVector<double> xData{0.5, -0.2, GSL_NAN, 2.0, -1.0}; 0735 const QVector<int> yData{1, 2, 3, 4, 5, 6}; 0736 0737 Spreadsheet sheet(QStringLiteral("test"), false); 0738 sheet.setColumnCount(2); 0739 sheet.setRowCount(10); 0740 auto* col0{sheet.column(0)}; 0741 auto* col1{sheet.column(1)}; 0742 col0->replaceValues(0, xData); 0743 col1->setColumnMode(AbstractColumn::ColumnMode::Integer); 0744 col1->replaceInteger(0, yData); 0745 0746 // sort 0747 sheet.sortColumns(col0, {col0, col1}, true); 0748 0749 // values 0750 QCOMPARE(col0->valueAt(0), -1.0); 0751 QCOMPARE(col0->valueAt(1), -0.2); 0752 QCOMPARE(col0->valueAt(2), 0.5); 0753 QCOMPARE(col0->valueAt(3), 2.0); 0754 // QCOMPARE(col0->valueAt(4), GSL_NAN); 0755 QCOMPARE(col1->integerAt(0), 5); 0756 QCOMPARE(col1->integerAt(1), 2); 0757 QCOMPARE(col1->integerAt(2), 1); 0758 QCOMPARE(col1->integerAt(3), 4); 0759 QCOMPARE(col1->integerAt(4), 3); 0760 QCOMPARE(col1->integerAt(5), 6); 0761 } 0762 0763 /* 0764 * check sorting double values with NaN descending as leading column 0765 */ 0766 void SpreadsheetTest::testSortNumeric2() { 0767 const QVector<double> xData{0.5, -0.2, GSL_NAN, 2.0, -1.0}; 0768 const QVector<int> yData{1, 2, 3, 4, 5, 6, 7}; 0769 0770 Spreadsheet sheet(QStringLiteral("test"), false); 0771 sheet.setColumnCount(2); 0772 sheet.setRowCount(10); 0773 auto* col0{sheet.column(0)}; 0774 auto* col1{sheet.column(1)}; 0775 col0->replaceValues(0, xData); 0776 col1->setColumnMode(AbstractColumn::ColumnMode::Integer); 0777 col1->replaceInteger(0, yData); 0778 0779 // sort 0780 sheet.sortColumns(col0, {col0, col1}, false); 0781 0782 // values 0783 QCOMPARE(col0->valueAt(0), 2.0); 0784 QCOMPARE(col0->valueAt(1), 0.5); 0785 QCOMPARE(col0->valueAt(2), -0.2); 0786 QCOMPARE(col0->valueAt(3), -1.0); 0787 QCOMPARE(col1->integerAt(0), 4); 0788 QCOMPARE(col1->integerAt(1), 1); 0789 QCOMPARE(col1->integerAt(2), 2); 0790 QCOMPARE(col1->integerAt(3), 5); 0791 QCOMPARE(col1->integerAt(4), 3); 0792 QCOMPARE(col1->integerAt(5), 6); 0793 QCOMPARE(col1->integerAt(6), 7); 0794 } 0795 0796 /* 0797 * check sorting integer values with empty entries ascending as leading column 0798 */ 0799 void SpreadsheetTest::testSortInteger1() { 0800 const QVector<int> xData1{4, 5, 2}; 0801 const QVector<int> xData2{3, 6, -1}; 0802 const QVector<int> yData{1, 2, 3, 4, 5, 6, 7}; 0803 0804 Spreadsheet sheet(QStringLiteral("test"), false); 0805 sheet.setColumnCount(2); 0806 sheet.setRowCount(7); 0807 auto* col0{sheet.column(0)}; 0808 auto* col1{sheet.column(1)}; 0809 col0->setColumnMode(AbstractColumn::ColumnMode::Integer); 0810 col0->replaceInteger(0, xData1); 0811 col0->replaceInteger(4, xData2); 0812 col1->setColumnMode(AbstractColumn::ColumnMode::Integer); 0813 col1->replaceInteger(0, yData); 0814 0815 // sort 0816 sheet.sortColumns(col0, {col0, col1}, true); 0817 0818 // values 0819 QCOMPARE(col0->integerAt(0), -1); 0820 QCOMPARE(col0->integerAt(1), 0); 0821 QCOMPARE(col0->integerAt(2), 2); 0822 QCOMPARE(col0->integerAt(3), 3); 0823 QCOMPARE(col0->integerAt(4), 4); 0824 QCOMPARE(col0->integerAt(5), 5); 0825 QCOMPARE(col0->integerAt(6), 6); 0826 QCOMPARE(col1->integerAt(0), 7); 0827 QCOMPARE(col1->integerAt(1), 4); 0828 QCOMPARE(col1->integerAt(2), 3); 0829 QCOMPARE(col1->integerAt(3), 5); 0830 QCOMPARE(col1->integerAt(4), 1); 0831 QCOMPARE(col1->integerAt(5), 2); 0832 QCOMPARE(col1->integerAt(6), 6); 0833 } 0834 0835 /* 0836 * check sorting integer values with empty entries descending as leading column 0837 */ 0838 void SpreadsheetTest::testSortInteger2() { 0839 const QVector<int> xData1{4, 5, 2}; 0840 const QVector<int> xData2{3, 6, -1}; 0841 const QVector<int> yData{1, 2, 3, 4, 5, 6, 7}; 0842 0843 Spreadsheet sheet(QStringLiteral("test"), false); 0844 sheet.setColumnCount(2); 0845 sheet.setRowCount(7); 0846 auto* col0{sheet.column(0)}; 0847 auto* col1{sheet.column(1)}; 0848 col0->setColumnMode(AbstractColumn::ColumnMode::Integer); 0849 col0->replaceInteger(0, xData1); 0850 col0->replaceInteger(4, xData2); 0851 col1->setColumnMode(AbstractColumn::ColumnMode::Integer); 0852 col1->replaceInteger(0, yData); 0853 0854 // sort 0855 sheet.sortColumns(col0, {col0, col1}, false); 0856 0857 // values 0858 QCOMPARE(col0->integerAt(6), -1); 0859 QCOMPARE(col0->integerAt(5), 0); 0860 QCOMPARE(col0->integerAt(4), 2); 0861 QCOMPARE(col0->integerAt(3), 3); 0862 QCOMPARE(col0->integerAt(2), 4); 0863 QCOMPARE(col0->integerAt(1), 5); 0864 QCOMPARE(col0->integerAt(0), 6); 0865 QCOMPARE(col1->integerAt(6), 7); 0866 QCOMPARE(col1->integerAt(5), 4); 0867 QCOMPARE(col1->integerAt(4), 3); 0868 QCOMPARE(col1->integerAt(3), 5); 0869 QCOMPARE(col1->integerAt(2), 1); 0870 QCOMPARE(col1->integerAt(1), 2); 0871 QCOMPARE(col1->integerAt(0), 6); 0872 } 0873 0874 /* 0875 * check sorting big int values with empty entries ascending as leading column 0876 */ 0877 void SpreadsheetTest::testSortBigInt1() { 0878 Spreadsheet sheet(QStringLiteral("test"), false); 0879 sheet.setColumnCount(2); 0880 sheet.setRowCount(7); 0881 0882 QVector<qint64> xData1{40000000000, 50000000000, 20000000000}; 0883 QVector<qint64> xData2{30000000000, 60000000000, -10000000000}; 0884 QVector<qint64> yData{1, 2, 3, 4, 5, 6, 7}; 0885 0886 auto* col0{sheet.column(0)}; 0887 auto* col1{sheet.column(1)}; 0888 col0->setColumnMode(AbstractColumn::ColumnMode::BigInt); 0889 col0->replaceBigInt(0, xData1); 0890 col0->replaceBigInt(4, xData2); 0891 col1->setColumnMode(AbstractColumn::ColumnMode::BigInt); 0892 col1->replaceBigInt(0, yData); 0893 0894 // sort 0895 sheet.sortColumns(col0, {col0, col1}, true); 0896 0897 // values 0898 QCOMPARE(col0->bigIntAt(0), -10000000000ll); 0899 QCOMPARE(col0->bigIntAt(1), 0); 0900 QCOMPARE(col0->bigIntAt(2), 20000000000ll); 0901 QCOMPARE(col0->bigIntAt(3), 30000000000ll); 0902 QCOMPARE(col0->bigIntAt(4), 40000000000ll); 0903 QCOMPARE(col0->bigIntAt(5), 50000000000ll); 0904 QCOMPARE(col0->bigIntAt(6), 60000000000ll); 0905 QCOMPARE(col1->bigIntAt(0), 7); 0906 QCOMPARE(col1->bigIntAt(1), 4); 0907 QCOMPARE(col1->bigIntAt(2), 3); 0908 QCOMPARE(col1->bigIntAt(3), 5); 0909 QCOMPARE(col1->bigIntAt(4), 1); 0910 QCOMPARE(col1->bigIntAt(5), 2); 0911 QCOMPARE(col1->bigIntAt(6), 6); 0912 } 0913 0914 /* 0915 * check sorting big int values with empty entries descending as leading column 0916 */ 0917 void SpreadsheetTest::testSortBigInt2() { 0918 Spreadsheet sheet(QStringLiteral("test"), false); 0919 sheet.setColumnCount(2); 0920 sheet.setRowCount(7); 0921 0922 QVector<qint64> xData1{40000000000, 50000000000, 20000000000}; 0923 QVector<qint64> xData2{30000000000, 60000000000, -10000000000}; 0924 QVector<qint64> yData{1, 2, 3, 4, 5, 6, 7}; 0925 0926 auto* col0{sheet.column(0)}; 0927 auto* col1{sheet.column(1)}; 0928 col0->setColumnMode(AbstractColumn::ColumnMode::BigInt); 0929 col0->replaceBigInt(0, xData1); 0930 col0->replaceBigInt(4, xData2); 0931 col1->setColumnMode(AbstractColumn::ColumnMode::BigInt); 0932 col1->replaceBigInt(0, yData); 0933 0934 // sort 0935 sheet.sortColumns(col0, {col0, col1}, false); 0936 0937 // values 0938 QCOMPARE(col0->bigIntAt(6), -10000000000ll); 0939 QCOMPARE(col0->bigIntAt(5), 0); 0940 QCOMPARE(col0->bigIntAt(4), 20000000000ll); 0941 QCOMPARE(col0->bigIntAt(3), 30000000000ll); 0942 QCOMPARE(col0->bigIntAt(2), 40000000000ll); 0943 QCOMPARE(col0->bigIntAt(1), 50000000000ll); 0944 QCOMPARE(col0->bigIntAt(0), 60000000000ll); 0945 QCOMPARE(col1->bigIntAt(6), 7); 0946 QCOMPARE(col1->bigIntAt(5), 4); 0947 QCOMPARE(col1->bigIntAt(4), 3); 0948 QCOMPARE(col1->bigIntAt(3), 5); 0949 QCOMPARE(col1->bigIntAt(2), 1); 0950 QCOMPARE(col1->bigIntAt(1), 2); 0951 QCOMPARE(col1->bigIntAt(0), 6); 0952 } 0953 0954 /* 0955 * check sorting text with empty entries ascending as leading column 0956 */ 0957 void SpreadsheetTest::testSortText1() { 0958 Spreadsheet sheet(QStringLiteral("test"), false); 0959 sheet.setColumnCount(2); 0960 sheet.setRowCount(8); 0961 0962 QVector<QString> xData{QStringLiteral("ben"), QStringLiteral("amy"), QStringLiteral("eddy"), QString(), QStringLiteral("carl"), QStringLiteral("dan")}; 0963 QVector<int> yData{1, 2, 3, 4, 5, 6, 7}; 0964 0965 auto* col0{sheet.column(0)}; 0966 auto* col1{sheet.column(1)}; 0967 col0->setColumnMode(AbstractColumn::ColumnMode::Text); 0968 col0->replaceTexts(0, xData); 0969 col1->setColumnMode(AbstractColumn::ColumnMode::Integer); 0970 col1->replaceInteger(0, yData); 0971 0972 // sort 0973 sheet.sortColumns(col0, {col0, col1}, true); 0974 0975 // values 0976 QCOMPARE(col0->textAt(0), QLatin1String("amy")); 0977 QCOMPARE(col0->textAt(1), QLatin1String("ben")); 0978 QCOMPARE(col0->textAt(2), QLatin1String("carl")); 0979 QCOMPARE(col0->textAt(3), QLatin1String("dan")); 0980 QCOMPARE(col0->textAt(4), QLatin1String("eddy")); 0981 QCOMPARE(col0->textAt(5), QString()); 0982 QCOMPARE(col0->textAt(6), QString()); 0983 QCOMPARE(col1->integerAt(0), 2); 0984 QCOMPARE(col1->integerAt(1), 1); 0985 QCOMPARE(col1->integerAt(2), 5); 0986 QCOMPARE(col1->integerAt(3), 6); 0987 QCOMPARE(col1->integerAt(4), 3); 0988 QCOMPARE(col1->integerAt(5), 4); 0989 QCOMPARE(col1->integerAt(6), 7); 0990 } 0991 0992 /* 0993 * check sorting text with empty entries descending as leading column 0994 */ 0995 void SpreadsheetTest::testSortText2() { 0996 Spreadsheet sheet(QStringLiteral("test"), false); 0997 sheet.setColumnCount(2); 0998 sheet.setRowCount(8); 0999 1000 QVector<QString> xData{QStringLiteral("ben"), QStringLiteral("amy"), QStringLiteral("eddy"), QString(), QStringLiteral("carl"), QStringLiteral("dan")}; 1001 QVector<int> yData{1, 2, 3, 4, 5, 6, 7}; 1002 1003 auto* col0{sheet.column(0)}; 1004 auto* col1{sheet.column(1)}; 1005 col0->setColumnMode(AbstractColumn::ColumnMode::Text); 1006 col0->replaceTexts(0, xData); 1007 col1->setColumnMode(AbstractColumn::ColumnMode::Integer); 1008 col1->replaceInteger(0, yData); 1009 1010 // sort 1011 sheet.sortColumns(col0, {col0, col1}, false); 1012 1013 // values 1014 QCOMPARE(col0->textAt(4), QLatin1String("amy")); 1015 QCOMPARE(col0->textAt(3), QLatin1String("ben")); 1016 QCOMPARE(col0->textAt(2), QLatin1String("carl")); 1017 QCOMPARE(col0->textAt(1), QLatin1String("dan")); 1018 QCOMPARE(col0->textAt(0), QLatin1String("eddy")); 1019 QCOMPARE(col0->textAt(5), QString()); 1020 QCOMPARE(col0->textAt(6), QString()); 1021 QCOMPARE(col1->integerAt(4), 2); 1022 QCOMPARE(col1->integerAt(3), 1); 1023 QCOMPARE(col1->integerAt(2), 5); 1024 QCOMPARE(col1->integerAt(1), 6); 1025 QCOMPARE(col1->integerAt(0), 3); 1026 QCOMPARE(col1->integerAt(5), 4); 1027 QCOMPARE(col1->integerAt(6), 7); 1028 } 1029 1030 /* 1031 * check sorting datetimes with invalid entries ascending as leading column 1032 */ 1033 void SpreadsheetTest::testSortDateTime1() { 1034 Spreadsheet sheet(QStringLiteral("test"), false); 1035 sheet.setColumnCount(2); 1036 sheet.setRowCount(8); 1037 1038 QVector<QDateTime> xData{ 1039 QDateTime(QDate(2020, 02, 29), QTime(12, 12, 12)), 1040 QDateTime(QDate(2020, 02, 28), QTime(12, 12, 12)), 1041 QDateTime(QDate(2019, 02, 28), QTime(12, 12, 12)), 1042 QDateTime(QDate(2019, 02, 29), QTime(12, 12, 12)), // invalid 1043 QDateTime(QDate(2020, 02, 29), QTime(12, 12, 13)), 1044 QDateTime(QDate(2020, 02, 29), QTime(11, 12, 12)), 1045 }; 1046 QVector<int> yData = {1, 2, 3, 4, 5, 6, 7}; 1047 1048 auto* col0{sheet.column(0)}; 1049 auto* col1{sheet.column(1)}; 1050 col0->setColumnMode(AbstractColumn::ColumnMode::DateTime); 1051 col0->replaceDateTimes(0, xData); 1052 col1->setColumnMode(AbstractColumn::ColumnMode::Integer); 1053 col1->replaceInteger(0, yData); 1054 1055 // sort 1056 sheet.sortColumns(col0, {col0, col1}, true); 1057 1058 // values 1059 QCOMPARE(col0->dateTimeAt(0), QDateTime(QDate(2019, 02, 28), QTime(12, 12, 12))); 1060 QCOMPARE(col0->dateTimeAt(1), QDateTime(QDate(2020, 02, 28), QTime(12, 12, 12))); 1061 QCOMPARE(col0->dateTimeAt(2), QDateTime(QDate(2020, 02, 29), QTime(11, 12, 12))); 1062 QCOMPARE(col0->dateTimeAt(3), QDateTime(QDate(2020, 02, 29), QTime(12, 12, 12))); 1063 QCOMPARE(col0->dateTimeAt(4), QDateTime(QDate(2020, 02, 29), QTime(12, 12, 13))); 1064 QCOMPARE(col1->integerAt(0), 3); 1065 QCOMPARE(col1->integerAt(1), 2); 1066 QCOMPARE(col1->integerAt(2), 6); 1067 QCOMPARE(col1->integerAt(3), 1); 1068 QCOMPARE(col1->integerAt(4), 5); 1069 QCOMPARE(col1->integerAt(5), 4); 1070 QCOMPARE(col1->integerAt(6), 7); 1071 } 1072 1073 /* 1074 * check sorting datetimes with invalid entries descending as leading column 1075 */ 1076 void SpreadsheetTest::testSortDateTime2() { 1077 const QVector<QDateTime> xData{ 1078 QDateTime(QDate(2020, 02, 29), QTime(12, 12, 12)), 1079 QDateTime(QDate(2020, 02, 28), QTime(12, 12, 12)), 1080 QDateTime(QDate(2019, 02, 28), QTime(12, 12, 12)), 1081 QDateTime(QDate(2019, 02, 29), QTime(12, 12, 12)), // invalid 1082 QDateTime(QDate(2020, 02, 29), QTime(12, 12, 13)), 1083 QDateTime(QDate(2020, 02, 29), QTime(11, 12, 12)), 1084 }; 1085 const QVector<int> yData = {1, 2, 3, 4, 5, 6, 7}; 1086 1087 Spreadsheet sheet(QStringLiteral("test"), false); 1088 sheet.setColumnCount(2); 1089 sheet.setRowCount(8); 1090 auto* col0{sheet.column(0)}; 1091 auto* col1{sheet.column(1)}; 1092 col0->setColumnMode(AbstractColumn::ColumnMode::DateTime); 1093 col0->replaceDateTimes(0, xData); 1094 col1->setColumnMode(AbstractColumn::ColumnMode::Integer); 1095 col1->replaceInteger(0, yData); 1096 1097 // sort 1098 sheet.sortColumns(col0, {col0, col1}, false); 1099 1100 // values 1101 QCOMPARE(col0->dateTimeAt(4), QDateTime(QDate(2019, 02, 28), QTime(12, 12, 12))); 1102 QCOMPARE(col0->dateTimeAt(3), QDateTime(QDate(2020, 02, 28), QTime(12, 12, 12))); 1103 QCOMPARE(col0->dateTimeAt(2), QDateTime(QDate(2020, 02, 29), QTime(11, 12, 12))); 1104 QCOMPARE(col0->dateTimeAt(1), QDateTime(QDate(2020, 02, 29), QTime(12, 12, 12))); 1105 QCOMPARE(col0->dateTimeAt(0), QDateTime(QDate(2020, 02, 29), QTime(12, 12, 13))); 1106 QCOMPARE(col1->integerAt(4), 3); 1107 QCOMPARE(col1->integerAt(3), 2); 1108 QCOMPARE(col1->integerAt(2), 6); 1109 QCOMPARE(col1->integerAt(1), 1); 1110 QCOMPARE(col1->integerAt(0), 5); 1111 QCOMPARE(col1->integerAt(5), 4); 1112 QCOMPARE(col1->integerAt(6), 7); 1113 } 1114 1115 // performance 1116 1117 /* 1118 * check performance of sorting double values in single column 1119 */ 1120 void SpreadsheetTest::testSortPerformanceNumeric1() { 1121 Spreadsheet sheet(QStringLiteral("test"), false); 1122 sheet.setColumnCount(1); 1123 sheet.setRowCount(10000); 1124 1125 QVector<double> xData; 1126 WARN("CREATE DATA") 1127 for (int i = 0; i < sheet.rowCount(); i++) 1128 #if (QT_VERSION >= QT_VERSION_CHECK(5, 10, 0)) 1129 xData << QRandomGenerator::global()->generateDouble(); 1130 #else 1131 xData << (double)(qrand()) / RAND_MAX; 1132 #endif 1133 1134 auto* col = sheet.column(0); 1135 col->replaceValues(0, xData); 1136 1137 // sort 1138 QBENCHMARK { sheet.sortColumns(nullptr, {col}, true); } 1139 } 1140 1141 /* 1142 * check performance of sorting double values with two columns 1143 */ 1144 void SpreadsheetTest::testSortPerformanceNumeric2() { 1145 Spreadsheet sheet(QStringLiteral("test"), false); 1146 sheet.setColumnCount(2); 1147 sheet.setRowCount(10000); 1148 1149 QVector<double> xData; 1150 QVector<int> yData; 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 yData << i + 1; 1159 } 1160 1161 auto* col0{sheet.column(0)}; 1162 auto* col1{sheet.column(1)}; 1163 col0->replaceValues(0, xData); 1164 col1->setColumnMode(AbstractColumn::ColumnMode::Integer); 1165 col1->replaceInteger(0, yData); 1166 1167 // sort 1168 QBENCHMARK { sheet.sortColumns(col0, {col0, col1}, true); } 1169 } 1170 1171 void SpreadsheetTest::testFlatten00() { 1172 Project project; 1173 auto* sheet = new Spreadsheet(QStringLiteral("test"), false); 1174 project.addChild(sheet); 1175 sheet->setColumnCount(5); 1176 sheet->setRowCount(4); 1177 1178 // "Year" 1179 auto* col1 = sheet->column(0); 1180 col1->setName(QStringLiteral("Year")); 1181 col1->setColumnMode(AbstractColumn::ColumnMode::Text); 1182 col1->setTextAt(0, QStringLiteral("2021")); 1183 col1->setTextAt(1, QStringLiteral("2022")); 1184 col1->setTextAt(2, QStringLiteral("2021")); 1185 col1->setTextAt(3, QStringLiteral("2022")); 1186 1187 // "Country" 1188 auto* col2 = sheet->column(1); 1189 col2->setName(QStringLiteral("Country")); 1190 col2->setColumnMode(AbstractColumn::ColumnMode::Text); 1191 col2->setTextAt(0, QStringLiteral("Germany")); 1192 col2->setTextAt(1, QStringLiteral("Germany")); 1193 col2->setTextAt(2, QStringLiteral("Poland")); 1194 col2->setTextAt(3, QStringLiteral("Poland")); 1195 1196 // "Sales for Product 1" 1197 auto* col3 = sheet->column(2); 1198 col3->setName(QStringLiteral("Product 1")); 1199 col3->setColumnMode(AbstractColumn::ColumnMode::Integer); 1200 col3->setIntegerAt(0, 1); 1201 col3->setIntegerAt(1, 10); 1202 col3->setIntegerAt(2, 4); 1203 col3->setIntegerAt(3, 40); 1204 1205 // "Sales for Product 2" 1206 auto* col4 = sheet->column(3); 1207 col4->setName(QStringLiteral("Product 2")); 1208 col4->setColumnMode(AbstractColumn::ColumnMode::Integer); 1209 col4->setIntegerAt(0, 2); 1210 col4->setIntegerAt(1, 20); 1211 col4->setIntegerAt(2, 5); 1212 col4->setIntegerAt(3, 50); 1213 1214 // "Sales for Product 3" 1215 auto* col5 = sheet->column(4); 1216 col5->setName(QStringLiteral("Product 3")); 1217 col5->setColumnMode(AbstractColumn::ColumnMode::Integer); 1218 col5->setIntegerAt(0, 3); 1219 col5->setIntegerAt(1, 30); 1220 col5->setIntegerAt(2, 6); 1221 col5->setIntegerAt(3, 60); 1222 1223 // flatten the product columns relatively to year and country 1224 FlattenColumnsDialog dlg(sheet); 1225 QVector<Column*> referenceColumns; 1226 referenceColumns << col1; 1227 referenceColumns << col2; 1228 1229 QVector<Column*> valueColumns; 1230 valueColumns << col3; 1231 valueColumns << col4; 1232 valueColumns << col5; 1233 1234 dlg.flatten(sheet, valueColumns, referenceColumns); 1235 1236 // checks 1237 // make sure a new target spreadsheet with the flattened data was created 1238 const auto& sheets = project.children<Spreadsheet>(); 1239 QCOMPARE(sheets.count(), 2); 1240 auto* targetSheet = sheets.at(1); 1241 QCOMPARE(targetSheet->columnCount(), 4); // two reference columns, column "Category" and column "Value" 1242 QCOMPARE(targetSheet->rowCount(), 12); 1243 1244 // check values 1245 col1 = targetSheet->column(0); 1246 QCOMPARE(col1->textAt(0), QStringLiteral("2021")); 1247 QCOMPARE(col1->textAt(1), QStringLiteral("2021")); 1248 QCOMPARE(col1->textAt(2), QStringLiteral("2021")); 1249 QCOMPARE(col1->textAt(3), QStringLiteral("2022")); 1250 QCOMPARE(col1->textAt(4), QStringLiteral("2022")); 1251 QCOMPARE(col1->textAt(5), QStringLiteral("2022")); 1252 QCOMPARE(col1->textAt(6), QStringLiteral("2021")); 1253 QCOMPARE(col1->textAt(7), QStringLiteral("2021")); 1254 QCOMPARE(col1->textAt(8), QStringLiteral("2021")); 1255 QCOMPARE(col1->textAt(9), QStringLiteral("2022")); 1256 QCOMPARE(col1->textAt(10), QStringLiteral("2022")); 1257 QCOMPARE(col1->textAt(11), QStringLiteral("2022")); 1258 1259 col4 = targetSheet->column(3); 1260 QCOMPARE(col4->integerAt(0), 1); 1261 QCOMPARE(col4->integerAt(1), 2); 1262 QCOMPARE(col4->integerAt(2), 3); 1263 QCOMPARE(col4->integerAt(3), 10); 1264 QCOMPARE(col4->integerAt(4), 20); 1265 QCOMPARE(col4->integerAt(5), 30); 1266 QCOMPARE(col4->integerAt(6), 4); 1267 QCOMPARE(col4->integerAt(7), 5); 1268 QCOMPARE(col4->integerAt(8), 6); 1269 QCOMPARE(col4->integerAt(9), 40); 1270 QCOMPARE(col4->integerAt(10), 50); 1271 QCOMPARE(col4->integerAt(11), 60); 1272 } 1273 1274 // test with a missing value in one of the reference columns 1275 void SpreadsheetTest::testFlatten01() { 1276 Project project; 1277 auto* sheet = new Spreadsheet(QStringLiteral("test"), false); 1278 project.addChild(sheet); 1279 sheet->setColumnCount(5); 1280 sheet->setRowCount(2); 1281 1282 // "Year" 1283 auto* col1 = sheet->column(0); 1284 col1->setName(QStringLiteral("Year")); 1285 col1->setColumnMode(AbstractColumn::ColumnMode::Text); 1286 col1->setTextAt(0, QStringLiteral("2021")); 1287 col1->setTextAt(1, QStringLiteral("2022")); 1288 1289 // "Country" 1290 auto* col2 = sheet->column(1); 1291 col2->setName(QStringLiteral("Country")); 1292 col2->setColumnMode(AbstractColumn::ColumnMode::Text); 1293 col2->setTextAt(0, QStringLiteral("Germany")); 1294 // missing value in the second row 1295 1296 // "Sales for Product 1" 1297 auto* col3 = sheet->column(2); 1298 col3->setName(QStringLiteral("Product 1")); 1299 col3->setColumnMode(AbstractColumn::ColumnMode::Integer); 1300 col3->setIntegerAt(0, 1); 1301 col3->setIntegerAt(1, 10); 1302 1303 // "Sales for Product 2" 1304 auto* col4 = sheet->column(3); 1305 col4->setName(QStringLiteral("Product 2")); 1306 col4->setColumnMode(AbstractColumn::ColumnMode::Integer); 1307 col4->setIntegerAt(0, 2); 1308 col4->setIntegerAt(1, 20); 1309 1310 // "Sales for Product 3" 1311 auto* col5 = sheet->column(4); 1312 col5->setName(QStringLiteral("Product 3")); 1313 col5->setColumnMode(AbstractColumn::ColumnMode::Integer); 1314 col5->setIntegerAt(0, 3); 1315 col5->setIntegerAt(1, 30); 1316 1317 // flatten the product columns relatively to year and country 1318 FlattenColumnsDialog dlg(sheet); 1319 QVector<Column*> referenceColumns; 1320 referenceColumns << col1; 1321 referenceColumns << col2; 1322 1323 QVector<Column*> valueColumns; 1324 valueColumns << col3; 1325 valueColumns << col4; 1326 valueColumns << col5; 1327 1328 dlg.flatten(sheet, valueColumns, referenceColumns); 1329 1330 // checks 1331 // make sure a new target spreadsheet with the flattened data was created 1332 const auto& sheets = project.children<Spreadsheet>(); 1333 QCOMPARE(sheets.count(), 2); 1334 auto* targetSheet = sheets.at(1); 1335 QCOMPARE(targetSheet->columnCount(), 4); // two reference columns, column "Category" and column "Value" 1336 QCOMPARE(targetSheet->rowCount(), 6); 1337 1338 // check values 1339 col1 = targetSheet->column(0); 1340 QCOMPARE(col1->textAt(0), QStringLiteral("2021")); 1341 QCOMPARE(col1->textAt(1), QStringLiteral("2021")); 1342 QCOMPARE(col1->textAt(2), QStringLiteral("2021")); 1343 QCOMPARE(col1->textAt(3), QStringLiteral("2022")); 1344 QCOMPARE(col1->textAt(4), QStringLiteral("2022")); 1345 QCOMPARE(col1->textAt(5), QStringLiteral("2022")); 1346 1347 col1 = targetSheet->column(1); 1348 QCOMPARE(col1->textAt(0), QStringLiteral("Germany")); 1349 QCOMPARE(col1->textAt(1), QStringLiteral("Germany")); 1350 QCOMPARE(col1->textAt(2), QStringLiteral("Germany")); 1351 QCOMPARE(col1->textAt(3), QString()); 1352 QCOMPARE(col1->textAt(4), QString()); 1353 QCOMPARE(col1->textAt(5), QString()); 1354 1355 col4 = targetSheet->column(3); 1356 QCOMPARE(col4->integerAt(0), 1); 1357 QCOMPARE(col4->integerAt(1), 2); 1358 QCOMPARE(col4->integerAt(2), 3); 1359 QCOMPARE(col4->integerAt(3), 10); 1360 QCOMPARE(col4->integerAt(4), 20); 1361 QCOMPARE(col4->integerAt(5), 30); 1362 } 1363 1364 // test with missing values in the reference columns - no result should be produced for these rows 1365 void SpreadsheetTest::testFlatten02() { 1366 Project project; 1367 auto* sheet = new Spreadsheet(QStringLiteral("test"), false); 1368 project.addChild(sheet); 1369 sheet->setColumnCount(5); 1370 sheet->setRowCount(2); 1371 1372 // "Year" 1373 auto* col1 = sheet->column(0); 1374 col1->setName(QStringLiteral("Year")); 1375 col1->setColumnMode(AbstractColumn::ColumnMode::Text); 1376 col1->setTextAt(0, QStringLiteral("2021")); 1377 // missing value in the second row 1378 1379 // "Country" 1380 auto* col2 = sheet->column(1); 1381 col2->setName(QStringLiteral("Country")); 1382 col2->setColumnMode(AbstractColumn::ColumnMode::Text); 1383 col2->setTextAt(0, QStringLiteral("Germany")); 1384 // missing value in the second rows 1385 1386 // "Sales for Product 1" 1387 auto* col3 = sheet->column(2); 1388 col3->setName(QStringLiteral("Product 1")); 1389 col3->setColumnMode(AbstractColumn::ColumnMode::Integer); 1390 col3->setIntegerAt(0, 1); 1391 col3->setIntegerAt(1, 10); 1392 1393 // "Sales for Product 2" 1394 auto* col4 = sheet->column(3); 1395 col4->setName(QStringLiteral("Product 2")); 1396 col4->setColumnMode(AbstractColumn::ColumnMode::Integer); 1397 col4->setIntegerAt(0, 2); 1398 col4->setIntegerAt(1, 20); 1399 1400 // "Sales for Product 3" 1401 auto* col5 = sheet->column(4); 1402 col5->setName(QStringLiteral("Product 3")); 1403 col5->setColumnMode(AbstractColumn::ColumnMode::Integer); 1404 col5->setIntegerAt(0, 3); 1405 col5->setIntegerAt(1, 30); 1406 1407 // flatten the product columns relatively to year and country 1408 FlattenColumnsDialog dlg(sheet); 1409 QVector<Column*> referenceColumns; 1410 referenceColumns << col1; 1411 referenceColumns << col2; 1412 1413 QVector<Column*> valueColumns; 1414 valueColumns << col3; 1415 valueColumns << col4; 1416 valueColumns << col5; 1417 1418 dlg.flatten(sheet, valueColumns, referenceColumns); 1419 1420 // checks 1421 // make sure a new target spreadsheet with the flattened data was created 1422 const auto& sheets = project.children<Spreadsheet>(); 1423 QCOMPARE(sheets.count(), 2); 1424 auto* targetSheet = sheets.at(1); 1425 QCOMPARE(targetSheet->columnCount(), 4); // two reference columns, column "Category" and column "Value" 1426 QCOMPARE(targetSheet->rowCount(), 3); 1427 1428 // check values 1429 col1 = targetSheet->column(0); 1430 QCOMPARE(col1->textAt(0), QStringLiteral("2021")); 1431 QCOMPARE(col1->textAt(1), QStringLiteral("2021")); 1432 QCOMPARE(col1->textAt(2), QStringLiteral("2021")); 1433 1434 col1 = targetSheet->column(1); 1435 QCOMPARE(col1->textAt(0), QStringLiteral("Germany")); 1436 QCOMPARE(col1->textAt(1), QStringLiteral("Germany")); 1437 QCOMPARE(col1->textAt(2), QStringLiteral("Germany")); 1438 1439 col4 = targetSheet->column(3); 1440 QCOMPARE(col4->integerAt(0), 1); 1441 QCOMPARE(col4->integerAt(1), 2); 1442 QCOMPARE(col4->integerAt(2), 3); 1443 } 1444 1445 // test with missing no reference columns 1446 void SpreadsheetTest::testFlatten03() { 1447 Project project; 1448 auto* sheet = new Spreadsheet(QStringLiteral("test"), false); 1449 project.addChild(sheet); 1450 sheet->setColumnCount(3); 1451 sheet->setRowCount(2); 1452 1453 // "Sales for Product 1" 1454 auto* col1 = sheet->column(0); 1455 col1->setName(QStringLiteral("Product 1")); 1456 col1->setColumnMode(AbstractColumn::ColumnMode::Integer); 1457 col1->setIntegerAt(0, 1); 1458 col1->setIntegerAt(1, 10); 1459 1460 // "Sales for Product 2" 1461 auto* col2 = sheet->column(1); 1462 col2->setName(QStringLiteral("Product 2")); 1463 col2->setColumnMode(AbstractColumn::ColumnMode::Integer); 1464 col2->setIntegerAt(0, 2); 1465 col2->setIntegerAt(1, 20); 1466 1467 // "Sales for Product 3" 1468 auto* col3 = sheet->column(2); 1469 col3->setName(QStringLiteral("Product 3")); 1470 col3->setColumnMode(AbstractColumn::ColumnMode::Integer); 1471 col3->setIntegerAt(0, 3); 1472 col3->setIntegerAt(1, 30); 1473 1474 // flatten the product columns without any reference columns 1475 QVector<Column*> valueColumns; 1476 valueColumns << col1; 1477 valueColumns << col2; 1478 valueColumns << col3; 1479 1480 FlattenColumnsDialog dlg(sheet); 1481 dlg.flatten(sheet, valueColumns, QVector<Column*>()); 1482 1483 // checks 1484 // make sure a new target spreadsheet with the flattened data was created 1485 const auto& sheets = project.children<Spreadsheet>(); 1486 QCOMPARE(sheets.count(), 2); 1487 auto* targetSheet = sheets.at(1); 1488 QCOMPARE(targetSheet->columnCount(), 2); // no reference columns, only column "Category" and column "Value" 1489 QCOMPARE(targetSheet->rowCount(), 6); 1490 1491 // check values 1492 col1 = targetSheet->column(0); 1493 QCOMPARE(col1->textAt(0), QStringLiteral("Product 1")); 1494 QCOMPARE(col1->textAt(1), QStringLiteral("Product 2")); 1495 QCOMPARE(col1->textAt(2), QStringLiteral("Product 3")); 1496 QCOMPARE(col1->textAt(3), QStringLiteral("Product 1")); 1497 QCOMPARE(col1->textAt(4), QStringLiteral("Product 2")); 1498 QCOMPARE(col1->textAt(5), QStringLiteral("Product 3")); 1499 1500 col2 = targetSheet->column(1); 1501 QCOMPARE(col2->integerAt(0), 1); 1502 QCOMPARE(col2->integerAt(1), 2); 1503 QCOMPARE(col2->integerAt(2), 3); 1504 QCOMPARE(col2->integerAt(3), 10); 1505 QCOMPARE(col2->integerAt(4), 20); 1506 QCOMPARE(col2->integerAt(5), 30); 1507 } 1508 1509 void SpreadsheetTest::testInsertRows() { 1510 Project project; 1511 auto* sheet = new Spreadsheet(QStringLiteral("test"), false); 1512 project.addChild(sheet); 1513 1514 auto* model = new SpreadsheetModel(sheet); 1515 int rowsAboutToBeInsertedCounter = 0; 1516 connect(model, &SpreadsheetModel::rowsAboutToBeInserted, [this, &rowsAboutToBeInsertedCounter]() { 1517 rowsAboutToBeInsertedCounter++; 1518 }); 1519 int rowsInsertedCounter = 0; 1520 connect(model, &SpreadsheetModel::rowsInserted, [this, &rowsInsertedCounter]() { 1521 rowsInsertedCounter++; 1522 }); 1523 int rowsAboutToBeRemovedCounter = 0; 1524 connect(model, &SpreadsheetModel::rowsAboutToBeRemoved, [this, &rowsAboutToBeRemovedCounter]() { 1525 rowsAboutToBeRemovedCounter++; 1526 }); 1527 int rowsRemovedCounter = 0; 1528 connect(model, &SpreadsheetModel::rowsRemoved, [this, &rowsRemovedCounter]() { 1529 rowsRemovedCounter++; 1530 }); 1531 1532 QCOMPARE(sheet->rowCount(), 100); 1533 sheet->setRowCount(101); // No crash shall happen 1534 QCOMPARE(sheet->rowCount(), 101); 1535 1536 sheet->undoStack()->undo(); 1537 QCOMPARE(sheet->rowCount(), 100); 1538 sheet->undoStack()->redo(); 1539 QCOMPARE(sheet->rowCount(), 101); 1540 1541 QCOMPARE(rowsAboutToBeInsertedCounter, 2); // set and redo() 1542 QCOMPARE(rowsInsertedCounter, 2); // set and redo() 1543 QCOMPARE(rowsAboutToBeRemovedCounter, 1); // undo() 1544 QCOMPARE(rowsRemovedCounter, 1); // undo() 1545 } 1546 1547 void SpreadsheetTest::testRemoveRows() { 1548 Project project; 1549 auto* sheet = new Spreadsheet(QStringLiteral("test"), false); 1550 project.addChild(sheet); 1551 1552 auto* model = new SpreadsheetModel(sheet); 1553 int rowsAboutToBeInsertedCounter = 0; 1554 connect(model, &SpreadsheetModel::rowsAboutToBeInserted, [this, &rowsAboutToBeInsertedCounter]() { 1555 rowsAboutToBeInsertedCounter++; 1556 }); 1557 int rowsInsertedCounter = 0; 1558 connect(model, &SpreadsheetModel::rowsInserted, [this, &rowsInsertedCounter]() { 1559 rowsInsertedCounter++; 1560 }); 1561 int rowsAboutToBeRemovedCounter = 0; 1562 connect(model, &SpreadsheetModel::rowsAboutToBeRemoved, [this, &rowsAboutToBeRemovedCounter]() { 1563 rowsAboutToBeRemovedCounter++; 1564 }); 1565 int rowsRemovedCounter = 0; 1566 connect(model, &SpreadsheetModel::rowsRemoved, [this, &rowsRemovedCounter]() { 1567 rowsRemovedCounter++; 1568 }); 1569 1570 QCOMPARE(sheet->rowCount(), 100); 1571 sheet->setRowCount(10); // No crash shall happen 1572 QCOMPARE(sheet->rowCount(), 10); 1573 1574 sheet->undoStack()->undo(); 1575 QCOMPARE(sheet->rowCount(), 100); 1576 sheet->undoStack()->redo(); 1577 QCOMPARE(sheet->rowCount(), 10); 1578 1579 QCOMPARE(rowsAboutToBeInsertedCounter, 1); // undo 1580 QCOMPARE(rowsInsertedCounter, 1); // undo 1581 QCOMPARE(rowsAboutToBeRemovedCounter, 2); // set and redo() 1582 QCOMPARE(rowsRemovedCounter, 2); // set and redo() 1583 } 1584 1585 void SpreadsheetTest::testInsertColumns() { 1586 Project project; 1587 auto* sheet = new Spreadsheet(QStringLiteral("test"), false); 1588 project.addChild(sheet); 1589 1590 auto* model = new SpreadsheetModel(sheet); 1591 1592 int columnsAboutToBeInsertedCounter = 0; 1593 connect(model, &SpreadsheetModel::columnsAboutToBeInserted, [this, &columnsAboutToBeInsertedCounter]() { 1594 columnsAboutToBeInsertedCounter++; 1595 }); 1596 int columnsInsertedCounter = 0; 1597 connect(model, &SpreadsheetModel::columnsInserted, [this, &columnsInsertedCounter]() { 1598 columnsInsertedCounter++; 1599 }); 1600 int columnsAboutToBeRemovedCounter = 0; 1601 connect(model, &SpreadsheetModel::columnsAboutToBeRemoved, [this, &columnsAboutToBeRemovedCounter]() { 1602 columnsAboutToBeRemovedCounter++; 1603 }); 1604 int columnsRemovedCounter = 0; 1605 connect(model, &SpreadsheetModel::columnsRemoved, [this, &columnsRemovedCounter]() { 1606 columnsRemovedCounter++; 1607 }); 1608 1609 QCOMPARE(sheet->columnCount(), 2); 1610 sheet->setColumnCount(5); // No crash shall happen 1611 QCOMPARE(sheet->columnCount(), 5); 1612 1613 sheet->undoStack()->undo(); 1614 QCOMPARE(sheet->columnCount(), 2); 1615 sheet->undoStack()->redo(); 1616 QCOMPARE(sheet->columnCount(), 5); 1617 1618 QCOMPARE(columnsAboutToBeInsertedCounter, 2); // set and redo() 1619 QCOMPARE(columnsInsertedCounter, 2); // set and redo() 1620 QCOMPARE(columnsRemovedCounter, 1); // undo() 1621 QCOMPARE(columnsAboutToBeRemovedCounter, 1); // undo() 1622 } 1623 1624 void SpreadsheetTest::testRemoveColumns() { 1625 Project project; 1626 auto* sheet = new Spreadsheet(QStringLiteral("test"), false); 1627 project.addChild(sheet); 1628 1629 auto* model = new SpreadsheetModel(sheet); 1630 1631 int columnsAboutToBeInsertedCounter = 0; 1632 connect(model, &SpreadsheetModel::columnsAboutToBeInserted, [this, &columnsAboutToBeInsertedCounter]() { 1633 columnsAboutToBeInsertedCounter++; 1634 }); 1635 int columnsInsertedCounter = 0; 1636 connect(model, &SpreadsheetModel::columnsInserted, [this, &columnsInsertedCounter]() { 1637 columnsInsertedCounter++; 1638 }); 1639 int columnsAboutToBeRemovedCounter = 0; 1640 connect(model, &SpreadsheetModel::columnsAboutToBeRemoved, [this, &columnsAboutToBeRemovedCounter]() { 1641 columnsAboutToBeRemovedCounter++; 1642 }); 1643 int columnsRemovedCounter = 0; 1644 connect(model, &SpreadsheetModel::columnsRemoved, [this, &columnsRemovedCounter]() { 1645 columnsRemovedCounter++; 1646 }); 1647 1648 QCOMPARE(sheet->columnCount(), 2); 1649 sheet->setColumnCount(1); // No crash shall happen 1650 QCOMPARE(sheet->columnCount(), 1); 1651 1652 sheet->undoStack()->undo(); 1653 QCOMPARE(sheet->columnCount(), 2); 1654 sheet->undoStack()->redo(); 1655 QCOMPARE(sheet->columnCount(), 1); 1656 1657 QCOMPARE(columnsAboutToBeInsertedCounter, 1); // undo() 1658 QCOMPARE(columnsInsertedCounter, 1); // undo() 1659 QCOMPARE(columnsRemovedCounter, 2); // set and redo() 1660 QCOMPARE(columnsAboutToBeRemovedCounter, 2); // set and redo() 1661 } 1662 1663 /*! 1664 * \brief testInsertRowsSuppressUpdate 1665 * It shall not crash 1666 * Testing if in the model begin and end are used properly 1667 */ 1668 void SpreadsheetTest::testInsertRowsSuppressUpdate() { 1669 Project project; 1670 auto* sheet = new Spreadsheet(QStringLiteral("test"), false); 1671 project.addChild(sheet); 1672 1673 auto* model = new SpreadsheetModel(sheet); 1674 1675 int rowsAboutToBeInsertedCounter = 0; 1676 connect(model, &SpreadsheetModel::rowsAboutToBeInserted, [this, &rowsAboutToBeInsertedCounter]() { 1677 rowsAboutToBeInsertedCounter++; 1678 }); 1679 int rowsInsertedCounter = 0; 1680 connect(model, &SpreadsheetModel::rowsInserted, [this, &rowsInsertedCounter]() { 1681 rowsInsertedCounter++; 1682 }); 1683 int rowsAboutToBeRemovedCounter = 0; 1684 connect(model, &SpreadsheetModel::rowsAboutToBeRemoved, [this, &rowsAboutToBeRemovedCounter]() { 1685 rowsAboutToBeRemovedCounter++; 1686 }); 1687 int rowsRemovedCounter = 0; 1688 connect(model, &SpreadsheetModel::rowsRemoved, [this, &rowsRemovedCounter]() { 1689 rowsRemovedCounter++; 1690 }); 1691 1692 int modelResetCounter = 0; 1693 connect(model, &SpreadsheetModel::modelReset, [this, &modelResetCounter]() { 1694 modelResetCounter++; 1695 }); 1696 int modelAboutToResetCounter = 0; 1697 connect(model, &SpreadsheetModel::modelAboutToBeReset, [this, &modelAboutToResetCounter]() { 1698 modelAboutToResetCounter++; 1699 }); 1700 1701 model->suppressSignals(true); 1702 1703 QCOMPARE(sheet->rowCount(), 100); 1704 sheet->setRowCount(101); // No crash shall happen 1705 QCOMPARE(sheet->rowCount(), 101); 1706 1707 sheet->undoStack()->undo(); 1708 QCOMPARE(sheet->rowCount(), 100); 1709 sheet->undoStack()->redo(); 1710 QCOMPARE(sheet->rowCount(), 101); 1711 1712 model->suppressSignals(false); 1713 1714 QCOMPARE(rowsAboutToBeInsertedCounter, 0); 1715 QCOMPARE(rowsInsertedCounter, 0); 1716 QCOMPARE(rowsAboutToBeRemovedCounter, 0); 1717 QCOMPARE(rowsRemovedCounter, 0); 1718 QCOMPARE(modelResetCounter, 1); 1719 QCOMPARE(modelAboutToResetCounter, 1); 1720 } 1721 1722 /*! 1723 * \brief testInsertColumnsSuppressUpdate 1724 * It shall not crash 1725 * Testing if in the model begin and end are used properly 1726 */ 1727 void SpreadsheetTest::testInsertColumnsSuppressUpdate() { 1728 Project project; 1729 auto* sheet = new Spreadsheet(QStringLiteral("test"), false); 1730 project.addChild(sheet); 1731 1732 auto* model = new SpreadsheetModel(sheet); 1733 1734 int columnsAboutToBeInsertedCounter = 0; 1735 connect(model, &SpreadsheetModel::columnsAboutToBeInserted, [this, &columnsAboutToBeInsertedCounter]() { 1736 columnsAboutToBeInsertedCounter++; 1737 }); 1738 int columnsInsertedCounter = 0; 1739 connect(model, &SpreadsheetModel::columnsInserted, [this, &columnsInsertedCounter]() { 1740 columnsInsertedCounter++; 1741 }); 1742 int columnsAboutToBeRemovedCounter = 0; 1743 connect(model, &SpreadsheetModel::columnsAboutToBeRemoved, [this, &columnsAboutToBeRemovedCounter]() { 1744 columnsAboutToBeRemovedCounter++; 1745 }); 1746 int columnsRemovedCounter = 0; 1747 connect(model, &SpreadsheetModel::columnsRemoved, [this, &columnsRemovedCounter]() { 1748 columnsRemovedCounter++; 1749 }); 1750 1751 int modelResetCounter = 0; 1752 connect(model, &SpreadsheetModel::modelReset, [this, &modelResetCounter]() { 1753 modelResetCounter++; 1754 }); 1755 int modelAboutToResetCounter = 0; 1756 connect(model, &SpreadsheetModel::modelAboutToBeReset, [this, &modelAboutToResetCounter]() { 1757 modelAboutToResetCounter++; 1758 }); 1759 1760 model->suppressSignals(true); 1761 1762 QCOMPARE(sheet->columnCount(), 2); 1763 sheet->setColumnCount(5); // No crash shall happen 1764 QCOMPARE(sheet->columnCount(), 5); 1765 1766 sheet->undoStack()->undo(); 1767 QCOMPARE(sheet->columnCount(), 2); 1768 sheet->undoStack()->redo(); 1769 QCOMPARE(sheet->columnCount(), 5); 1770 1771 model->suppressSignals(false); 1772 1773 QCOMPARE(columnsAboutToBeInsertedCounter, 0); 1774 QCOMPARE(columnsInsertedCounter, 0); 1775 QCOMPARE(columnsRemovedCounter, 0); 1776 QCOMPARE(columnsAboutToBeRemovedCounter, 0); 1777 QCOMPARE(modelResetCounter, 1); 1778 QCOMPARE(modelAboutToResetCounter, 1); 1779 } 1780 1781 void SpreadsheetTest::testLinkSpreadsheetsUndoRedo() { 1782 Project project; 1783 auto* sheetData = new Spreadsheet(QStringLiteral("data"), false); 1784 project.addChild(sheetData); 1785 sheetData->setColumnCount(3); 1786 sheetData->setRowCount(10); 1787 1788 auto* sheetData2 = new Spreadsheet(QStringLiteral("data2"), false); 1789 project.addChild(sheetData2); 1790 sheetData2->setColumnCount(3); 1791 sheetData2->setRowCount(100); 1792 1793 auto* sheetCalculations = new Spreadsheet(QStringLiteral("calculations"), false); 1794 project.addChild(sheetCalculations); 1795 sheetCalculations->setColumnCount(3); 1796 sheetCalculations->setRowCount(2); 1797 1798 SpreadsheetDock dock(nullptr); 1799 dock.setSpreadsheets({sheetCalculations}); 1800 1801 QCOMPARE(dock.ui.cbLinkingEnabled->isChecked(), false); 1802 QCOMPARE(dock.ui.cbLinkedSpreadsheet->isVisible(), false); 1803 QCOMPARE(dock.ui.sbRowCount->isEnabled(), true); 1804 QCOMPARE(dock.m_spreadsheet->linking(), false); 1805 1806 dock.ui.cbLinkingEnabled->toggled(true); 1807 1808 // QCOMPARE(dock.ui.cbLinkingEnabled->isChecked(), true); // does not work here. Don't know why 1809 // QCOMPARE(dock.ui.cbLinkedSpreadsheet->isVisible(), true); 1810 // QCOMPARE(dock.ui.sbRowCount->isEnabled(), false); 1811 QCOMPARE(sheetCalculations->linking(), true); 1812 QCOMPARE(sheetCalculations->linkedSpreadsheet(), nullptr); 1813 QCOMPARE(sheetCalculations->linkedSpreadsheetPath(), QLatin1String()); 1814 QCOMPARE(sheetCalculations->rowCount(), 2); 1815 1816 const auto index = dock.m_aspectTreeModel->modelIndexOfAspect(sheetData); 1817 QCOMPARE(index.isValid(), true); 1818 // dock.ui.cbLinkedSpreadsheet->setCurrentModelIndex(index); // Does not trigger the slot 1819 sheetCalculations->setLinkedSpreadsheet(sheetData); 1820 1821 QCOMPARE(sheetCalculations->linkedSpreadsheet(), sheetData); 1822 QCOMPARE(sheetCalculations->linkedSpreadsheetPath(), sheetData->path()); 1823 QCOMPARE(sheetCalculations->rowCount(), 10); 1824 1825 sheetCalculations->setLinkedSpreadsheet(sheetData2); 1826 1827 QCOMPARE(sheetCalculations->linking(), true); 1828 QCOMPARE(sheetCalculations->linkedSpreadsheet(), sheetData2); 1829 QCOMPARE(sheetCalculations->linkedSpreadsheetPath(), sheetData2->path()); 1830 QCOMPARE(sheetCalculations->rowCount(), 100); 1831 1832 sheetCalculations->undoStack()->undo(); 1833 1834 QCOMPARE(sheetCalculations->linking(), true); 1835 QCOMPARE(sheetCalculations->linkedSpreadsheet(), sheetData); 1836 QCOMPARE(sheetCalculations->linkedSpreadsheetPath(), sheetData->path()); 1837 QCOMPARE(sheetCalculations->rowCount(), 10); 1838 1839 sheetCalculations->undoStack()->redo(); 1840 1841 QCOMPARE(sheetCalculations->linking(), true); 1842 QCOMPARE(sheetCalculations->linkedSpreadsheet(), sheetData2); 1843 QCOMPARE(sheetCalculations->linkedSpreadsheetPath(), sheetData2->path()); 1844 QCOMPARE(sheetCalculations->rowCount(), 100); 1845 1846 sheetCalculations->undoStack()->undo(); // first undo 1847 QCOMPARE(sheetCalculations->linking(), true); 1848 QCOMPARE(sheetCalculations->linkedSpreadsheet(), sheetData); 1849 QCOMPARE(sheetCalculations->linkedSpreadsheetPath(), sheetData->path()); 1850 QCOMPARE(sheetCalculations->rowCount(), 10); 1851 1852 sheetCalculations->undoStack()->undo(); 1853 1854 QCOMPARE(sheetCalculations->linking(), true); 1855 QCOMPARE(sheetCalculations->linkedSpreadsheet(), nullptr); // No linked spreadsheet anymore 1856 QCOMPARE(sheetCalculations->linkedSpreadsheetPath(), QLatin1String()); 1857 QCOMPARE(sheetCalculations->rowCount(), 2); // Go back to original row count 1858 1859 sheetCalculations->undoStack()->undo(); 1860 QCOMPARE(sheetCalculations->linking(), false); 1861 QCOMPARE(sheetCalculations->linkedSpreadsheet(), nullptr); 1862 QCOMPARE(sheetCalculations->linkedSpreadsheetPath(), QLatin1String()); 1863 QCOMPARE(sheetCalculations->rowCount(), 2); 1864 } 1865 1866 void SpreadsheetTest::testLinkSpreadsheetDeleteAdd() { 1867 Project project; 1868 auto* sheetData = new Spreadsheet(QStringLiteral("data"), false); 1869 project.addChild(sheetData); 1870 sheetData->setColumnCount(3); 1871 sheetData->setRowCount(10); 1872 1873 auto* sheetCalculations = new Spreadsheet(QStringLiteral("calculations"), false); 1874 project.addChild(sheetCalculations); 1875 sheetCalculations->setColumnCount(3); 1876 sheetCalculations->setRowCount(2); 1877 1878 SpreadsheetDock dock(nullptr); 1879 dock.setSpreadsheets({sheetCalculations}); 1880 1881 QCOMPARE(dock.ui.cbLinkingEnabled->isChecked(), false); 1882 QCOMPARE(dock.ui.cbLinkedSpreadsheet->isVisible(), false); 1883 QCOMPARE(dock.ui.sbRowCount->isEnabled(), true); 1884 QCOMPARE(sheetCalculations->linking(), false); 1885 1886 Q_EMIT dock.ui.cbLinkingEnabled->toggled(true); 1887 1888 sheetCalculations->setLinkedSpreadsheet(sheetData); 1889 1890 QCOMPARE(sheetCalculations->linking(), true); 1891 QCOMPARE(sheetCalculations->linkedSpreadsheet(), sheetData); 1892 QCOMPARE(sheetCalculations->linkedSpreadsheetPath(), sheetData->path()); 1893 QCOMPARE(sheetCalculations->rowCount(), 10); 1894 1895 sheetData->remove(); 1896 sheetData->setRowCount(100); 1897 1898 QCOMPARE(sheetCalculations->linking(), true); 1899 QCOMPARE(sheetCalculations->linkedSpreadsheet(), nullptr); 1900 QCOMPARE(sheetCalculations->linkedSpreadsheetPath(), QStringLiteral("Project/data")); 1901 QCOMPARE(sheetCalculations->rowCount(), 10); // does not change 1902 1903 auto* sheetDataNew = new Spreadsheet(QStringLiteral("data"), false); 1904 sheetDataNew->setColumnCount(3); 1905 sheetDataNew->setRowCount(12); 1906 project.addChild(sheetDataNew); 1907 1908 QCOMPARE(sheetCalculations->linking(), true); 1909 QCOMPARE(sheetCalculations->linkedSpreadsheet(), sheetDataNew); 1910 QCOMPARE(sheetCalculations->linkedSpreadsheetPath(), sheetDataNew->path()); 1911 QCOMPARE(sheetCalculations->rowCount(), 12); 1912 } 1913 1914 void SpreadsheetTest::testLinkSpreadsheetAddRow() { 1915 Project project; 1916 auto* sheetData = new Spreadsheet(QStringLiteral("data"), false); 1917 project.addChild(sheetData); 1918 sheetData->setColumnCount(3); 1919 sheetData->setRowCount(10); 1920 1921 auto* sheetCalculations = new Spreadsheet(QStringLiteral("calculations"), false); 1922 project.addChild(sheetCalculations); 1923 sheetCalculations->setColumnCount(3); 1924 sheetCalculations->setRowCount(2); 1925 1926 SpreadsheetDock dock(nullptr); 1927 dock.setSpreadsheets({sheetCalculations}); 1928 1929 QCOMPARE(dock.ui.cbLinkingEnabled->isChecked(), false); 1930 QCOMPARE(dock.ui.cbLinkedSpreadsheet->isVisible(), false); 1931 QCOMPARE(dock.ui.sbRowCount->isEnabled(), true); 1932 QCOMPARE(sheetCalculations->linking(), false); 1933 1934 Q_EMIT dock.ui.cbLinkingEnabled->toggled(true); 1935 1936 sheetCalculations->setLinkedSpreadsheet(sheetData); 1937 1938 QCOMPARE(sheetCalculations->linking(), true); 1939 QCOMPARE(sheetCalculations->linkedSpreadsheet(), sheetData); 1940 QCOMPARE(sheetCalculations->linkedSpreadsheetPath(), sheetData->path()); 1941 QCOMPARE(sheetCalculations->rowCount(), 10); 1942 1943 new SpreadsheetModel(sheetData); // otherwise emitRowCountChanged will not be called 1944 sheetData->setRowCount(13); 1945 1946 QCOMPARE(sheetCalculations->linking(), true); 1947 QCOMPARE(sheetCalculations->linkedSpreadsheet(), sheetData); 1948 QCOMPARE(sheetCalculations->linkedSpreadsheetPath(), sheetData->path()); 1949 QCOMPARE(sheetCalculations->rowCount(), 13); 1950 } 1951 1952 void SpreadsheetTest::testLinkSpreadsheetRemoveRow() { 1953 Project project; 1954 auto* sheetData = new Spreadsheet(QStringLiteral("data"), false); 1955 project.addChild(sheetData); 1956 sheetData->setColumnCount(3); 1957 sheetData->setRowCount(10); 1958 1959 auto* sheetCalculations = new Spreadsheet(QStringLiteral("calculations"), false); 1960 project.addChild(sheetCalculations); 1961 sheetCalculations->setColumnCount(3); 1962 sheetCalculations->setRowCount(2); 1963 1964 SpreadsheetDock dock(nullptr); 1965 dock.setSpreadsheets({sheetCalculations}); 1966 1967 QCOMPARE(dock.ui.cbLinkingEnabled->isChecked(), false); 1968 QCOMPARE(dock.ui.cbLinkedSpreadsheet->isVisible(), false); 1969 QCOMPARE(dock.ui.sbRowCount->isEnabled(), true); 1970 QCOMPARE(sheetCalculations->linking(), false); 1971 1972 dock.ui.cbLinkingEnabled->toggled(true); 1973 1974 sheetCalculations->setLinkedSpreadsheet(sheetData); 1975 1976 QCOMPARE(sheetCalculations->linking(), true); 1977 QCOMPARE(sheetCalculations->linkedSpreadsheet(), sheetData); 1978 QCOMPARE(sheetCalculations->linkedSpreadsheetPath(), sheetData->path()); 1979 QCOMPARE(sheetCalculations->rowCount(), 10); 1980 1981 new SpreadsheetModel(sheetData); // otherwise emitRowCountChanged will not be called 1982 sheetData->setRowCount(7); 1983 1984 QCOMPARE(sheetCalculations->linking(), true); 1985 QCOMPARE(sheetCalculations->linkedSpreadsheet(), sheetData); 1986 QCOMPARE(sheetCalculations->linkedSpreadsheetPath(), sheetData->path()); 1987 QCOMPARE(sheetCalculations->rowCount(), 7); 1988 } 1989 1990 void SpreadsheetTest::testLinkSpreadsheetRecalculate() { 1991 Project project; 1992 auto* sheetData = new Spreadsheet(QStringLiteral("data"), false); 1993 project.addChild(sheetData); 1994 sheetData->setColumnCount(2); 1995 sheetData->setRowCount(10); 1996 auto* sheetDataColumn0 = sheetData->child<Column>(0); 1997 sheetDataColumn0->replaceValues(0, {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}); 1998 QVERIFY(sheetDataColumn0); 1999 auto* sheetDataColumn1 = sheetData->child<Column>(1); 2000 QVERIFY(sheetDataColumn1); 2001 sheetDataColumn1->replaceValues(0, {1, 2, 1, 2, 1, 2, 1, 2, 1, 3}); 2002 2003 auto* sheetCalculations = new Spreadsheet(QStringLiteral("calculations"), false); 2004 project.addChild(sheetCalculations); 2005 sheetCalculations->setColumnCount(1); 2006 sheetCalculations->setRowCount(2); 2007 auto* sheetCalculationsColumn0 = sheetCalculations->child<Column>(0); 2008 QVERIFY(sheetCalculationsColumn0); 2009 sheetCalculationsColumn0->setFormula(QStringLiteral("x + y"), {QStringLiteral("x"), QStringLiteral("y")}, {sheetDataColumn0, sheetDataColumn1}, true); 2010 sheetCalculationsColumn0->updateFormula(); 2011 2012 { 2013 QVector<double> ref{2, 4, 4, 6, 6, 8, 8, 10, 10, 13}; 2014 QCOMPARE(sheetCalculationsColumn0->rowCount(), 10); // currently the update() triggers a resize 2015 for (int i = 0; i < 10; i++) 2016 VALUES_EQUAL(sheetCalculationsColumn0->doubleAt(i), ref.at(i)); 2017 } 2018 sheetCalculations->setLinking(true); 2019 sheetCalculations->setLinkedSpreadsheet(sheetData); 2020 2021 QCOMPARE(sheetCalculations->linking(), true); 2022 QCOMPARE(sheetCalculations->linkedSpreadsheet(), sheetData); 2023 QCOMPARE(sheetCalculations->linkedSpreadsheetPath(), sheetData->path()); 2024 QCOMPARE(sheetCalculations->rowCount(), 10); 2025 2026 new SpreadsheetModel(sheetData); // otherwise emitRowCountChanged will not be called 2027 sheetData->setRowCount(7); 2028 sheetDataColumn0->replaceValues(0, {3, 4, 6, 2, 1, 8, 5}); 2029 QCOMPARE(sheetDataColumn0->rowCount(), 7); 2030 2031 { 2032 QVector<double> ref{4, 6, 7, 4, 2, 10, 6}; 2033 QCOMPARE(sheetCalculationsColumn0->rowCount(), ref.count()); 2034 for (int i = 0; i < ref.count(); i++) { 2035 qDebug() << i; 2036 VALUES_EQUAL(sheetCalculationsColumn0->doubleAt(i), ref.at(i)); 2037 } 2038 } 2039 } 2040 2041 void SpreadsheetTest::testLinkSpreadsheetSaveLoad() { 2042 QString savePath; 2043 { 2044 Project project; 2045 auto model = new AspectTreeModel(&project, this); 2046 ProjectExplorer pe; // Needed otherwise the state key is missing in the file and then no restorePointers will be called 2047 pe.setProject(&project); 2048 pe.setModel(model); 2049 auto* sheetData = new Spreadsheet(QStringLiteral("data"), false); 2050 project.addChild(sheetData); 2051 sheetData->setColumnCount(3); 2052 sheetData->setRowCount(10); 2053 2054 auto* sheetCalculations = new Spreadsheet(QStringLiteral("calculations"), false); 2055 project.addChild(sheetCalculations); 2056 sheetCalculations->setColumnCount(3); 2057 sheetCalculations->setRowCount(2); 2058 2059 SpreadsheetDock dock(nullptr); 2060 dock.setSpreadsheets({sheetCalculations}); 2061 2062 QCOMPARE(dock.ui.cbLinkingEnabled->isChecked(), false); 2063 QCOMPARE(dock.ui.cbLinkedSpreadsheet->isVisible(), false); 2064 QCOMPARE(dock.ui.sbRowCount->isEnabled(), true); 2065 QCOMPARE(sheetCalculations->linking(), false); 2066 2067 Q_EMIT dock.ui.cbLinkingEnabled->toggled(true); 2068 2069 sheetCalculations->setLinkedSpreadsheet(sheetData); 2070 2071 QCOMPARE(sheetCalculations->linking(), true); 2072 QCOMPARE(sheetCalculations->linkedSpreadsheet(), sheetData); 2073 QCOMPARE(sheetCalculations->linkedSpreadsheetPath(), sheetData->path()); 2074 QCOMPARE(sheetCalculations->rowCount(), 10); 2075 2076 SAVE_PROJECT("testLinkSpreadsheetSaveLoad") 2077 } 2078 2079 { 2080 Project project; 2081 QCOMPARE(project.load(savePath), true); 2082 2083 auto sheetData = project.child<Spreadsheet>(0); 2084 QVERIFY(sheetData); 2085 auto sheetCalculations = project.child<Spreadsheet>(1); 2086 QVERIFY(sheetCalculations); 2087 2088 QCOMPARE(sheetCalculations->linking(), true); 2089 QCOMPARE(sheetCalculations->linkedSpreadsheetPath(), sheetData->path()); 2090 QCOMPARE(sheetCalculations->linkedSpreadsheet(), sheetData); 2091 QCOMPARE(sheetCalculations->rowCount(), 10); 2092 2093 new SpreadsheetModel(sheetData); // otherwise emitRowCountChanged will not be called 2094 sheetData->setRowCount(11); // Changing shall also update sheetCalculations also after loading 2095 2096 QCOMPARE(sheetCalculations->linking(), true); 2097 QCOMPARE(sheetCalculations->linkedSpreadsheet(), sheetData); 2098 QCOMPARE(sheetCalculations->linkedSpreadsheetPath(), sheetData->path()); 2099 QCOMPARE(sheetCalculations->rowCount(), 11); 2100 } 2101 } 2102 2103 #ifdef HAVE_VECTOR_BLF 2104 // Copied from BLFFilterTest.cpp 2105 namespace { 2106 static const std::string PRIMITIVE_DBC = 2107 R"(VERSION "1.0.0" 2108 2109 NS_ : 2110 2111 BS_: 2112 2113 BU_: DBG DRIVER IO MOTOR SENSOR 2114 2115 )"; 2116 2117 void createDBCFile(const QString& filename, const std::string& content) { 2118 auto* file = std::fopen(filename.toStdString().c_str(), "w"); 2119 QVERIFY(file); 2120 std::fputs(PRIMITIVE_DBC.c_str(), file); 2121 std::fputs(content.c_str(), file); 2122 std::fclose(file); 2123 } 2124 2125 Vector::BLF::CanMessage2* createCANMessage(uint32_t id, uint64_t timestamp, const std::vector<uint8_t>& data) { 2126 auto* canMessage = new Vector::BLF::CanMessage2(); 2127 canMessage->channel = 1; 2128 canMessage->flags = 1; // TX 2129 canMessage->dlc = std::min<uint8_t>(data.size(), 8); 2130 canMessage->id = id; 2131 canMessage->objectTimeStamp = timestamp; 2132 canMessage->objectFlags = Vector::BLF::ObjectHeader::ObjectFlags::TimeOneNans; 2133 if (canMessage->data.size() < canMessage->dlc) 2134 canMessage->data.resize(canMessage->dlc); 2135 2136 for (int i = 0; i < canMessage->dlc; i++) { 2137 canMessage->data[i] = data.at(i); 2138 } 2139 return canMessage; 2140 } 2141 2142 void createBLFFile(const QString& filename, QVector<Vector::BLF::CanMessage2*> messages) { 2143 Vector::BLF::File blfFile; 2144 blfFile.open(filename.toStdString().c_str(), std::ios_base::out); 2145 QVERIFY(blfFile.is_open()); 2146 2147 for (auto msg : messages) { 2148 blfFile.write(msg); 2149 } 2150 // Finish creating files 2151 blfFile.close(); 2152 } 2153 } 2154 2155 void SpreadsheetTest::testLinkSpreadSheetImportBLF() { 2156 QTemporaryFile blfFileName(QStringLiteral("XXXXXX.blf")); 2157 QVERIFY(blfFileName.open()); 2158 QVector<Vector::BLF::CanMessage2*> messages{ 2159 createCANMessage(337, 5, {0, 4, 252, 19, 0, 0, 0, 0}), 2160 createCANMessage(541, 10, {7, 39, 118, 33, 250, 30, 76, 24}), // 99.91, 85.66, 79.3, 22.2 2161 createCANMessage(337, 15, {47, 4, 60, 29, 0, 0, 0, 0}), 2162 createCANMessage(337, 20, {57, 4, 250, 29, 0, 0, 0, 0}), 2163 createCANMessage(541, 25, {7, 39, 118, 33, 250, 30, 76, 24}), // 99.91, 85.66, 79.3, 22.2 2164 }; // time is in nanoseconds 2165 createBLFFile(blfFileName.fileName(), messages); 2166 2167 QTemporaryFile dbcFile(QStringLiteral("XXXXXX.dbc")); 2168 QVERIFY(dbcFile.open()); 2169 const auto dbcContent = R"(BO_ 337 STATUS: 8 Vector__XXX 2170 SG_ Value6 : 27|3@1+ (1,0) [0|7] "" Vector__XXX 2171 SG_ Value5 : 16|11@1+ (0.1,-102) [-102|102] "%" Vector__XXX 2172 SG_ Value2 : 8|2@1+ (1,0) [0|2] "" Vector__XXX 2173 SG_ Value3 : 10|1@1+ (1,0) [0|1] "" Vector__XXX 2174 SG_ Value7 : 30|2@1+ (1,0) [0|3] "" Vector__XXX 2175 SG_ Value4 : 11|4@1+ (1,0) [0|3] "" Vector__XXX 2176 SG_ Value1 : 0|8@1+ (1,0) [0|204] "Km/h" Vector__XXX" 2177 BO_ 541 MSG2: 8 Vector__XXX 2178 SG_ MSG2Value4 : 48|16@1+ (0.01,-40) [-40|125] "C" Vector__XXX 2179 SG_ MSG2Value1 : 0|16@1+ (0.01,0) [0|100] "%" Vector__XXX 2180 SG_ MSG2Value3 : 32|16@1+ (0.01,0) [0|100] "%" Vector__XXX 2181 SG_ MSG2Value2 : 16|16@1+ (0.01,0) [0|100] "%" Vector__XXX 2182 )"; 2183 createDBCFile(dbcFile.fileName(), dbcContent); 2184 2185 //------------------------------------------------------------------------------------------ 2186 Project project; 2187 const auto spreadsheetName = blfFileName.fileName().replace(QStringLiteral(".blf"), QStringLiteral("")); 2188 auto* sheetData = new Spreadsheet(spreadsheetName, false); 2189 project.addChild(sheetData); 2190 sheetData->setColumnCount(2); 2191 sheetData->setRowCount(10); 2192 auto* sheetDataColumn0 = sheetData->child<Column>(0); 2193 sheetDataColumn0->setName(QStringLiteral("Value6_")); 2194 sheetDataColumn0->replaceValues(0, {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}); 2195 QVERIFY(sheetDataColumn0); 2196 auto* sheetDataColumn1 = sheetData->child<Column>(1); 2197 sheetDataColumn1->setName(QStringLiteral("Value5_%")); 2198 QVERIFY(sheetDataColumn1); 2199 sheetDataColumn1->replaceValues(0, {1, 2, 1, 2, 1, 2, 1, 2, 1, 3}); 2200 2201 auto* sheetCalculations = new Spreadsheet(QStringLiteral("calculations"), false); 2202 project.addChild(sheetCalculations); 2203 sheetCalculations->setColumnCount(2); 2204 sheetCalculations->setRowCount(2); 2205 2206 auto* sheetCalculationsColumn0 = sheetCalculations->child<Column>(0); 2207 QVERIFY(sheetCalculationsColumn0); 2208 sheetCalculationsColumn0->setFormula(QStringLiteral("2*x"), {QStringLiteral("x")}, {sheetDataColumn0}, true); 2209 sheetCalculationsColumn0->updateFormula(); 2210 2211 auto* sheetCalculationsColumn1 = sheetCalculations->child<Column>(1); 2212 QVERIFY(sheetCalculationsColumn1); 2213 sheetCalculationsColumn1->setFormula(QStringLiteral("2*x"), {QStringLiteral("x")}, {sheetDataColumn1}, true); 2214 sheetCalculationsColumn1->updateFormula(); 2215 2216 { 2217 QVector<double> ref{2, 4, 6, 8, 10, 12, 14, 16, 18, 20}; 2218 QCOMPARE(sheetCalculationsColumn0->rowCount(), 10); 2219 for (int i = 0; i < 10; i++) 2220 VALUES_EQUAL(sheetCalculationsColumn0->doubleAt(i), ref.at(i)); 2221 } 2222 2223 { 2224 QVector<double> ref{2, 4, 2, 4, 2, 4, 2, 4, 2, 6}; 2225 QCOMPARE(sheetCalculationsColumn1->rowCount(), 10); 2226 for (int i = 0; i < 10; i++) 2227 VALUES_EQUAL(sheetCalculationsColumn1->doubleAt(i), ref.at(i)); 2228 } 2229 2230 sheetCalculations->setLinking(true); 2231 sheetCalculations->setLinkedSpreadsheet(sheetData); 2232 2233 QCOMPARE(sheetCalculations->linking(), true); 2234 QCOMPARE(sheetCalculations->linkedSpreadsheet(), sheetData); 2235 QCOMPARE(sheetCalculations->linkedSpreadsheetPath(), sheetData->path()); 2236 QCOMPARE(sheetCalculations->rowCount(), 10); 2237 2238 new SpreadsheetModel(sheetData); // otherwise emitRowCountChanged will not be called 2239 2240 VectorBLFFilter filter; 2241 filter.setConvertTimeToSeconds(true); 2242 filter.setTimeHandlingMode(CANFilter::TimeHandling::ConcatPrevious); 2243 QCOMPARE(filter.isValid(blfFileName.fileName()), true); 2244 2245 // Valid blf and valid dbc 2246 filter.setDBCFile(dbcFile.fileName()); 2247 filter.readDataFromFile(blfFileName.fileName(), sheetData); 2248 QCOMPARE(sheetData->columnCount(), 12); 2249 2250 QCOMPARE(sheetData->rowCount(), 5); 2251 QCOMPARE(sheetDataColumn0->rowCount(), 5); 2252 QCOMPARE(sheetDataColumn1->rowCount(), 5); 2253 2254 const auto* sheetDataColumn6 = sheetData->child<Column>(1); 2255 QCOMPARE(sheetDataColumn6->name(), QStringLiteral("Value6_")); 2256 const auto* sheetDataColumn5 = sheetData->child<Column>(2); 2257 QCOMPARE(sheetDataColumn5->name(), QStringLiteral("Value5_%")); 2258 2259 { 2260 QVector<double> ref{4., 4., 6., 6., 6.}; 2261 const auto* sheetCalculationsColumn = sheetCalculations->child<Column>(0); 2262 QCOMPARE(sheetCalculationsColumn->formulaData().at(0).column(), sheetDataColumn6); 2263 QCOMPARE(sheetCalculationsColumn->rowCount(), ref.count()); 2264 for (int i = 0; i < ref.count(); i++) { 2265 qDebug() << i; 2266 VALUES_EQUAL(sheetCalculationsColumn->doubleAt(i), ref.at(i)); 2267 } 2268 } 2269 2270 { 2271 QVector<double> ref{0., 0., 64., 102., 102.}; 2272 const auto* sheetCalculationsColumn = sheetCalculations->child<Column>(1); 2273 QCOMPARE(sheetCalculationsColumn->formulaData().at(0).column(), sheetDataColumn5); 2274 QCOMPARE(sheetCalculationsColumn->rowCount(), ref.count()); 2275 for (int i = 0; i < ref.count(); i++) { 2276 qDebug() << i; 2277 VALUES_EQUAL(sheetCalculationsColumn->doubleAt(i), ref.at(i)); 2278 } 2279 } 2280 } 2281 #endif // HAVE_VECTOR_BLF 2282 2283 QTEST_MAIN(SpreadsheetTest)