From 26490bf7ccac77883645ccf483eb22328c8e59a3 2017-10-30 16:31:16 From: Alexandre Leroux Date: 2017-10-30 16:31:16 Subject: [PATCH] Unit tests (2): Refactoring Refactors unit tests for DataSeries by moving generic unit tests in a utility class and dispatching tests in dedicated classes (one per type of DataSeries) --- diff --git a/core/tests/Data/DataSeriesUtils.cpp b/core/tests/Data/DataSeriesUtils.cpp new file mode 100644 index 0000000..b4162e8 --- /dev/null +++ b/core/tests/Data/DataSeriesUtils.cpp @@ -0,0 +1,24 @@ +#include "DataSeriesUtils.h" + +void validateRange(DataSeriesIterator first, DataSeriesIterator last, const DataContainer &xData, + const DataContainer &valuesData) +{ + QVERIFY(std::equal(first, last, xData.cbegin(), xData.cend(), + [](const auto &it, const auto &expectedX) { return it.x() == expectedX; })); + QVERIFY(std::equal( + first, last, valuesData.cbegin(), valuesData.cend(), + [](const auto &it, const auto &expectedVal) { return it.value() == expectedVal; })); +} + +void validateRange(DataSeriesIterator first, DataSeriesIterator last, const DataContainer &xData, const std::vector &valuesData) +{ + QVERIFY(std::equal(first, last, xData.cbegin(), xData.cend(), + [](const auto &it, const auto &expectedX) { return it.x() == expectedX; })); + for (auto i = 0; i < valuesData.size(); ++i) { + auto componentData = valuesData.at(i); + + QVERIFY(std::equal( + first, last, componentData.cbegin(), componentData.cend(), + [i](const auto &it, const auto &expectedVal) { return it.value(i) == expectedVal; })); + } +} diff --git a/core/tests/Data/DataSeriesUtils.h b/core/tests/Data/DataSeriesUtils.h new file mode 100644 index 0000000..d12657f --- /dev/null +++ b/core/tests/Data/DataSeriesUtils.h @@ -0,0 +1,373 @@ +/** + * The DataSeriesUtils file contains a set of utility methods that can be used to test the operations on a DataSeries. + * + * Most of these methods are template methods to adapt to any series (scalars, vectors, spectrograms...) + * + * @sa DataSeries + */ +#ifndef SCIQLOP_DATASERIESUTILS_H +#define SCIQLOP_DATASERIESUTILS_H + +#include +#include +#include +#include + +#include +#include + +/// Underlying data in ArrayData +using DataContainer = std::vector; + +Q_DECLARE_METATYPE(std::shared_ptr) +Q_DECLARE_METATYPE(std::shared_ptr) +Q_DECLARE_METATYPE(std::shared_ptr) + +/** + * Checks that the range of a 1-dim data series contains the expected x-axis data and values data + * @param first the iterator on the beginning of the range to check + * @param last the iterator on the end of the range to check + * @param xData expected x-axis data for the range + * @param valuesData expected values data for the range + */ +void validateRange(DataSeriesIterator first, DataSeriesIterator last, const DataContainer &xData, + const DataContainer &valuesData); + +/** + * Checks that the range of a 2-dim data series contains the expected x-axis data and values data + * @param first the iterator on the beginning of the range to check + * @param last the iterator on the end of the range to check + * @param xData expected x-axis data for the range + * @param valuesData expected values data for the range + */ +void validateRange(DataSeriesIterator first, DataSeriesIterator last, const DataContainer &xData, + const std::vector &valuesData); + +/** + * Sets the structure of unit tests concerning merge of two data series + * @tparam DataSeriesType the type of data series to merge + * @tparam ExpectedValuesType the type of values expected after merge + * @sa testMerge_t() + */ +template +void testMerge_struct() { + // Data series to merge + QTest::addColumn >("dataSeries"); + QTest::addColumn >("dataSeries2"); + + // Expected values in the first data series after merge + QTest::addColumn("expectedXAxisData"); + QTest::addColumn("expectedValuesData"); +} + +/** + * Unit test concerning merge of two data series + * @sa testMerge_struct() + */ +template +void testMerge_t(){ + // Merges series + QFETCH(std::shared_ptr, dataSeries); + QFETCH(std::shared_ptr, dataSeries2); + + dataSeries->merge(dataSeries2.get()); + + // Validates results : we check that the merge is valid + QFETCH(DataContainer, expectedXAxisData); + QFETCH(ExpectedValuesType, expectedValuesData); + + validateRange(dataSeries->cbegin(), dataSeries->cend(), expectedXAxisData, expectedValuesData); +} + +/** + * Sets the structure of unit tests concerning merge of two data series that are of a different type + * @tparam SourceType the type of data series with which to make the merge + * @tparam DestType the type of data series in which to make the merge + * @sa testMergeDifferentTypes_t() + */ +template +void testMergeDifferentTypes_struct() +{ + // Data series to merge + QTest::addColumn >("dest"); + QTest::addColumn >("source"); + + // Expected values in the dest data series after merge + QTest::addColumn("expectedXAxisData"); + QTest::addColumn("expectedValuesData"); +} + +/** + * Unit test concerning merge of two data series that are of a different type + * @sa testMergeDifferentTypes_struct() + */ +template +void testMergeDifferentTypes_t() +{ + // Merges series + QFETCH(std::shared_ptr, source); + QFETCH(std::shared_ptr, dest); + + dest->merge(source.get()); + + // Validates results : we check that the merge is valid and the data series is sorted on its + // x-axis data + QFETCH(DataContainer, expectedXAxisData); + QFETCH(DataContainer, expectedValuesData); + + validateRange(dest->cbegin(), dest->cend(), expectedXAxisData, expectedValuesData); +} + +/** + * Sets the structure of unit tests concerning getting the min x-axis data of a data series + * @tparam T the type of data series on which to make the operation + * @sa testMinXAxisData_t() + */ +template +void testMinXAxisData_struct(){ + // Data series to get min data + QTest::addColumn >("dataSeries"); + + // Min data + QTest::addColumn("min"); + + // Expected results + QTest::addColumn( + "expectedOK"); // if true, expects to have a result (i.e. the iterator != end iterator) + QTest::addColumn( + "expectedMin"); // Expected value when method doesn't return end iterator +} + +/** + * Unit test concerning getting the min x-axis data of a data series + * @sa testMinXAxisData_struct() + */ +template +void testMinXAxisData_t() +{ + QFETCH(std::shared_ptr, dataSeries); + QFETCH(double, min); + + QFETCH(bool, expectedOK); + QFETCH(double, expectedMin); + + auto it = dataSeries->minXAxisData(min); + + QCOMPARE(expectedOK, it != dataSeries->cend()); + + // If the method doesn't return a end iterator, checks with expected value + if (expectedOK) { + QCOMPARE(expectedMin, it->x()); + } +} + +/** + * Sets the structure of unit tests concerning getting the max x-axis data of a data series + * @tparam T the type of data series on which to make the operation + * @sa testMaxXAxisData_t() + */ +template +void testMaxXAxisData_struct(){ + // Data series to get max data + QTest::addColumn >("dataSeries"); + + // Max data + QTest::addColumn("max"); + + // Expected results + QTest::addColumn( + "expectedOK"); // if true, expects to have a result (i.e. the iterator != end iterator) + QTest::addColumn( + "expectedMax"); // Expected value when method doesn't return end iterator + +} + +/** + * Unit test concerning getting the max x-axis data of a data series + * @sa testMaxXAxisData_struct() + */ +template +void testMaxXAxisData_t() +{ + QFETCH(std::shared_ptr, dataSeries); + QFETCH(double, max); + + QFETCH(bool, expectedOK); + QFETCH(double, expectedMax); + + auto it = dataSeries->maxXAxisData(max); + + QCOMPARE(expectedOK, it != dataSeries->cend()); + + // If the method doesn't return a end iterator, checks with expected value + if (expectedOK) { + QCOMPARE(expectedMax, it->x()); + } +} + +/** + * Sets the structure of unit tests concerning getting the purge of a data series + * @tparam T the type of data series on which to make the operation + * @sa testMinXAxisData_t() + */ +template +void testPurge_struct() +{ + // Data series to purge + QTest::addColumn >("dataSeries"); + QTest::addColumn("min"); + QTest::addColumn("max"); + + // Expected values after purge + QTest::addColumn("expectedXAxisData"); + QTest::addColumn >("expectedValuesData"); +} + +/** + * Unit test concerning getting the purge of a data series + * @sa testPurge_struct() + */ +template +void testPurge_t(){ + QFETCH(std::shared_ptr, dataSeries); + QFETCH(double, min); + QFETCH(double, max); + + dataSeries->purge(min, max); + + // Validates results + QFETCH(DataContainer, expectedXAxisData); + QFETCH(std::vector, expectedValuesData); + + validateRange(dataSeries->cbegin(), dataSeries->cend(), expectedXAxisData, + expectedValuesData); +} + +/** + * Sets the structure of unit tests concerning getting subdata of a data series + * @tparam DataSeriesType the type of data series on which to make the operation + * @tparam ExpectedValuesType the type of values expected after the operation + * @sa testSubDataSeries_t() + */ +template +void testSubDataSeries_struct() { + // Data series from which extract the subdata series + QTest::addColumn >("dataSeries"); + // Range to extract + QTest::addColumn("range"); + + // Expected values for the subdata series + QTest::addColumn("expectedXAxisData"); + QTest::addColumn("expectedValuesData"); +} + +/** + * Unit test concerning getting subdata of a data series + * @sa testSubDataSeries_struct() + */ +template +void testSubDataSeries_t(){ + QFETCH(std::shared_ptr, dataSeries); + QFETCH(SqpRange, range); + + // Makes the operation + auto subDataSeries = std::dynamic_pointer_cast(dataSeries->subDataSeries(range)); + QVERIFY(subDataSeries != nullptr); + + // Validates results + QFETCH(DataContainer, expectedXAxisData); + QFETCH(ExpectedValuesType, expectedValuesData); + + validateRange(subDataSeries->cbegin(), subDataSeries->cend(), expectedXAxisData, expectedValuesData); +} + +/** + * Sets the structure of unit tests concerning getting the range of a data series + * @tparam T the type of data series on which to make the operation + * @sa testXAxisRange_t() + */ +template +void testXAxisRange_struct(){ + // Data series to get x-axis range + QTest::addColumn >("dataSeries"); + + // Min/max values + QTest::addColumn("min"); + QTest::addColumn("max"); + + // Expected values + QTest::addColumn("expectedXAxisData"); + QTest::addColumn("expectedValuesData"); +} + +/** + * Unit test concerning getting the range of a data series + * @sa testXAxisRange_struct() + */ +template +void testXAxisRange_t(){ + QFETCH(std::shared_ptr, dataSeries); + QFETCH(double, min); + QFETCH(double, max); + + QFETCH(DataContainer, expectedXAxisData); + QFETCH(DataContainer, expectedValuesData); + + auto bounds = dataSeries->xAxisRange(min, max); + validateRange(bounds.first, bounds.second, expectedXAxisData, expectedValuesData); +} + +/** + * Sets the structure of unit tests concerning getting values bounds of a data series + * @tparam T the type of data series on which to make the operation + * @sa testValuesBounds_t() + */ +template +void testValuesBounds_struct() +{ + // Data series to get values bounds + QTest::addColumn >("dataSeries"); + + // x-axis range + QTest::addColumn("minXAxis"); + QTest::addColumn("maxXAxis"); + + // Expected results + QTest::addColumn( + "expectedOK"); // Test is expected to be ok (i.e. method doesn't return end iterators) + QTest::addColumn("expectedMinValue"); + QTest::addColumn("expectedMaxValue"); +} + +/** + * Unit test concerning getting values bounds of a data series + * @sa testValuesBounds_struct() + */ +template +void testValuesBounds_t() +{ + QFETCH(std::shared_ptr, dataSeries); + QFETCH(double, minXAxis); + QFETCH(double, maxXAxis); + + QFETCH(bool, expectedOK); + QFETCH(double, expectedMinValue); + QFETCH(double, expectedMaxValue); + + auto minMaxIts = dataSeries->valuesBounds(minXAxis, maxXAxis); + auto end = dataSeries->cend(); + + // Checks iterators with expected result + QCOMPARE(expectedOK, minMaxIts.first != end && minMaxIts.second != end); + + if (expectedOK) { + auto compare = [](const auto &v1, const auto &v2) { + return (std::isnan(v1) && std::isnan(v2)) || v1 == v2; + }; + + QVERIFY(compare(expectedMinValue, minMaxIts.first->minValue())); + QVERIFY(compare(expectedMaxValue, minMaxIts.second->maxValue())); + } +} + +#endif // SCIQLOP_DATASERIESUTILS_H diff --git a/core/tests/Data/TestDataSeries.cpp b/core/tests/Data/TestDataSeries.cpp deleted file mode 100644 index 15a9f10..0000000 --- a/core/tests/Data/TestDataSeries.cpp +++ /dev/null @@ -1,707 +0,0 @@ -#include "Data/DataSeries.h" -#include "Data/ScalarSeries.h" -#include "Data/VectorSeries.h" - -#include - -#include -#include - -Q_DECLARE_METATYPE(std::shared_ptr) -Q_DECLARE_METATYPE(std::shared_ptr) - -namespace { - -using DataContainer = std::vector; - -void validateRange(DataSeriesIterator first, DataSeriesIterator last, const DataContainer &xData, - const DataContainer &valuesData) -{ - QVERIFY(std::equal(first, last, xData.cbegin(), xData.cend(), - [](const auto &it, const auto &expectedX) { return it.x() == expectedX; })); - QVERIFY(std::equal( - first, last, valuesData.cbegin(), valuesData.cend(), - [](const auto &it, const auto &expectedVal) { return it.value() == expectedVal; })); -} - -void validateRange(DataSeriesIterator first, DataSeriesIterator last, const DataContainer &xData, - const std::vector &valuesData) -{ - QVERIFY(std::equal(first, last, xData.cbegin(), xData.cend(), - [](const auto &it, const auto &expectedX) { return it.x() == expectedX; })); - for (auto i = 0; i < valuesData.size(); ++i) { - auto componentData = valuesData.at(i); - - QVERIFY(std::equal( - first, last, componentData.cbegin(), componentData.cend(), - [i](const auto &it, const auto &expectedVal) { return it.value(i) == expectedVal; })); - } -} - -} // namespace - -class TestDataSeries : public QObject { - Q_OBJECT -private: - template - void testValuesBoundsStructure() - { - // ////////////// // - // Test structure // - // ////////////// // - - // Data series to get values bounds - QTest::addColumn >("dataSeries"); - - // x-axis range - QTest::addColumn("minXAxis"); - QTest::addColumn("maxXAxis"); - - // Expected results - QTest::addColumn( - "expectedOK"); // Test is expected to be ok (i.e. method doesn't return end iterators) - QTest::addColumn("expectedMinValue"); - QTest::addColumn("expectedMaxValue"); - } - - template - void testValuesBounds() - { - QFETCH(std::shared_ptr, dataSeries); - QFETCH(double, minXAxis); - QFETCH(double, maxXAxis); - - QFETCH(bool, expectedOK); - QFETCH(double, expectedMinValue); - QFETCH(double, expectedMaxValue); - - auto minMaxIts = dataSeries->valuesBounds(minXAxis, maxXAxis); - auto end = dataSeries->cend(); - - // Checks iterators with expected result - QCOMPARE(expectedOK, minMaxIts.first != end && minMaxIts.second != end); - - if (expectedOK) { - auto compare = [](const auto &v1, const auto &v2) { - return (std::isnan(v1) && std::isnan(v2)) || v1 == v2; - }; - - QVERIFY(compare(expectedMinValue, minMaxIts.first->minValue())); - QVERIFY(compare(expectedMaxValue, minMaxIts.second->maxValue())); - } - } - - template - void testPurgeStructure() - { - // ////////////// // - // Test structure // - // ////////////// // - - // Data series to purge - QTest::addColumn >("dataSeries"); - QTest::addColumn("min"); - QTest::addColumn("max"); - - // Expected values after purge - QTest::addColumn("expectedXAxisData"); - QTest::addColumn >("expectedValuesData"); - } - - template - void testPurge() - { - QFETCH(std::shared_ptr, dataSeries); - QFETCH(double, min); - QFETCH(double, max); - - dataSeries->purge(min, max); - - // Validates results - QFETCH(DataContainer, expectedXAxisData); - QFETCH(std::vector, expectedValuesData); - - validateRange(dataSeries->cbegin(), dataSeries->cend(), expectedXAxisData, - expectedValuesData); - } - - template - void testMergeDifferentTypesStructure() - { - // ////////////// // - // Test structure // - // ////////////// // - - // Data series to merge - QTest::addColumn >("dest"); - QTest::addColumn >("source"); - - // Expected values in the dest data series after merge - QTest::addColumn("expectedXAxisData"); - QTest::addColumn("expectedValuesData"); - } - - template - void testMergeDifferentTypes() - { - // Merges series - QFETCH(std::shared_ptr, source); - QFETCH(std::shared_ptr, dest); - - dest->merge(source.get()); - - // Validates results : we check that the merge is valid and the data series is sorted on its - // x-axis data - QFETCH(DataContainer, expectedXAxisData); - QFETCH(DataContainer, expectedValuesData); - - validateRange(dest->cbegin(), dest->cend(), expectedXAxisData, expectedValuesData); - } - -private slots: - - /// Input test data - /// @sa testCtor() - void testCtor_data(); - - /// Tests construction of a data series - void testCtor(); - - /// Input test data - /// @sa testMerge() - void testMerge_data(); - - /// Tests merge of two data series - void testMerge(); - - /// Input test data - /// @sa testMergeVectorInScalar() - void testMergeVectorInScalar_data(); - - /// Tests merge of vector series in scalar series - void testMergeVectorInScalar(); - - /// Input test data - /// @sa testPurgeScalar() - void testPurgeScalar_data(); - - /// Tests purge of a scalar series - void testPurgeScalar(); - - /// Input test data - /// @sa testPurgeVector() - void testPurgeVector_data(); - - /// Tests purge of a vector series - void testPurgeVector(); - - /// Input test data - /// @sa testMinXAxisData() - void testMinXAxisData_data(); - - /// Tests get min x-axis data of a data series - void testMinXAxisData(); - - /// Input test data - /// @sa testMaxXAxisData() - void testMaxXAxisData_data(); - - /// Tests get max x-axis data of a data series - void testMaxXAxisData(); - - /// Input test data - /// @sa testXAxisRange() - void testXAxisRange_data(); - - /// Tests get x-axis range of a data series - void testXAxisRange(); - - /// Input test data - /// @sa testValuesBoundsScalar() - void testValuesBoundsScalar_data(); - - /// Tests get values bounds of a scalar series - void testValuesBoundsScalar(); - - /// Input test data - /// @sa testValuesBoundsVector() - void testValuesBoundsVector_data(); - - /// Tests get values bounds of a vector series - void testValuesBoundsVector(); -}; - -void TestDataSeries::testCtor_data() -{ - // ////////////// // - // Test structure // - // ////////////// // - - // x-axis data - QTest::addColumn("xAxisData"); - // values data - QTest::addColumn("valuesData"); - - // expected x-axis data - QTest::addColumn("expectedXAxisData"); - // expected values data - QTest::addColumn("expectedValuesData"); - - // ////////// // - // Test cases // - // ////////// // - - QTest::newRow("invalidData (different sizes of vectors)") - << DataContainer{1., 2., 3., 4., 5.} << DataContainer{100., 200., 300.} << DataContainer{} - << DataContainer{}; - - QTest::newRow("sortedData") << DataContainer{1., 2., 3., 4., 5.} - << DataContainer{100., 200., 300., 400., 500.} - << DataContainer{1., 2., 3., 4., 5.} - << DataContainer{100., 200., 300., 400., 500.}; - - QTest::newRow("unsortedData") << DataContainer{5., 4., 3., 2., 1.} - << DataContainer{100., 200., 300., 400., 500.} - << DataContainer{1., 2., 3., 4., 5.} - << DataContainer{500., 400., 300., 200., 100.}; - - QTest::newRow("unsortedData2") - << DataContainer{1., 4., 3., 5., 2.} << DataContainer{100., 200., 300., 400., 500.} - << DataContainer{1., 2., 3., 4., 5.} << DataContainer{100., 500., 300., 200., 400.}; -} - -void TestDataSeries::testCtor() -{ - // Creates series - QFETCH(DataContainer, xAxisData); - QFETCH(DataContainer, valuesData); - - auto series = std::make_shared(std::move(xAxisData), std::move(valuesData), - Unit{}, Unit{}); - - // Validates results : we check that the data series is sorted on its x-axis data - QFETCH(DataContainer, expectedXAxisData); - QFETCH(DataContainer, expectedValuesData); - - validateRange(series->cbegin(), series->cend(), expectedXAxisData, expectedValuesData); -} - -namespace { - -std::shared_ptr createScalarSeries(DataContainer xAxisData, DataContainer valuesData) -{ - return std::make_shared(std::move(xAxisData), std::move(valuesData), Unit{}, - Unit{}); -} - -std::shared_ptr createVectorSeries(DataContainer xAxisData, DataContainer xValuesData, - DataContainer yValuesData, - DataContainer zValuesData) -{ - return std::make_shared(std::move(xAxisData), std::move(xValuesData), - std::move(yValuesData), std::move(zValuesData), Unit{}, - Unit{}); -} - -} // namespace - -void TestDataSeries::testMerge_data() -{ - // ////////////// // - // Test structure // - // ////////////// // - - // Data series to merge - QTest::addColumn >("dataSeries"); - QTest::addColumn >("dataSeries2"); - - // Expected values in the first data series after merge - QTest::addColumn("expectedXAxisData"); - QTest::addColumn("expectedValuesData"); - - // ////////// // - // Test cases // - // ////////// // - - QTest::newRow("sortedMerge") - << createScalarSeries({1., 2., 3., 4., 5.}, {100., 200., 300., 400., 500.}) - << createScalarSeries({6., 7., 8., 9., 10.}, {600., 700., 800., 900., 1000.}) - << DataContainer{1., 2., 3., 4., 5., 6., 7., 8., 9., 10.} - << DataContainer{100., 200., 300., 400., 500., 600., 700., 800., 900., 1000.}; - - QTest::newRow("unsortedMerge") - << createScalarSeries({6., 7., 8., 9., 10.}, {600., 700., 800., 900., 1000.}) - << createScalarSeries({1., 2., 3., 4., 5.}, {100., 200., 300., 400., 500.}) - << DataContainer{1., 2., 3., 4., 5., 6., 7., 8., 9., 10.} - << DataContainer{100., 200., 300., 400., 500., 600., 700., 800., 900., 1000.}; - - QTest::newRow("unsortedMerge2 (merge not made because source is in the bounds of dest)") - << createScalarSeries({1., 2., 8., 9., 10}, {100., 200., 800., 900., 1000.}) - << createScalarSeries({3., 4., 5., 6., 7.}, {300., 400., 500., 600., 700.}) - << DataContainer{1., 2., 8., 9., 10.} << DataContainer{100., 200., 800., 900., 1000.}; - - QTest::newRow("unsortedMerge3") - << createScalarSeries({3., 4., 5., 7., 8}, {300., 400., 500., 700., 800.}) - << createScalarSeries({1., 2., 3., 7., 10.}, {100., 200., 333., 777., 1000.}) - << DataContainer{1., 2., 3., 4., 5., 7., 8., 10.} - << DataContainer{100., 200., 300., 400., 500., 700., 800., 1000.}; - - QTest::newRow("emptySource") << createScalarSeries({3., 4., 5., 7., 8}, - {300., 400., 500., 700., 800.}) - << createScalarSeries({}, {}) << DataContainer{3., 4., 5., 7., 8.} - << DataContainer{300., 400., 500., 700., 800.}; -} - -void TestDataSeries::testMerge() -{ - // Merges series - QFETCH(std::shared_ptr, dataSeries); - QFETCH(std::shared_ptr, dataSeries2); - - dataSeries->merge(dataSeries2.get()); - - // Validates results : we check that the merge is valid and the data series is sorted on its - // x-axis data - QFETCH(DataContainer, expectedXAxisData); - QFETCH(DataContainer, expectedValuesData); - - validateRange(dataSeries->cbegin(), dataSeries->cend(), expectedXAxisData, expectedValuesData); -} - -void TestDataSeries::testMergeVectorInScalar_data() -{ - testMergeDifferentTypesStructure(); - - // ////////// // - // Test cases // - // ////////// // - - QTest::newRow("purgeVectorInScalar") - << createScalarSeries({1., 2., 3., 4., 5.}, {100., 200., 300., 400., 500.}) - << createVectorSeries({6., 7., 8., 9., 10.}, {600., 700., 800., 900., 1000.}, - {610., 710., 810., 910., 1010.}, {620., 720., 820., 920., 1020.}) - << DataContainer{1., 2., 3., 4., 5.} << DataContainer{100., 200., 300., 400., 500.}; -} - -void TestDataSeries::testMergeVectorInScalar() -{ - testMergeDifferentTypes(); -} - -void TestDataSeries::testPurgeScalar_data() -{ - testPurgeStructure(); - - // ////////// // - // Test cases // - // ////////// // - - QTest::newRow("purgeScalar") << createScalarSeries({1., 2., 3., 4., 5.}, - {100., 200., 300., 400., 500.}) - << 2. << 4. << DataContainer{2., 3., 4.} - << std::vector{{200., 300., 400.}}; - QTest::newRow("purgeScalar1 (min/max swap)") - << createScalarSeries({1., 2., 3., 4., 5.}, {100., 200., 300., 400., 500.}) << 4. << 2. - << DataContainer{2., 3., 4.} << std::vector{{200., 300., 400.}}; - QTest::newRow("purgeScalar2") << createScalarSeries({1., 2., 3., 4., 5.}, - {100., 200., 300., 400., 500.}) - << 0. << 2.5 << DataContainer{1., 2.} - << std::vector{{100., 200.}}; - QTest::newRow("purgeScalar3") << createScalarSeries({1., 2., 3., 4., 5.}, - {100., 200., 300., 400., 500.}) - << 3.5 << 7. << DataContainer{4., 5.} - << std::vector{{400., 500.}}; - QTest::newRow("purgeScalar4") << createScalarSeries({1., 2., 3., 4., 5.}, - {100., 200., 300., 400., 500.}) - << 0. << 7. << DataContainer{1., 2., 3., 4., 5.} - << std::vector{{100., 200., 300., 400., 500.}}; - QTest::newRow("purgeScalar5") << createScalarSeries({1., 2., 3., 4., 5.}, - {100., 200., 300., 400., 500.}) - << 5.5 << 7. << DataContainer{} << std::vector{{}}; -} - -void TestDataSeries::testPurgeScalar() -{ - testPurge(); -} - -void TestDataSeries::testPurgeVector_data() -{ - testPurgeStructure(); - - // ////////// // - // Test cases // - // ////////// // - - QTest::newRow("purgeVector") << createVectorSeries({1., 2., 3., 4., 5.}, {6., 7., 8., 9., 10.}, - {11., 12., 13., 14., 15.}, - {16., 17., 18., 19., 20.}) - << 2. << 4. << DataContainer{2., 3., 4.} - << std::vector{ - {7., 8., 9.}, {12., 13., 14.}, {17., 18., 19.}}; -} - -void TestDataSeries::testPurgeVector() -{ - testPurge(); -} - -void TestDataSeries::testMinXAxisData_data() -{ - // ////////////// // - // Test structure // - // ////////////// // - - // Data series to get min data - QTest::addColumn >("dataSeries"); - - // Min data - QTest::addColumn("min"); - - // Expected results - QTest::addColumn( - "expectedOK"); // if true, expects to have a result (i.e. the iterator != end iterator) - QTest::addColumn( - "expectedMin"); // Expected value when method doesn't return end iterator - - // ////////// // - // Test cases // - // ////////// // - - QTest::newRow("minData1") << createScalarSeries({1., 2., 3., 4., 5.}, - {100., 200., 300., 400., 500.}) - << 0. << true << 1.; - QTest::newRow("minData2") << createScalarSeries({1., 2., 3., 4., 5.}, - {100., 200., 300., 400., 500.}) - << 1. << true << 1.; - QTest::newRow("minData3") << createScalarSeries({1., 2., 3., 4., 5.}, - {100., 200., 300., 400., 500.}) - << 1.1 << true << 2.; - QTest::newRow("minData4") << createScalarSeries({1., 2., 3., 4., 5.}, - {100., 200., 300., 400., 500.}) - << 5. << true << 5.; - QTest::newRow("minData5") << createScalarSeries({1., 2., 3., 4., 5.}, - {100., 200., 300., 400., 500.}) - << 5.1 << false << std::numeric_limits::quiet_NaN(); - QTest::newRow("minData6") << createScalarSeries({}, {}) << 1.1 << false - << std::numeric_limits::quiet_NaN(); -} - -void TestDataSeries::testMinXAxisData() -{ - QFETCH(std::shared_ptr, dataSeries); - QFETCH(double, min); - - QFETCH(bool, expectedOK); - QFETCH(double, expectedMin); - - auto it = dataSeries->minXAxisData(min); - - QCOMPARE(expectedOK, it != dataSeries->cend()); - - // If the method doesn't return a end iterator, checks with expected value - if (expectedOK) { - QCOMPARE(expectedMin, it->x()); - } -} - -void TestDataSeries::testMaxXAxisData_data() -{ - // ////////////// // - // Test structure // - // ////////////// // - - // Data series to get max data - QTest::addColumn >("dataSeries"); - - // Max data - QTest::addColumn("max"); - - // Expected results - QTest::addColumn( - "expectedOK"); // if true, expects to have a result (i.e. the iterator != end iterator) - QTest::addColumn( - "expectedMax"); // Expected value when method doesn't return end iterator - - // ////////// // - // Test cases // - // ////////// // - - QTest::newRow("maxData1") << createScalarSeries({1., 2., 3., 4., 5.}, - {100., 200., 300., 400., 500.}) - << 6. << true << 5.; - QTest::newRow("maxData2") << createScalarSeries({1., 2., 3., 4., 5.}, - {100., 200., 300., 400., 500.}) - << 5. << true << 5.; - QTest::newRow("maxData3") << createScalarSeries({1., 2., 3., 4., 5.}, - {100., 200., 300., 400., 500.}) - << 4.9 << true << 4.; - QTest::newRow("maxData4") << createScalarSeries({1., 2., 3., 4., 5.}, - {100., 200., 300., 400., 500.}) - << 1.1 << true << 1.; - QTest::newRow("maxData5") << createScalarSeries({1., 2., 3., 4., 5.}, - {100., 200., 300., 400., 500.}) - << 1. << true << 1.; - QTest::newRow("maxData6") << createScalarSeries({}, {}) << 1.1 << false - << std::numeric_limits::quiet_NaN(); -} - -void TestDataSeries::testMaxXAxisData() -{ - QFETCH(std::shared_ptr, dataSeries); - QFETCH(double, max); - - QFETCH(bool, expectedOK); - QFETCH(double, expectedMax); - - auto it = dataSeries->maxXAxisData(max); - - QCOMPARE(expectedOK, it != dataSeries->cend()); - - // If the method doesn't return a end iterator, checks with expected value - if (expectedOK) { - QCOMPARE(expectedMax, it->x()); - } -} - -void TestDataSeries::testXAxisRange_data() -{ - // ////////////// // - // Test structure // - // ////////////// // - - // Data series to get x-axis range - QTest::addColumn >("dataSeries"); - - // Min/max values - QTest::addColumn("min"); - QTest::addColumn("max"); - - // Expected values - QTest::addColumn("expectedXAxisData"); - QTest::addColumn("expectedValuesData"); - - // ////////// // - // Test cases // - // ////////// // - - QTest::newRow("xAxisRange") << createScalarSeries({1., 2., 3., 4., 5.}, - {100., 200., 300., 400., 500.}) - << -1. << 3.2 << DataContainer{1., 2., 3.} - << DataContainer{100., 200., 300.}; - QTest::newRow("xAxisRange1 (min/max swap)") - << createScalarSeries({1., 2., 3., 4., 5.}, {100., 200., 300., 400., 500.}) << 3.2 << -1. - << DataContainer{1., 2., 3.} << DataContainer{100., 200., 300.}; - QTest::newRow("xAxisRange2") << createScalarSeries({1., 2., 3., 4., 5.}, - {100., 200., 300., 400., 500.}) - << 1. << 4. << DataContainer{1., 2., 3., 4.} - << DataContainer{100., 200., 300., 400.}; - QTest::newRow("xAxisRange3") << createScalarSeries({1., 2., 3., 4., 5.}, - {100., 200., 300., 400., 500.}) - << 1. << 3.9 << DataContainer{1., 2., 3.} - << DataContainer{100., 200., 300.}; - QTest::newRow("xAxisRange4") << createScalarSeries({1., 2., 3., 4., 5.}, - {100., 200., 300., 400., 500.}) - << 0. << 0.9 << DataContainer{} << DataContainer{}; - QTest::newRow("xAxisRange5") << createScalarSeries({1., 2., 3., 4., 5.}, - {100., 200., 300., 400., 500.}) - << 0. << 1. << DataContainer{1.} << DataContainer{100.}; - QTest::newRow("xAxisRange6") << createScalarSeries({1., 2., 3., 4., 5.}, - {100., 200., 300., 400., 500.}) - << 2.1 << 6. << DataContainer{3., 4., 5.} - << DataContainer{300., 400., 500.}; - QTest::newRow("xAxisRange7") << createScalarSeries({1., 2., 3., 4., 5.}, - {100., 200., 300., 400., 500.}) - << 6. << 9. << DataContainer{} << DataContainer{}; - QTest::newRow("xAxisRange8") << createScalarSeries({1., 2., 3., 4., 5.}, - {100., 200., 300., 400., 500.}) - << 5. << 9. << DataContainer{5.} << DataContainer{500.}; -} - -void TestDataSeries::testXAxisRange() -{ - QFETCH(std::shared_ptr, dataSeries); - QFETCH(double, min); - QFETCH(double, max); - - QFETCH(DataContainer, expectedXAxisData); - QFETCH(DataContainer, expectedValuesData); - - auto bounds = dataSeries->xAxisRange(min, max); - validateRange(bounds.first, bounds.second, expectedXAxisData, expectedValuesData); -} - -void TestDataSeries::testValuesBoundsScalar_data() -{ - testValuesBoundsStructure(); - - // ////////// // - // Test cases // - // ////////// // - auto nan = std::numeric_limits::quiet_NaN(); - - QTest::newRow("scalarBounds1") - << createScalarSeries({1., 2., 3., 4., 5.}, {100., 200., 300., 400., 500.}) << 0. << 6. - << true << 100. << 500.; - QTest::newRow("scalarBounds2") - << createScalarSeries({1., 2., 3., 4., 5.}, {100., 200., 300., 400., 500.}) << 2. << 4. - << true << 200. << 400.; - QTest::newRow("scalarBounds3") - << createScalarSeries({1., 2., 3., 4., 5.}, {100., 200., 300., 400., 500.}) << 0. << 0.5 - << false << nan << nan; - QTest::newRow("scalarBounds4") - << createScalarSeries({1., 2., 3., 4., 5.}, {100., 200., 300., 400., 500.}) << 5.1 << 6. - << false << nan << nan; - QTest::newRow("scalarBounds5") << createScalarSeries({1.}, {100.}) << 0. << 2. << true << 100. - << 100.; - QTest::newRow("scalarBounds6") << createScalarSeries({}, {}) << 0. << 2. << false << nan << nan; - - // Tests with NaN values: NaN values are not included in min/max search - QTest::newRow("scalarBounds7") - << createScalarSeries({1., 2., 3., 4., 5.}, {nan, 200., 300., 400., nan}) << 0. << 6. - << true << 200. << 400.; - QTest::newRow("scalarBounds8") - << createScalarSeries({1., 2., 3., 4., 5.}, {nan, nan, nan, nan, nan}) << 0. << 6. << true - << std::numeric_limits::quiet_NaN() << std::numeric_limits::quiet_NaN(); -} - -void TestDataSeries::testValuesBoundsScalar() -{ - testValuesBounds(); -} - -void TestDataSeries::testValuesBoundsVector_data() -{ - testValuesBoundsStructure(); - - // ////////// // - // Test cases // - // ////////// // - auto nan = std::numeric_limits::quiet_NaN(); - - QTest::newRow("vectorBounds1") - << createVectorSeries({1., 2., 3., 4., 5.}, {10., 15., 20., 13., 12.}, - {35., 24., 10., 9., 0.3}, {13., 14., 12., 9., 24.}) - << 0. << 6. << true << 0.3 << 35.; // min/max in same component - QTest::newRow("vectorBounds2") - << createVectorSeries({1., 2., 3., 4., 5.}, {2.3, 15., 20., 13., 12.}, - {35., 24., 10., 9., 4.}, {13., 14., 12., 9., 24.}) - << 0. << 6. << true << 2.3 << 35.; // min/max in same entry - QTest::newRow("vectorBounds3") - << createVectorSeries({1., 2., 3., 4., 5.}, {2.3, 15., 20., 13., 12.}, - {35., 24., 10., 9., 4.}, {13., 14., 12., 9., 24.}) - << 2. << 3. << true << 10. << 24.; - - // Tests with NaN values: NaN values are not included in min/max search - QTest::newRow("vectorBounds4") - << createVectorSeries({1., 2.}, {nan, nan}, {nan, nan}, {nan, nan}) << 0. << 6. << true - << nan << nan; -} - -void TestDataSeries::testValuesBoundsVector() -{ - testValuesBounds(); -} - -QTEST_MAIN(TestDataSeries) -#include "TestDataSeries.moc" diff --git a/core/tests/Data/TestScalarSeries.cpp b/core/tests/Data/TestScalarSeries.cpp new file mode 100644 index 0000000..75b1bb6 --- /dev/null +++ b/core/tests/Data/TestScalarSeries.cpp @@ -0,0 +1,426 @@ +#include "Data/ScalarSeries.h" + +#include "DataSeriesBuilders.h" +#include "DataSeriesUtils.h" + +#include +#include + +/** + * @brief The TestScalarSeries class defines unit tests on scalar series. + * + * Most of these unit tests use generic tests defined for DataSeries (@sa DataSeriesUtils) + */ +class TestScalarSeries : public QObject { + Q_OBJECT +private slots: + /// Tests construction of a scalar series + void testCtor_data(); + void testCtor(); + + /// Tests merge of two scalar series + void testMerge_data(); + void testMerge(); + + /// Tests merge of a vector series in a scalar series + void testMergeWithVector_data(); + void testMergeWithVector(); + + /// Tests get min x-axis data of a scalar series + void testMinXAxisData_data(); + void testMinXAxisData(); + + /// Tests get max x-axis data of a scalar series + void testMaxXAxisData_data(); + void testMaxXAxisData(); + + /// Tests purge of a scalar series + void testPurge_data(); + void testPurge(); + + /// Tests get x-axis range of a scalar series + void testXAxisRange_data(); + void testXAxisRange(); + + /// Tests get values bounds of a scalar series + void testValuesBounds_data(); + void testValuesBounds(); +}; + +void TestScalarSeries::testCtor_data() +{ + // x-axis data + QTest::addColumn("xAxisData"); + // values data + QTest::addColumn("valuesData"); + + // construction expected to be valid + QTest::addColumn("expectOK"); + // expected x-axis data (when construction is valid) + QTest::addColumn("expectedXAxisData"); + // expected values data (when construction is valid) + QTest::addColumn("expectedValuesData"); + + QTest::newRow("invalidData (different sizes of vectors)") + << DataContainer{1., 2., 3., 4., 5.} << DataContainer{100., 200., 300.} << false + << DataContainer{} << DataContainer{}; + + QTest::newRow("sortedData") << DataContainer{1., 2., 3., 4., 5.} + << DataContainer{100., 200., 300., 400., 500.} << true + << DataContainer{1., 2., 3., 4., 5.} + << DataContainer{100., 200., 300., 400., 500.}; + + QTest::newRow("unsortedData") << DataContainer{5., 4., 3., 2., 1.} + << DataContainer{100., 200., 300., 400., 500.} << true + << DataContainer{1., 2., 3., 4., 5.} + << DataContainer{500., 400., 300., 200., 100.}; + + QTest::newRow("unsortedData2") + << DataContainer{1., 4., 3., 5., 2.} << DataContainer{100., 200., 300., 400., 500.} << true + << DataContainer{1., 2., 3., 4., 5.} << DataContainer{100., 500., 300., 200., 400.}; +} + +void TestScalarSeries::testCtor() +{ + // Creates series + QFETCH(DataContainer, xAxisData); + QFETCH(DataContainer, valuesData); + QFETCH(bool, expectOK); + + if (expectOK) { + auto series = std::make_shared(std::move(xAxisData), std::move(valuesData), + Unit{}, Unit{}); + + // Validates results : we check that the data series is sorted on its x-axis data + QFETCH(DataContainer, expectedXAxisData); + QFETCH(DataContainer, expectedValuesData); + + validateRange(series->cbegin(), series->cend(), expectedXAxisData, expectedValuesData); + } + else { + QVERIFY_EXCEPTION_THROWN(std::make_shared( + std::move(xAxisData), std::move(valuesData), Unit{}, Unit{}), + std::invalid_argument); + } +} + +void TestScalarSeries::testMerge_data() +{ + testMerge_struct(); + + QTest::newRow("sortedMerge") << ScalarBuilder{} + .setX({1., 2., 3., 4., 5.}) + .setValues({100., 200., 300., 400., 500.}) + .build() + << ScalarBuilder{} + .setX({6., 7., 8., 9., 10.}) + .setValues({600., 700., 800., 900., 1000.}) + .build() + << DataContainer{1., 2., 3., 4., 5., 6., 7., 8., 9., 10.} + << DataContainer{100., 200., 300., 400., 500., + 600., 700., 800., 900., 1000.}; + + QTest::newRow("unsortedMerge") + << ScalarBuilder{} + .setX({6., 7., 8., 9., 10.}) + .setValues({600., 700., 800., 900., 1000.}) + .build() + << ScalarBuilder{} + .setX({1., 2., 3., 4., 5.}) + .setValues({100., 200., 300., 400., 500.}) + .build() + << DataContainer{1., 2., 3., 4., 5., 6., 7., 8., 9., 10.} + << DataContainer{100., 200., 300., 400., 500., 600., 700., 800., 900., 1000.}; + + QTest::newRow("unsortedMerge2 (merge not made because source is in the bounds of dest)") + << ScalarBuilder{} + .setX({1., 2., 8., 9., 10}) + .setValues({100., 200., 800., 900., 1000.}) + .build() + << ScalarBuilder{} + .setX({3., 4., 5., 6., 7.}) + .setValues({300., 400., 500., 600., 700.}) + .build() + << DataContainer{1., 2., 8., 9., 10.} << DataContainer{100., 200., 800., 900., 1000.}; + + QTest::newRow("unsortedMerge3") + << ScalarBuilder{} + .setX({3., 4., 5., 7., 8}) + .setValues({300., 400., 500., 700., 800.}) + .build() + << ScalarBuilder{} + .setX({1., 2., 3., 7., 10.}) + .setValues({100., 200., 333., 777., 1000.}) + .build() + << DataContainer{1., 2., 3., 4., 5., 7., 8., 10.} + << DataContainer{100., 200., 300., 400., 500., 700., 800., 1000.}; + + QTest::newRow("emptySource") << ScalarBuilder{} + .setX({3., 4., 5., 7., 8}) + .setValues({300., 400., 500., 700., 800.}) + .build() + << ScalarBuilder{}.setX({}).setValues({}).build() + << DataContainer{3., 4., 5., 7., 8.} + << DataContainer{300., 400., 500., 700., 800.}; +} + +void TestScalarSeries::testMerge() +{ + testMerge_t(); +} + +void TestScalarSeries::testMergeWithVector_data() +{ + testMergeDifferentTypes_struct(); + + QTest::newRow("mergeVectorInScalar") + << ScalarBuilder{} + .setX({1., 2., 3., 4., 5.}) + .setValues({100., 200., 300., 400., 500.}) + .build() + << VectorBuilder{} + .setX({6., 7., 8., 9., 10.}) + .setXValues({600., 700., 800., 900., 1000.}) + .setYValues({610., 710., 810., 910., 1010.}) + .setZValues({620., 720., 820., 920., 1020.}) + .build() + << DataContainer{1., 2., 3., 4., 5.} << DataContainer{100., 200., 300., 400., 500.}; +} + +void TestScalarSeries::testMergeWithVector() +{ + testMergeDifferentTypes_t(); +} + +void TestScalarSeries::testMinXAxisData_data() +{ + testMinXAxisData_struct(); + + QTest::newRow("minData1") << ScalarBuilder{} + .setX({1., 2., 3., 4., 5.}) + .setValues({100., 200., 300., 400., 500.}) + .build() + << 0. << true << 1.; + QTest::newRow("minData2") << ScalarBuilder{} + .setX({1., 2., 3., 4., 5.}) + .setValues({100., 200., 300., 400., 500.}) + .build() + << 1. << true << 1.; + QTest::newRow("minData3") << ScalarBuilder{} + .setX({1., 2., 3., 4., 5.}) + .setValues({100., 200., 300., 400., 500.}) + .build() + << 1.1 << true << 2.; + QTest::newRow("minData4") << ScalarBuilder{} + .setX({1., 2., 3., 4., 5.}) + .setValues({100., 200., 300., 400., 500.}) + .build() + << 5. << true << 5.; + QTest::newRow("minData5") << ScalarBuilder{} + .setX({1., 2., 3., 4., 5.}) + .setValues({100., 200., 300., 400., 500.}) + .build() + << 5.1 << false << std::numeric_limits::quiet_NaN(); + QTest::newRow("minData6") << ScalarBuilder{}.setX({}).setValues({}).build() << 1.1 << false + << std::numeric_limits::quiet_NaN(); +} + +void TestScalarSeries::testMinXAxisData() +{ + testMinXAxisData_t(); +} + +void TestScalarSeries::testMaxXAxisData_data() +{ + testMaxXAxisData_struct(); + + QTest::newRow("maxData1") << ScalarBuilder{} + .setX({1., 2., 3., 4., 5.}) + .setValues({100., 200., 300., 400., 500.}) + .build() + << 6. << true << 5.; + QTest::newRow("maxData2") << ScalarBuilder{} + .setX({1., 2., 3., 4., 5.}) + .setValues({100., 200., 300., 400., 500.}) + .build() + << 5. << true << 5.; + QTest::newRow("maxData3") << ScalarBuilder{} + .setX({1., 2., 3., 4., 5.}) + .setValues({100., 200., 300., 400., 500.}) + .build() + << 4.9 << true << 4.; + QTest::newRow("maxData4") << ScalarBuilder{} + .setX({1., 2., 3., 4., 5.}) + .setValues({100., 200., 300., 400., 500.}) + .build() + << 1.1 << true << 1.; + QTest::newRow("maxData5") << ScalarBuilder{} + .setX({1., 2., 3., 4., 5.}) + .setValues({100., 200., 300., 400., 500.}) + .build() + << 1. << true << 1.; + QTest::newRow("maxData6") << ScalarBuilder{}.setX({}).setValues({}).build() << 1.1 << false + << std::numeric_limits::quiet_NaN(); +} + +void TestScalarSeries::testMaxXAxisData() +{ + testMaxXAxisData_t(); +} + +void TestScalarSeries::testPurge_data() +{ + testPurge_struct(); + + QTest::newRow("purgeScalar") << ScalarBuilder{} + .setX({1., 2., 3., 4., 5.}) + .setValues({100., 200., 300., 400., 500.}) + .build() + << 2. << 4. << DataContainer{2., 3., 4.} + << std::vector{{200., 300., 400.}}; + QTest::newRow("purgeScalar1 (min/max swap)") + << ScalarBuilder{} + .setX({1., 2., 3., 4., 5.}) + .setValues({100., 200., 300., 400., 500.}) + .build() + << 4. << 2. << DataContainer{2., 3., 4.} << std::vector{{200., 300., 400.}}; + QTest::newRow("purgeScalar2") << ScalarBuilder{} + .setX({1., 2., 3., 4., 5.}) + .setValues({100., 200., 300., 400., 500.}) + .build() + << 0. << 2.5 << DataContainer{1., 2.} + << std::vector{{100., 200.}}; + QTest::newRow("purgeScalar3") << ScalarBuilder{} + .setX({1., 2., 3., 4., 5.}) + .setValues({100., 200., 300., 400., 500.}) + .build() + << 3.5 << 7. << DataContainer{4., 5.} + << std::vector{{400., 500.}}; + QTest::newRow("purgeScalar4") << ScalarBuilder{} + .setX({1., 2., 3., 4., 5.}) + .setValues({100., 200., 300., 400., 500.}) + .build() + << 0. << 7. << DataContainer{1., 2., 3., 4., 5.} + << std::vector{{100., 200., 300., 400., 500.}}; + QTest::newRow("purgeScalar5") << ScalarBuilder{} + .setX({1., 2., 3., 4., 5.}) + .setValues({100., 200., 300., 400., 500.}) + .build() + << 5.5 << 7. << DataContainer{} << std::vector{{}}; +} + +void TestScalarSeries::testPurge() +{ + testPurge_t(); +} + +void TestScalarSeries::testXAxisRange_data() +{ + testXAxisRange_struct(); + + QTest::newRow("xAxisRange") << ScalarBuilder{} + .setX({1., 2., 3., 4., 5.}) + .setValues({100., 200., 300., 400., 500.}) + .build() + << -1. << 3.2 << DataContainer{1., 2., 3.} + << DataContainer{100., 200., 300.}; + QTest::newRow("xAxisRange1 (min/max swap)") + << ScalarBuilder{} + .setX({1., 2., 3., 4., 5.}) + .setValues({100., 200., 300., 400., 500.}) + .build() + << 3.2 << -1. << DataContainer{1., 2., 3.} << DataContainer{100., 200., 300.}; + QTest::newRow("xAxisRange2") << ScalarBuilder{} + .setX({1., 2., 3., 4., 5.}) + .setValues({100., 200., 300., 400., 500.}) + .build() + << 1. << 4. << DataContainer{1., 2., 3., 4.} + << DataContainer{100., 200., 300., 400.}; + QTest::newRow("xAxisRange3") << ScalarBuilder{} + .setX({1., 2., 3., 4., 5.}) + .setValues({100., 200., 300., 400., 500.}) + .build() + << 1. << 3.9 << DataContainer{1., 2., 3.} + << DataContainer{100., 200., 300.}; + QTest::newRow("xAxisRange4") << ScalarBuilder{} + .setX({1., 2., 3., 4., 5.}) + .setValues({100., 200., 300., 400., 500.}) + .build() + << 0. << 0.9 << DataContainer{} << DataContainer{}; + QTest::newRow("xAxisRange5") << ScalarBuilder{} + .setX({1., 2., 3., 4., 5.}) + .setValues({100., 200., 300., 400., 500.}) + .build() + << 0. << 1. << DataContainer{1.} << DataContainer{100.}; + QTest::newRow("xAxisRange6") << ScalarBuilder{} + .setX({1., 2., 3., 4., 5.}) + .setValues({100., 200., 300., 400., 500.}) + .build() + << 2.1 << 6. << DataContainer{3., 4., 5.} + << DataContainer{300., 400., 500.}; + QTest::newRow("xAxisRange7") << ScalarBuilder{} + .setX({1., 2., 3., 4., 5.}) + .setValues({100., 200., 300., 400., 500.}) + .build() + << 6. << 9. << DataContainer{} << DataContainer{}; + QTest::newRow("xAxisRange8") << ScalarBuilder{} + .setX({1., 2., 3., 4., 5.}) + .setValues({100., 200., 300., 400., 500.}) + .build() + << 5. << 9. << DataContainer{5.} << DataContainer{500.}; +} + +void TestScalarSeries::testXAxisRange() +{ + testXAxisRange_t(); +} + +void TestScalarSeries::testValuesBounds_data() +{ + testValuesBounds_struct(); + + auto nan = std::numeric_limits::quiet_NaN(); + + QTest::newRow("scalarBounds1") << ScalarBuilder{} + .setX({1., 2., 3., 4., 5.}) + .setValues({100., 200., 300., 400., 500.}) + .build() + << 0. << 6. << true << 100. << 500.; + QTest::newRow("scalarBounds2") << ScalarBuilder{} + .setX({1., 2., 3., 4., 5.}) + .setValues({100., 200., 300., 400., 500.}) + .build() + << 2. << 4. << true << 200. << 400.; + QTest::newRow("scalarBounds3") << ScalarBuilder{} + .setX({1., 2., 3., 4., 5.}) + .setValues({100., 200., 300., 400., 500.}) + .build() + << 0. << 0.5 << false << nan << nan; + QTest::newRow("scalarBounds4") << ScalarBuilder{} + .setX({1., 2., 3., 4., 5.}) + .setValues({100., 200., 300., 400., 500.}) + .build() + << 5.1 << 6. << false << nan << nan; + QTest::newRow("scalarBounds5") + << ScalarBuilder{}.setX({1.}).setValues({100.}).build() << 0. << 2. << true << 100. << 100.; + QTest::newRow("scalarBounds6") + << ScalarBuilder{}.setX({}).setValues({}).build() << 0. << 2. << false << nan << nan; + + // Tests with NaN values: NaN values are not included in min/max search + QTest::newRow("scalarBounds7") << ScalarBuilder{} + .setX({1., 2., 3., 4., 5.}) + .setValues({nan, 200., 300., 400., nan}) + .build() + << 0. << 6. << true << 200. << 400.; + QTest::newRow("scalarBounds8") + << ScalarBuilder{}.setX({1., 2., 3., 4., 5.}).setValues({nan, nan, nan, nan, nan}).build() + << 0. << 6. << true << nan << nan; +} + +void TestScalarSeries::testValuesBounds() +{ + testValuesBounds_t(); +} + +QTEST_MAIN(TestScalarSeries) +#include "TestScalarSeries.moc" diff --git a/core/tests/Data/TestVectorSeries.cpp b/core/tests/Data/TestVectorSeries.cpp new file mode 100644 index 0000000..3542fd9 --- /dev/null +++ b/core/tests/Data/TestVectorSeries.cpp @@ -0,0 +1,90 @@ +#include "Data/VectorSeries.h" + +#include "DataSeriesBuilders.h" +#include "DataSeriesUtils.h" + +#include +#include + +/** + * @brief The TestVectorSeries class defines unit tests on vector series. + * + * Most of these unit tests use generic tests defined for DataSeries (@sa DataSeriesUtils) + */ +class TestVectorSeries : public QObject { + Q_OBJECT +private slots: + /// Tests purge of a vector series + void testPurge_data(); + void testPurge(); + + /// Tests get values bounds of a vector series + void testValuesBounds_data(); + void testValuesBounds(); +}; + +void TestVectorSeries::testPurge_data() +{ + testPurge_struct(); + + QTest::newRow("purgeVector") << VectorBuilder{} + .setX({1., 2., 3., 4., 5.}) + .setXValues({6., 7., 8., 9., 10.}) + .setYValues({11., 12., 13., 14., 15.}) + .setZValues({16., 17., 18., 19., 20.}) + .build() + << 2. << 4. << DataContainer{2., 3., 4.} + << std::vector{ + {7., 8., 9.}, {12., 13., 14.}, {17., 18., 19.}}; +} + +void TestVectorSeries::testPurge() +{ + testPurge_t(); +} + +void TestVectorSeries::testValuesBounds_data() +{ + testValuesBounds_struct(); + + auto nan = std::numeric_limits::quiet_NaN(); + + QTest::newRow("vectorBounds1") << VectorBuilder{} + .setX({1., 2., 3., 4., 5.}) + .setXValues({10., 15., 20., 13., 12.}) + .setYValues({35., 24., 10., 9., 0.3}) + .setZValues({13., 14., 12., 9., 24.}) + .build() + << 0. << 6. << true << 0.3 << 35.; // min/max in same component + QTest::newRow("vectorBounds2") << VectorBuilder{} + .setX({1., 2., 3., 4., 5.}) + .setXValues({2.3, 15., 20., 13., 12.}) + .setYValues({35., 24., 10., 9., 4.}) + .setZValues({13., 14., 12., 9., 24.}) + .build() + << 0. << 6. << true << 2.3 << 35.; // min/max in same entry + QTest::newRow("vectorBounds3") << VectorBuilder{} + .setX({1., 2., 3., 4., 5.}) + .setXValues({2.3, 15., 20., 13., 12.}) + .setYValues({35., 24., 10., 9., 4.}) + .setZValues({13., 14., 12., 9., 24.}) + .build() + << 2. << 3. << true << 10. << 24.; + + // Tests with NaN values: NaN values are not included in min/max search + QTest::newRow("vectorBounds4") << VectorBuilder{} + .setX({1., 2.}) + .setXValues({nan, nan}) + .setYValues({nan, nan}) + .setZValues({nan, nan}) + .build() + << 0. << 6. << true << nan << nan; +} + +void TestVectorSeries::testValuesBounds() +{ + testValuesBounds_t(); +} + +QTEST_MAIN(TestVectorSeries) +#include "TestVectorSeries.moc" diff --git a/core/tests/meson.build b/core/tests/meson.build index 136abe7..015b1b7 100644 --- a/core/tests/meson.build +++ b/core/tests/meson.build @@ -2,7 +2,8 @@ tests = [ [['Common/TestStringUtils.cpp'],'test_string_utils','StringUtils test'], - [['Data/TestDataSeries.cpp'],'test_data','DataSeries test'], + [['Data/TestScalarSeries.cpp'],'test_scalar','ScalarSeries test'], + [['Data/TestVectorSeries.cpp'],'test_vector','VectorSeries test'], [['Data/TestOneDimArrayData.cpp'],'test_1d','One Dim Array test'], [['Data/TestOptionalAxis.cpp'],'test_optional_axis','OptionalAxis test'], [['Data/TestTwoDimArrayData.cpp'],'test_2d','Two Dim Array test'],