##// END OF EJS Templates
Implements unit test (3)...
Alexandre Leroux -
r689:e4699d579435
parent child
Show More
@@ -1,109 +1,110
1 #include "CosinusProvider.h"
1 #include "CosinusProvider.h"
2
2
3 #include <Data/DataProviderParameters.h>
3 #include <Data/DataProviderParameters.h>
4 #include <Data/ScalarSeries.h>
4 #include <Data/ScalarSeries.h>
5
5
6 #include <cmath>
6 #include <cmath>
7
7
8 #include <QFuture>
8 #include <QFuture>
9 #include <QThread>
9 #include <QThread>
10 #include <QtConcurrent/QtConcurrent>
10 #include <QtConcurrent/QtConcurrent>
11
11
12 Q_LOGGING_CATEGORY(LOG_CosinusProvider, "CosinusProvider")
12 Q_LOGGING_CATEGORY(LOG_CosinusProvider, "CosinusProvider")
13
13
14 std::shared_ptr<IDataProvider> CosinusProvider::clone() const
14 std::shared_ptr<IDataProvider> CosinusProvider::clone() const
15 {
15 {
16 // No copy is made in clone
16 // No copy is made in clone
17 return std::make_shared<CosinusProvider>();
17 return std::make_shared<CosinusProvider>();
18 }
18 }
19
19
20 std::shared_ptr<IDataSeries> CosinusProvider::retrieveData(QUuid acqIdentifier,
20 std::shared_ptr<IDataSeries> CosinusProvider::retrieveData(QUuid acqIdentifier,
21 const SqpRange &dataRangeRequested)
21 const SqpRange &dataRangeRequested)
22 {
22 {
23 // TODO: Add Mutex
23 // TODO: Add Mutex
24 auto dataIndex = 0;
24 auto dataIndex = 0;
25
25
26 // Gets the timerange from the parameters
26 // Gets the timerange from the parameters
27 double freq = 100.0;
27 double freq = 100.0;
28 double start = std::ceil(dataRangeRequested.m_TStart * freq); // 100 htz
28 double start = std::ceil(dataRangeRequested.m_TStart * freq); // 100 htz
29 double end = std::floor(dataRangeRequested.m_TEnd * freq); // 100 htz
29 double end = std::floor(dataRangeRequested.m_TEnd * freq); // 100 htz
30
30
31 // We assure that timerange is valid
31 // We assure that timerange is valid
32 if (end < start) {
32 if (end < start) {
33 std::swap(start, end);
33 std::swap(start, end);
34 }
34 }
35
35
36 // Generates scalar series containing cosinus values (one value per second)
36 // Generates scalar series containing cosinus values (one value per second, end value is
37 auto dataCount = end - start;
37 // included)
38 auto dataCount = end - start + 1;
38
39
39 auto xAxisData = std::vector<double>{};
40 auto xAxisData = std::vector<double>{};
40 xAxisData.resize(dataCount);
41 xAxisData.resize(dataCount);
41
42
42 auto valuesData = std::vector<double>{};
43 auto valuesData = std::vector<double>{};
43 valuesData.resize(dataCount);
44 valuesData.resize(dataCount);
44
45
45 int progress = 0;
46 int progress = 0;
46 auto progressEnd = dataCount;
47 auto progressEnd = dataCount;
47 for (auto time = start; time < end; ++time, ++dataIndex) {
48 for (auto time = start; time <= end; ++time, ++dataIndex) {
48 auto it = m_VariableToEnableProvider.find(acqIdentifier);
49 auto it = m_VariableToEnableProvider.find(acqIdentifier);
49 if (it != m_VariableToEnableProvider.end() && it.value()) {
50 if (it != m_VariableToEnableProvider.end() && it.value()) {
50 const auto timeOnFreq = time / freq;
51 const auto timeOnFreq = time / freq;
51
52
52 xAxisData[dataIndex] = timeOnFreq;
53 xAxisData[dataIndex] = timeOnFreq;
53 valuesData[dataIndex] = std::cos(timeOnFreq);
54 valuesData[dataIndex] = std::cos(timeOnFreq);
54
55
55 // progression
56 // progression
56 int currentProgress = (time - start) * 100.0 / progressEnd;
57 int currentProgress = (time - start) * 100.0 / progressEnd;
57 if (currentProgress != progress) {
58 if (currentProgress != progress) {
58 progress = currentProgress;
59 progress = currentProgress;
59
60
60 emit dataProvidedProgress(acqIdentifier, progress);
61 emit dataProvidedProgress(acqIdentifier, progress);
61 }
62 }
62 }
63 }
63 else {
64 else {
64 if (!it.value()) {
65 if (!it.value()) {
65 qCDebug(LOG_CosinusProvider())
66 qCDebug(LOG_CosinusProvider())
66 << "CosinusProvider::retrieveData: ARRET De l'acquisition detectΓ©"
67 << "CosinusProvider::retrieveData: ARRET De l'acquisition detectΓ©"
67 << end - time;
68 << end - time;
68 }
69 }
69 }
70 }
70 }
71 }
71 emit dataProvidedProgress(acqIdentifier, 0.0);
72 emit dataProvidedProgress(acqIdentifier, 0.0);
72
73
73 return std::make_shared<ScalarSeries>(std::move(xAxisData), std::move(valuesData),
74 return std::make_shared<ScalarSeries>(std::move(xAxisData), std::move(valuesData),
74 Unit{QStringLiteral("t"), true}, Unit{});
75 Unit{QStringLiteral("t"), true}, Unit{});
75 }
76 }
76
77
77 void CosinusProvider::requestDataLoading(QUuid acqIdentifier,
78 void CosinusProvider::requestDataLoading(QUuid acqIdentifier,
78 const DataProviderParameters &parameters)
79 const DataProviderParameters &parameters)
79 {
80 {
80 // TODO: Add Mutex
81 // TODO: Add Mutex
81 m_VariableToEnableProvider[acqIdentifier] = true;
82 m_VariableToEnableProvider[acqIdentifier] = true;
82 qCDebug(LOG_CosinusProvider()) << "TORM: CosinusProvider::requestDataLoading"
83 qCDebug(LOG_CosinusProvider()) << "TORM: CosinusProvider::requestDataLoading"
83 << QThread::currentThread()->objectName();
84 << QThread::currentThread()->objectName();
84 // NOTE: Try to use multithread if possible
85 // NOTE: Try to use multithread if possible
85 const auto times = parameters.m_Times;
86 const auto times = parameters.m_Times;
86
87
87 for (const auto &dateTime : qAsConst(times)) {
88 for (const auto &dateTime : qAsConst(times)) {
88 if (m_VariableToEnableProvider[acqIdentifier]) {
89 if (m_VariableToEnableProvider[acqIdentifier]) {
89 auto scalarSeries = this->retrieveData(acqIdentifier, dateTime);
90 auto scalarSeries = this->retrieveData(acqIdentifier, dateTime);
90 qCDebug(LOG_CosinusProvider()) << "TORM: CosinusProvider::dataProvided";
91 qCDebug(LOG_CosinusProvider()) << "TORM: CosinusProvider::dataProvided";
91 emit dataProvided(acqIdentifier, scalarSeries, dateTime);
92 emit dataProvided(acqIdentifier, scalarSeries, dateTime);
92 }
93 }
93 }
94 }
94 }
95 }
95
96
96 void CosinusProvider::requestDataAborting(QUuid acqIdentifier)
97 void CosinusProvider::requestDataAborting(QUuid acqIdentifier)
97 {
98 {
98 // TODO: Add Mutex
99 // TODO: Add Mutex
99 qCDebug(LOG_CosinusProvider()) << "CosinusProvider::requestDataAborting" << acqIdentifier
100 qCDebug(LOG_CosinusProvider()) << "CosinusProvider::requestDataAborting" << acqIdentifier
100 << QThread::currentThread()->objectName();
101 << QThread::currentThread()->objectName();
101 auto it = m_VariableToEnableProvider.find(acqIdentifier);
102 auto it = m_VariableToEnableProvider.find(acqIdentifier);
102 if (it != m_VariableToEnableProvider.end()) {
103 if (it != m_VariableToEnableProvider.end()) {
103 it.value() = false;
104 it.value() = false;
104 }
105 }
105 else {
106 else {
106 qCWarning(LOG_CosinusProvider())
107 qCWarning(LOG_CosinusProvider())
107 << tr("Aborting progression of inexistant identifier detected !!!");
108 << tr("Aborting progression of inexistant identifier detected !!!");
108 }
109 }
109 }
110 }
@@ -1,123 +1,163
1 #include "CosinusProvider.h"
1 #include "CosinusProvider.h"
2
2
3 #include <Data/DataProviderParameters.h>
3 #include <Data/DataProviderParameters.h>
4 #include <Data/ScalarSeries.h>
4 #include <Data/ScalarSeries.h>
5 #include <SqpApplication.h>
5 #include <SqpApplication.h>
6 #include <Time/TimeController.h>
6 #include <Time/TimeController.h>
7 #include <Variable/Variable.h>
7 #include <Variable/Variable.h>
8 #include <Variable/VariableController.h>
8 #include <Variable/VariableController.h>
9
9
10 #include <QObject>
10 #include <QObject>
11 #include <QtTest>
11 #include <QtTest>
12
12
13 #include <cmath>
13 #include <cmath>
14 #include <memory>
14 #include <memory>
15
15
16 namespace {
16 namespace {
17
17
18 /// Path for the tests
18 /// Path for the tests
19 const auto TESTS_RESOURCES_PATH = QFileInfo{
19 const auto TESTS_RESOURCES_PATH = QFileInfo{
20 QString{MOCKPLUGIN_TESTS_RESOURCES_DIR},
20 QString{MOCKPLUGIN_TESTS_RESOURCES_DIR},
21 "TestCosinusAcquisition"}.absoluteFilePath();
21 "TestCosinusAcquisition"}.absoluteFilePath();
22
22
23 /// Format of dates in data files
23 /// Format of dates in data files
24 const auto DATETIME_FORMAT = QStringLiteral("yyyy/MM/dd hh:mm:ss:zzz");
24 const auto DATETIME_FORMAT = QStringLiteral("yyyy/MM/dd hh:mm:ss:zzz");
25
25
26 /// Delay after each operation on the variable before validating it (in ms)
26 /// Delay after each operation on the variable before validating it (in ms)
27 const auto OPERATION_DELAY = 250;
27 const auto OPERATION_DELAY = 250;
28
28
29 /**
30 * Verifies that the data in the candidate series are identical to the data in the reference series
31 * in a specific range
32 * @param candidate the candidate data series
33 * @param range the range to check
34 * @param reference the reference data series
35 * @return true if the data of the candidate series and the reference series are identical in the
36 * range, false otherwise
37 */
38 bool checkDataSeries(std::shared_ptr<IDataSeries> candidate, const SqpRange &range,
39 std::shared_ptr<IDataSeries> reference)
40 {
41 if (candidate == nullptr || reference == nullptr) {
42 return candidate == reference;
43 }
44
45 auto referenceIt = reference->xAxisRange(range.m_TStart, range.m_TEnd);
46
47 return std::equal(candidate->cbegin(), candidate->cend(), referenceIt.first, referenceIt.second,
48 [](const auto &it1, const auto &it2) {
49 // - milliseconds precision for time
50 // - 1e-6 precision for value
51 return std::abs(it1.x() - it2.x()) < 1e-3
52 && std::abs(it1.value() - it2.value()) < 1e-6;
53 });
54 }
55
29 /// Generates the data series from the reading of a data stream
56 /// Generates the data series from the reading of a data stream
30 std::shared_ptr<IDataSeries> readDataStream(QTextStream &stream)
57 std::shared_ptr<IDataSeries> readDataStream(QTextStream &stream)
31 {
58 {
32 std::vector<double> xAxisData, valuesData;
59 std::vector<double> xAxisData, valuesData;
33
60
34 QString line{};
61 QString line{};
35 while (stream.readLineInto(&line)) {
62 while (stream.readLineInto(&line)) {
36 // Separates date (x-axis data) to value data
63 // Separates date (x-axis data) to value data
37 auto splitLine = line.split('\t');
64 auto splitLine = line.split('\t');
38 if (splitLine.size() == 2) {
65 if (splitLine.size() == 2) {
39 // Converts datetime to double
66 // Converts datetime to double
40 auto dateTime = QDateTime::fromString(splitLine[0], DATETIME_FORMAT);
67 auto dateTime = QDateTime::fromString(splitLine[0], DATETIME_FORMAT);
41 dateTime.setTimeSpec(Qt::UTC);
68 dateTime.setTimeSpec(Qt::UTC);
42 xAxisData.push_back(DateUtils::secondsSinceEpoch(dateTime));
69 xAxisData.push_back(DateUtils::secondsSinceEpoch(dateTime));
43
70
44 valuesData.push_back(splitLine[1].toDouble());
71 valuesData.push_back(splitLine[1].toDouble());
45 }
72 }
46 }
73 }
47
74
48 return std::make_shared<ScalarSeries>(std::move(xAxisData), std::move(valuesData),
75 return std::make_shared<ScalarSeries>(std::move(xAxisData), std::move(valuesData),
49 Unit{{}, true}, Unit{});
76 Unit{{}, true}, Unit{});
50 }
77 }
51
78
52 } // namespace
79 } // namespace
53
80
54 /**
81 /**
55 * @brief The TestCosinusAcquisition class tests acquisition in SciQlop (operations like zooms in,
82 * @brief The TestCosinusAcquisition class tests acquisition in SciQlop (operations like zooms in,
56 * zooms out, pans) of data from CosinusProvider
83 * zooms out, pans) of data from CosinusProvider
57 * @sa CosinusProvider
84 * @sa CosinusProvider
58 */
85 */
59 class TestCosinusAcquisition : public QObject {
86 class TestCosinusAcquisition : public QObject {
60 Q_OBJECT
87 Q_OBJECT
61
88
62 private slots:
89 private slots:
63 /// Input data for @sa testAcquisition()
90 /// Input data for @sa testAcquisition()
64 void testAcquisition_data();
91 void testAcquisition_data();
65 void testAcquisition();
92 void testAcquisition();
66 };
93 };
67
94
68 void TestCosinusAcquisition::testAcquisition_data()
95 void TestCosinusAcquisition::testAcquisition_data()
69 {
96 {
70 // ////////////// //
97 // ////////////// //
71 // Test structure //
98 // Test structure //
72 // ////////////// //
99 // ////////////// //
73
100
74 QTest::addColumn<QString>("dataFilename"); // File containing expected data of acquisitions
101 QTest::addColumn<QString>("dataFilename"); // File containing expected data of acquisitions
75 QTest::addColumn<SqpRange>("initialRange"); // First acquisition
102 QTest::addColumn<SqpRange>("initialRange"); // First acquisition
76 QTest::addColumn<std::vector<SqpRange> >("operations"); // Acquisitions to make
103 QTest::addColumn<std::vector<SqpRange> >("operations"); // Acquisitions to make
77 }
104 }
78
105
79 void TestCosinusAcquisition::testAcquisition()
106 void TestCosinusAcquisition::testAcquisition()
80 {
107 {
81 // Retrieves data file
108 // Retrieves data file
82 QFETCH(QString, dataFilename);
109 QFETCH(QString, dataFilename);
83
110
84 auto dataFilePath = QFileInfo{TESTS_RESOURCES_PATH, dataFilename}.absoluteFilePath();
111 auto dataFilePath = QFileInfo{TESTS_RESOURCES_PATH, dataFilename}.absoluteFilePath();
85 QFile dataFile{dataFilePath};
112 QFile dataFile{dataFilePath};
86
113
87 if (dataFile.open(QFile::ReadOnly)) {
114 if (dataFile.open(QFile::ReadOnly)) {
88 // Generates data series to compare with
115 // Generates data series to compare with
89 QTextStream dataStream{&dataFile};
116 QTextStream dataStream{&dataFile};
90 auto dataSeries = readDataStream(dataStream);
117 auto dataSeries = readDataStream(dataStream);
91
118
119 /// Lambda used to validate a variable at each step
120 auto validateVariable = [dataSeries](std::shared_ptr<Variable> variable,
121 const SqpRange &range) {
122 // Checks that the variable's range has changed
123 QCOMPARE(variable->range(), range);
124
125 // Checks the variable's data series
126 QVERIFY(checkDataSeries(variable->dataSeries(), variable->cacheRange(), dataSeries));
127 };
128
92 // Creates variable
129 // Creates variable
93 QFETCH(SqpRange, initialRange);
130 QFETCH(SqpRange, initialRange);
94 sqpApp->timeController().onTimeToUpdate(initialRange);
131 sqpApp->timeController().onTimeToUpdate(initialRange);
95 auto provider = std::make_shared<CosinusProvider>();
132 auto provider = std::make_shared<CosinusProvider>();
96 auto variable = sqpApp->variableController().createVariable("MMS", {}, provider);
133 auto variable = sqpApp->variableController().createVariable("MMS", {}, provider);
97
134
98 QTest::qWait(OPERATION_DELAY);
135 QTest::qWait(OPERATION_DELAY);
136 validateVariable(variable, initialRange);
137
99 // Makes operations on the variable
138 // Makes operations on the variable
100 QFETCH(std::vector<SqpRange>, operations);
139 QFETCH(std::vector<SqpRange>, operations);
101 for (const auto &operation : operations) {
140 for (const auto &operation : operations) {
102 // Asks request on the variable and waits during its execution
141 // Asks request on the variable and waits during its execution
103 sqpApp->variableController().onRequestDataLoading({variable}, operation,
142 sqpApp->variableController().onRequestDataLoading({variable}, operation,
104 variable->range(), true);
143 variable->range(), true);
105
144
106 QTest::qWait(OPERATION_DELAY);
145 QTest::qWait(OPERATION_DELAY);
146 validateVariable(variable, operation);
107 }
147 }
108 }
148 }
109 else {
149 else {
110 QFAIL("Can't read input data file");
150 QFAIL("Can't read input data file");
111 }
151 }
112 }
152 }
113
153
114 int main(int argc, char *argv[])
154 int main(int argc, char *argv[])
115 {
155 {
116 SqpApplication app{argc, argv};
156 SqpApplication app{argc, argv};
117 app.setAttribute(Qt::AA_Use96Dpi, true);
157 app.setAttribute(Qt::AA_Use96Dpi, true);
118 TestCosinusAcquisition testObject{};
158 TestCosinusAcquisition testObject{};
119 QTEST_SET_MAIN_SOURCE_PATH
159 QTEST_SET_MAIN_SOURCE_PATH
120 return QTest::qExec(&testObject, argc, argv);
160 return QTest::qExec(&testObject, argc, argv);
121 }
161 }
122
162
123 #include "TestCosinusAcquisition.moc"
163 #include "TestCosinusAcquisition.moc"
General Comments 0
You need to be logged in to leave comments. Login now