TestAmdaResultParser.cpp
451 lines
| 16.9 KiB
| text/x-c
|
CppLexer
|
r395 | #include "AmdaResultParser.h" | ||
|
r397 | #include <Data/ScalarSeries.h> | ||
|
r970 | #include <Data/SpectrogramSeries.h> | ||
|
r568 | #include <Data/VectorSeries.h> | ||
|
r397 | |||
|
r395 | #include <QObject> | ||
#include <QtTest> | ||||
namespace { | ||||
/// Path for the tests | ||||
const auto TESTS_RESOURCES_PATH | ||||
= QFileInfo{QString{AMDA_TESTS_RESOURCES_DIR}, "TestAmdaResultParser"}.absoluteFilePath(); | ||||
|
r568 | QDateTime dateTime(int year, int month, int day, int hours, int minutes, int seconds) | ||
{ | ||||
return QDateTime{{year, month, day}, {hours, minutes, seconds}, Qt::UTC}; | ||||
} | ||||
|
r395 | QString inputFilePath(const QString &inputFileName) | ||
{ | ||||
return QFileInfo{TESTS_RESOURCES_PATH, inputFileName}.absoluteFilePath(); | ||||
} | ||||
|
r568 | template <typename T> | ||
|
r396 | struct ExpectedResults { | ||
|
r968 | ExpectedResults &setParsingOK(bool parsingOK) | ||
|
r568 | { | ||
|
r968 | m_ParsingOK = parsingOK; | ||
return *this; | ||||
|
r568 | } | ||
|
r968 | ExpectedResults &setXAxisUnit(Unit xAxisUnit) | ||
|
r396 | { | ||
|
r968 | m_XAxisUnit = std::move(xAxisUnit); | ||
return *this; | ||||
} | ||||
ExpectedResults &setXAxisData(const QVector<QDateTime> &xAxisData) | ||||
{ | ||||
m_XAxisData.clear(); | ||||
|
r396 | // Converts QVector<QDateTime> to QVector<double> | ||
std::transform(xAxisData.cbegin(), xAxisData.cend(), std::back_inserter(m_XAxisData), | ||||
[](const auto &dateTime) { return dateTime.toMSecsSinceEpoch() / 1000.; }); | ||||
|
r968 | |||
return *this; | ||||
} | ||||
ExpectedResults &setValuesUnit(Unit valuesUnit) | ||||
{ | ||||
m_ValuesUnit = std::move(valuesUnit); | ||||
return *this; | ||||
} | ||||
ExpectedResults &setValuesData(QVector<double> valuesData) | ||||
{ | ||||
m_ValuesData.clear(); | ||||
m_ValuesData.push_back(std::move(valuesData)); | ||||
return *this; | ||||
} | ||||
ExpectedResults &setValuesData(QVector<QVector<double> > valuesData) | ||||
{ | ||||
m_ValuesData = std::move(valuesData); | ||||
return *this; | ||||
|
r396 | } | ||
|
r969 | ExpectedResults &setYAxisEnabled(bool yAxisEnabled) | ||
{ | ||||
m_YAxisEnabled = yAxisEnabled; | ||||
return *this; | ||||
} | ||||
ExpectedResults &setYAxisUnit(Unit yAxisUnit) | ||||
{ | ||||
m_YAxisUnit = std::move(yAxisUnit); | ||||
return *this; | ||||
} | ||||
ExpectedResults &setYAxisData(QVector<double> yAxisData) | ||||
{ | ||||
m_YAxisData = std::move(yAxisData); | ||||
return *this; | ||||
} | ||||
|
r396 | /** | ||
* Validates a DataSeries compared to the expected results | ||||
* @param results the DataSeries to validate | ||||
*/ | ||||
void validate(std::shared_ptr<IDataSeries> results) | ||||
{ | ||||
if (m_ParsingOK) { | ||||
|
r568 | auto dataSeries = dynamic_cast<T *>(results.get()); | ||
r835 | if (dataSeries == nullptr) { | |||
// No unit detected, parsink ok but data is nullptr | ||||
// TODO, improve the test to verify that the data is null | ||||
return; | ||||
} | ||||
|
r396 | |||
// Checks units | ||||
|
r568 | QVERIFY(dataSeries->xAxisUnit() == m_XAxisUnit); | ||
QVERIFY(dataSeries->valuesUnit() == m_ValuesUnit); | ||||
|
r396 | |||
|
r647 | auto verifyRange = [dataSeries](const auto &expectedData, const auto &equalFun) { | ||
QVERIFY(std::equal(dataSeries->cbegin(), dataSeries->cend(), expectedData.cbegin(), | ||||
expectedData.cend(), | ||||
[&equalFun](const auto &dataSeriesIt, const auto &expectedX) { | ||||
return equalFun(dataSeriesIt, expectedX); | ||||
})); | ||||
}; | ||||
// Checks x-axis data | ||||
verifyRange(m_XAxisData, [](const auto &seriesIt, const auto &value) { | ||||
return seriesIt.x() == value; | ||||
}); | ||||
// Checks values data of each component | ||||
for (auto i = 0; i < m_ValuesData.size(); ++i) { | ||||
verifyRange(m_ValuesData.at(i), [i](const auto &seriesIt, const auto &value) { | ||||
auto itValue = seriesIt.value(i); | ||||
return (std::isnan(itValue) && std::isnan(value)) || seriesIt.value(i) == value; | ||||
}); | ||||
} | ||||
|
r969 | |||
// Checks y-axis (if defined) | ||||
auto yAxis = dataSeries->yAxis(); | ||||
QCOMPARE(yAxis.isDefined(), m_YAxisEnabled); | ||||
if (m_YAxisEnabled) { | ||||
// Unit | ||||
QCOMPARE(yAxis.unit(), m_YAxisUnit); | ||||
// Data | ||||
auto yAxisSize = yAxis.size(); | ||||
QCOMPARE(yAxisSize, m_YAxisData.size()); | ||||
for (auto i = 0; i < yAxisSize; ++i) { | ||||
QCOMPARE(yAxis.at(i), m_YAxisData.at(i)); | ||||
} | ||||
} | ||||
|
r396 | } | ||
else { | ||||
QVERIFY(results == nullptr); | ||||
} | ||||
} | ||||
// Parsing was successfully completed | ||||
bool m_ParsingOK{false}; | ||||
// Expected x-axis unit | ||||
Unit m_XAxisUnit{}; | ||||
// Expected x-axis data | ||||
QVector<double> m_XAxisData{}; | ||||
|
r968 | // Expected values unit | ||
Unit m_ValuesUnit{}; | ||||
|
r396 | // Expected values data | ||
|
r568 | QVector<QVector<double> > m_ValuesData{}; | ||
|
r969 | // Expected data series has y-axis | ||
bool m_YAxisEnabled{false}; | ||||
// Expected y-axis unit (if axis defined) | ||||
Unit m_YAxisUnit{}; | ||||
// Expected y-axis data (if axis defined) | ||||
QVector<double> m_YAxisData{}; | ||||
|
r396 | }; | ||
|
r395 | } // namespace | ||
|
r568 | Q_DECLARE_METATYPE(ExpectedResults<ScalarSeries>) | ||
|
r970 | Q_DECLARE_METATYPE(ExpectedResults<SpectrogramSeries>) | ||
|
r568 | Q_DECLARE_METATYPE(ExpectedResults<VectorSeries>) | ||
|
r396 | |||
|
r395 | class TestAmdaResultParser : public QObject { | ||
Q_OBJECT | ||||
|
r568 | private: | ||
template <typename T> | ||||
void testReadDataStructure() | ||||
{ | ||||
// ////////////// // | ||||
// Test structure // | ||||
// ////////////// // | ||||
// Name of TXT file to read | ||||
QTest::addColumn<QString>("inputFileName"); | ||||
// Expected results | ||||
QTest::addColumn<ExpectedResults<T> >("expectedResults"); | ||||
} | ||||
template <typename T> | ||||
void testRead(AmdaResultParser::ValueType valueType) | ||||
{ | ||||
QFETCH(QString, inputFileName); | ||||
QFETCH(ExpectedResults<T>, expectedResults); | ||||
// Parses file | ||||
auto filePath = inputFilePath(inputFileName); | ||||
auto results = AmdaResultParser::readTxt(filePath, valueType); | ||||
// ///////////////// // | ||||
// Validates results // | ||||
// ///////////////// // | ||||
expectedResults.validate(results); | ||||
} | ||||
|
r395 | private slots: | ||
/// Input test data | ||||
|
r568 | /// @sa testReadScalarTxt() | ||
void testReadScalarTxt_data(); | ||||
|
r395 | |||
|
r568 | /// Tests parsing scalar series of a TXT file | ||
void testReadScalarTxt(); | ||||
|
r970 | /// Input test data | ||
/// @sa testReadSpectrogramTxt() | ||||
void testReadSpectrogramTxt_data(); | ||||
/// Tests parsing spectrogram series of a TXT file | ||||
void testReadSpectrogramTxt(); | ||||
|
r568 | /// Input test data | ||
/// @sa testReadVectorTxt() | ||||
void testReadVectorTxt_data(); | ||||
/// Tests parsing vector series of a TXT file | ||||
void testReadVectorTxt(); | ||||
|
r395 | }; | ||
|
r568 | void TestAmdaResultParser::testReadScalarTxt_data() | ||
|
r395 | { | ||
|
r568 | testReadDataStructure<ScalarSeries>(); | ||
|
r396 | |||
|
r397 | // ////////// // | ||
// Test cases // | ||||
// ////////// // | ||||
|
r497 | // Valid files | ||
|
r397 | QTest::newRow("Valid file") | ||
<< QStringLiteral("ValidScalar1.txt") | ||||
|
r968 | << ExpectedResults<ScalarSeries>{} | ||
.setParsingOK(true) | ||||
.setXAxisUnit(Unit{"nT", true}) | ||||
.setXAxisData({dateTime(2013, 9, 23, 9, 0, 30), dateTime(2013, 9, 23, 9, 1, 30), | ||||
dateTime(2013, 9, 23, 9, 2, 30), dateTime(2013, 9, 23, 9, 3, 30), | ||||
dateTime(2013, 9, 23, 9, 4, 30), dateTime(2013, 9, 23, 9, 5, 30), | ||||
dateTime(2013, 9, 23, 9, 6, 30), dateTime(2013, 9, 23, 9, 7, 30), | ||||
dateTime(2013, 9, 23, 9, 8, 30), dateTime(2013, 9, 23, 9, 9, 30)}) | ||||
.setValuesData({-2.83950, -2.71850, -2.52150, -2.57633, -2.58050, -2.48325, -2.63025, | ||||
-2.55800, -2.43250, -2.42200}); | ||||
|
r397 | |||
|
r497 | QTest::newRow("Valid file (value of first line is invalid but it is converted to NaN") | ||
<< QStringLiteral("WrongValue.txt") | ||||
|
r968 | << ExpectedResults<ScalarSeries>{} | ||
.setParsingOK(true) | ||||
.setXAxisUnit(Unit{"nT", true}) | ||||
.setXAxisData({dateTime(2013, 9, 23, 9, 0, 30), dateTime(2013, 9, 23, 9, 1, 30), | ||||
dateTime(2013, 9, 23, 9, 2, 30)}) | ||||
.setValuesData({std::numeric_limits<double>::quiet_NaN(), -2.71850, -2.52150}); | ||||
|
r497 | |||
QTest::newRow("Valid file that contains NaN values") | ||||
<< QStringLiteral("NaNValue.txt") | ||||
|
r968 | << ExpectedResults<ScalarSeries>{} | ||
.setParsingOK(true) | ||||
.setXAxisUnit(Unit{("nT"), true}) | ||||
.setXAxisData({dateTime(2013, 9, 23, 9, 0, 30), dateTime(2013, 9, 23, 9, 1, 30), | ||||
dateTime(2013, 9, 23, 9, 2, 30)}) | ||||
.setValuesData({std::numeric_limits<double>::quiet_NaN(), -2.71850, -2.52150}); | ||||
|
r497 | |||
|
r397 | // Valid files but with some invalid lines (wrong unit, wrong values, etc.) | ||
|
r968 | QTest::newRow("No unit file") | ||
<< QStringLiteral("NoUnit.txt") | ||||
<< ExpectedResults<ScalarSeries>{}.setParsingOK(true).setXAxisUnit(Unit{"", true}); | ||||
|
r397 | QTest::newRow("Wrong unit file") | ||
<< QStringLiteral("WrongUnit.txt") | ||||
|
r968 | << ExpectedResults<ScalarSeries>{} | ||
.setParsingOK(true) | ||||
.setXAxisUnit(Unit{"", true}) | ||||
.setXAxisData({dateTime(2013, 9, 23, 9, 0, 30), dateTime(2013, 9, 23, 9, 1, 30), | ||||
dateTime(2013, 9, 23, 9, 2, 30)}) | ||||
.setValuesData({-2.83950, -2.71850, -2.52150}); | ||||
|
r397 | |||
QTest::newRow("Wrong results file (date of first line is invalid") | ||||
<< QStringLiteral("WrongDate.txt") | ||||
|
r968 | << ExpectedResults<ScalarSeries>{} | ||
.setParsingOK(true) | ||||
.setXAxisUnit(Unit{"nT", true}) | ||||
.setXAxisData({dateTime(2013, 9, 23, 9, 1, 30), dateTime(2013, 9, 23, 9, 2, 30)}) | ||||
.setValuesData({-2.71850, -2.52150}); | ||||
|
r397 | |||
QTest::newRow("Wrong results file (too many values for first line") | ||||
<< QStringLiteral("TooManyValues.txt") | ||||
|
r968 | << ExpectedResults<ScalarSeries>{} | ||
.setParsingOK(true) | ||||
.setXAxisUnit(Unit{"nT", true}) | ||||
.setXAxisData({dateTime(2013, 9, 23, 9, 1, 30), dateTime(2013, 9, 23, 9, 2, 30)}) | ||||
.setValuesData({-2.71850, -2.52150}); | ||||
|
r397 | |||
|
r497 | QTest::newRow("Wrong results file (x of first line is NaN") | ||
<< QStringLiteral("NaNX.txt") | ||||
|
r968 | << ExpectedResults<ScalarSeries>{} | ||
.setParsingOK(true) | ||||
.setXAxisUnit(Unit{"nT", true}) | ||||
.setXAxisData({dateTime(2013, 9, 23, 9, 1, 30), dateTime(2013, 9, 23, 9, 2, 30)}) | ||||
.setValuesData({-2.71850, -2.52150}); | ||||
|
r397 | |||
|
r568 | QTest::newRow("Invalid file type (vector)") | ||
<< QStringLiteral("ValidVector1.txt") | ||||
|
r968 | << ExpectedResults<ScalarSeries>{}.setParsingOK(true).setXAxisUnit(Unit{"nT", true}); | ||
|
r568 | |||
|
r446 | // Invalid files | ||
|
r968 | QTest::newRow("Invalid file (unexisting file)") | ||
<< QStringLiteral("UnexistingFile.txt") | ||||
<< ExpectedResults<ScalarSeries>{}.setParsingOK(false); | ||||
|
r568 | |||
|
r968 | QTest::newRow("Invalid file (file not found on server)") | ||
<< QStringLiteral("FileNotFound.txt") | ||||
<< ExpectedResults<ScalarSeries>{}.setParsingOK(false); | ||||
|
r568 | } | ||
|
r446 | |||
|
r568 | void TestAmdaResultParser::testReadScalarTxt() | ||
{ | ||||
testRead<ScalarSeries>(AmdaResultParser::ValueType::SCALAR); | ||||
|
r395 | } | ||
|
r970 | void TestAmdaResultParser::testReadSpectrogramTxt_data() | ||
{ | ||||
testReadDataStructure<SpectrogramSeries>(); | ||||
// ////////// // | ||||
// Test cases // | ||||
// ////////// // | ||||
|
r971 | // Valid files | ||
QTest::newRow("Valid file (three bands)") | ||||
<< QStringLiteral("spectro/ValidSpectrogram1.txt") | ||||
<< ExpectedResults<SpectrogramSeries>{} | ||||
.setParsingOK(true) | ||||
.setXAxisUnit(Unit{"t", true}) | ||||
.setXAxisData({dateTime(2012, 11, 6, 9, 14, 35), dateTime(2012, 11, 6, 9, 16, 10), | ||||
dateTime(2012, 11, 6, 9, 17, 45), dateTime(2012, 11, 6, 9, 19, 20), | ||||
dateTime(2012, 11, 6, 9, 20, 55)}) | ||||
.setYAxisEnabled(true) | ||||
.setYAxisUnit(Unit{"eV"}) | ||||
.setYAxisData({5.75, 7.6, 10.05}) // middle of the intervals of each band | ||||
.setValuesUnit(Unit{"eV/(cm^2-s-sr-eV)"}) | ||||
.setValuesData(QVector<QVector<double> >{ | ||||
{16313.780, 12631.465, 8223.368, 27595.301, 12820.613}, | ||||
{15405.838, 11957.925, 15026.249, 25617.533, 11179.109}, | ||||
{8946.475, 18133.158, 10875.621, 24051.619, 19283.221}}); | ||||
auto fourBandsResult | ||||
= ExpectedResults<SpectrogramSeries>{} | ||||
.setParsingOK(true) | ||||
.setXAxisUnit(Unit{"t", true}) | ||||
.setXAxisData({dateTime(2012, 11, 6, 9, 14, 35), dateTime(2012, 11, 6, 9, 16, 10), | ||||
dateTime(2012, 11, 6, 9, 17, 45), dateTime(2012, 11, 6, 9, 19, 20), | ||||
dateTime(2012, 11, 6, 9, 20, 55)}) | ||||
.setYAxisEnabled(true) | ||||
.setYAxisUnit(Unit{"eV"}) | ||||
.setYAxisData({5.75, 7.6, 10.05, 13.}) // middle of the intervals of each band | ||||
.setValuesUnit(Unit{"eV/(cm^2-s-sr-eV)"}) | ||||
.setValuesData(QVector<QVector<double> >{ | ||||
{16313.780, 12631.465, 8223.368, 27595.301, 12820.613}, | ||||
{15405.838, 11957.925, 15026.249, 25617.533, 11179.109}, | ||||
{8946.475, 18133.158, 10875.621, 24051.619, 19283.221}, | ||||
{20907.664, 32076.725, 13008.381, 13142.759, 23226.998}}); | ||||
QTest::newRow("Valid file (four bands)") | ||||
<< QStringLiteral("spectro/ValidSpectrogram2.txt") << fourBandsResult; | ||||
QTest::newRow("Valid file (four unsorted bands)") | ||||
<< QStringLiteral("spectro/ValidSpectrogram3.txt") | ||||
<< fourBandsResult; // Bands and values are sorted | ||||
|
r972 | auto nan = std::numeric_limits<double>::quiet_NaN(); | ||
auto nanValuesResult | ||||
= ExpectedResults<SpectrogramSeries>{} | ||||
.setParsingOK(true) | ||||
.setXAxisUnit(Unit{"t", true}) | ||||
.setXAxisData({dateTime(2012, 11, 6, 9, 14, 35), dateTime(2012, 11, 6, 9, 16, 10), | ||||
dateTime(2012, 11, 6, 9, 17, 45), dateTime(2012, 11, 6, 9, 19, 20), | ||||
dateTime(2012, 11, 6, 9, 20, 55)}) | ||||
.setYAxisEnabled(true) | ||||
.setYAxisUnit(Unit{"eV"}) | ||||
.setYAxisData({5.75, 7.6, 10.05, 13.}) // middle of the intervals of each band | ||||
.setValuesUnit(Unit{"eV/(cm^2-s-sr-eV)"}) | ||||
.setValuesData( | ||||
QVector<QVector<double> >{{nan, 12631.465, 8223.368, 27595.301, 12820.613}, | ||||
{15405.838, nan, nan, 25617.533, 11179.109}, | ||||
{8946.475, 18133.158, 10875.621, 24051.619, 19283.221}, | ||||
{nan, nan, nan, nan, nan}}); | ||||
QTest::newRow("Valid file (containing NaN values)") | ||||
<< QStringLiteral("spectro/ValidSpectrogramNaNValues.txt") << nanValuesResult; | ||||
QTest::newRow("Valid file (containing fill values)") | ||||
<< QStringLiteral("spectro/ValidSpectrogramFillValues.txt") | ||||
<< nanValuesResult; // Fill values are replaced by NaN values in the data series | ||||
|
r973 | // Invalid files | ||
QTest::newRow("Invalid file (inconsistent bands)") | ||||
<< QStringLiteral("spectro/InvalidSpectrogramWrongBands.txt") | ||||
<< ExpectedResults<SpectrogramSeries>{}.setParsingOK(false); | ||||
|
r970 | } | ||
void TestAmdaResultParser::testReadSpectrogramTxt() | ||||
{ | ||||
testRead<SpectrogramSeries>(AmdaResultParser::ValueType::SPECTROGRAM); | ||||
} | ||||
|
r568 | void TestAmdaResultParser::testReadVectorTxt_data() | ||
|
r395 | { | ||
|
r568 | testReadDataStructure<VectorSeries>(); | ||
// ////////// // | ||||
// Test cases // | ||||
// ////////// // | ||||
// Valid files | ||||
QTest::newRow("Valid file") | ||||
<< QStringLiteral("ValidVector1.txt") | ||||
|
r968 | << ExpectedResults<VectorSeries>{} | ||
.setParsingOK(true) | ||||
.setXAxisUnit(Unit{"nT", true}) | ||||
.setXAxisData({dateTime(2013, 7, 2, 9, 13, 50), dateTime(2013, 7, 2, 9, 14, 6), | ||||
dateTime(2013, 7, 2, 9, 14, 22), dateTime(2013, 7, 2, 9, 14, 38), | ||||
dateTime(2013, 7, 2, 9, 14, 54), dateTime(2013, 7, 2, 9, 15, 10), | ||||
dateTime(2013, 7, 2, 9, 15, 26), dateTime(2013, 7, 2, 9, 15, 42), | ||||
dateTime(2013, 7, 2, 9, 15, 58), dateTime(2013, 7, 2, 9, 16, 14)}) | ||||
.setValuesData( | ||||
{{-0.332, -1.011, -1.457, -1.293, -1.217, -1.443, -1.278, -1.202, -1.22, -1.259}, | ||||
{3.206, 2.999, 2.785, 2.736, 2.612, 2.564, 2.892, 2.862, 2.859, 2.764}, | ||||
{0.058, 0.496, 1.018, 1.485, 1.662, 1.505, 1.168, 1.244, 1.15, 1.358}}); | ||||
|
r396 | |||
|
r568 | // Valid files but with some invalid lines (wrong unit, wrong values, etc.) | ||
QTest::newRow("Invalid file type (scalar)") | ||||
<< QStringLiteral("ValidScalar1.txt") | ||||
|
r968 | << ExpectedResults<VectorSeries>{} | ||
.setParsingOK(true) | ||||
.setXAxisUnit(Unit{"nT", true}) | ||||
.setXAxisData({}) | ||||
.setValuesData(QVector<QVector<double> >{{}, {}, {}}); | ||||
|
r568 | } | ||
|
r396 | |||
|
r568 | void TestAmdaResultParser::testReadVectorTxt() | ||
{ | ||||
testRead<VectorSeries>(AmdaResultParser::ValueType::VECTOR); | ||||
|
r395 | } | ||
QTEST_MAIN(TestAmdaResultParser) | ||||
#include "TestAmdaResultParser.moc" | ||||