File indexing completed on 2024-12-01 12:27:06

0001 /***************************************************************************
0002     File                 : SpreadsheetTest.cpp
0003     Project              : LabPlot
0004     Description          : Tests for the Spreadsheet
0005     --------------------------------------------------------------------
0006     Copyright            : (C) 2020 Alexander Semke (alexander.semke@web.de)
0007  ***************************************************************************/
0008 
0009 /***************************************************************************
0010  *                                                                         *
0011  *  This program is free software; you can redistribute it and/or modify   *
0012  *  it under the terms of the GNU General Public License as published by   *
0013  *  the Free Software Foundation; either version 2 of the License, or      *
0014  *  (at your option) any later version.                                    *
0015  *                                                                         *
0016  *  This program is distributed in the hope that it will be useful,        *
0017  *  but WITHOUT ANY WARRANTY; without even the implied warranty of         *
0018  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the          *
0019  *  GNU General Public License for more details.                           *
0020  *                                                                         *
0021  *   You should have received a copy of the GNU General Public License     *
0022  *   along with this program; if not, write to the Free Software           *
0023  *   Foundation, Inc., 51 Franklin Street, Fifth Floor,                    *
0024  *   Boston, MA  02110-1301  USA                                           *
0025  *                                                                         *
0026  ***************************************************************************/
0027 
0028 #include "SpreadsheetTest.h"
0029 #include "backend/spreadsheet/Spreadsheet.h"
0030 #include "backend/core/datatypes/DateTime2StringFilter.h"
0031 #include "backend/core/Project.h"
0032 #include "commonfrontend/spreadsheet/SpreadsheetView.h"
0033 
0034 #include <QApplication>
0035 #include <QClipboard>
0036 #include <QUndoStack>
0037 #if (QT_VERSION >= QT_VERSION_CHECK(5, 10, 0))
0038 #include <QRandomGenerator>
0039 #endif
0040 
0041 extern "C" {
0042 #include <gsl/gsl_math.h>
0043 }
0044 
0045 void SpreadsheetTest::initTestCase() {
0046     qRegisterMetaType<const AbstractAspect*>("const AbstractAspect*");
0047     qRegisterMetaType<const AbstractColumn*>("const AbstractColumn*");
0048     QLocale::setDefault(QLocale(QLocale::C));
0049 }
0050 
0051 //**********************************************************
0052 //****************** Copy&Paste tests **********************
0053 //**********************************************************
0054 
0055 //**********************************************************
0056 //********** Handling of different columns modes ***********
0057 //**********************************************************
0058 /*!
0059    insert two columns with float values into an empty spreadsheet
0060 */
0061 void SpreadsheetTest::testCopyPasteColumnMode00() {
0062     Spreadsheet sheet("test", false);
0063     sheet.setColumnCount(2);
0064     sheet.setRowCount(100);
0065 
0066     const QString str = "10.0 100.0\n20.0 200.0";
0067     QApplication::clipboard()->setText(str);
0068 
0069     SpreadsheetView view(&sheet, false);
0070     view.pasteIntoSelection();
0071 
0072     //spreadsheet size
0073     QCOMPARE(sheet.columnCount(), 2);
0074     QCOMPARE(sheet.rowCount(), 100);
0075 
0076     //column modes
0077     QCOMPARE(sheet.column(0)->columnMode(), AbstractColumn::ColumnMode::Numeric);
0078     QCOMPARE(sheet.column(1)->columnMode(), AbstractColumn::ColumnMode::Numeric);
0079 
0080     //values
0081     QCOMPARE(sheet.column(0)->valueAt(0), 10.0);
0082     QCOMPARE(sheet.column(1)->valueAt(0), 100.0);
0083     QCOMPARE(sheet.column(0)->valueAt(1), 20.0);
0084     QCOMPARE(sheet.column(1)->valueAt(1), 200.0);
0085 }
0086 
0087 /*!
0088    insert one column with integer values and one column with float numbers into an empty spreadsheet.
0089    the first column has to be converted to integer column.
0090 */
0091 void SpreadsheetTest::testCopyPasteColumnMode01() {
0092     Spreadsheet sheet("test", false);
0093     sheet.setColumnCount(2);
0094     sheet.setRowCount(100);
0095 
0096     const QString str = "10 " + QString::number(std::numeric_limits<long long>::min())
0097                         + "\n20 " + QString::number(std::numeric_limits<long long>::max());
0098     QApplication::clipboard()->setText(str);
0099 
0100     SpreadsheetView view(&sheet, false);
0101     view.pasteIntoSelection();
0102 
0103     //spreadsheet size
0104     QCOMPARE(sheet.columnCount(), 2);
0105     QCOMPARE(sheet.rowCount(), 100);
0106 
0107     //column modes
0108     QCOMPARE(sheet.column(0)->columnMode(), AbstractColumn::ColumnMode::Integer);
0109     QCOMPARE(sheet.column(1)->columnMode(), AbstractColumn::ColumnMode::BigInt);
0110 
0111     //values
0112     QCOMPARE(sheet.column(0)->integerAt(0), 10);
0113     QCOMPARE(sheet.column(1)->bigIntAt(0), std::numeric_limits<long long>::min());
0114     QCOMPARE(sheet.column(0)->integerAt(1), 20);
0115     QCOMPARE(sheet.column(1)->bigIntAt(1), std::numeric_limits<long long>::max());
0116 }
0117 
0118 /*!
0119    insert one column with integer and one column with big integer values into an empty spreadsheet.
0120    the first column has to be converted to integer column, the second to big integer.
0121 */
0122 void SpreadsheetTest::testCopyPasteColumnMode02() {
0123     Spreadsheet sheet("test", false);
0124     sheet.setColumnCount(2);
0125     sheet.setRowCount(100);
0126 
0127     const QString str = "10 100.0\n20 200.0";
0128     QApplication::clipboard()->setText(str);
0129 
0130     SpreadsheetView view(&sheet, false);
0131     view.pasteIntoSelection();
0132 
0133     //spreadsheet size
0134     QCOMPARE(sheet.columnCount(), 2);
0135     QCOMPARE(sheet.rowCount(), 100);
0136 
0137     //column modes
0138     QCOMPARE(sheet.column(0)->columnMode(), AbstractColumn::ColumnMode::Integer);
0139     QCOMPARE(sheet.column(1)->columnMode(), AbstractColumn::ColumnMode::Numeric);
0140 
0141     //values
0142     QCOMPARE(sheet.column(0)->integerAt(0), 10);
0143     QCOMPARE(sheet.column(1)->valueAt(0), 100.0);
0144     QCOMPARE(sheet.column(0)->integerAt(1), 20);
0145     QCOMPARE(sheet.column(1)->valueAt(1), 200.0);
0146 }
0147 
0148 
0149 /*!
0150    Properly handle empty values in the tab separated data.
0151 */
0152 void SpreadsheetTest::testCopyPasteColumnMode03() {
0153     Spreadsheet sheet("test", false);
0154     sheet.setColumnCount(2);
0155     sheet.setRowCount(100);
0156 
0157     const QString str = "1000       1000        1000\n"
0158                         "985        985     985\n"
0159                         "970    -7.06562    970     970\n"
0160                         "955    -5.93881    955     955\n"
0161                         "940    -4.97594    940 -4.97594    940";
0162 
0163     QApplication::clipboard()->setText(str);
0164 
0165     SpreadsheetView view(&sheet, false);
0166     view.pasteIntoSelection();
0167 
0168     //spreadsheet size
0169     QCOMPARE(sheet.columnCount(), 5);
0170     QCOMPARE(sheet.rowCount(), 100);
0171 
0172     //column modes
0173     QCOMPARE(sheet.column(0)->columnMode(), AbstractColumn::ColumnMode::Integer);
0174     QCOMPARE(sheet.column(1)->columnMode(), AbstractColumn::ColumnMode::Numeric);
0175     QCOMPARE(sheet.column(2)->columnMode(), AbstractColumn::ColumnMode::Integer);
0176     QCOMPARE(sheet.column(3)->columnMode(), AbstractColumn::ColumnMode::Numeric);
0177     QCOMPARE(sheet.column(4)->columnMode(), AbstractColumn::ColumnMode::Integer);
0178 
0179     //values
0180     QCOMPARE(sheet.column(0)->integerAt(0), 1000);
0181     QCOMPARE((bool)std::isnan(sheet.column(1)->valueAt(0)), true);
0182     QCOMPARE(sheet.column(2)->integerAt(0), 1000);
0183     QCOMPARE((bool)std::isnan(sheet.column(3)->valueAt(0)), true);
0184     QCOMPARE(sheet.column(4)->integerAt(0), 1000);
0185 
0186     QCOMPARE(sheet.column(0)->integerAt(1), 985);
0187     QCOMPARE((bool)std::isnan(sheet.column(1)->valueAt(1)), true);
0188     QCOMPARE(sheet.column(2)->integerAt(1), 985);
0189     QCOMPARE((bool)std::isnan(sheet.column(3)->valueAt(1)), true);
0190     QCOMPARE(sheet.column(4)->integerAt(1), 985);
0191 
0192     QCOMPARE(sheet.column(0)->integerAt(2), 970);
0193     QCOMPARE(sheet.column(1)->valueAt(2), -7.06562);
0194     QCOMPARE(sheet.column(2)->integerAt(2), 970);
0195     QCOMPARE((bool)std::isnan(sheet.column(3)->valueAt(2)), true);
0196     QCOMPARE(sheet.column(4)->integerAt(2), 970);
0197 
0198     QCOMPARE(sheet.column(0)->integerAt(3), 955);
0199     QCOMPARE(sheet.column(1)->valueAt(3), -5.93881);
0200     QCOMPARE(sheet.column(2)->integerAt(3), 955);
0201     QCOMPARE((bool)std::isnan(sheet.column(3)->valueAt(3)), true);
0202     QCOMPARE(sheet.column(4)->integerAt(3), 955);
0203 
0204     QCOMPARE(sheet.column(0)->integerAt(4), 940);
0205     QCOMPARE(sheet.column(1)->valueAt(4), -4.97594);
0206     QCOMPARE(sheet.column(2)->integerAt(4), 940);
0207     QCOMPARE(sheet.column(1)->valueAt(4), -4.97594);
0208     QCOMPARE(sheet.column(4)->integerAt(4), 940);
0209 }
0210 
0211 /*!
0212     automatically detect the proper format for the datetime columns
0213  */
0214 void SpreadsheetTest::testCopyPasteColumnMode04() {
0215     Spreadsheet sheet("test", false);
0216     sheet.setColumnCount(2);
0217     sheet.setRowCount(100);
0218 
0219     const QString str = "2020-09-20 11:21:40:849    7.7\n"
0220                         "2020-09-20 11:21:41:830    4.2";
0221 
0222     QApplication::clipboard()->setText(str);
0223 
0224     SpreadsheetView view(&sheet, false);
0225     view.pasteIntoSelection();
0226 
0227     //spreadsheet size
0228     QCOMPARE(sheet.columnCount(), 2);
0229     QCOMPARE(sheet.rowCount(), 100);
0230 
0231     //column modes
0232     QCOMPARE(sheet.column(0)->columnMode(), AbstractColumn::ColumnMode::DateTime);
0233     QCOMPARE(sheet.column(1)->columnMode(), AbstractColumn::ColumnMode::Numeric);
0234 
0235     //values
0236     auto* filter = static_cast<DateTime2StringFilter*>(sheet.column(0)->outputFilter());
0237     const QString& format = filter->format();
0238 
0239     QCOMPARE(sheet.column(0)->dateTimeAt(0).toString(format), QLatin1String("2020-09-20 11:21:40:849"));
0240     QCOMPARE(sheet.column(1)->valueAt(0), 7.7);
0241 
0242     QCOMPARE(sheet.column(0)->dateTimeAt(1).toString(format), QLatin1String("2020-09-20 11:21:41:830"));
0243     QCOMPARE(sheet.column(1)->valueAt(1), 4.2);
0244 }
0245 
0246 /*!
0247     automatically detect the proper format for the datetime columns, time part only
0248  */
0249 void SpreadsheetTest::testCopyPasteColumnMode05() {
0250     Spreadsheet sheet("test", false);
0251     sheet.setColumnCount(2);
0252     sheet.setRowCount(100);
0253 
0254     const QString str = "11:21:40   7.7\n"
0255                         "11:21:41   4.2";
0256 
0257     QApplication::clipboard()->setText(str);
0258 
0259     SpreadsheetView view(&sheet, false);
0260     view.pasteIntoSelection();
0261 
0262     //spreadsheet size
0263     QCOMPARE(sheet.columnCount(), 2);
0264     QCOMPARE(sheet.rowCount(), 100);
0265 
0266     //column modes
0267     QCOMPARE(sheet.column(0)->columnMode(), AbstractColumn::ColumnMode::DateTime);
0268     QCOMPARE(sheet.column(1)->columnMode(), AbstractColumn::ColumnMode::Numeric);
0269 
0270     //values
0271     auto* filter = static_cast<DateTime2StringFilter*>(sheet.column(0)->outputFilter());
0272     const QString& format = filter->format();
0273 
0274     QCOMPARE(sheet.column(0)->dateTimeAt(0).toString(format), QLatin1String("11:21:40"));
0275     QCOMPARE(sheet.column(1)->valueAt(0), 7.7);
0276 
0277     QCOMPARE(sheet.column(0)->dateTimeAt(1).toString(format), QLatin1String("11:21:41"));
0278     QCOMPARE(sheet.column(1)->valueAt(1), 4.2);
0279 }
0280 
0281 //**********************************************************
0282 //********* Handling of spreadsheet size changes ***********
0283 //**********************************************************
0284 /*!
0285    insert irregular data, new columns should be added appropriately.
0286 */
0287 void SpreadsheetTest::testCopyPasteSizeChange00() {
0288     Project project;
0289     Spreadsheet* sheet = new Spreadsheet("test", false);
0290     project.addChild(sheet);
0291     sheet->setColumnCount(2);
0292     sheet->setRowCount(100);
0293 
0294     const QString str = "0\n"
0295                         "10 20\n"
0296                         "11 21 31\n"
0297                         "12 22 32 42\n"
0298                         "13 23\n"
0299                         "14";
0300     QApplication::clipboard()->setText(str);
0301 
0302 
0303     SpreadsheetView view(sheet, false);
0304     view.pasteIntoSelection();
0305 
0306     //spreadsheet size
0307     QCOMPARE(sheet->columnCount(), 4);
0308     QCOMPARE(sheet->rowCount(), 100);
0309 
0310     //column modes
0311     QCOMPARE(sheet->column(0)->columnMode(), AbstractColumn::ColumnMode::Integer);
0312     QCOMPARE(sheet->column(1)->columnMode(), AbstractColumn::ColumnMode::Integer);
0313     QCOMPARE(sheet->column(2)->columnMode(), AbstractColumn::ColumnMode::Integer);
0314     QCOMPARE(sheet->column(3)->columnMode(), AbstractColumn::ColumnMode::Integer);
0315 
0316     //values
0317     QCOMPARE(sheet->column(0)->integerAt(0), 0);
0318     QCOMPARE(sheet->column(1)->integerAt(0), 0);
0319     QCOMPARE(sheet->column(2)->integerAt(0), 0);
0320     QCOMPARE(sheet->column(3)->integerAt(0), 0);
0321 
0322     QCOMPARE(sheet->column(0)->integerAt(1), 10);
0323     QCOMPARE(sheet->column(1)->integerAt(1), 20);
0324     QCOMPARE(sheet->column(2)->integerAt(1), 0);
0325     QCOMPARE(sheet->column(3)->integerAt(1), 0);
0326 
0327     QCOMPARE(sheet->column(0)->integerAt(2), 11);
0328     QCOMPARE(sheet->column(1)->integerAt(2), 21);
0329     QCOMPARE(sheet->column(2)->integerAt(2), 31);
0330     QCOMPARE(sheet->column(3)->integerAt(2), 0);
0331 
0332     QCOMPARE(sheet->column(0)->integerAt(3), 12);
0333     QCOMPARE(sheet->column(1)->integerAt(3), 22);
0334     QCOMPARE(sheet->column(2)->integerAt(3), 32);
0335     QCOMPARE(sheet->column(3)->integerAt(3), 42);
0336 
0337     QCOMPARE(sheet->column(0)->integerAt(4), 13);
0338     QCOMPARE(sheet->column(1)->integerAt(4), 23);
0339     QCOMPARE(sheet->column(2)->integerAt(4), 0);
0340     QCOMPARE(sheet->column(3)->integerAt(4), 0);
0341 
0342     QCOMPARE(sheet->column(0)->integerAt(5), 14);
0343     QCOMPARE(sheet->column(1)->integerAt(5), 0);
0344     QCOMPARE(sheet->column(2)->integerAt(5), 0);
0345     QCOMPARE(sheet->column(3)->integerAt(5), 0);
0346 
0347 
0348     //undo the changes and check the results again
0349     project.undoStack()->undo();
0350 
0351     //spreadsheet size
0352     QCOMPARE(sheet->columnCount(), 2);
0353     QCOMPARE(sheet->rowCount(), 100);
0354 
0355     //column modes
0356     QCOMPARE(sheet->column(0)->columnMode(), AbstractColumn::ColumnMode::Numeric);
0357     QCOMPARE(sheet->column(1)->columnMode(), AbstractColumn::ColumnMode::Numeric);
0358 
0359     //values
0360     QCOMPARE((bool)std::isnan(sheet->column(0)->valueAt(0)), true);
0361     QCOMPARE((bool)std::isnan(sheet->column(1)->valueAt(0)), true);
0362 
0363     QCOMPARE((bool)std::isnan(sheet->column(0)->valueAt(1)), true);
0364     QCOMPARE((bool)std::isnan(sheet->column(1)->valueAt(1)), true);
0365 
0366     QCOMPARE((bool)std::isnan(sheet->column(0)->valueAt(2)), true);
0367     QCOMPARE((bool)std::isnan(sheet->column(1)->valueAt(2)), true);
0368 
0369     QCOMPARE((bool)std::isnan(sheet->column(0)->valueAt(3)), true);
0370     QCOMPARE((bool)std::isnan(sheet->column(1)->valueAt(3)), true);
0371 
0372     QCOMPARE((bool)std::isnan(sheet->column(0)->valueAt(4)), true);
0373     QCOMPARE((bool)std::isnan(sheet->column(1)->valueAt(4)), true);
0374 
0375     QCOMPARE((bool)std::isnan(sheet->column(0)->valueAt(5)), true);
0376     QCOMPARE((bool)std::isnan(sheet->column(1)->valueAt(5)), true);
0377 }
0378 
0379 /*!
0380    insert the data at the edge of the spreadsheet and paste the data.
0381    the spreadsheet has to be extended accordingly
0382 */
0383 void SpreadsheetTest::testCopyPasteSizeChange01() {
0384     Spreadsheet sheet("test", false);
0385     sheet.setColumnCount(2);
0386     sheet.setRowCount(100);
0387 
0388     const QString str = "1.1 2.2\n"
0389                         "3.3 4.4";
0390     QApplication::clipboard()->setText(str);
0391 
0392     SpreadsheetView view(&sheet, false);
0393     view.goToCell(1, 1); //havigate to the edge of the spreadsheet
0394     view.pasteIntoSelection();
0395 
0396     //spreadsheet size
0397     QCOMPARE(sheet.columnCount(), 3);
0398     QCOMPARE(sheet.rowCount(), 100);
0399 
0400     //column modes
0401     QCOMPARE(sheet.column(0)->columnMode(), AbstractColumn::ColumnMode::Numeric);
0402     QCOMPARE(sheet.column(1)->columnMode(), AbstractColumn::ColumnMode::Numeric);
0403     QCOMPARE(sheet.column(2)->columnMode(), AbstractColumn::ColumnMode::Numeric);
0404 
0405     //values
0406     QCOMPARE((bool)std::isnan(sheet.column(0)->valueAt(0)), true);
0407     QCOMPARE((bool)std::isnan(sheet.column(1)->valueAt(0)), true);
0408     QCOMPARE((bool)std::isnan(sheet.column(2)->valueAt(0)), true);
0409 
0410     QCOMPARE((bool)std::isnan(sheet.column(0)->valueAt(1)), true);
0411     QCOMPARE(sheet.column(1)->valueAt(1), 1.1);
0412     QCOMPARE(sheet.column(2)->valueAt(1), 2.2);
0413 
0414     QCOMPARE((bool)std::isnan(sheet.column(0)->valueAt(2)), true);
0415     QCOMPARE(sheet.column(1)->valueAt(2), 3.3);
0416     QCOMPARE(sheet.column(2)->valueAt(2), 4.4);
0417 }
0418 
0419 /////////////////////////////// Sorting tests ////////////////////////////
0420 // single column
0421 
0422 /*
0423  * check sorting single column of double values with NaN ascending
0424  */
0425 void SpreadsheetTest::testSortSingleNumeric1() {
0426     const QVector<double> xData{0.5, -0.2, GSL_NAN, 2.0, -1.0};
0427 
0428     Spreadsheet sheet("test", false);
0429     sheet.setColumnCount(1);
0430     sheet.setRowCount(7);
0431     auto* col = sheet.column(0);
0432     col->replaceValues(0, xData);
0433 
0434     // sort
0435     sheet.sortColumns(nullptr, {col}, true);
0436 
0437     //values
0438     QCOMPARE(col->valueAt(0), -1.0);
0439     QCOMPARE(col->valueAt(1), -0.2);
0440     QCOMPARE(col->valueAt(2), 0.5);
0441     QCOMPARE(col->valueAt(3), 2.0);
0442 }
0443 
0444 /*
0445  * check sorting single column of double values with NaN descending
0446  */
0447 void SpreadsheetTest::testSortSingleNumeric2() {
0448     const QVector<double> xData{0.5, -0.2, GSL_NAN, 2.0, -1.0};
0449 
0450     Spreadsheet sheet("test", false);
0451     sheet.setColumnCount(1);
0452     sheet.setRowCount(7);
0453     auto* col = sheet.column(0);
0454     col->replaceValues(0, xData);
0455 
0456     // sort
0457     sheet.sortColumns(nullptr, {col}, false);
0458 
0459     //values
0460     QCOMPARE(col->valueAt(0), 2.0);
0461     QCOMPARE(col->valueAt(1), 0.5);
0462     QCOMPARE(col->valueAt(2), -0.2);
0463     QCOMPARE(col->valueAt(3), -1.0);
0464 }
0465 
0466 /*
0467  * check sorting single column of integer values with empty entries ascending
0468  */
0469 void SpreadsheetTest::testSortSingleInteger1() {
0470     const QVector<int> xData1{4, 5, 2};
0471     const QVector<int> xData2{3, 6, -1};
0472 
0473     Spreadsheet sheet("test", false);
0474     sheet.setColumnCount(1);
0475     sheet.setRowCount(7);
0476     auto* col = sheet.column(0);
0477     col->setColumnMode(AbstractColumn::ColumnMode::Integer);
0478     col->replaceInteger(0, xData1);
0479     col->replaceInteger(4, xData2);
0480 
0481     // sort
0482     sheet.sortColumns(nullptr, {col}, true);
0483 
0484     //values
0485     QCOMPARE(col->integerAt(0), -1);
0486     QCOMPARE(col->integerAt(1), 0);
0487     QCOMPARE(col->integerAt(2), 2);
0488     QCOMPARE(col->integerAt(3), 3);
0489     QCOMPARE(col->integerAt(4), 4);
0490     QCOMPARE(col->integerAt(5), 5);
0491     QCOMPARE(col->integerAt(6), 6);
0492 }
0493 
0494 /*
0495  * check sorting single column of integer values with empty entries ascending
0496  */
0497 void SpreadsheetTest::testSortSingleInteger2() {
0498     const QVector<int> xData1{4, 5, 2};
0499     const QVector<int> xData2{3, 6, -1};
0500 
0501     Spreadsheet sheet("test", false);
0502     sheet.setColumnCount(1);
0503     sheet.setRowCount(7);
0504     auto* col = sheet.column(0);
0505     col->setColumnMode(AbstractColumn::ColumnMode::Integer);
0506     col->replaceInteger(0, xData1);
0507     col->replaceInteger(4, xData2);
0508 
0509     // sort
0510     sheet.sortColumns(nullptr, {col}, false);
0511 
0512     //values
0513     QCOMPARE(col->integerAt(6), -1);
0514     QCOMPARE(col->integerAt(5), 0);
0515     QCOMPARE(col->integerAt(4), 2);
0516     QCOMPARE(col->integerAt(3), 3);
0517     QCOMPARE(col->integerAt(2), 4);
0518     QCOMPARE(col->integerAt(1), 5);
0519     QCOMPARE(col->integerAt(0), 6);
0520 }
0521 
0522 /*
0523  * check sorting single column of big int values with empty entries ascending
0524  */
0525 void SpreadsheetTest::testSortSingleBigInt1() {
0526     const QVector<qint64> xData1{40000000000, 50000000000, 20000000000};
0527     const QVector<qint64> xData2{30000000000, 60000000000, -10000000000};
0528 
0529     Spreadsheet sheet("test", false);
0530     sheet.setColumnCount(1);
0531     sheet.setRowCount(7);
0532     auto* col = sheet.column(0);
0533     col->setColumnMode(AbstractColumn::ColumnMode::BigInt);
0534     col->replaceBigInt(0, xData1);
0535     col->replaceBigInt(4, xData2);
0536 
0537     // sort
0538     sheet.sortColumns(nullptr, {col}, true);
0539 
0540     //values
0541     QCOMPARE(col->bigIntAt(0), -10000000000ll);
0542     QCOMPARE(col->bigIntAt(1), 0);
0543     QCOMPARE(col->bigIntAt(2), 20000000000ll);
0544     QCOMPARE(col->bigIntAt(3), 30000000000ll);
0545     QCOMPARE(col->bigIntAt(4), 40000000000ll);
0546     QCOMPARE(col->bigIntAt(5), 50000000000ll);
0547     QCOMPARE(col->bigIntAt(6), 60000000000ll);
0548 }
0549 
0550 /*
0551  * check sorting single column of big int values with empty entries descending
0552  */
0553 void SpreadsheetTest::testSortSingleBigInt2() {
0554     const QVector<qint64> xData1{40000000000, 50000000000, 20000000000};
0555     const QVector<qint64> xData2{30000000000, 60000000000, -10000000000};
0556 
0557     Spreadsheet sheet("test", false);
0558     sheet.setColumnCount(1);
0559     sheet.setRowCount(7);
0560     auto* col = sheet.column(0);
0561     col->setColumnMode(AbstractColumn::ColumnMode::BigInt);
0562     col->replaceBigInt(0, xData1);
0563     col->replaceBigInt(4, xData2);
0564 
0565     // sort
0566     sheet.sortColumns(nullptr, {col}, false);
0567 
0568     //values
0569     QCOMPARE(col->bigIntAt(6), -10000000000ll);
0570     QCOMPARE(col->bigIntAt(5), 0);
0571     QCOMPARE(col->bigIntAt(4), 20000000000ll);
0572     QCOMPARE(col->bigIntAt(3), 30000000000ll);
0573     QCOMPARE(col->bigIntAt(2), 40000000000ll);
0574     QCOMPARE(col->bigIntAt(1), 50000000000ll);
0575     QCOMPARE(col->bigIntAt(0), 60000000000ll);
0576 }
0577 
0578 /*
0579  * check sorting single column of text with empty entries ascending
0580  */
0581 void SpreadsheetTest::testSortSingleText1() {
0582     const QVector<QString> xData{"ben", "amy", "eddy", "", "carl", "dan"};
0583 
0584     Spreadsheet sheet("test", false);
0585     sheet.setColumnCount(1);
0586     sheet.setRowCount(8);
0587     auto* col = sheet.column(0);
0588     col->setColumnMode(AbstractColumn::ColumnMode::Text);
0589     col->replaceTexts(0, xData);
0590 
0591     // sort
0592     sheet.sortColumns(nullptr, {col}, true);
0593 
0594     //values
0595     QCOMPARE(col->textAt(0), QLatin1String("amy"));
0596     QCOMPARE(col->textAt(1), QLatin1String("ben"));
0597     QCOMPARE(col->textAt(2), QLatin1String("carl"));
0598     QCOMPARE(col->textAt(3), QLatin1String("dan"));
0599     QCOMPARE(col->textAt(4), QLatin1String("eddy"));
0600     QCOMPARE(col->textAt(5), QLatin1String(""));
0601     QCOMPARE(col->textAt(6), QLatin1String(""));
0602 }
0603 
0604 /*
0605  * check sorting single column of text with empty entries descending
0606  */
0607 void SpreadsheetTest::testSortSingleText2() {
0608     const QVector<QString> xData = {"ben", "amy", "eddy", "", "carl", "dan"};
0609 
0610     Spreadsheet sheet("test", false);
0611     sheet.setColumnCount(1);
0612     sheet.setRowCount(8);
0613     auto* col = sheet.column(0);
0614     col->setColumnMode(AbstractColumn::ColumnMode::Text);
0615     col->replaceTexts(0, xData);
0616 
0617     // sort
0618     sheet.sortColumns(nullptr, {col}, false);
0619 
0620     //values
0621     QCOMPARE(col->textAt(0), QLatin1String("eddy"));
0622     QCOMPARE(col->textAt(1), QLatin1String("dan"));
0623     QCOMPARE(col->textAt(2), QLatin1String("carl"));
0624     QCOMPARE(col->textAt(3), QLatin1String("ben"));
0625     QCOMPARE(col->textAt(4), QLatin1String("amy"));
0626     QCOMPARE(col->textAt(5), QLatin1String(""));
0627     QCOMPARE(col->textAt(6), QLatin1String(""));
0628 }
0629 
0630 /*
0631  * check sorting single column of datetimes with invalid entries ascending
0632  */
0633 void SpreadsheetTest::testSortSingleDateTime1() {
0634     const QVector<QDateTime> xData{
0635         QDateTime(QDate(2020, 02, 29), QTime(12, 12, 12)),
0636         QDateTime(QDate(2020, 02, 28), QTime(12, 12, 12)),
0637         QDateTime(QDate(2019, 02, 28), QTime(12, 12, 12)),
0638         QDateTime(QDate(2019, 02, 29), QTime(12, 12, 12)),  // invalid
0639         QDateTime(QDate(2020, 02, 29), QTime(12, 12, 13)),
0640         QDateTime(QDate(2020, 02, 29), QTime(11, 12, 12)),
0641         };
0642 
0643     Spreadsheet sheet("test", false);
0644     sheet.setColumnCount(1);
0645     sheet.setRowCount(8);
0646     auto* col{sheet.column(0)};
0647     col->setColumnMode(AbstractColumn::ColumnMode::DateTime);
0648     col->replaceDateTimes(0, xData);
0649 
0650     // sort
0651     sheet.sortColumns(nullptr, {col}, true);
0652 
0653     //values
0654     QCOMPARE(col->dateTimeAt(0), QDateTime(QDate(2019, 02, 28), QTime(12, 12, 12)));
0655     QCOMPARE(col->dateTimeAt(1), QDateTime(QDate(2020, 02, 28), QTime(12, 12, 12)));
0656     QCOMPARE(col->dateTimeAt(2), QDateTime(QDate(2020, 02, 29), QTime(11, 12, 12)));
0657     QCOMPARE(col->dateTimeAt(3), QDateTime(QDate(2020, 02, 29), QTime(12, 12, 12)));
0658     QCOMPARE(col->dateTimeAt(4), QDateTime(QDate(2020, 02, 29), QTime(12, 12, 13)));
0659 }
0660 
0661 /*
0662  * check sorting single column of datetimes with invalid entries descending
0663  */
0664 void SpreadsheetTest::testSortSingleDateTime2() {
0665 
0666     const QVector<QDateTime> xData{
0667         QDateTime(QDate(2020, 02, 29), QTime(12, 12, 12)),
0668         QDateTime(QDate(2020, 02, 28), QTime(12, 12, 12)),
0669         QDateTime(QDate(2019, 02, 28), QTime(12, 12, 12)),
0670         QDateTime(QDate(2019, 02, 29), QTime(12, 12, 12)),  // invalid
0671         QDateTime(QDate(2020, 02, 29), QTime(12, 12, 13)),
0672         QDateTime(QDate(2020, 02, 29), QTime(11, 12, 12)),
0673         };
0674 
0675     Spreadsheet sheet("test", false);
0676     sheet.setColumnCount(1);
0677     sheet.setRowCount(8);
0678     auto* col = sheet.column(0);
0679     col->setColumnMode(AbstractColumn::ColumnMode::DateTime);
0680     col->replaceDateTimes(0, xData);
0681 
0682     // sort
0683     sheet.sortColumns(nullptr, {col}, false);
0684 
0685     //values
0686     QCOMPARE(col->dateTimeAt(4), QDateTime(QDate(2019, 02, 28), QTime(12, 12, 12)));
0687     QCOMPARE(col->dateTimeAt(3), QDateTime(QDate(2020, 02, 28), QTime(12, 12, 12)));
0688     QCOMPARE(col->dateTimeAt(2), QDateTime(QDate(2020, 02, 29), QTime(11, 12, 12)));
0689     QCOMPARE(col->dateTimeAt(1), QDateTime(QDate(2020, 02, 29), QTime(12, 12, 12)));
0690     QCOMPARE(col->dateTimeAt(0), QDateTime(QDate(2020, 02, 29), QTime(12, 12, 13)));
0691 }
0692 
0693 // multiple column
0694 /*
0695  * check sorting double values with NaN ascending as leading column
0696  */
0697 void SpreadsheetTest::testSortNumeric1() {
0698     const QVector<double> xData{0.5, -0.2, GSL_NAN, 2.0, -1.0};
0699     const QVector<int> yData{1, 2, 3, 4, 5, 6};
0700 
0701     Spreadsheet sheet("test", false);
0702     sheet.setColumnCount(2);
0703     sheet.setRowCount(10);
0704     auto* col0{sheet.column(0)};
0705     auto* col1{sheet.column(1)};
0706     col0->replaceValues(0, xData);
0707     col1->setColumnMode(AbstractColumn::ColumnMode::Integer);
0708     col1->replaceInteger(0, yData);
0709 
0710     // sort
0711     sheet.sortColumns(col0, {col0, col1}, true);
0712 
0713     //values
0714     QCOMPARE(col0->valueAt(0), -1.0);
0715     QCOMPARE(col0->valueAt(1), -0.2);
0716     QCOMPARE(col0->valueAt(2), 0.5);
0717     QCOMPARE(col0->valueAt(3), 2.0);
0718     //QCOMPARE(col0->valueAt(4), GSL_NAN);
0719     QCOMPARE(col1->integerAt(0), 5);
0720     QCOMPARE(col1->integerAt(1), 2);
0721     QCOMPARE(col1->integerAt(2), 1);
0722     QCOMPARE(col1->integerAt(3), 4);
0723     QCOMPARE(col1->integerAt(4), 3);
0724     QCOMPARE(col1->integerAt(5), 6);
0725 }
0726 
0727 /*
0728  * check sorting double values with NaN descending as leading column
0729  */
0730 void SpreadsheetTest::testSortNumeric2() {
0731     const QVector<double> xData{0.5, -0.2, GSL_NAN, 2.0, -1.0};
0732     const QVector<int> yData{1, 2, 3, 4, 5, 6, 7};
0733 
0734     Spreadsheet sheet("test", false);
0735     sheet.setColumnCount(2);
0736     sheet.setRowCount(10);
0737     auto* col0{sheet.column(0)};
0738     auto* col1{sheet.column(1)};
0739     col0->replaceValues(0, xData);
0740     col1->setColumnMode(AbstractColumn::ColumnMode::Integer);
0741     col1->replaceInteger(0, yData);
0742 
0743     // sort
0744     sheet.sortColumns(col0, {col0, col1}, false);
0745 
0746     //values
0747     QCOMPARE(col0->valueAt(0), 2.0);
0748     QCOMPARE(col0->valueAt(1), 0.5);
0749     QCOMPARE(col0->valueAt(2), -0.2);
0750     QCOMPARE(col0->valueAt(3), -1.0);
0751     QCOMPARE(col1->integerAt(0), 4);
0752     QCOMPARE(col1->integerAt(1), 1);
0753     QCOMPARE(col1->integerAt(2), 2);
0754     QCOMPARE(col1->integerAt(3), 5);
0755     QCOMPARE(col1->integerAt(4), 3);
0756     QCOMPARE(col1->integerAt(5), 6);
0757     QCOMPARE(col1->integerAt(6), 7);
0758 }
0759 
0760 /*
0761  * check sorting integer values with empty entries ascending as leading column
0762  */
0763 void SpreadsheetTest::testSortInteger1() {
0764     const QVector<int> xData1{4, 5, 2};
0765     const QVector<int> xData2{3, 6, -1};
0766     const QVector<int> yData{1, 2, 3, 4, 5, 6, 7};
0767 
0768     Spreadsheet sheet("test", false);
0769     sheet.setColumnCount(2);
0770     sheet.setRowCount(7);
0771     auto* col0{sheet.column(0)};
0772     auto* col1{sheet.column(1)};
0773     col0->setColumnMode(AbstractColumn::ColumnMode::Integer);
0774     col0->replaceInteger(0, xData1);
0775     col0->replaceInteger(4, xData2);
0776     col1->setColumnMode(AbstractColumn::ColumnMode::Integer);
0777     col1->replaceInteger(0, yData);
0778 
0779     // sort
0780     sheet.sortColumns(col0, {col0, col1}, true);
0781 
0782     //values
0783     QCOMPARE(col0->integerAt(0), -1);
0784     QCOMPARE(col0->integerAt(1), 0);
0785     QCOMPARE(col0->integerAt(2), 2);
0786     QCOMPARE(col0->integerAt(3), 3);
0787     QCOMPARE(col0->integerAt(4), 4);
0788     QCOMPARE(col0->integerAt(5), 5);
0789     QCOMPARE(col0->integerAt(6), 6);
0790     QCOMPARE(col1->integerAt(0), 7);
0791     QCOMPARE(col1->integerAt(1), 4);
0792     QCOMPARE(col1->integerAt(2), 3);
0793     QCOMPARE(col1->integerAt(3), 5);
0794     QCOMPARE(col1->integerAt(4), 1);
0795     QCOMPARE(col1->integerAt(5), 2);
0796     QCOMPARE(col1->integerAt(6), 6);
0797 }
0798 
0799 /*
0800  * check sorting integer values with empty entries descending as leading column
0801  */
0802 void SpreadsheetTest::testSortInteger2() {
0803     const QVector<int> xData1{4, 5, 2};
0804     const QVector<int> xData2{3, 6, -1};
0805     const QVector<int> yData{1, 2, 3, 4, 5, 6, 7};
0806 
0807     Spreadsheet sheet("test", false);
0808     sheet.setColumnCount(2);
0809     sheet.setRowCount(7);
0810     auto* col0{sheet.column(0)};
0811     auto* col1{sheet.column(1)};
0812     col0->setColumnMode(AbstractColumn::ColumnMode::Integer);
0813     col0->replaceInteger(0, xData1);
0814     col0->replaceInteger(4, xData2);
0815     col1->setColumnMode(AbstractColumn::ColumnMode::Integer);
0816     col1->replaceInteger(0, yData);
0817 
0818     // sort
0819     sheet.sortColumns(col0, {col0, col1}, false);
0820 
0821     //values
0822     QCOMPARE(col0->integerAt(6), -1);
0823     QCOMPARE(col0->integerAt(5), 0);
0824     QCOMPARE(col0->integerAt(4), 2);
0825     QCOMPARE(col0->integerAt(3), 3);
0826     QCOMPARE(col0->integerAt(2), 4);
0827     QCOMPARE(col0->integerAt(1), 5);
0828     QCOMPARE(col0->integerAt(0), 6);
0829     QCOMPARE(col1->integerAt(6), 7);
0830     QCOMPARE(col1->integerAt(5), 4);
0831     QCOMPARE(col1->integerAt(4), 3);
0832     QCOMPARE(col1->integerAt(3), 5);
0833     QCOMPARE(col1->integerAt(2), 1);
0834     QCOMPARE(col1->integerAt(1), 2);
0835     QCOMPARE(col1->integerAt(0), 6);
0836 }
0837 
0838 /*
0839  * check sorting big int values with empty entries ascending as leading column
0840  */
0841 void SpreadsheetTest::testSortBigInt1() {
0842     Spreadsheet sheet("test", false);
0843     sheet.setColumnCount(2);
0844     sheet.setRowCount(7);
0845 
0846     QVector<qint64> xData1{40000000000, 50000000000, 20000000000};
0847     QVector<qint64> xData2{30000000000, 60000000000, -10000000000};
0848     QVector<qint64> yData{1, 2, 3, 4, 5, 6, 7};
0849 
0850     auto* col0{sheet.column(0)};
0851     auto* col1{sheet.column(1)};
0852     col0->setColumnMode(AbstractColumn::ColumnMode::BigInt);
0853     col0->replaceBigInt(0, xData1);
0854     col0->replaceBigInt(4, xData2);
0855     col1->setColumnMode(AbstractColumn::ColumnMode::BigInt);
0856     col1->replaceBigInt(0, yData);
0857 
0858     // sort
0859     sheet.sortColumns(col0, {col0, col1}, true);
0860 
0861     //values
0862     QCOMPARE(col0->bigIntAt(0), -10000000000ll);
0863     QCOMPARE(col0->bigIntAt(1), 0);
0864     QCOMPARE(col0->bigIntAt(2), 20000000000ll);
0865     QCOMPARE(col0->bigIntAt(3), 30000000000ll);
0866     QCOMPARE(col0->bigIntAt(4), 40000000000ll);
0867     QCOMPARE(col0->bigIntAt(5), 50000000000ll);
0868     QCOMPARE(col0->bigIntAt(6), 60000000000ll);
0869     QCOMPARE(col1->bigIntAt(0), 7);
0870     QCOMPARE(col1->bigIntAt(1), 4);
0871     QCOMPARE(col1->bigIntAt(2), 3);
0872     QCOMPARE(col1->bigIntAt(3), 5);
0873     QCOMPARE(col1->bigIntAt(4), 1);
0874     QCOMPARE(col1->bigIntAt(5), 2);
0875     QCOMPARE(col1->bigIntAt(6), 6);
0876 }
0877 
0878 /*
0879  * check sorting big int values with empty entries descending as leading column
0880  */
0881 void SpreadsheetTest::testSortBigInt2() {
0882     Spreadsheet sheet("test", false);
0883     sheet.setColumnCount(2);
0884     sheet.setRowCount(7);
0885 
0886     QVector<qint64> xData1{40000000000, 50000000000, 20000000000};
0887     QVector<qint64> xData2{30000000000, 60000000000, -10000000000};
0888     QVector<qint64> yData{1, 2, 3, 4, 5, 6, 7};
0889 
0890     auto* col0{sheet.column(0)};
0891     auto* col1{sheet.column(1)};
0892     col0->setColumnMode(AbstractColumn::ColumnMode::BigInt);
0893     col0->replaceBigInt(0, xData1);
0894     col0->replaceBigInt(4, xData2);
0895     col1->setColumnMode(AbstractColumn::ColumnMode::BigInt);
0896     col1->replaceBigInt(0, yData);
0897 
0898     // sort
0899     sheet.sortColumns(col0, {col0, col1}, false);
0900 
0901     //values
0902     QCOMPARE(col0->bigIntAt(6), -10000000000ll);
0903     QCOMPARE(col0->bigIntAt(5), 0);
0904     QCOMPARE(col0->bigIntAt(4), 20000000000ll);
0905     QCOMPARE(col0->bigIntAt(3), 30000000000ll);
0906     QCOMPARE(col0->bigIntAt(2), 40000000000ll);
0907     QCOMPARE(col0->bigIntAt(1), 50000000000ll);
0908     QCOMPARE(col0->bigIntAt(0), 60000000000ll);
0909     QCOMPARE(col1->bigIntAt(6), 7);
0910     QCOMPARE(col1->bigIntAt(5), 4);
0911     QCOMPARE(col1->bigIntAt(4), 3);
0912     QCOMPARE(col1->bigIntAt(3), 5);
0913     QCOMPARE(col1->bigIntAt(2), 1);
0914     QCOMPARE(col1->bigIntAt(1), 2);
0915     QCOMPARE(col1->bigIntAt(0), 6);
0916 }
0917 
0918 /*
0919  * check sorting text with empty entries ascending as leading column
0920  */
0921 void SpreadsheetTest::testSortText1() {
0922     Spreadsheet sheet("test", false);
0923     sheet.setColumnCount(2);
0924     sheet.setRowCount(8);
0925 
0926     QVector<QString> xData{"ben", "amy", "eddy", "", "carl", "dan"};
0927     QVector<int> yData{1, 2, 3, 4, 5, 6, 7};
0928 
0929     auto* col0{sheet.column(0)};
0930     auto* col1{sheet.column(1)};
0931     col0->setColumnMode(AbstractColumn::ColumnMode::Text);
0932     col0->replaceTexts(0, xData);
0933     col1->setColumnMode(AbstractColumn::ColumnMode::Integer);
0934     col1->replaceInteger(0, yData);
0935 
0936     // sort
0937     sheet.sortColumns(col0, {col0, col1}, true);
0938 
0939     //values
0940     QCOMPARE(col0->textAt(0), QLatin1String("amy"));
0941     QCOMPARE(col0->textAt(1), QLatin1String("ben"));
0942     QCOMPARE(col0->textAt(2), QLatin1String("carl"));
0943     QCOMPARE(col0->textAt(3), QLatin1String("dan"));
0944     QCOMPARE(col0->textAt(4), QLatin1String("eddy"));
0945     QCOMPARE(col0->textAt(5), QLatin1String(""));
0946     QCOMPARE(col0->textAt(6), QLatin1String(""));
0947     QCOMPARE(col1->integerAt(0), 2);
0948     QCOMPARE(col1->integerAt(1), 1);
0949     QCOMPARE(col1->integerAt(2), 5);
0950     QCOMPARE(col1->integerAt(3), 6);
0951     QCOMPARE(col1->integerAt(4), 3);
0952     QCOMPARE(col1->integerAt(5), 4);
0953     QCOMPARE(col1->integerAt(6), 7);
0954 }
0955 
0956 /*
0957  * check sorting text with empty entries descending as leading column
0958  */
0959 void SpreadsheetTest::testSortText2() {
0960     Spreadsheet sheet("test", false);
0961     sheet.setColumnCount(2);
0962     sheet.setRowCount(8);
0963 
0964     QVector<QString> xData{"ben", "amy", "eddy", "", "carl", "dan"};
0965     QVector<int> yData{1, 2, 3, 4, 5, 6, 7};
0966 
0967     auto* col0{sheet.column(0)};
0968     auto* col1{sheet.column(1)};
0969     col0->setColumnMode(AbstractColumn::ColumnMode::Text);
0970     col0->replaceTexts(0, xData);
0971     col1->setColumnMode(AbstractColumn::ColumnMode::Integer);
0972     col1->replaceInteger(0, yData);
0973 
0974     // sort
0975     sheet.sortColumns(col0, {col0, col1}, false);
0976 
0977     //values
0978     QCOMPARE(col0->textAt(4), QLatin1String("amy"));
0979     QCOMPARE(col0->textAt(3), QLatin1String("ben"));
0980     QCOMPARE(col0->textAt(2), QLatin1String("carl"));
0981     QCOMPARE(col0->textAt(1), QLatin1String("dan"));
0982     QCOMPARE(col0->textAt(0), QLatin1String("eddy"));
0983     QCOMPARE(col0->textAt(5), QLatin1String(""));
0984     QCOMPARE(col0->textAt(6), QLatin1String(""));
0985     QCOMPARE(col1->integerAt(4), 2);
0986     QCOMPARE(col1->integerAt(3), 1);
0987     QCOMPARE(col1->integerAt(2), 5);
0988     QCOMPARE(col1->integerAt(1), 6);
0989     QCOMPARE(col1->integerAt(0), 3);
0990     QCOMPARE(col1->integerAt(5), 4);
0991     QCOMPARE(col1->integerAt(6), 7);
0992 }
0993 
0994 /*
0995  * check sorting datetimes with invalid entries ascending as leading column
0996  */
0997 void SpreadsheetTest::testSortDateTime1() {
0998     Spreadsheet sheet("test", false);
0999     sheet.setColumnCount(2);
1000     sheet.setRowCount(8);
1001 
1002     QVector<QDateTime> xData{
1003         QDateTime(QDate(2020, 02, 29), QTime(12, 12, 12)),
1004         QDateTime(QDate(2020, 02, 28), QTime(12, 12, 12)),
1005         QDateTime(QDate(2019, 02, 28), QTime(12, 12, 12)),
1006         QDateTime(QDate(2019, 02, 29), QTime(12, 12, 12)),  // invalid
1007         QDateTime(QDate(2020, 02, 29), QTime(12, 12, 13)),
1008         QDateTime(QDate(2020, 02, 29), QTime(11, 12, 12)),
1009         };
1010     QVector<int> yData = {1, 2, 3, 4, 5, 6, 7};
1011 
1012     auto* col0{sheet.column(0)};
1013     auto* col1{sheet.column(1)};
1014     col0->setColumnMode(AbstractColumn::ColumnMode::DateTime);
1015     col0->replaceDateTimes(0, xData);
1016     col1->setColumnMode(AbstractColumn::ColumnMode::Integer);
1017     col1->replaceInteger(0, yData);
1018 
1019     // sort
1020     sheet.sortColumns(col0, {col0, col1}, true);
1021 
1022     //values
1023     QCOMPARE(col0->dateTimeAt(0), QDateTime(QDate(2019, 02, 28), QTime(12, 12, 12)));
1024     QCOMPARE(col0->dateTimeAt(1), QDateTime(QDate(2020, 02, 28), QTime(12, 12, 12)));
1025     QCOMPARE(col0->dateTimeAt(2), QDateTime(QDate(2020, 02, 29), QTime(11, 12, 12)));
1026     QCOMPARE(col0->dateTimeAt(3), QDateTime(QDate(2020, 02, 29), QTime(12, 12, 12)));
1027     QCOMPARE(col0->dateTimeAt(4), QDateTime(QDate(2020, 02, 29), QTime(12, 12, 13)));
1028     QCOMPARE(col1->integerAt(0), 3);
1029     QCOMPARE(col1->integerAt(1), 2);
1030     QCOMPARE(col1->integerAt(2), 6);
1031     QCOMPARE(col1->integerAt(3), 1);
1032     QCOMPARE(col1->integerAt(4), 5);
1033     QCOMPARE(col1->integerAt(5), 4);
1034     QCOMPARE(col1->integerAt(6), 7);
1035 }
1036 
1037 /*
1038  * check sorting datetimes with invalid entries descending as leading column
1039  */
1040 void SpreadsheetTest::testSortDateTime2() {
1041     const QVector<QDateTime> xData{
1042         QDateTime(QDate(2020, 02, 29), QTime(12, 12, 12)),
1043         QDateTime(QDate(2020, 02, 28), QTime(12, 12, 12)),
1044         QDateTime(QDate(2019, 02, 28), QTime(12, 12, 12)),
1045         QDateTime(QDate(2019, 02, 29), QTime(12, 12, 12)),  // invalid
1046         QDateTime(QDate(2020, 02, 29), QTime(12, 12, 13)),
1047         QDateTime(QDate(2020, 02, 29), QTime(11, 12, 12)),
1048         };
1049     const QVector<int> yData = {1, 2, 3, 4, 5, 6, 7};
1050 
1051     Spreadsheet sheet("test", false);
1052     sheet.setColumnCount(2);
1053     sheet.setRowCount(8);
1054     auto* col0{sheet.column(0)};
1055     auto* col1{sheet.column(1)};
1056     col0->setColumnMode(AbstractColumn::ColumnMode::DateTime);
1057     col0->replaceDateTimes(0, xData);
1058     col1->setColumnMode(AbstractColumn::ColumnMode::Integer);
1059     col1->replaceInteger(0, yData);
1060 
1061     // sort
1062     sheet.sortColumns(col0, {col0, col1}, false);
1063 
1064     //values
1065     QCOMPARE(col0->dateTimeAt(4), QDateTime(QDate(2019, 02, 28), QTime(12, 12, 12)));
1066     QCOMPARE(col0->dateTimeAt(3), QDateTime(QDate(2020, 02, 28), QTime(12, 12, 12)));
1067     QCOMPARE(col0->dateTimeAt(2), QDateTime(QDate(2020, 02, 29), QTime(11, 12, 12)));
1068     QCOMPARE(col0->dateTimeAt(1), QDateTime(QDate(2020, 02, 29), QTime(12, 12, 12)));
1069     QCOMPARE(col0->dateTimeAt(0), QDateTime(QDate(2020, 02, 29), QTime(12, 12, 13)));
1070     QCOMPARE(col1->integerAt(4), 3);
1071     QCOMPARE(col1->integerAt(3), 2);
1072     QCOMPARE(col1->integerAt(2), 6);
1073     QCOMPARE(col1->integerAt(1), 1);
1074     QCOMPARE(col1->integerAt(0), 5);
1075     QCOMPARE(col1->integerAt(5), 4);
1076     QCOMPARE(col1->integerAt(6), 7);
1077 }
1078 
1079 // performance
1080 
1081 /*
1082  * check performance of sorting double values in single column
1083  */
1084 void SpreadsheetTest::testSortPerformanceNumeric1() {
1085     Spreadsheet sheet("test", false);
1086     sheet.setColumnCount(1);
1087     sheet.setRowCount(10000);
1088 
1089     QVector<double> xData;
1090     for (int i = 0; i < sheet.rowCount(); i++)
1091 #if (QT_VERSION >= QT_VERSION_CHECK(5, 10, 0))
1092         xData << QRandomGenerator::global()->generateDouble();
1093 #else
1094         xData << (double)(qrand())/RAND_MAX;
1095 #endif
1096 
1097     auto* col = sheet.column(0);
1098     col->replaceValues(0, xData);
1099 
1100     // sort
1101     QBENCHMARK {
1102         sheet.sortColumns(nullptr, {col}, true);
1103     }
1104 }
1105 
1106 /*
1107  * check performance of sorting double values with two columns
1108  */
1109 void SpreadsheetTest::testSortPerformanceNumeric2() {
1110     Spreadsheet sheet("test", false);
1111     sheet.setColumnCount(2);
1112     sheet.setRowCount(10000);
1113 
1114     QVector<double> xData;
1115     QVector<int> yData;
1116     for (int i = 0; i < sheet.rowCount(); i++) {
1117 #if (QT_VERSION >= QT_VERSION_CHECK(5, 10, 0))
1118         xData << QRandomGenerator::global()->generateDouble();
1119 #else
1120         xData << (double)(qrand())/RAND_MAX;
1121 #endif
1122         yData << i + 1;
1123     }
1124 
1125 
1126     auto* col0{sheet.column(0)};
1127     auto* col1{sheet.column(1)};
1128     col0->replaceValues(0, xData);
1129     col1->setColumnMode(AbstractColumn::ColumnMode::Integer);
1130     col1->replaceInteger(0, yData);
1131 
1132     // sort
1133     QBENCHMARK {
1134         sheet.sortColumns(col0, {col0, col1}, true);
1135     }
1136 }
1137 
1138 QTEST_MAIN(SpreadsheetTest)