TestDataSeriesUtils.cpp
206 lines
| 8.0 KiB
| text/x-c
|
CppLexer
Alexandre Leroux
|
r979 | #include <Data/DataSeriesUtils.h> | ||
#include <QObject> | ||||
#include <QtTest> | ||||
Alexandre Leroux
|
r1016 | namespace { | ||
/// Path for resources | ||||
const auto TESTS_RESOURCES_PATH | ||||
= QFileInfo{QString{CORE_TESTS_RESOURCES_DIR}, "TestDataSeriesUtils"}.absoluteFilePath(); | ||||
QString inputFilePath(const QString &inputFileName) | ||||
{ | ||||
return QFileInfo{TESTS_RESOURCES_PATH, inputFileName}.absoluteFilePath(); | ||||
} | ||||
} // namespace | ||||
Alexandre Leroux
|
r979 | class TestDataSeriesUtils : public QObject { | ||
Q_OBJECT | ||||
private slots: | ||||
Alexandre Leroux
|
r1016 | /// Tests @sa DataSeriesUtils::thresholds() method | ||
void testThresholds_data(); | ||||
void testThresholds(); | ||||
Alexandre Leroux
|
r979 | /// Tests @sa DataSeriesUtils::fillDataHoles() method | ||
void testFillDataHoles_data(); | ||||
void testFillDataHoles(); | ||||
}; | ||||
void TestDataSeriesUtils::testFillDataHoles_data() | ||||
{ | ||||
QTest::addColumn<std::vector<double> >("xAxisData"); | ||||
QTest::addColumn<std::vector<double> >("valuesData"); | ||||
QTest::addColumn<double>("resolution"); | ||||
QTest::addColumn<double>("fillValue"); | ||||
Alexandre Leroux
|
r983 | QTest::addColumn<double>("minBound"); | ||
QTest::addColumn<double>("maxBound"); | ||||
Alexandre Leroux
|
r979 | QTest::addColumn<std::vector<double> >( | ||
"expectedXAxisData"); // expected x-axis data after filling holes | ||||
QTest::addColumn<std::vector<double> >( | ||||
"expectedValuesData"); // expected values data after filling holes | ||||
auto nan = std::numeric_limits<double>::quiet_NaN(); | ||||
QTest::newRow("fillDataHoles (basic case)") | ||||
<< std::vector<double>{0., 1., 5., 7., 14.} << std::vector<double>{0., 1., 2., 3., 4.} << 2. | ||||
Alexandre Leroux
|
r983 | << nan << nan << nan << std::vector<double>{0., 1., 3., 5., 7., 9., 11., 13., 14.} | ||
Alexandre Leroux
|
r979 | << std::vector<double>{0., 1., nan, 2., 3., nan, nan, nan, 4.}; | ||
QTest::newRow("fillDataHoles (change nb components)") | ||||
<< std::vector<double>{0., 1., 5., 7., 14.} | ||||
Alexandre Leroux
|
r983 | << std::vector<double>{0., 1., 2., 3., 4., 5., 6., 7., 8., 9.} << 2. << nan << nan << nan | ||
Alexandre Leroux
|
r979 | << std::vector<double>{0., 1., 3., 5., 7., 9., 11., 13., 14.} | ||
<< std::vector<double>{0., 1., 2., 3., nan, nan, 4., 5., 6., | ||||
7., nan, nan, nan, nan, nan, nan, 8., 9.}; | ||||
QTest::newRow("fillDataHoles (change resolution)") | ||||
<< std::vector<double>{0., 1., 5., 7., 14.} << std::vector<double>{0., 1., 2., 3., 4.} | ||||
Alexandre Leroux
|
r983 | << 1.5 << nan << nan << nan | ||
<< std::vector<double>{0., 1., 2.5, 4., 5., 6.5, 7., 8.5, 10., 11.5, 13., 14.} | ||||
Alexandre Leroux
|
r979 | << std::vector<double>{0., 1., nan, nan, 2., nan, 3., nan, nan, nan, nan, 4.}; | ||
QTest::newRow("fillDataHoles (with no data (no changes made))") | ||||
Alexandre Leroux
|
r983 | << std::vector<double>{} << std::vector<double>{} << 2. << nan << nan << nan | ||
<< std::vector<double>{} << std::vector<double>{}; | ||||
Alexandre Leroux
|
r979 | |||
QTest::newRow("fillDataHoles (with no resolution (no changes made))") | ||||
<< std::vector<double>{0., 1., 5., 7., 14.} << std::vector<double>{0., 1., 2., 3., 4.} << 0. | ||||
Alexandre Leroux
|
r983 | << nan << nan << nan << std::vector<double>{0., 1., 5., 7., 14.} | ||
Alexandre Leroux
|
r979 | << std::vector<double>{0., 1., 2., 3., 4.}; | ||
QTest::newRow("fillDataHoles (change fill value)") | ||||
<< std::vector<double>{0., 1., 5., 7., 14.} << std::vector<double>{0., 1., 2., 3., 4.} << 2. | ||||
Alexandre Leroux
|
r983 | << -1. << nan << nan << std::vector<double>{0., 1., 3., 5., 7., 9., 11., 13., 14.} | ||
Alexandre Leroux
|
r979 | << std::vector<double>{0., 1., -1., 2., 3., -1., -1., -1., 4.}; | ||
Alexandre Leroux
|
r983 | |||
QTest::newRow("fillDataHoles (add data holes to the beginning)") | ||||
<< std::vector<double>{5., 7., 9., 11., 13.} << std::vector<double>{0., 1., 2., 3., 4.} | ||||
<< 2. << nan << 0. << nan << std::vector<double>{1., 3., 5., 7., 9., 11., 13.} | ||||
<< std::vector<double>{nan, nan, 0., 1., 2., 3., 4.}; | ||||
QTest::newRow("fillDataHoles (add data holes to the end)") | ||||
<< std::vector<double>{5., 7., 9., 11., 13.} << std::vector<double>{0., 1., 2., 3., 4.} | ||||
<< 2. << nan << nan << 21. << std::vector<double>{5., 7., 9., 11., 13., 15., 17., 19., 21.} | ||||
<< std::vector<double>{0., 1., 2., 3., 4., nan, nan, nan, nan}; | ||||
QTest::newRow("fillDataHoles (invalid min/max bounds (no changes made))") | ||||
<< std::vector<double>{5., 7., 9., 11., 13.} << std::vector<double>{0., 1., 2., 3., 4.} | ||||
<< 2. << nan << 8. << 13. << std::vector<double>{5., 7., 9., 11., 13.} | ||||
<< std::vector<double>{0., 1., 2., 3., 4.}; | ||||
Alexandre Leroux
|
r979 | } | ||
void TestDataSeriesUtils::testFillDataHoles() | ||||
{ | ||||
QFETCH(std::vector<double>, xAxisData); | ||||
QFETCH(std::vector<double>, valuesData); | ||||
QFETCH(double, resolution); | ||||
QFETCH(double, fillValue); | ||||
Alexandre Leroux
|
r983 | QFETCH(double, minBound); | ||
QFETCH(double, maxBound); | ||||
Alexandre Leroux
|
r979 | |||
QFETCH(std::vector<double>, expectedXAxisData); | ||||
QFETCH(std::vector<double>, expectedValuesData); | ||||
// Executes method (xAxisData and valuesData are modified) | ||||
Alexandre Leroux
|
r983 | DataSeriesUtils::fillDataHoles(xAxisData, valuesData, resolution, fillValue, minBound, | ||
maxBound); | ||||
Alexandre Leroux
|
r979 | |||
// Checks results | ||||
auto equal = [](const auto &data, const auto &expectedData) { | ||||
// Compares with NaN values | ||||
return std::equal(data.begin(), data.end(), expectedData.begin(), expectedData.end(), | ||||
[](const auto &val, const auto &expectedVal) { | ||||
return (std::isnan(val) && std::isnan(expectedVal)) | ||||
|| val == expectedVal; | ||||
}); | ||||
}; | ||||
QVERIFY(equal(xAxisData, expectedXAxisData)); | ||||
QVERIFY(equal(valuesData, expectedValuesData)); | ||||
} | ||||
Alexandre Leroux
|
r1016 | namespace { | ||
const auto LINE_SEP = QRegularExpression{QStringLiteral("\\s+")}; | ||||
std::vector<double> fromFile(const QString &filePath) | ||||
{ | ||||
QFile file{filePath}; | ||||
if (!file.open(QFile::ReadOnly | QIODevice::Text)) { | ||||
return {}; | ||||
} | ||||
std::vector<double> result{}; | ||||
QTextStream stream{&file}; | ||||
QString line{}; | ||||
while (stream.readLineInto(&line)) { | ||||
auto lineData = line.split(LINE_SEP, QString::SkipEmptyParts); | ||||
for (auto data : lineData) { | ||||
bool valueOk; | ||||
auto value = data.toDouble(&valueOk); | ||||
result.push_back(valueOk ? value : std::numeric_limits<double>::quiet_NaN()); | ||||
} | ||||
} | ||||
return result; | ||||
} | ||||
} // namespace | ||||
void TestDataSeriesUtils::testThresholds_data() | ||||
{ | ||||
QTest::addColumn<std::vector<double> >("input"); | ||||
QTest::addColumn<bool>("logarithmic"); | ||||
QTest::addColumn<double>("expectedMinThreshold"); | ||||
QTest::addColumn<double>("expectedMaxThreshold"); | ||||
auto nan = std::numeric_limits<double>::quiet_NaN(); | ||||
QTest::newRow("thresholds (basic case)") | ||||
<< std::vector<double>{1., 2., 3., 4., 5., 6., 7., 8., 9., 10.} << false << 1. << 10.; | ||||
QTest::newRow("thresholds (with nan values)") | ||||
<< std::vector<double>{nan, 2., 3., 4., 5., 6., 7., 8., 9., nan} << false << 2. << 9.; | ||||
QTest::newRow("thresholds (case with low values and aberrant value)") | ||||
<< std::vector<double>{1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 2., | ||||
2., 2., 2., 2., 2., 2., 2., 2., 2., 2., 2., 2., 2., 2., 3., 3., | ||||
3., 3., 3., 3., 3., 3., 3., 3., 3., 3., 3., 3., 3., 100.} | ||||
<< false << 1. << 47.073; | ||||
QTest::newRow("thresholds (empty data)") << std::vector<double>{} << false << nan << nan; | ||||
r1159 | QTest::newRow("thresholds (only nan values)") << std::vector<double>{nan, nan, nan, nan, nan} | |||
<< false << nan << nan; | ||||
Alexandre Leroux
|
r1016 | |||
QTest::newRow("thresholds (from file with logarithmic scale)") | ||||
<< fromFile(inputFilePath("TestThresholds.txt")) << true << 832.005 << 17655064.730; | ||||
} | ||||
void TestDataSeriesUtils::testThresholds() | ||||
{ | ||||
QFETCH(std::vector<double>, input); | ||||
QFETCH(bool, logarithmic); | ||||
QFETCH(double, expectedMinThreshold); | ||||
QFETCH(double, expectedMaxThreshold); | ||||
double minThreshold, maxThreshold; | ||||
std::tie(minThreshold, maxThreshold) | ||||
= DataSeriesUtils::thresholds(input.begin(), input.end(), logarithmic); | ||||
auto compareWithNaN = [](const auto &v1, const auto &v2) { | ||||
return (std::isnan(v1) && std::isnan(v2)) || std::abs(v1 - v2) < 1e-3; | ||||
}; | ||||
QVERIFY(compareWithNaN(minThreshold, expectedMinThreshold)); | ||||
QVERIFY(compareWithNaN(maxThreshold, expectedMaxThreshold)); | ||||
} | ||||
Alexandre Leroux
|
r979 | QTEST_MAIN(TestDataSeriesUtils) | ||
#include "TestDataSeriesUtils.moc" | ||||