File indexing completed on 2024-11-10 03:33:02
0001 /* 0002 File : ColumnTest.cpp 0003 Project : LabPlot 0004 Description : Tests for Column 0005 -------------------------------------------------------------------- 0006 SPDX-FileCopyrightText: 2022 Martin Marmsoler <martin.marmsoler@gmail.com> 0007 SPDX-FileCopyrightText: 2022-2023 Stefan Gerlach <stefan.gerlach@uni.kn> 0008 SPDX-FileCopyrightText: 2022-2023 Alexander Semke <alexander.semke@web.de> 0009 0010 SPDX-License-Identifier: GPL-2.0-or-later 0011 */ 0012 0013 #include "ColumnTest.h" 0014 #include "backend/core/Project.h" 0015 #include "backend/core/column/Column.h" 0016 #include "backend/core/column/ColumnPrivate.h" 0017 #include "backend/lib/XmlStreamReader.h" 0018 #include "backend/lib/trace.h" 0019 #include "backend/spreadsheet/Spreadsheet.h" 0020 0021 #include <QUndoStack> 0022 0023 #define SETUP_C1_C2_COLUMNS(c1Vector, c2Vector) \ 0024 auto c1 = Column(QStringLiteral("DataColumn"), Column::ColumnMode::Double); \ 0025 c1.replaceValues(-1, c1Vector); \ 0026 auto c2 = Column(QStringLiteral("FormulaColumn"), Column::ColumnMode::Double); \ 0027 c2.replaceValues(-1, c2Vector); 0028 0029 #define COLUMN2_SET_FORMULA_AND_EVALUATE(formula, result) \ 0030 c2.setFormula(QStringLiteral(formula), {QStringLiteral("x")}, QVector<Column*>({&c1}), true); \ 0031 c2.updateFormula(); \ 0032 QCOMPARE(c2.rowCount(), 8); \ 0033 for (int i = 0; i < c2.rowCount(); i++) \ 0034 VALUES_EQUAL(c2.valueAt(i), result); 0035 0036 void ColumnTest::initTestCase() { 0037 // needed in order to have the signals triggered by SignallingUndoCommand, see LabPlot.cpp 0038 // TODO: redesign/remove this 0039 qRegisterMetaType<const AbstractAspect*>("const AbstractAspect*"); 0040 qRegisterMetaType<const AbstractColumn*>("const AbstractColumn*"); 0041 } 0042 0043 void ColumnTest::doubleMinimum() { 0044 Column c(QStringLiteral("Double column"), Column::ColumnMode::Double); 0045 c.setValues({-1.0, 2.0, 5.0}); 0046 QCOMPARE(c.properties(), Column::Properties::MonotonicIncreasing); 0047 QCOMPARE(c.minimum(0, 2), -1.0); 0048 QCOMPARE(c.minimum(1, 2), 2.0); 0049 0050 c.setValues({-1.0, -3.0, -4.0}); 0051 QCOMPARE(c.properties(), Column::Properties::MonotonicDecreasing); 0052 QCOMPARE(c.minimum(0, 2), -4.0); 0053 QCOMPARE(c.minimum(1, 2), -4.0); 0054 0055 c.setValues({-1.0, 2.0, -4.0}); 0056 QCOMPARE(c.properties(), Column::Properties::NonMonotonic); 0057 QCOMPARE(c.minimum(0, 2), -4.0); 0058 QCOMPARE(c.minimum(0, 1), -1.0); 0059 } 0060 0061 void ColumnTest::doubleMaximum() { 0062 Column c(QStringLiteral("Double column"), Column::ColumnMode::Double); 0063 c.setValues({-1.0, 2.0, 5.0}); 0064 QCOMPARE(c.maximum(0, 2), 5.0); 0065 QCOMPARE(c.maximum(1, 1), 2.0); 0066 0067 c.setValues({-1.0, -3.0, -4.0}); 0068 QCOMPARE(c.maximum(0, 2), -1.0); 0069 QCOMPARE(c.maximum(1, 2), -3.0); 0070 0071 c.setValues({-1.0, 2.0, -4.0}); 0072 QCOMPARE(c.maximum(0, 2), 2.0); 0073 QCOMPARE(c.maximum(0, 1), 2.0); 0074 } 0075 0076 void ColumnTest::integerMinimum() { 0077 Column c(QStringLiteral("Integer column"), Column::ColumnMode::Integer); 0078 c.setIntegers({-1, 2, 5}); 0079 QCOMPARE(c.properties(), Column::Properties::MonotonicIncreasing); 0080 QCOMPARE(c.minimum(0, 2), -1); 0081 QCOMPARE(c.minimum(1, 2), 2); 0082 0083 c.setIntegers({-1, -3, -4}); 0084 QCOMPARE(c.properties(), Column::Properties::MonotonicDecreasing); 0085 QCOMPARE(c.minimum(0, 2), -4); 0086 QCOMPARE(c.minimum(1, 2), -4); 0087 0088 c.setIntegers({-1, 2, -4}); 0089 QCOMPARE(c.properties(), Column::Properties::NonMonotonic); 0090 QCOMPARE(c.minimum(0, 2), -4); 0091 QCOMPARE(c.minimum(0, 1), -1); 0092 } 0093 0094 void ColumnTest::integerMaximum() { 0095 Column c(QStringLiteral("Integer column"), Column::ColumnMode::Integer); 0096 c.setIntegers({-1, 2, 5}); 0097 QCOMPARE(c.maximum(0, 2), 5); 0098 QCOMPARE(c.maximum(1, 1), 2); 0099 0100 c.setIntegers({-1, -3, -4}); 0101 QCOMPARE(c.maximum(0, 2), -1); 0102 QCOMPARE(c.maximum(1, 2), -3); 0103 0104 c.setIntegers({-1, 2, -4}); 0105 QCOMPARE(c.maximum(0, 2), 2); 0106 QCOMPARE(c.maximum(0, 1), 2); 0107 } 0108 0109 void ColumnTest::bigIntMinimum() { 0110 Column c(QStringLiteral("BigInt column"), Column::ColumnMode::BigInt); 0111 c.setBigInts({-1, 2, 5}); 0112 QCOMPARE(c.properties(), Column::Properties::MonotonicIncreasing); 0113 QCOMPARE(c.minimum(0, 2), -1); 0114 QCOMPARE(c.minimum(1, 2), 2); 0115 0116 c.setBigInts({-1, -3, -4}); 0117 QCOMPARE(c.properties(), Column::Properties::MonotonicDecreasing); 0118 QCOMPARE(c.minimum(0, 2), -4); 0119 QCOMPARE(c.minimum(1, 2), -4); 0120 0121 c.setBigInts({-1, 2, -4}); 0122 QCOMPARE(c.properties(), Column::Properties::NonMonotonic); 0123 QCOMPARE(c.minimum(0, 2), -4); 0124 QCOMPARE(c.minimum(0, 1), -1); 0125 } 0126 0127 void ColumnTest::bigIntMaximum() { 0128 Column c(QStringLiteral("BigInt column"), Column::ColumnMode::BigInt); 0129 c.setBigInts({-1, 2, 5}); 0130 QCOMPARE(c.maximum(0, 2), 5); 0131 QCOMPARE(c.maximum(0, 1), 2); 0132 0133 c.setBigInts({-1, -3, -4}); 0134 QCOMPARE(c.maximum(0, 2), -1); 0135 QCOMPARE(c.maximum(1, 2), -3); 0136 0137 c.setBigInts({-1, 2, -4}); 0138 QCOMPARE(c.maximum(0, 2), 2); 0139 QCOMPARE(c.maximum(0, 1), 2); 0140 } 0141 0142 ///////////////////////////////////////////////////// 0143 0144 void ColumnTest::statisticsDouble() { 0145 Column c(QStringLiteral("Double column"), Column::ColumnMode::Double); 0146 c.setValues({1.0, 1.0, 2.0, 5.0}); 0147 0148 auto& stats = c.statistics(); 0149 0150 QCOMPARE(stats.size, 4); 0151 QCOMPARE(stats.minimum, 1.); 0152 QCOMPARE(stats.maximum, 5.); 0153 QCOMPARE(stats.arithmeticMean, 2.25); 0154 QCOMPARE(stats.geometricMean, pow(10., 0.25)); 0155 QCOMPARE(stats.harmonicMean, 40. / 27.); 0156 QCOMPARE(stats.contraharmonicMean, 31. / 9.); 0157 0158 QCOMPARE(stats.mode, 1.); 0159 QCOMPARE(stats.firstQuartile, 1.); 0160 QCOMPARE(stats.median, 1.5); 0161 QCOMPARE(stats.thirdQuartile, 2.75); 0162 QCOMPARE(stats.iqr, 1.75); 0163 QCOMPARE(stats.percentile_1, 1.); 0164 QCOMPARE(stats.percentile_5, 1.); 0165 QCOMPARE(stats.percentile_10, 1.); 0166 QCOMPARE(stats.percentile_90, 4.1); 0167 QCOMPARE(stats.percentile_95, 4.55); 0168 QCOMPARE(stats.percentile_99, 4.91); 0169 QCOMPARE(stats.trimean, 1.6875); 0170 QCOMPARE(stats.variance, 3.58333333333); 0171 QCOMPARE(stats.standardDeviation, 1.8929694486); 0172 QCOMPARE(stats.meanDeviation, 1.375); 0173 QCOMPARE(stats.meanDeviationAroundMedian, 1.25); 0174 QCOMPARE(stats.medianDeviation, 0.5); 0175 QCOMPARE(stats.skewness, 0.95754916255356); 0176 QCOMPARE(stats.kurtosis, 2.1487290427258); 0177 QCOMPARE(stats.entropy, 1.5); 0178 } 0179 void ColumnTest::statisticsDoubleNegative() { 0180 Column c(QStringLiteral("Double column"), Column::ColumnMode::Double); 0181 c.setValues({-1.0, 0.0, 2.0, 5.0}); 0182 0183 auto& stats = c.statistics(); 0184 0185 QCOMPARE(stats.size, 4); 0186 QCOMPARE(stats.minimum, -1.); 0187 QCOMPARE(stats.maximum, 5.); 0188 QCOMPARE(stats.arithmeticMean, 1.5); 0189 QCOMPARE(stats.geometricMean, 1.474323891188); // special case 0190 QCOMPARE(stats.harmonicMean, 0.); 0191 QCOMPARE(stats.contraharmonicMean, 5.); 0192 0193 QCOMPARE(stats.mode, NAN); 0194 QCOMPARE(stats.firstQuartile, -.25); 0195 QCOMPARE(stats.median, 1.); 0196 QCOMPARE(stats.thirdQuartile, 2.75); 0197 QCOMPARE(stats.iqr, 3.); 0198 QCOMPARE(stats.percentile_1, -.97); 0199 QCOMPARE(stats.percentile_5, -.85); 0200 QCOMPARE(stats.percentile_10, -.7); 0201 QCOMPARE(stats.percentile_90, 4.1); 0202 QCOMPARE(stats.percentile_95, 4.55); 0203 QCOMPARE(stats.percentile_99, 4.91); 0204 QCOMPARE(stats.trimean, 1.125); 0205 QCOMPARE(stats.variance, 7.); 0206 QCOMPARE(stats.standardDeviation, 2.64575131106459); 0207 QCOMPARE(stats.meanDeviation, 2.); 0208 QCOMPARE(stats.meanDeviationAroundMedian, 2.); 0209 QCOMPARE(stats.medianDeviation, 1.5); 0210 QCOMPARE(stats.skewness, 0.49878374911084); 0211 QCOMPARE(stats.kurtosis, 1.7619047619048); 0212 QCOMPARE(stats.entropy, 2.); 0213 } 0214 void ColumnTest::statisticsDoubleBigNegative() { 0215 Column c(QStringLiteral("Double column"), Column::ColumnMode::Double); 0216 c.setValues({-100.0, 0.0, 2.0, 5.0}); 0217 0218 auto& stats = c.statistics(); 0219 0220 QCOMPARE(stats.size, 4); 0221 QCOMPARE(stats.minimum, -100.); 0222 QCOMPARE(stats.maximum, 5.); 0223 QCOMPARE(stats.arithmeticMean, -23.25); 0224 QCOMPARE(stats.geometricMean, NAN); // special case 0225 QCOMPARE(stats.harmonicMean, 0.); 0226 QCOMPARE(stats.contraharmonicMean, -3343. / 31.); 0227 0228 QCOMPARE(stats.mode, NAN); 0229 QCOMPARE(stats.firstQuartile, -25.); 0230 QCOMPARE(stats.median, 1.); 0231 QCOMPARE(stats.thirdQuartile, 2.75); 0232 QCOMPARE(stats.iqr, 27.75); 0233 QCOMPARE(stats.percentile_1, -97.); 0234 QCOMPARE(stats.percentile_5, -85.); 0235 QCOMPARE(stats.percentile_10, -70.); 0236 QCOMPARE(stats.percentile_90, 4.1); 0237 QCOMPARE(stats.percentile_95, 4.55); 0238 QCOMPARE(stats.percentile_99, 4.91); 0239 QCOMPARE(stats.trimean, -5.0625); 0240 QCOMPARE(stats.variance, 2622.25); 0241 QCOMPARE(stats.standardDeviation, 51.2079095453036); 0242 QCOMPARE(stats.meanDeviation, 38.375); 0243 QCOMPARE(stats.meanDeviationAroundMedian, 26.75); 0244 QCOMPARE(stats.medianDeviation, 2.5); 0245 QCOMPARE(stats.skewness, -1.1491083404244); 0246 QCOMPARE(stats.kurtosis, 2.3290867987696); 0247 QCOMPARE(stats.entropy, 2.); 0248 } 0249 void ColumnTest::statisticsDoubleZero() { 0250 Column c(QStringLiteral("Double column"), Column::ColumnMode::Double); 0251 c.setValues({1.0, 0.0, 2.0, 5.0}); 0252 0253 auto& stats = c.statistics(); 0254 0255 QCOMPARE(stats.size, 4); 0256 QCOMPARE(stats.minimum, 0.); 0257 QCOMPARE(stats.maximum, 5.); 0258 QCOMPARE(stats.arithmeticMean, 2.); 0259 QCOMPARE(stats.geometricMean, 1.77827941003892); // special case 0260 QCOMPARE(stats.harmonicMean, 0.); 0261 QCOMPARE(stats.contraharmonicMean, 3.75); 0262 0263 QCOMPARE(stats.mode, NAN); 0264 QCOMPARE(stats.firstQuartile, 0.75); 0265 QCOMPARE(stats.median, 1.5); 0266 QCOMPARE(stats.thirdQuartile, 2.75); 0267 QCOMPARE(stats.iqr, 2.); 0268 QCOMPARE(stats.percentile_1, 0.03); 0269 QCOMPARE(stats.percentile_5, 0.15); 0270 QCOMPARE(stats.percentile_10, 0.3); 0271 QCOMPARE(stats.percentile_90, 4.1); 0272 QCOMPARE(stats.percentile_95, 4.55); 0273 QCOMPARE(stats.percentile_99, 4.91); 0274 QCOMPARE(stats.trimean, 1.625); 0275 QCOMPARE(stats.variance, 4.6666666666667); 0276 QCOMPARE(stats.standardDeviation, 2.16024689946929); 0277 QCOMPARE(stats.meanDeviation, 1.5); 0278 QCOMPARE(stats.meanDeviationAroundMedian, 1.5); 0279 QCOMPARE(stats.medianDeviation, 1.); 0280 QCOMPARE(stats.skewness, 0.68724319348909); 0281 QCOMPARE(stats.kurtosis, 2.); 0282 QCOMPARE(stats.entropy, 2.); 0283 } 0284 0285 void ColumnTest::statisticsInt() { 0286 Column c(QStringLiteral("Integer column"), Column::ColumnMode::Integer); 0287 c.setIntegers({1, 1, 2, 5}); 0288 0289 auto& stats = c.statistics(); 0290 0291 QCOMPARE(stats.size, 4); 0292 QCOMPARE(stats.minimum, 1.); 0293 QCOMPARE(stats.maximum, 5.); 0294 QCOMPARE(stats.arithmeticMean, 2.25); 0295 QCOMPARE(stats.geometricMean, pow(10., 0.25)); 0296 QCOMPARE(stats.harmonicMean, 40. / 27.); 0297 QCOMPARE(stats.contraharmonicMean, 31. / 9.); 0298 0299 QCOMPARE(stats.mode, 1.); 0300 QCOMPARE(stats.firstQuartile, 1.); 0301 QCOMPARE(stats.median, 1.5); 0302 QCOMPARE(stats.thirdQuartile, 2.75); 0303 QCOMPARE(stats.iqr, 1.75); 0304 QCOMPARE(stats.percentile_1, 1.); 0305 QCOMPARE(stats.percentile_5, 1.); 0306 QCOMPARE(stats.percentile_10, 1.); 0307 QCOMPARE(stats.percentile_90, 4.1); 0308 QCOMPARE(stats.percentile_95, 4.55); 0309 QCOMPARE(stats.percentile_99, 4.91); 0310 QCOMPARE(stats.trimean, 1.6875); 0311 QCOMPARE(stats.variance, 3.58333333333); 0312 QCOMPARE(stats.standardDeviation, 1.8929694486); 0313 QCOMPARE(stats.meanDeviation, 1.375); 0314 QCOMPARE(stats.meanDeviationAroundMedian, 1.25); 0315 QCOMPARE(stats.medianDeviation, 0.5); 0316 QCOMPARE(stats.skewness, 0.95754916255356); 0317 QCOMPARE(stats.kurtosis, 2.1487290427258); 0318 QCOMPARE(stats.entropy, 1.5); 0319 } 0320 void ColumnTest::statisticsIntNegative() { 0321 Column c(QStringLiteral("Integer column"), Column::ColumnMode::Integer); 0322 c.setIntegers({-1, 0, 2, 5}); 0323 0324 auto& stats = c.statistics(); 0325 0326 QCOMPARE(stats.size, 4); 0327 QCOMPARE(stats.minimum, -1.); 0328 QCOMPARE(stats.maximum, 5.); 0329 QCOMPARE(stats.arithmeticMean, 1.5); 0330 QCOMPARE(stats.geometricMean, 1.474323891188); // special case 0331 QCOMPARE(stats.harmonicMean, 0.); 0332 QCOMPARE(stats.contraharmonicMean, 5.); 0333 0334 QCOMPARE(stats.mode, NAN); 0335 QCOMPARE(stats.firstQuartile, -.25); 0336 QCOMPARE(stats.median, 1.); 0337 QCOMPARE(stats.thirdQuartile, 2.75); 0338 QCOMPARE(stats.iqr, 3.); 0339 QCOMPARE(stats.percentile_1, -.97); 0340 QCOMPARE(stats.percentile_5, -.85); 0341 QCOMPARE(stats.percentile_10, -.7); 0342 QCOMPARE(stats.percentile_90, 4.1); 0343 QCOMPARE(stats.percentile_95, 4.55); 0344 QCOMPARE(stats.percentile_99, 4.91); 0345 QCOMPARE(stats.trimean, 1.125); 0346 QCOMPARE(stats.variance, 7.); 0347 QCOMPARE(stats.standardDeviation, 2.64575131106459); 0348 QCOMPARE(stats.meanDeviation, 2.); 0349 QCOMPARE(stats.meanDeviationAroundMedian, 2.); 0350 QCOMPARE(stats.medianDeviation, 1.5); 0351 QCOMPARE(stats.skewness, 0.49878374911084); 0352 QCOMPARE(stats.kurtosis, 1.7619047619048); 0353 QCOMPARE(stats.entropy, 2.); 0354 } 0355 void ColumnTest::statisticsIntBigNegative() { 0356 Column c(QStringLiteral("Integer column"), Column::ColumnMode::Integer); 0357 c.setIntegers({-100, 0, 2, 5}); 0358 0359 auto& stats = c.statistics(); 0360 0361 QCOMPARE(stats.size, 4); 0362 QCOMPARE(stats.minimum, -100.); 0363 QCOMPARE(stats.maximum, 5.); 0364 QCOMPARE(stats.arithmeticMean, -23.25); 0365 QCOMPARE(stats.geometricMean, NAN); // special case 0366 QCOMPARE(stats.harmonicMean, 0.); 0367 QCOMPARE(stats.contraharmonicMean, -3343. / 31.); 0368 0369 QCOMPARE(stats.mode, NAN); 0370 QCOMPARE(stats.firstQuartile, -25.); 0371 QCOMPARE(stats.median, 1.); 0372 QCOMPARE(stats.thirdQuartile, 2.75); 0373 QCOMPARE(stats.iqr, 27.75); 0374 QCOMPARE(stats.percentile_1, -97.); 0375 QCOMPARE(stats.percentile_5, -85.); 0376 QCOMPARE(stats.percentile_10, -70.); 0377 QCOMPARE(stats.percentile_90, 4.1); 0378 QCOMPARE(stats.percentile_95, 4.55); 0379 QCOMPARE(stats.percentile_99, 4.91); 0380 QCOMPARE(stats.trimean, -5.0625); 0381 QCOMPARE(stats.variance, 2622.25); 0382 QCOMPARE(stats.standardDeviation, 51.2079095453036); 0383 QCOMPARE(stats.meanDeviation, 38.375); 0384 QCOMPARE(stats.meanDeviationAroundMedian, 26.75); 0385 QCOMPARE(stats.medianDeviation, 2.5); 0386 QCOMPARE(stats.skewness, -1.1491083404244); 0387 QCOMPARE(stats.kurtosis, 2.3290867987696); 0388 QCOMPARE(stats.entropy, 2.); 0389 } 0390 void ColumnTest::statisticsIntZero() { 0391 Column c(QStringLiteral("Integer column"), Column::ColumnMode::Integer); 0392 c.setIntegers({1, 0, 2, 5}); 0393 0394 auto& stats = c.statistics(); 0395 0396 QCOMPARE(stats.size, 4); 0397 QCOMPARE(stats.minimum, 0.); 0398 QCOMPARE(stats.maximum, 5.); 0399 QCOMPARE(stats.arithmeticMean, 2.); 0400 QCOMPARE(stats.geometricMean, 1.77827941003892); // special case 0401 QCOMPARE(stats.harmonicMean, 0.); 0402 QCOMPARE(stats.contraharmonicMean, 3.75); 0403 0404 QCOMPARE(stats.mode, NAN); 0405 QCOMPARE(stats.firstQuartile, 0.75); 0406 QCOMPARE(stats.median, 1.5); 0407 QCOMPARE(stats.thirdQuartile, 2.75); 0408 QCOMPARE(stats.iqr, 2.); 0409 QCOMPARE(stats.percentile_1, 0.03); 0410 QCOMPARE(stats.percentile_5, 0.15); 0411 QCOMPARE(stats.percentile_10, 0.3); 0412 QCOMPARE(stats.percentile_90, 4.1); 0413 QCOMPARE(stats.percentile_95, 4.55); 0414 QCOMPARE(stats.percentile_99, 4.91); 0415 QCOMPARE(stats.trimean, 1.625); 0416 QCOMPARE(stats.variance, 4.6666666666667); 0417 QCOMPARE(stats.standardDeviation, 2.16024689946929); 0418 QCOMPARE(stats.meanDeviation, 1.5); 0419 QCOMPARE(stats.meanDeviationAroundMedian, 1.5); 0420 QCOMPARE(stats.medianDeviation, 1.); 0421 QCOMPARE(stats.skewness, 0.68724319348909); 0422 QCOMPARE(stats.kurtosis, 2.); 0423 QCOMPARE(stats.entropy, 2.); 0424 } 0425 void ColumnTest::statisticsIntOverflow() { 0426 Column c(QStringLiteral("Integer column"), Column::ColumnMode::Integer); 0427 c.setIntegers({1000000000, 1100000000, 1200000000, 1300000000}); 0428 0429 auto& stats = c.statistics(); 0430 0431 QCOMPARE(stats.size, 4); 0432 QCOMPARE(stats.minimum, 1000000000); 0433 QCOMPARE(stats.maximum, 1300000000); 0434 QCOMPARE(stats.arithmeticMean, 1150000000); 0435 QCOMPARE(stats.geometricMean, 1144535640.12); 0436 QCOMPARE(stats.harmonicMean, 1139064055.75838); 0437 QCOMPARE(stats.contraharmonicMean, 1160869565.21739); 0438 0439 QCOMPARE(stats.mode, NAN); 0440 QCOMPARE(stats.firstQuartile, 1075000000); 0441 QCOMPARE(stats.median, 1150000000); 0442 QCOMPARE(stats.thirdQuartile, 1225000000); 0443 QCOMPARE(stats.iqr, 150000000); 0444 QCOMPARE(stats.percentile_1, 1003000000); 0445 QCOMPARE(stats.percentile_5, 1015000000); 0446 QCOMPARE(stats.percentile_10, 1030000000); 0447 QCOMPARE(stats.percentile_90, 1270000000); 0448 QCOMPARE(stats.percentile_95, 1285000000); 0449 QCOMPARE(stats.percentile_99, 1297000000); 0450 QCOMPARE(stats.trimean, 1150000000); 0451 QCOMPARE(stats.variance, 1.66666666666667e+16); 0452 QCOMPARE(stats.standardDeviation, 129099444.873581); 0453 QCOMPARE(stats.meanDeviation, 100000000); 0454 QCOMPARE(stats.meanDeviationAroundMedian, 100000000); 0455 QCOMPARE(stats.medianDeviation, 100000000); 0456 QCOMPARE(stats.skewness, 0.); 0457 QCOMPARE(stats.kurtosis, 1.64); 0458 QCOMPARE(stats.entropy, 2.); 0459 } 0460 void ColumnTest::statisticsBigInt() { 0461 Column c(QStringLiteral("BigInt column"), Column::ColumnMode::BigInt); 0462 c.setBigInts({-10000000000, 0, 1000000000, 10000000000}); 0463 0464 auto& stats = c.statistics(); 0465 0466 QCOMPARE(stats.size, 4); 0467 QCOMPARE(stats.minimum, -10000000000); 0468 QCOMPARE(stats.maximum, 10000000000); 0469 QCOMPARE(stats.arithmeticMean, 250000000); 0470 QCOMPARE(stats.geometricMean, NAN); 0471 QCOMPARE(stats.harmonicMean, 0.); 0472 QCOMPARE(stats.contraharmonicMean, 201000000000); 0473 0474 QCOMPARE(stats.mode, NAN); 0475 // Windows CI fails here 0476 #ifndef HAVE_WINDOWS 0477 QCOMPARE(stats.firstQuartile, -2500000000); 0478 QCOMPARE(stats.median, 500000000); 0479 QCOMPARE(stats.thirdQuartile, 3250000000); 0480 QCOMPARE(stats.iqr, 5750000000); 0481 QCOMPARE(stats.percentile_1, -9700000000); 0482 QCOMPARE(stats.percentile_5, -8500000000); 0483 QCOMPARE(stats.percentile_10, -7000000000); 0484 FuzzyCompare(stats.percentile_90, 7300000000.); 0485 FuzzyCompare(stats.percentile_95, 8650000000.); 0486 FuzzyCompare(stats.percentile_99, 9730000000.); 0487 QCOMPARE(stats.trimean, 437500000); 0488 QCOMPARE(stats.variance, 6.69166666666667e+19); 0489 QCOMPARE(stats.standardDeviation, 8180260794.53868); 0490 QCOMPARE(stats.meanDeviation, 5250000000); 0491 QCOMPARE(stats.meanDeviationAroundMedian, 5250000000); 0492 QCOMPARE(stats.medianDeviation, 5000000000); 0493 QCOMPARE(stats.skewness, -0.10520849985915); 0494 QCOMPARE(stats.kurtosis, 1.9925605877089); 0495 QCOMPARE(stats.entropy, 2.); 0496 #endif 0497 } 0498 0499 void ColumnTest::statisticsText() { 0500 Column c(QStringLiteral("Text column"), Column::ColumnMode::Text); 0501 c.setTextAt(0, QStringLiteral("yes")); 0502 c.setTextAt(1, QStringLiteral("no")); 0503 c.setTextAt(2, QStringLiteral("no")); 0504 c.setTextAt(3, QStringLiteral("yes")); 0505 c.setTextAt(4, QStringLiteral("yes")); 0506 0507 const auto& stats = c.statistics(); 0508 0509 QCOMPARE(stats.size, 5); 0510 QCOMPARE(stats.unique, 2); 0511 } 0512 0513 void ColumnTest::statisticsMaskValues() { 0514 Project project; 0515 auto* c = new Column(QStringLiteral("Integer column"), Column::ColumnMode::Integer); 0516 c->setIntegers({1, 2, 3}); 0517 project.addChild(c); 0518 0519 // check the statistics 0520 auto& stats1 = c->statistics(); 0521 QCOMPARE(stats1.size, 3); 0522 QCOMPARE(stats1.minimum, 1.); 0523 QCOMPARE(stats1.maximum, 3.); 0524 0525 // mask the last value and check the statistics 0526 c->setMasked(2); 0527 auto& stats2 = c->statistics(); 0528 QCOMPARE(stats2.size, 2); 0529 QCOMPARE(stats2.minimum, 1.); 0530 QCOMPARE(stats2.maximum, 2.); 0531 0532 // undo the masking change and check the statistics 0533 project.undoStack()->undo(); 0534 auto& stats3 = c->statistics(); 0535 QCOMPARE(stats3.size, 3); 0536 QCOMPARE(stats3.minimum, 1.); 0537 QCOMPARE(stats3.maximum, 3.); 0538 0539 // redo the masking change and check the statistics 0540 project.undoStack()->redo(); 0541 auto& stats4 = c->statistics(); 0542 QCOMPARE(stats4.size, 2); 0543 QCOMPARE(stats4.minimum, 1.); 0544 QCOMPARE(stats4.maximum, 2.); 0545 } 0546 0547 void ColumnTest::statisticsClearSpreadsheetMasks() { 0548 Project project; 0549 0550 auto* spreadsheet = new Spreadsheet(QStringLiteral("spreadsheet")); 0551 project.addChild(spreadsheet); 0552 spreadsheet->setColumnCount(1); 0553 spreadsheet->setRowCount(3); 0554 auto* c = spreadsheet->column(0); 0555 c->setValues({1., 2., 3.}); 0556 0557 // check the statistics 0558 auto& stats1 = c->statistics(); 0559 QCOMPARE(stats1.size, 3); 0560 QCOMPARE(stats1.minimum, 1.); 0561 QCOMPARE(stats1.maximum, 3.); 0562 0563 // mask the last value and check the statistics 0564 c->setMasked(2); 0565 auto& stats2 = c->statistics(); 0566 QCOMPARE(stats2.size, 2); 0567 QCOMPARE(stats2.minimum, 1.); 0568 QCOMPARE(stats2.maximum, 2.); 0569 0570 // clear the masked values in the spreadsheet 0571 spreadsheet->clearMasks(); 0572 auto& stats3 = c->statistics(); 0573 QCOMPARE(stats3.size, 3); 0574 QCOMPARE(stats3.minimum, 1.); 0575 QCOMPARE(stats3.maximum, 3.); 0576 0577 // undo the "clear masked valus"-change and check the statistics 0578 project.undoStack()->undo(); 0579 auto& stats4 = c->statistics(); 0580 QCOMPARE(stats4.size, 2); 0581 QCOMPARE(stats4.minimum, 1.); 0582 QCOMPARE(stats4.maximum, 2.); 0583 0584 // redo the "clear masked values"-change and check the statistics 0585 project.undoStack()->redo(); 0586 auto& stats5 = c->statistics(); 0587 QCOMPARE(stats5.size, 3); 0588 QCOMPARE(stats5.minimum, 1.); 0589 QCOMPARE(stats5.maximum, 3.); 0590 } 0591 0592 void ColumnTest::testFormulaAutoUpdateEnabled() { 0593 Column sourceColumn(QStringLiteral("source"), Column::ColumnMode::Integer); 0594 sourceColumn.setIntegers({1, 2, 3}); 0595 0596 Column targetColumn(QStringLiteral("target"), Column::ColumnMode::Integer); 0597 targetColumn.setIntegers({3, 2, 1}); 0598 0599 // evaluatue 2*x and check the generated values in the target column 0600 targetColumn.setColumnMode(AbstractColumn::ColumnMode::Double); // should happen automatically in Column::setFormula() 0601 targetColumn.setFormula(QStringLiteral("2*x"), 0602 QStringList{QStringLiteral("x")}, 0603 QVector<Column*>({&sourceColumn}), 0604 true /* autoUpdate */, 0605 false /* autoResize */); 0606 targetColumn.updateFormula(); 0607 QCOMPARE(targetColumn.rowCount(), 3); 0608 QCOMPARE(targetColumn.valueAt(0), 2); 0609 QCOMPARE(targetColumn.valueAt(1), 4); 0610 QCOMPARE(targetColumn.valueAt(2), 6); 0611 0612 // modify value in the source column and check the target column again which should be updated 0613 sourceColumn.setIntegers({3, 2, 1}); 0614 QCOMPARE(targetColumn.rowCount(), 3); 0615 QCOMPARE(targetColumn.valueAt(0), 6); 0616 QCOMPARE(targetColumn.valueAt(1), 4); 0617 QCOMPARE(targetColumn.valueAt(2), 2); 0618 } 0619 0620 void ColumnTest::testFormulaAutoUpdateDisabled() { 0621 Column sourceColumn(QStringLiteral("source"), Column::ColumnMode::Integer); 0622 sourceColumn.setIntegers({1, 2, 3}); 0623 0624 Column targetColumn(QStringLiteral("target"), Column::ColumnMode::Integer); 0625 targetColumn.setIntegers({3, 2, 1}); 0626 0627 // evaluatue 2*x and check the generated values in the target column 0628 targetColumn.setColumnMode(AbstractColumn::ColumnMode::Double); 0629 targetColumn.setFormula(QStringLiteral("2*x"), 0630 QStringList{QStringLiteral("x")}, 0631 QVector<Column*>({&sourceColumn}), 0632 false /* autoUpdate */, 0633 false /* autoResize */); 0634 targetColumn.updateFormula(); 0635 QCOMPARE(targetColumn.rowCount(), 3); 0636 QCOMPARE(targetColumn.valueAt(0), 2); 0637 QCOMPARE(targetColumn.valueAt(1), 4); 0638 QCOMPARE(targetColumn.valueAt(2), 6); 0639 0640 // modify value in the source column and check the target column again which shouldn't be updated 0641 sourceColumn.setIntegers({3, 2, 1}); 0642 QCOMPARE(targetColumn.rowCount(), 3); 0643 QCOMPARE(targetColumn.valueAt(0), 2); 0644 QCOMPARE(targetColumn.valueAt(1), 4); 0645 QCOMPARE(targetColumn.valueAt(2), 6); 0646 } 0647 0648 void ColumnTest::testFormulaAutoResizeEnabled() { 0649 Column sourceColumn1(QStringLiteral("source1"), Column::ColumnMode::Integer); 0650 sourceColumn1.setIntegers({1, 2, 3}); 0651 0652 Column sourceColumn2(QStringLiteral("source2"), Column::ColumnMode::Integer); 0653 sourceColumn2.setIntegers({1, 2, 3}); 0654 0655 // spreadsheet needs to be created since the resize of the column is happening via the resize of the spreadsheet 0656 Spreadsheet targetSpreadsheet(QStringLiteral("target")); 0657 targetSpreadsheet.setColumnCount(1); 0658 targetSpreadsheet.setRowCount(1); 0659 Column* targetColumn = targetSpreadsheet.column(0); 0660 0661 // evaluatue x+y 0662 targetColumn->setColumnMode(AbstractColumn::ColumnMode::Double); 0663 targetColumn->setFormula(QStringLiteral("x+y"), 0664 QStringList{QStringLiteral("x"), QStringLiteral("y")}, 0665 QVector<Column*>({&sourceColumn1, &sourceColumn2}), 0666 false /* autoUpdate */, 0667 true /* autoResize */); 0668 targetColumn->updateFormula(); 0669 0670 // check the generated values in the target column which should have been resized 0671 QCOMPARE(targetColumn->rowCount(), 3); 0672 QCOMPARE(targetColumn->valueAt(0), 2); 0673 QCOMPARE(targetColumn->valueAt(1), 4); 0674 QCOMPARE(targetColumn->valueAt(2), 6); 0675 } 0676 0677 void ColumnTest::testFormulaAutoResizeDisabled() { 0678 Column sourceColumn1(QStringLiteral("source1"), Column::ColumnMode::Integer); 0679 sourceColumn1.setIntegers({1, 2, 3}); 0680 0681 Column sourceColumn2(QStringLiteral("source2"), Column::ColumnMode::Integer); 0682 sourceColumn2.setIntegers({1, 2, 3}); 0683 0684 Column targetColumn(QStringLiteral("target"), Column::ColumnMode::Integer); 0685 targetColumn.setIntegers({1}); 0686 0687 // evaluatue x+y 0688 targetColumn.setColumnMode(AbstractColumn::ColumnMode::Double); 0689 targetColumn.setFormula(QStringLiteral("x+y"), 0690 QStringList{QStringLiteral("x"), QStringLiteral("y")}, 0691 QVector<Column*>({&sourceColumn1, &sourceColumn2}), 0692 false /* autoUpdate */, 0693 false /* autoResize */); 0694 targetColumn.updateFormula(); 0695 0696 // check the generated values in the target column which should not have been resized 0697 QCOMPARE(targetColumn.rowCount(), 1); 0698 QCOMPARE(targetColumn.valueAt(0), 2); 0699 } 0700 0701 void ColumnTest::testFormulaAutoUpdateEnabledResize() { 0702 Column sourceColumn(QStringLiteral("source"), Column::ColumnMode::Integer); 0703 sourceColumn.setIntegers({1, 2, 3, 4}); 0704 0705 Column targetColumn(QStringLiteral("target"), Column::ColumnMode::Integer); 0706 targetColumn.setIntegers({3, 2, 1}); 0707 0708 // evaluatue 2*x and check the generated values in the target column 0709 targetColumn.setColumnMode(AbstractColumn::ColumnMode::Double); // should happen automatically in Column::setFormula() 0710 targetColumn.setFormula(QStringLiteral("2*x"), 0711 QStringList{QStringLiteral("x")}, 0712 QVector<Column*>({&sourceColumn}), 0713 true /* autoUpdate */, 0714 false /* autoResize */); 0715 targetColumn.updateFormula(); 0716 QCOMPARE(targetColumn.rowCount(), 3); 0717 QCOMPARE(targetColumn.valueAt(0), 2); 0718 QCOMPARE(targetColumn.valueAt(1), 4); 0719 QCOMPARE(targetColumn.valueAt(2), 6); 0720 0721 targetColumn.insertRows(3, 1); // Rowcount of the target changes 0722 0723 // Values updated 0724 QCOMPARE(targetColumn.rowCount(), 4); 0725 QCOMPARE(targetColumn.valueAt(0), 2); 0726 QCOMPARE(targetColumn.valueAt(1), 4); 0727 QCOMPARE(targetColumn.valueAt(2), 6); 0728 QCOMPARE(targetColumn.valueAt(3), 8); 0729 } 0730 0731 void ColumnTest::testDictionaryIndex() { 0732 Column c(QStringLiteral("Text column"), Column::ColumnMode::Text); 0733 c.setTextAt(0, QStringLiteral("yes")); 0734 c.setTextAt(1, QStringLiteral("no")); 0735 c.setTextAt(2, QStringLiteral("no")); 0736 c.setTextAt(3, QStringLiteral("yes")); 0737 c.setTextAt(4, QStringLiteral("yes")); 0738 0739 // check the position of the distinct values in the dictionary 0740 QCOMPARE(c.dictionaryIndex(0), 0); 0741 QCOMPARE(c.dictionaryIndex(1), 1); 0742 QCOMPARE(c.dictionaryIndex(2), 1); 0743 QCOMPARE(c.dictionaryIndex(3), 0); 0744 QCOMPARE(c.dictionaryIndex(4), 0); 0745 0746 // modify a value which will invalidate the dictionary and verify it again 0747 c.setTextAt(1, QStringLiteral("yes")); 0748 0749 QCOMPARE(c.dictionaryIndex(0), 0); 0750 QCOMPARE(c.dictionaryIndex(1), 0); 0751 QCOMPARE(c.dictionaryIndex(2), 1); 0752 QCOMPARE(c.dictionaryIndex(3), 0); 0753 QCOMPARE(c.dictionaryIndex(4), 0); 0754 } 0755 0756 void ColumnTest::testTextFrequencies() { 0757 Column c(QStringLiteral("Text column"), Column::ColumnMode::Text); 0758 c.setTextAt(0, QStringLiteral("yes")); 0759 c.setTextAt(1, QStringLiteral("no")); 0760 c.setTextAt(2, QStringLiteral("no")); 0761 c.setTextAt(3, QStringLiteral("yes")); 0762 c.setTextAt(4, QStringLiteral("yes")); 0763 0764 const auto& frequencies = c.frequencies(); 0765 0766 QCOMPARE(frequencies[QStringLiteral("yes")], 3); 0767 QCOMPARE(frequencies[QStringLiteral("no")], 2); 0768 } 0769 0770 ////////////////////////////////////////////////// 0771 0772 void ColumnTest::saveLoadDateTime() { 0773 Column c(QStringLiteral("Datetime column"), Column::ColumnMode::DateTime); 0774 c.setDateTimes({ 0775 QDateTime::fromString( 0776 QStringLiteral("2017-03-26T02:14:34.000Z"), 0777 Qt::DateFormat::ISODateWithMs), // without the timezone declaration it would be invalid (in some regions), because of the daylight time 0778 QDateTime::fromString(QStringLiteral("2018-03-26T02:14:34.000Z"), Qt::DateFormat::ISODateWithMs), 0779 QDateTime::fromString(QStringLiteral("2019-03-26T02:14:34.000Z"), Qt::DateFormat::ISODateWithMs), 0780 QDateTime::fromString(QStringLiteral("2019-26-03 02:14:34:000"), QStringLiteral("yyyy-dd-MM hh:mm:ss:zzz")), 0781 }); 0782 0783 QByteArray array; 0784 QXmlStreamWriter writer(&array); 0785 c.save(&writer); 0786 0787 QDEBUG(array); 0788 0789 Column c2(QStringLiteral("Datetime 2 column"), Column::ColumnMode::DateTime); 0790 XmlStreamReader reader(array); 0791 bool found = false; 0792 while (!reader.atEnd()) { 0793 reader.readNext(); 0794 if (reader.isStartElement() && reader.name() == QLatin1String("column")) { 0795 found = true; 0796 break; 0797 } 0798 } 0799 QCOMPARE(found, true); 0800 QCOMPARE(c2.load(&reader, false), true); 0801 0802 QCOMPARE(c2.rowCount(), 4); 0803 QCOMPARE(c2.dateTimeAt(0).isValid(), true); 0804 QCOMPARE(c2.dateTimeAt(0), QDateTime::fromString(QStringLiteral("2017-03-26T02:14:34.000Z"), Qt::DateFormat::ISODateWithMs)); 0805 QCOMPARE(c2.dateTimeAt(1).isValid(), true); 0806 QCOMPARE(c2.dateTimeAt(1), QDateTime::fromString(QStringLiteral("2018-03-26T02:14:34.000Z"), Qt::DateFormat::ISODateWithMs)); 0807 QCOMPARE(c2.dateTimeAt(2).isValid(), true); 0808 QCOMPARE(c2.dateTimeAt(2), QDateTime::fromString(QStringLiteral("2019-03-26T02:14:34.000Z"), Qt::DateFormat::ISODateWithMs)); 0809 QCOMPARE(c2.dateTimeAt(3).isValid(), true); 0810 QCOMPARE(c2.dateTimeAt(3), QDateTime::fromString(QStringLiteral("2019-03-26T02:14:34.000Z"), Qt::DateFormat::ISODateWithMs)); 0811 } 0812 0813 void ColumnTest::loadDoubleFromProject() { 0814 Project project; 0815 project.load(QFINDTESTDATA(QLatin1String("data/Load.lml"))); 0816 0817 auto* doublespreadSheet = project.child<AbstractAspect>(0); 0818 QVERIFY(doublespreadSheet != nullptr); 0819 QCOMPARE(doublespreadSheet->name(), QLatin1String("Double")); 0820 QCOMPARE(doublespreadSheet->type(), AspectType::Spreadsheet); 0821 0822 auto childs = doublespreadSheet->children(AspectType::Column); 0823 QVERIFY(childs.count() >= 1); 0824 auto* doubleColumn = static_cast<Column*>(childs.at(0)); 0825 QCOMPARE(doubleColumn->columnMode(), AbstractColumn::ColumnMode::Double); 0826 QCOMPARE(doubleColumn->rowCount(), 100); 0827 const double doubleValues[] = {0.625, 0828 1, 0829 1, 0830 4, 0831 1.125, 0832 1.66666666666667, 0833 11, 0834 6, 0835 2.16666666666667, 0836 14, 0837 1.5, 0838 2.28571428571429, 0839 2.125, 0840 2, 0841 1.9, 0842 2, 0843 3.5, 0844 22, 0845 2.3, 0846 2.66666666666667, 0847 5, 0848 26, 0849 3, 0850 4, 0851 4.14285714285714, 0852 3.33333333333333, 0853 10.3333333333333, 0854 32, 0855 8.25, 0856 3.4, 0857 8.75, 0858 5.14285714285714, 0859 9.25, 0860 6.33333333333333, 0861 4.33333333333333, 0862 4.44444444444444, 0863 4.55555555555556, 0864 4.2, 0865 6.14285714285714, 0866 5.5, 0867 7.5, 0868 46, 0869 4.7, 0870 12, 0871 7, 0872 7.14285714285714, 0873 6.375, 0874 5.2, 0875 26.5, 0876 18, 0877 27.5, 0878 14, 0879 11.4, 0880 8.28571428571429, 0881 29.5, 0882 10, 0883 15.25, 0884 12.4, 0885 12.6, 0886 64, 0887 65, 0888 33, 0889 8.375, 0890 13.6, 0891 17.25, 0892 14, 0893 23.6666666666667, 0894 8, 0895 8.11111111111111, 0896 10.5714285714286, 0897 12.5, 0898 8.44444444444444, 0899 19.25, 0900 8.66666666666667, 0901 11.2857142857143, 0902 8, 0903 20.25, 0904 27.3333333333333, 0905 20.75, 0906 16.8, 0907 42.5, 0908 9.55555555555556, 0909 9.66666666666667, 0910 17.6, 0911 44.5, 0912 90, 0913 18.2, 0914 46, 0915 31, 0916 47, 0917 23.75, 0918 96, 0919 12.125, 0920 19.6, 0921 16.5, 0922 11.1111111111111, 0923 33.6666666666667, 0924 12.75, 0925 25.75, 0926 13}; 0927 for (int i = 0; i < 100; i++) 0928 QCOMPARE(doubleColumn->valueAt(i), doubleValues[i]); 0929 } 0930 0931 void ColumnTest::loadIntegerFromProject() { 0932 Project project; 0933 project.load(QFINDTESTDATA(QLatin1String("data/Load.lml"))); 0934 0935 auto* integerSpreadsheet = project.child<AbstractAspect>(1); 0936 QVERIFY(integerSpreadsheet != nullptr); 0937 QCOMPARE(integerSpreadsheet->name(), QLatin1String("Integer")); 0938 QCOMPARE(integerSpreadsheet->type(), AspectType::Spreadsheet); 0939 0940 auto childs = integerSpreadsheet->children(AspectType::Column); 0941 QVERIFY(childs.count() >= 1); 0942 auto* integerColumn = static_cast<Column*>(childs.at(0)); 0943 QCOMPARE(integerColumn->columnMode(), AbstractColumn::ColumnMode::Integer); 0944 QCOMPARE(integerColumn->rowCount(), 133); 0945 const int integerValues[133] = {291, 75, 21, 627, 163, 677, 712, 66, 733, 653, 502, 515, 379, 70, 762, 261, 304, 541, 298, 462, 623, 382, 94, 0946 232, 679, 132, 124, 212, 122, 118, 486, 126, 107, 677, 386, 118, 731, 484, 638, 127, 779, 109, 708, 298, 680, 249, 0947 591, 155, 351, 178, 70, 768, 2, 504, 179, 747, 789, 213, 144, 143, 61, 761, 113, 766, 18, 617, 406, 489, 299, 0948 658, 326, 181, 773, 228, 653, 242, 382, 11, 267, 29, 283, 30, 251, 453, 699, 286, 739, 406, 729, 159, 506, 20, 0949 766, 443, 646, 161, 545, 400, 160, 693, 722, 463, 121, 350, 194, 558, 503, 72, 516, 509, 118, 340, 342, 495, 50, 0950 549, 643, 241, 248, 483, 408, 768, 634, 589, 159, 518, 475, 403, 165, 122, 268, 537, 33}; 0951 for (int i = 0; i < 133; i++) 0952 QCOMPARE(integerColumn->integerAt(i), integerValues[i]); 0953 } 0954 0955 void ColumnTest::loadBigIntegerFromProject() { 0956 Project project; 0957 project.load(QFINDTESTDATA(QLatin1String("data/Load.lml"))); 0958 0959 auto* bigIntegerSpreadsheet = project.child<AbstractAspect>(2); 0960 QVERIFY(bigIntegerSpreadsheet != nullptr); 0961 QCOMPARE(bigIntegerSpreadsheet->name(), QLatin1String("BigInteger")); 0962 QCOMPARE(bigIntegerSpreadsheet->type(), AspectType::Spreadsheet); 0963 0964 auto childs = bigIntegerSpreadsheet->children(AspectType::Column); 0965 QVERIFY(childs.count() >= 1); 0966 auto* bigIntegerColumn = static_cast<Column*>(childs.at(0)); 0967 QCOMPARE(bigIntegerColumn->columnMode(), AbstractColumn::ColumnMode::BigInt); 0968 QCOMPARE(bigIntegerColumn->rowCount(), 98); 0969 const qint64 bigIntegerValues[] = { 0970 423448954198, 5641410204, 30408827812, 28654888657, 49080407041, 49609860873, 3687941775, 19532027992, 35894087224, 5820636581, 28739047077, 0971 13946526866, 36153607843, 3240340694, 2375891120, 3014999117, 17758738424, 31303772749, 36400461519, 29813286102, 14068980943, 24595715523, 0972 390096547, 27927541822, 35442936843, 33577242277, 34966078315, 45550480998, 11834545810, 25714661808, 6979002160, 35138449350, 3597002515, 0973 707044300, 27971594979, 25699976843, 35231282278, 11659858605, 45858935838, 25070072891, 15136182059, 6266852861, 42582813575, 23784333993, 0974 14361566136, 27840747719, 41099229867, 40403331476, 21708972571, 10995493445, 36292237893, 4264327752, 45637575339, 13530360473, 40816873119, 0975 15346300490, 30807486688, 23771858665, 36762855436, 351630653, 22270715573, 31792268673, 25001237450, 16558491573, 21771715873, 20963298299, 0976 25197909817, 41130528918, 13134975803, 43222173019, 17071520882, 8356069280, 27671796182, 29309739294, 9377292482, 30451803959, 47318250898, 0977 21100469009, 28764337224, 36898356693, 36091695104, 12019973504, 15605135996, 13711330940, 13010481591, 45193969649, 25444985954, 34831527437, 0978 8208098526, 29897950771, 5631513384, 47590874807, 4659417951, 28338882094, 14853737313, 22965578753, 6544735402, 32209366817}; 0979 for (int i = 0; i < 98; i++) 0980 QCOMPARE(bigIntegerColumn->bigIntAt(i), bigIntegerValues[i]); 0981 } 0982 0983 void ColumnTest::loadTextFromProject() { 0984 Project project; 0985 project.load(QFINDTESTDATA(QLatin1String("data/Load.lml"))); 0986 0987 auto* textSpreadsheet = project.child<AbstractAspect>(3); 0988 QVERIFY(textSpreadsheet != nullptr); 0989 QCOMPARE(textSpreadsheet->name(), QLatin1String("Text")); 0990 QCOMPARE(textSpreadsheet->type(), AspectType::Spreadsheet); 0991 0992 auto childs = textSpreadsheet->children(AspectType::Column); 0993 QVERIFY(childs.count() >= 1); 0994 auto* textColumn = static_cast<Column*>(childs.at(0)); 0995 QCOMPARE(textColumn->columnMode(), AbstractColumn::ColumnMode::Text); 0996 QCOMPARE(textColumn->rowCount(), 10); 0997 QStringList texts = {QStringLiteral("first value"), 0998 QStringLiteral("second value"), 0999 QStringLiteral("third value"), 1000 QStringLiteral("fourth value"), 1001 QStringLiteral("fifth value"), 1002 QStringLiteral("sixt value"), 1003 QStringLiteral("sevent value"), 1004 QStringLiteral("eigth value"), 1005 QStringLiteral("ninth value"), 1006 QStringLiteral("tenth value")}; 1007 for (int i = 0; i < 10; i++) { 1008 QCOMPARE(textColumn->textAt(i), texts.at(i)); 1009 } 1010 } 1011 1012 void ColumnTest::loadDateTimeFromProject() { 1013 Project project; 1014 project.load(QFINDTESTDATA(QLatin1String("data/Load.lml"))); 1015 1016 auto* dateTimeSpreadsheet = project.child<AbstractAspect>(4); 1017 QVERIFY(dateTimeSpreadsheet != nullptr); 1018 QCOMPARE(dateTimeSpreadsheet->name(), QLatin1String("Datetime")); 1019 QCOMPARE(dateTimeSpreadsheet->type(), AspectType::Spreadsheet); 1020 1021 auto childs = dateTimeSpreadsheet->children(AspectType::Column); 1022 QVERIFY(childs.count() == 3); 1023 auto* dateTimeColumn = static_cast<Column*>(childs.at(0)); 1024 QCOMPARE(dateTimeColumn->rowCount(), 8); 1025 // TODO: 1026 // auto* dayColumn = static_cast<Column*>(childs.at(1)); 1027 // auto* monthColumn = static_cast<Column*>(childs.at(2)); 1028 1029 // TODO: must be implemented 1030 // for (int i=0; i < 8; i++) { 1031 // QCOMPARE(dateTimeColumn->dateTimeAt(i), QDateTime::fromString("2022-01-12T12:30:24.920")); 1032 // } 1033 } 1034 1035 void ColumnTest::testIndexForValue() { 1036 { 1037 const double value = 5; 1038 QVector<QPointF> points{}; 1039 Column::Properties properties = Column::Properties::MonotonicIncreasing; 1040 QCOMPARE(Column::indexForValue(value, points, properties), -1); 1041 } 1042 1043 { 1044 const double value = 5; 1045 QVector<QPointF> points{QPointF(10, 1), QPointF(20, 1), QPointF(30, 1), QPointF(40, 1), QPointF(50, 1)}; 1046 Column::Properties properties = Column::Properties::MonotonicIncreasing; 1047 QCOMPARE(Column::indexForValue(value, points, properties), 0); 1048 } 1049 1050 { 1051 const double value = 60; 1052 QVector<QPointF> points{QPointF(10, 1), QPointF(20, 1), QPointF(30, 1), QPointF(40, 1), QPointF(50, 1)}; 1053 Column::Properties properties = Column::Properties::MonotonicIncreasing; 1054 QCOMPARE(Column::indexForValue(value, points, properties), 4); 1055 } 1056 1057 { 1058 const double value = 16; 1059 QVector<QPointF> points{QPointF(10, 1), QPointF(20, 1), QPointF(30, 1), QPointF(40, 1), QPointF(50, 1)}; 1060 Column::Properties properties = Column::Properties::MonotonicIncreasing; 1061 QCOMPARE(Column::indexForValue(value, points, properties), 1); 1062 } 1063 1064 { 1065 const double value = 20; 1066 QVector<QPointF> points{QPointF(10, 1), QPointF(20, 1), QPointF(30, 1), QPointF(40, 1), QPointF(50, 1)}; 1067 Column::Properties properties = Column::Properties::MonotonicIncreasing; 1068 QCOMPARE(Column::indexForValue(value, points, properties), 1); 1069 } 1070 } 1071 1072 void ColumnTest::testIndexForValueDoubleVector() { 1073 { 1074 const double value = 5; 1075 QVector<double> points{}; 1076 Column::Properties properties = Column::Properties::MonotonicIncreasing; 1077 QCOMPARE(Column::indexForValue(value, points, properties), -1); 1078 } 1079 1080 { 1081 const double value = 5; 1082 QVector<double> points{10, 20, 30, 40, 50}; 1083 Column::Properties properties = Column::Properties::MonotonicIncreasing; 1084 QCOMPARE(Column::indexForValue(value, points, properties), 0); 1085 } 1086 1087 { 1088 const double value = 60; 1089 QVector<double> points{10, 20, 30, 40, 50}; 1090 Column::Properties properties = Column::Properties::MonotonicIncreasing; 1091 QCOMPARE(Column::indexForValue(value, points, properties), 4); 1092 } 1093 1094 { 1095 const double value = 16; 1096 QVector<double> points{10, 20, 30, 40, 50}; 1097 Column::Properties properties = Column::Properties::MonotonicIncreasing; 1098 QCOMPARE(Column::indexForValue(value, points, properties), 1); 1099 } 1100 1101 { 1102 const double value = 20; 1103 QVector<double> points{10, 20, 30, 40, 50}; 1104 Column::Properties properties = Column::Properties::MonotonicIncreasing; 1105 QCOMPARE(Column::indexForValue(value, points, properties), 1); 1106 } 1107 } 1108 1109 void ColumnTest::testInsertRow() { 1110 Project project; 1111 auto* c = new Column(QStringLiteral("Test"), Column::ColumnMode::Double); 1112 project.addChild(c); 1113 c->resizeTo(100); 1114 QCOMPARE(c->rowCount(), 100); 1115 1116 int rowsAboutToBeInsertedCounter = 0; 1117 connect(c, &Column::rowsAboutToBeInserted, [&rowsAboutToBeInsertedCounter, c](const AbstractColumn* source, int before, int count) { 1118 QCOMPARE(source, c); 1119 switch (rowsAboutToBeInsertedCounter) { 1120 case 0: 1121 QCOMPARE(before, 100); 1122 QCOMPARE(count, 2); 1123 break; 1124 case 1: 1125 QCOMPARE(before, 102); 1126 QCOMPARE(count, 3); 1127 break; 1128 case 3: // redo() 1129 QCOMPARE(before, 102); 1130 QCOMPARE(count, 3); 1131 break; 1132 } 1133 rowsAboutToBeInsertedCounter++; 1134 }); 1135 1136 int rowsAboutToBeRemovedCounter = 0; 1137 connect(c, &Column::rowsAboutToBeRemoved, [&rowsAboutToBeRemovedCounter, c](const AbstractColumn* source, int first, int count) { 1138 QCOMPARE(source, c); 1139 switch (rowsAboutToBeRemovedCounter) { 1140 case 0: 1141 QCOMPARE(first, 102); 1142 QCOMPARE(count, 3); 1143 break; 1144 } 1145 rowsAboutToBeRemovedCounter++; 1146 }); 1147 1148 int rowsInsertedCounter = 0; 1149 connect(c, &Column::rowsInserted, [&rowsInsertedCounter, c](const AbstractColumn* source, int before, int count) { 1150 QCOMPARE(source, c); 1151 1152 switch (rowsInsertedCounter) { 1153 case 0: 1154 QCOMPARE(before, 100); 1155 QCOMPARE(count, 2); 1156 break; 1157 case 1: 1158 QCOMPARE(before, 102); 1159 QCOMPARE(count, 3); 1160 break; 1161 case 3: // redo() 1162 QCOMPARE(before, 102); 1163 QCOMPARE(count, 3); 1164 break; 1165 } 1166 1167 rowsInsertedCounter++; 1168 }); 1169 1170 int rowsRemovedCounter = 0; 1171 connect(c, &Column::rowsRemoved, [&rowsRemovedCounter, c](const AbstractColumn* source, int first, int count) { 1172 QCOMPARE(source, c); 1173 1174 switch (rowsRemovedCounter) { 1175 case 0: 1176 QCOMPARE(first, 102); 1177 QCOMPARE(count, 3); 1178 break; 1179 } 1180 1181 rowsRemovedCounter++; 1182 }); 1183 1184 c->insertRows(c->rowCount(), 2); 1185 QCOMPARE(c->rowCount(), 102); 1186 c->insertRows(c->rowCount(), 3); 1187 QCOMPARE(c->rowCount(), 105); 1188 1189 c->undoStack()->undo(); 1190 QCOMPARE(c->rowCount(), 102); 1191 c->undoStack()->redo(); 1192 QCOMPARE(c->rowCount(), 105); 1193 1194 QCOMPARE(rowsAboutToBeInsertedCounter, 3); 1195 QCOMPARE(rowsAboutToBeRemovedCounter, 1); 1196 QCOMPARE(rowsInsertedCounter, 3); 1197 QCOMPARE(rowsRemovedCounter, 1); 1198 } 1199 1200 void ColumnTest::testRemoveRow() { 1201 Project project; 1202 auto* c = new Column(QStringLiteral("Test"), Column::ColumnMode::Double); 1203 project.addChild(c); 1204 c->resizeTo(100); 1205 QCOMPARE(c->rowCount(), 100); 1206 1207 int rowsAboutToBeInsertedCounter = 0; 1208 connect(c, &Column::rowsAboutToBeInserted, [&rowsAboutToBeInsertedCounter, c](const AbstractColumn* source, int before, int count) { 1209 QCOMPARE(source, c); 1210 QCOMPARE(before, 96); 1211 QCOMPARE(count, 3); 1212 rowsAboutToBeInsertedCounter++; 1213 }); 1214 1215 int rowsAboutToBeRemovedCounter = 0; 1216 connect(c, &Column::rowsAboutToBeRemoved, [&rowsAboutToBeRemovedCounter, c](const AbstractColumn* source, int first, int count) { 1217 QCOMPARE(source, c); 1218 switch (rowsAboutToBeRemovedCounter) { 1219 case 0: 1220 QCOMPARE(first, 99); 1221 QCOMPARE(count, 1); 1222 break; 1223 case 1: 1224 QCOMPARE(first, 96); 1225 QCOMPARE(count, 3); 1226 break; 1227 case 2: // redo() 1228 QCOMPARE(first, 96); 1229 QCOMPARE(count, 3); 1230 break; 1231 } 1232 rowsAboutToBeRemovedCounter++; 1233 }); 1234 1235 int rowsInsertedCounter = 0; 1236 connect(c, &Column::rowsInserted, [&rowsInsertedCounter, c](const AbstractColumn* source, int before, int count) { 1237 QCOMPARE(source, c); 1238 1239 QCOMPARE(before, 96); 1240 QCOMPARE(count, 3); 1241 1242 rowsInsertedCounter++; 1243 }); 1244 1245 int rowsRemovedCounter = 0; 1246 connect(c, &Column::rowsRemoved, [&rowsRemovedCounter, c](const AbstractColumn* source, int first, int count) { 1247 QCOMPARE(source, c); 1248 1249 switch (rowsRemovedCounter) { 1250 case 0: 1251 QCOMPARE(first, 99); 1252 QCOMPARE(count, 1); 1253 break; 1254 case 1: 1255 QCOMPARE(first, 96); 1256 QCOMPARE(count, 3); 1257 break; 1258 case 2: // redo() 1259 QCOMPARE(first, 96); 1260 QCOMPARE(count, 3); 1261 break; 1262 } 1263 1264 rowsRemovedCounter++; 1265 }); 1266 1267 c->removeRows(c->rowCount() - 1, 1); 1268 QCOMPARE(c->rowCount(), 99); 1269 c->removeRows(c->rowCount() - 3, 3); 1270 QCOMPARE(c->rowCount(), 96); 1271 1272 c->undoStack()->undo(); 1273 QCOMPARE(c->rowCount(), 99); 1274 c->undoStack()->redo(); 1275 QCOMPARE(c->rowCount(), 96); 1276 1277 QCOMPARE(rowsAboutToBeInsertedCounter, 1); 1278 QCOMPARE(rowsAboutToBeRemovedCounter, 3); 1279 QCOMPARE(rowsInsertedCounter, 1); 1280 QCOMPARE(rowsRemovedCounter, 3); 1281 } 1282 1283 void ColumnTest::testFormula() { 1284 auto c1 = Column(QStringLiteral("DataColumn"), Column::ColumnMode::Double); 1285 c1.replaceValues(-1, {1., 2., 3.}); 1286 1287 auto c2 = Column(QStringLiteral("FormulaColumn"), Column::ColumnMode::Double); 1288 c2.replaceValues(-1, {11., 12., 13., 14., 15., 16., 17.}); 1289 1290 c2.setFormula(QStringLiteral("mean(x)"), {QStringLiteral("x")}, QVector<Column*>({&c1}), true); 1291 c2.updateFormula(); 1292 QCOMPARE(c2.rowCount(), 7); 1293 for (int i = 0; i < c2.rowCount(); i++) { 1294 VALUES_EQUAL(c2.valueAt(i), 2.); 1295 } 1296 } 1297 1298 void ColumnTest::testFormulaCell() { 1299 auto c1 = Column(QStringLiteral("DataColumn"), Column::ColumnMode::Double); 1300 c1.replaceValues(-1, {1., 5., -1.}); 1301 1302 auto c3 = Column(QStringLiteral("DataColumn"), Column::ColumnMode::Double); 1303 c3.replaceValues(-1, {3., 2., 1.}); 1304 1305 auto c2 = Column(QStringLiteral("FormulaColumn"), Column::ColumnMode::Double); 1306 c2.replaceValues(-1, {11., 12., 13., 14., 15., 16., 17.}); 1307 1308 c2.setFormula(QStringLiteral("cell(y; x)"), {QStringLiteral("x"), QStringLiteral("y")}, QVector<Column*>({&c1, &c3}), true); 1309 c2.updateFormula(); 1310 QCOMPARE(c2.rowCount(), 7); 1311 VALUES_EQUAL(c2.valueAt(0), -1.); 1312 VALUES_EQUAL(c2.valueAt(1), 5.); 1313 VALUES_EQUAL(c2.valueAt(2), 1.); 1314 VALUES_EQUAL(c2.valueAt(3), NAN); 1315 VALUES_EQUAL(c2.valueAt(4), NAN); 1316 VALUES_EQUAL(c2.valueAt(5), NAN); 1317 VALUES_EQUAL(c2.valueAt(6), NAN); 1318 } 1319 1320 /*! 1321 * index in cell higher than rownumber 1322 */ 1323 void ColumnTest::testFormulaCellInvalid() { 1324 auto c1 = Column(QStringLiteral("DataColumn"), Column::ColumnMode::Double); 1325 c1.replaceValues(-1, {1., 2., 3.}); 1326 1327 auto c2 = Column(QStringLiteral("FormulaColumn"), Column::ColumnMode::Double); 1328 c2.replaceValues(-1, {11., 12., 13., 14., 15., 16., 17.}); 1329 1330 c2.setFormula(QStringLiteral("cell(10,x)"), {QStringLiteral("x")}, QVector<Column*>({&c1}), true); 1331 c2.updateFormula(); 1332 QCOMPARE(c2.rowCount(), 7); 1333 // All invalid 1334 for (int i = 0; i < c2.rowCount(); i++) 1335 VALUES_EQUAL(c2.valueAt(i), NAN); 1336 } 1337 1338 void ColumnTest::testFormulaCellConstExpression() { 1339 auto c1 = Column(QStringLiteral("DataColumn"), Column::ColumnMode::Double); 1340 c1.replaceValues(-1, {1., -1., 5.}); 1341 1342 auto c2 = Column(QStringLiteral("FormulaColumn"), Column::ColumnMode::Double); 1343 c2.replaceValues(-1, {11., 12., 13., 14., 15., 16., 17.}); 1344 1345 c2.setFormula(QStringLiteral("cell(2; x)"), {QStringLiteral("x")}, QVector<Column*>({&c1}), true); 1346 c2.updateFormula(); 1347 QCOMPARE(c2.rowCount(), 7); 1348 // All invalid 1349 for (int i = 0; i < c2.rowCount(); i++) 1350 VALUES_EQUAL(c2.valueAt(i), -1.); 1351 } 1352 1353 void ColumnTest::testFormulaCellMulti() { 1354 auto c1 = Column(QStringLiteral("DataColumn"), Column::ColumnMode::Double); 1355 c1.replaceValues(-1, {1., -1., 5.}); 1356 1357 auto c3 = Column(QStringLiteral("DataColumn"), Column::ColumnMode::Double); 1358 c3.replaceValues(-1, {-5., 100., 3}); 1359 1360 auto c2 = Column(QStringLiteral("FormulaColumn"), Column::ColumnMode::Double); 1361 c2.replaceValues(-1, {11., 12., 13., 14., 15., 16., 17.}); 1362 1363 c2.setFormula(QStringLiteral("cell(2; x) + cell(1; y)"), {QStringLiteral("x"), QStringLiteral("y")}, QVector<Column*>({&c1, &c3}), true); 1364 c2.updateFormula(); 1365 QCOMPARE(c2.rowCount(), 7); 1366 for (int i = 0; i < c2.rowCount(); i++) 1367 VALUES_EQUAL(c2.valueAt(i), -6.); 1368 } 1369 1370 void ColumnTest::testFormulasmmin() { 1371 auto c1 = Column(QStringLiteral("DataColumn"), Column::ColumnMode::Double); 1372 c1.replaceValues(-1, {1., -1., 5., 5., 3., 8., 10., -5}); 1373 1374 auto c2 = Column(QStringLiteral("FormulaColumn"), Column::ColumnMode::Double); 1375 c2.replaceValues(-1, {11., 12., 13., 14., 15., 16., 17., 18.}); 1376 1377 c2.setFormula(QStringLiteral("smmin(3; x)"), {QStringLiteral("x")}, {&c1}, true); 1378 c2.updateFormula(); 1379 QCOMPARE(c2.rowCount(), 8); 1380 VALUES_EQUAL(c2.valueAt(0), 1.); 1381 VALUES_EQUAL(c2.valueAt(1), -1.); 1382 VALUES_EQUAL(c2.valueAt(2), -1.); 1383 VALUES_EQUAL(c2.valueAt(3), -1.); 1384 VALUES_EQUAL(c2.valueAt(4), 3.); 1385 VALUES_EQUAL(c2.valueAt(5), 3.); 1386 VALUES_EQUAL(c2.valueAt(6), 3.); 1387 VALUES_EQUAL(c2.valueAt(7), -5.); 1388 } 1389 1390 void ColumnTest::testFormulasmmax() { 1391 auto c1 = Column(QStringLiteral("DataColumn"), Column::ColumnMode::Double); 1392 c1.replaceValues(-1, {1., -1., 5., 5., 3., 8., 10., -5}); 1393 1394 auto c2 = Column(QStringLiteral("FormulaColumn"), Column::ColumnMode::Double); 1395 c2.replaceValues(-1, {11., 12., 13., 14., 15., 16., 17., 18.}); 1396 1397 c2.setFormula(QStringLiteral("smmax(3; x)"), {QStringLiteral("x")}, QVector<Column*>({&c1}), true); 1398 c2.updateFormula(); 1399 QCOMPARE(c2.rowCount(), 8); 1400 VALUES_EQUAL(c2.valueAt(0), 1.); 1401 VALUES_EQUAL(c2.valueAt(1), 1.); 1402 VALUES_EQUAL(c2.valueAt(2), 5.); 1403 VALUES_EQUAL(c2.valueAt(3), 5.); 1404 VALUES_EQUAL(c2.valueAt(4), 5.); 1405 VALUES_EQUAL(c2.valueAt(5), 8.); 1406 VALUES_EQUAL(c2.valueAt(6), 10.); 1407 VALUES_EQUAL(c2.valueAt(7), 10.); 1408 } 1409 1410 void ColumnTest::testFormulasma() { 1411 auto c1 = Column(QStringLiteral("DataColumn"), Column::ColumnMode::Double); 1412 c1.replaceValues(-1, {1., -1., 5., 5., 3., 8., 10., -5}); 1413 1414 auto c2 = Column(QStringLiteral("FormulaColumn"), Column::ColumnMode::Double); 1415 c2.replaceValues(-1, {11., 12., 13., 14., 15., 16., 17., 18.}); 1416 1417 c2.setFormula(QStringLiteral("sma(3; x)"), {QStringLiteral("x")}, QVector<Column*>({&c1}), true); 1418 c2.updateFormula(); 1419 QCOMPARE(c2.rowCount(), 8); 1420 VALUES_EQUAL(c2.valueAt(0), 1. / 3.); 1421 VALUES_EQUAL(c2.valueAt(1), 0.); 1422 VALUES_EQUAL(c2.valueAt(2), 5. / 3.); 1423 VALUES_EQUAL(c2.valueAt(3), 3.); 1424 VALUES_EQUAL(c2.valueAt(4), 13. / 3.); 1425 VALUES_EQUAL(c2.valueAt(5), 16. / 3.); 1426 VALUES_EQUAL(c2.valueAt(6), 7.); 1427 VALUES_EQUAL(c2.valueAt(7), 13. / 3.); 1428 } 1429 1430 void ColumnTest::testFormulasMinColumnInvalid() { 1431 const QVector<double> c1Vector = {1., -1., 5., 5., 3., 8., 10., -5}, c2Vector = {11., 12., 13., 14., 15., 16., 17., 18.}; 1432 SETUP_C1_C2_COLUMNS(c1Vector, c2Vector) 1433 COLUMN2_SET_FORMULA_AND_EVALUATE("min()", NAN) // All invalid 1434 } 1435 1436 void ColumnTest::testFormulasSize() { 1437 const QVector<double> c1Vector = {1., -1., 8., 10., -5}, c2Vector = {11., 12., 13., 14., 15., 16., 17., 18.}; 1438 SETUP_C1_C2_COLUMNS(c1Vector, c2Vector) 1439 COLUMN2_SET_FORMULA_AND_EVALUATE("size(x)", 5.) 1440 } 1441 void ColumnTest::testFormulasMin() { 1442 const QVector<double> c1Vector = {1., -1., 8., 10., -5}, c2Vector = {11., 12., 13., 14., 15., 16., 17., 18.}; 1443 SETUP_C1_C2_COLUMNS(c1Vector, c2Vector) 1444 COLUMN2_SET_FORMULA_AND_EVALUATE("min(x)", -5.) 1445 } 1446 void ColumnTest::testFormulasMax() { 1447 const QVector<double> c1Vector = {1., -1., 8., 10., -5}, c2Vector = {11., 12., 13., 14., 15., 16., 17., 18.}; 1448 SETUP_C1_C2_COLUMNS(c1Vector, c2Vector) 1449 COLUMN2_SET_FORMULA_AND_EVALUATE("max(x)", 10.) 1450 } 1451 void ColumnTest::testFormulasMean() { 1452 const QVector<double> c1Vector = {1., -1., 8., 10., -5}, c2Vector = {11., 12., 13., 14., 15., 16., 17., 18.}; 1453 SETUP_C1_C2_COLUMNS(c1Vector, c2Vector) 1454 COLUMN2_SET_FORMULA_AND_EVALUATE("mean(x)", 13. / 5.) 1455 } 1456 void ColumnTest::testFormulasMedian() { 1457 const QVector<double> c1Vector = {1., -1., 8., 10., -5}, c2Vector = {11., 12., 13., 14., 15., 16., 17., 18.}; 1458 SETUP_C1_C2_COLUMNS(c1Vector, c2Vector) 1459 COLUMN2_SET_FORMULA_AND_EVALUATE("median(x)", 1.) 1460 } 1461 void ColumnTest::testFormulasStdev() { 1462 const QVector<double> c1Vector = {1., -1., 8., 10., -5}, c2Vector = {11., 12., 13., 14., 15., 16., 17., 18.}; 1463 SETUP_C1_C2_COLUMNS(c1Vector, c2Vector) 1464 COLUMN2_SET_FORMULA_AND_EVALUATE("stdev(x)", 6.2689712074) // calculated with octave "std" 1465 } 1466 void ColumnTest::testFormulasVar() { 1467 const QVector<double> c1Vector = {1., -1., 8., 10., -5}, c2Vector = {11., 12., 13., 14., 15., 16., 17., 18.}; 1468 SETUP_C1_C2_COLUMNS(c1Vector, c2Vector) 1469 COLUMN2_SET_FORMULA_AND_EVALUATE("var(x)", 39.3) // calculated with octave "var" 1470 } 1471 void ColumnTest::testFormulasGm() { 1472 const QVector<double> c1Vector = {1., 100., 8., 10., 3}, c2Vector = {11., 12., 13., 14., 15., 16., 17., 18.}; 1473 SETUP_C1_C2_COLUMNS(c1Vector, c2Vector) 1474 COLUMN2_SET_FORMULA_AND_EVALUATE("gm(x)", 7.51696) // Calculated with R exp(mean(log(x))) 1475 } 1476 void ColumnTest::testFormulasHm() { 1477 const QVector<double> c1Vector = {1., -3., 8., 10., -5}, c2Vector = {11., 12., 13., 14., 15., 16., 17., 18.}; 1478 SETUP_C1_C2_COLUMNS(c1Vector, c2Vector) 1479 COLUMN2_SET_FORMULA_AND_EVALUATE("hm(x)", 7.228916) // calculated with R harmonic.mean(x) 1480 } 1481 void ColumnTest::testFormulasChm() { 1482 const QVector<double> c1Vector = {1.0, 0.0, 2.0, 5.0}, c2Vector = {11., 12., 13., 14., 15., 16., 17., 18.}; 1483 SETUP_C1_C2_COLUMNS(c1Vector, c2Vector) 1484 COLUMN2_SET_FORMULA_AND_EVALUATE("chm(x)", 3.75) // Result used from: statisticsDoubleZero() 1485 } 1486 void ColumnTest::testFormulasStatisticsMode() { 1487 const QVector<double> c1Vector = {1., -1., 8., 10., -5}, c2Vector = {11., 12., 13., 14., 15., 16., 17., 18.}; 1488 1489 // Calculated with R: 1490 // Mode <- function(x) { 1491 // ux <- unique(x) 1492 // ux[which.max(tabulate(match(x, ux)))] 1493 // } 1494 // Mode(x) 1495 SETUP_C1_C2_COLUMNS(c1Vector, c2Vector) 1496 COLUMN2_SET_FORMULA_AND_EVALUATE("mode(x)", NAN) 1497 } 1498 void ColumnTest::testFormulasQuartile1() { 1499 const QVector<double> c1Vector = {1., -1., 8., 10., -5}, c2Vector = {11., 12., 13., 14., 15., 16., 17., 18.}; 1500 SETUP_C1_C2_COLUMNS(c1Vector, c2Vector) 1501 COLUMN2_SET_FORMULA_AND_EVALUATE("quartile1(x)", -1.) // Calculated with R: summary(x) 1502 } 1503 void ColumnTest::testFormulasQuartile3() { 1504 const QVector<double> c1Vector = {1., -1., 8., 10., -5}, c2Vector = {11., 12., 13., 14., 15., 16., 17., 18.}; 1505 1506 SETUP_C1_C2_COLUMNS(c1Vector, c2Vector) 1507 COLUMN2_SET_FORMULA_AND_EVALUATE("quartile3(x)", 8.) // Calculated with R: summary(x) 1508 } 1509 void ColumnTest::testFormulasIqr() { 1510 const QVector<double> c1Vector = {1., -1., 8., 10., -5}, c2Vector = {11., 12., 13., 14., 15., 16., 17., 18.}; 1511 1512 SETUP_C1_C2_COLUMNS(c1Vector, c2Vector) 1513 COLUMN2_SET_FORMULA_AND_EVALUATE("iqr(x)", 9.); // Calculated with R: IQR(x) 1514 } 1515 void ColumnTest::testFormulasPercentile1() { 1516 const QVector<double> c1Vector = {1., -1., 8., 10., -5}, c2Vector = {11., 12., 13., 14., 15., 16., 17., 18.}; 1517 1518 SETUP_C1_C2_COLUMNS(c1Vector, c2Vector) 1519 COLUMN2_SET_FORMULA_AND_EVALUATE("percentile1(x)", -4.84); // Calculated with R: quantile(x, 1/100) 1520 } 1521 void ColumnTest::testFormulasPercentile5() { 1522 const QVector<double> c1Vector = {1., -1., 8., 10., -5}, c2Vector = {11., 12., 13., 14., 15., 16., 17., 18.}; 1523 1524 SETUP_C1_C2_COLUMNS(c1Vector, c2Vector) 1525 COLUMN2_SET_FORMULA_AND_EVALUATE("percentile5(x)", -4.2); // Calculated with R: quantile(x, 5/100) 1526 } 1527 void ColumnTest::testFormulasPercentile10() { 1528 const QVector<double> c1Vector = {1., -1., 8., 10., -5}, c2Vector = {11., 12., 13., 14., 15., 16., 17., 18.}; 1529 1530 SETUP_C1_C2_COLUMNS(c1Vector, c2Vector) 1531 COLUMN2_SET_FORMULA_AND_EVALUATE("percentile10(x)", -3.4); // Calculated with R: quantile(x, 10/100) 1532 } 1533 void ColumnTest::testFormulasPercentile90() { 1534 const QVector<double> c1Vector = {1., -1., 8., 10., -5}, c2Vector = {11., 12., 13., 14., 15., 16., 17., 18.}; 1535 1536 SETUP_C1_C2_COLUMNS(c1Vector, c2Vector) 1537 COLUMN2_SET_FORMULA_AND_EVALUATE("percentile90(x)", 9.2); // Calculated with R: quantile(x, 90/100) 1538 } 1539 void ColumnTest::testFormulasPercentile95() { 1540 const QVector<double> c1Vector = {1., -1., 8., 10., -5}, c2Vector = {11., 12., 13., 14., 15., 16., 17., 18.}; 1541 1542 SETUP_C1_C2_COLUMNS(c1Vector, c2Vector) 1543 COLUMN2_SET_FORMULA_AND_EVALUATE("percentile95(x)", 9.6); // Calculated with R: quantile(x, 95/100) 1544 } 1545 void ColumnTest::testFormulasPercentile99() { 1546 const QVector<double> c1Vector = {1., -1., 8., 10., -5}, c2Vector = {11., 12., 13., 14., 15., 16., 17., 18.}; 1547 1548 SETUP_C1_C2_COLUMNS(c1Vector, c2Vector) 1549 COLUMN2_SET_FORMULA_AND_EVALUATE("percentile99(x)", 9.92); // Calculated with R: quantile(x, 99/100) 1550 } 1551 void ColumnTest::testFormulasTrimean() { 1552 const QVector<double> c1Vector = {1.0, 0.0, 2.0, 5.0}, c2Vector = {11., 12., 13., 14., 15., 16., 17., 18.}; 1553 1554 SETUP_C1_C2_COLUMNS(c1Vector, c2Vector) 1555 COLUMN2_SET_FORMULA_AND_EVALUATE("trimean(x)", 1.625); // Value used from statisticsDoubleZero() 1556 } 1557 void ColumnTest::testFormulasMeandev() { 1558 const QVector<double> c1Vector = {1.0, 0.0, 2.0, 5.0}, c2Vector = {11., 12., 13., 14., 15., 16., 17., 18.}; 1559 1560 SETUP_C1_C2_COLUMNS(c1Vector, c2Vector) 1561 COLUMN2_SET_FORMULA_AND_EVALUATE("meandev(x)", 1.5); // Value used from statisticsDoubleZero() 1562 } 1563 void ColumnTest::testFormulasMeandevmedian() { 1564 const QVector<double> c1Vector = {1.0, 0.0, 2.0, 5.0}, c2Vector = {11., 12., 13., 14., 15., 16., 17., 18.}; 1565 1566 SETUP_C1_C2_COLUMNS(c1Vector, c2Vector) 1567 COLUMN2_SET_FORMULA_AND_EVALUATE("meandevmedian(x)", 1.5); // Value used from statisticsDoubleZero() 1568 } 1569 void ColumnTest::testFormulasMediandev() { 1570 const QVector<double> c1Vector = {1.0, 0.0, 2.0, 5.0}, c2Vector = {11., 12., 13., 14., 15., 16., 17., 18.}; 1571 1572 SETUP_C1_C2_COLUMNS(c1Vector, c2Vector) 1573 COLUMN2_SET_FORMULA_AND_EVALUATE("mediandev(x)", 1.); // Value used from statisticsDoubleZero() 1574 } 1575 void ColumnTest::testFormulasSkew() { 1576 const QVector<double> c1Vector = {1., -1., 8., 10., -5}, c2Vector = {11., 12., 13., 14., 15., 16., 17., 18.}; 1577 1578 SETUP_C1_C2_COLUMNS(c1Vector, c2Vector) 1579 COLUMN2_SET_FORMULA_AND_EVALUATE("skew(x)", 0.082773441985478); // Calculated with R: skewness(x) 1580 } 1581 void ColumnTest::testFormulasKurt() { 1582 const QVector<double> c1Vector = {1., -1., 8., 10., -5}, c2Vector = {11., 12., 13., 14., 15., 16., 17., 18.}; 1583 1584 SETUP_C1_C2_COLUMNS(c1Vector, c2Vector) 1585 COLUMN2_SET_FORMULA_AND_EVALUATE("kurt(x)", 1.4891031991143); // Calculated with R: kurtosis(x) 1586 } 1587 void ColumnTest::testFormulasEntropy() { 1588 const QVector<double> c1Vector = {1.0, 0.0, 2.0, 5.0}, c2Vector = {11., 12., 13., 14., 15., 16., 17., 18.}; 1589 1590 SETUP_C1_C2_COLUMNS(c1Vector, c2Vector) 1591 COLUMN2_SET_FORMULA_AND_EVALUATE("entropy(x)", 2.); // Value from statisticsDoubleZero() 1592 } 1593 1594 void ColumnTest::testFormulasQuantile() { 1595 QLocale::setDefault(QLocale::C); // . as decimal separator 1596 const QVector<double> c1Vector = {1., -1., 8., 10., -5}, c2Vector = {11., 12., 13., 14., 15., 16., 17., 18.}; 1597 1598 SETUP_C1_C2_COLUMNS(c1Vector, c2Vector) 1599 COLUMN2_SET_FORMULA_AND_EVALUATE("quantile(0.1;x)", -3.4); // Calculated with R: quantile(x, 0.1) 1600 } 1601 1602 void ColumnTest::testFormulasPercentile() { 1603 const QVector<double> c1Vector = {1., -1., 8., 10., -5}, c2Vector = {11., 12., 13., 14., 15., 16., 17., 18.}; 1604 1605 SETUP_C1_C2_COLUMNS(c1Vector, c2Vector) 1606 COLUMN2_SET_FORMULA_AND_EVALUATE("percentile(30;x)", -0.6); // Calculated with R: quantile(x, 30/100) 1607 } 1608 1609 void ColumnTest::clearContentNoFormula() { 1610 Project project; 1611 auto* c = new Column(QStringLiteral("Test"), Column::ColumnMode::Double); 1612 project.addChild(c); 1613 c->resizeTo(100); 1614 QCOMPARE(c->rowCount(), 100); 1615 1616 for (int i = 0; i < c->rowCount(); i++) 1617 c->setValueAt(i, i); 1618 1619 QCOMPARE(c->rowCount(), 100); 1620 for (int i = 0; i < c->rowCount(); i++) 1621 QCOMPARE(c->valueAt(i), i); 1622 1623 c->clear(); 1624 1625 QCOMPARE(c->rowCount(), 100); 1626 for (int i = 0; i < c->rowCount(); i++) 1627 QCOMPARE(c->valueAt(i), NAN); 1628 } 1629 1630 void ColumnTest::clearContentFormula() { 1631 Project project; 1632 auto* c = new Column(QStringLiteral("Test"), Column::ColumnMode::Double); 1633 project.addChild(c); 1634 c->resizeTo(100); 1635 QCOMPARE(c->rowCount(), 100); 1636 1637 for (int i = 0; i < c->rowCount(); i++) 1638 c->setValueAt(i, i); 1639 1640 QCOMPARE(c->rowCount(), 100); 1641 for (int i = 0; i < c->rowCount(); i++) 1642 QCOMPARE(c->valueAt(i), i); 1643 1644 c->setFormula(QStringLiteral("x"), {QStringLiteral("zet")}, QVector<Column*>({c}), true); 1645 c->clear(); 1646 1647 QCOMPARE(c->rowCount(), 100); 1648 for (int i = 0; i < c->rowCount(); i++) 1649 QCOMPARE(c->valueAt(i), NAN); 1650 1651 QCOMPARE(c->formula().isEmpty(), true); 1652 1653 c->undoStack()->undo(); 1654 1655 QCOMPARE(c->rowCount(), 100); 1656 for (int i = 0; i < c->rowCount(); i++) 1657 QCOMPARE(c->valueAt(i), i); 1658 1659 QCOMPARE(c->formula(), QStringLiteral("x")); 1660 QCOMPARE(c->formulaData().count(), 1); 1661 QCOMPARE(c->formulaData().at(0).column(), c); 1662 QCOMPARE(c->formulaData().at(0).variableName(), QStringLiteral("zet")); 1663 } 1664 1665 void ColumnTest::testRowCountMonotonIncrease() { 1666 Column c(QStringLiteral("Test"), Column::ColumnMode::Double); 1667 c.replaceValues(-1, {-3., 1., 2., 5., 11.}); 1668 1669 QCOMPARE(c.rowCount(1., 5.), 3); 1670 } 1671 1672 void ColumnTest::testRowCountMonotonDecrease() { 1673 Column c(QStringLiteral("Test"), Column::ColumnMode::Double); 1674 c.replaceValues(-1, {11., 9., 3., -4., -154.}); 1675 1676 QCOMPARE(c.rowCount(9., -4.), 3); 1677 } 1678 1679 void ColumnTest::testRowCountNonMonoton() { 1680 Column c(QStringLiteral("Test"), Column::ColumnMode::Double); 1681 c.replaceValues(-1, {-3., 1., -5., 5., 11., 9., 100., 2., 4.}); 1682 1683 QCOMPARE(c.rowCount(1., 5.), 4); 1684 } 1685 1686 void ColumnTest::testRowCountDateTime() { 1687 Column c(QStringLiteral("Test"), Column::ColumnMode::DateTime); 1688 c.replaceDateTimes(-1, 1689 {QDateTime::fromString(QStringLiteral("2018-03-26T02:14:34.000Z"), Qt::DateFormat::ISODateWithMs), 1690 QDateTime::fromString(QStringLiteral("2018-03-27T02:14:34.000Z"), Qt::DateFormat::ISODateWithMs), 1691 QDateTime::fromString(QStringLiteral("2018-03-28T02:14:34.000Z"), Qt::DateFormat::ISODateWithMs), 1692 QDateTime::fromString(QStringLiteral("2018-03-29T02:14:34.000Z"), Qt::DateFormat::ISODateWithMs), 1693 QDateTime::fromString(QStringLiteral("2018-03-30T02:14:34.000Z"), Qt::DateFormat::ISODateWithMs), 1694 QDateTime::fromString(QStringLiteral("2018-03-31T02:14:34.000Z"), Qt::DateFormat::ISODateWithMs)}); 1695 1696 QCOMPARE(c.rowCount(QDateTime::fromString(QStringLiteral("2018-03-27T02:14:34.000Z"), Qt::DateFormat::ISODateWithMs).toMSecsSinceEpoch(), 1697 QDateTime::fromString(QStringLiteral("2018-03-30T02:14:34.000Z"), Qt::DateFormat::ISODateWithMs).toMSecsSinceEpoch()), 1698 4); 1699 } 1700 1701 void ColumnTest::testRowCountDateTimeMonotonDecrease() { 1702 Column c(QStringLiteral("Test"), Column::ColumnMode::DateTime); 1703 c.replaceDateTimes(-1, 1704 { 1705 QDateTime::fromString(QStringLiteral("2018-03-31T02:14:34.000Z"), Qt::DateFormat::ISODateWithMs), 1706 QDateTime::fromString(QStringLiteral("2018-03-30T02:14:34.000Z"), Qt::DateFormat::ISODateWithMs), 1707 QDateTime::fromString(QStringLiteral("2018-03-29T02:14:34.000Z"), Qt::DateFormat::ISODateWithMs), 1708 QDateTime::fromString(QStringLiteral("2018-03-28T02:14:34.000Z"), Qt::DateFormat::ISODateWithMs), 1709 QDateTime::fromString(QStringLiteral("2018-03-27T02:14:34.000Z"), Qt::DateFormat::ISODateWithMs), 1710 QDateTime::fromString(QStringLiteral("2018-03-26T02:14:34.000Z"), Qt::DateFormat::ISODateWithMs), 1711 }); 1712 1713 QCOMPARE(c.rowCount(QDateTime::fromString(QStringLiteral("2018-03-27T02:14:34.000Z"), Qt::DateFormat::ISODateWithMs).toMSecsSinceEpoch(), 1714 QDateTime::fromString(QStringLiteral("2018-03-30T02:14:34.000Z"), Qt::DateFormat::ISODateWithMs).toMSecsSinceEpoch()), 1715 4); 1716 } 1717 1718 void ColumnTest::testRowCountValueLabels() { 1719 Column c(QStringLiteral("Test"), Column::ColumnMode::Double); 1720 c.addValueLabel(-2., QStringLiteral("Status 1")); 1721 c.addValueLabel(-1., QStringLiteral("Status 2")); 1722 c.addValueLabel(4., QStringLiteral("Status 3")); 1723 c.addValueLabel(5., QStringLiteral("Status 2")); 1724 c.addValueLabel(6., QStringLiteral("Status 3")); 1725 1726 QCOMPARE(c.valueLabelsCount(-1., 5.), 3); 1727 } 1728 1729 void ColumnTest::testRowCountValueLabelsDateTime() { 1730 Column c(QStringLiteral("Test"), Column::ColumnMode::DateTime); 1731 c.addValueLabel(QDateTime::fromString(QStringLiteral("2018-03-26T02:14:34.000Z"), Qt::DateFormat::ISODateWithMs), QStringLiteral("Status 1")); 1732 c.addValueLabel(QDateTime::fromString(QStringLiteral("2018-03-27T02:14:34.000Z"), Qt::DateFormat::ISODateWithMs), QStringLiteral("Status 2")); 1733 c.addValueLabel(QDateTime::fromString(QStringLiteral("2018-03-28T02:14:34.000Z"), Qt::DateFormat::ISODateWithMs), QStringLiteral("Status 3")); 1734 c.addValueLabel(QDateTime::fromString(QStringLiteral("2018-03-30T02:14:34.000Z"), Qt::DateFormat::ISODateWithMs), QStringLiteral("Status 4")); 1735 c.addValueLabel(QDateTime::fromString(QStringLiteral("2018-03-31T02:14:34.000Z"), Qt::DateFormat::ISODateWithMs), QStringLiteral("Status 5")); 1736 1737 QCOMPARE(c.valueLabelsCount(QDateTime::fromString(QStringLiteral("2018-03-27T02:14:34.000Z"), Qt::DateFormat::ISODateWithMs).toMSecsSinceEpoch(), 1738 QDateTime::fromString(QStringLiteral("2018-03-30T02:14:34.000Z"), Qt::DateFormat::ISODateWithMs).toMSecsSinceEpoch()), 1739 3); 1740 } 1741 1742 QTEST_MAIN(ColumnTest)