##// END OF EJS Templates
Merge branch 'feature/CosinusProvider2' into develop
Alexandre Leroux -
r789:2e59750a3b2a merge
parent child
Show More
@@ -0,0 +1,23
1 #ifndef SCIQLOP_MOCKDEFS_H
2 #define SCIQLOP_MOCKDEFS_H
3
4 #include "MockPluginGlobal.h"
5
6 #include <QString>
7 #include <QVariant>
8
9 // ////////////// //
10 // Mock constants //
11 // ////////////// //
12
13 // Metadata for cosinus provider //
14
15 /// Cosinus frequency (Hz)
16 extern SCIQLOP_MOCKPLUGIN_EXPORT const QString COSINUS_FREQUENCY_KEY;
17 extern SCIQLOP_MOCKPLUGIN_EXPORT const QVariant COSINUS_FREQUENCY_DEFAULT_VALUE;
18
19 /// Cosinus type ("scalar" or "vector")
20 extern SCIQLOP_MOCKPLUGIN_EXPORT const QString COSINUS_TYPE_KEY;
21 extern SCIQLOP_MOCKPLUGIN_EXPORT const QVariant COSINUS_TYPE_DEFAULT_VALUE;
22
23 #endif // SCIQLOP_MOCKDEFS_H
@@ -0,0 +1,7
1 #include "MockDefs.h"
2
3 const QString COSINUS_FREQUENCY_KEY = QStringLiteral("cosinusFrequency");
4 const QVariant COSINUS_FREQUENCY_DEFAULT_VALUE = 60.;
5
6 const QString COSINUS_TYPE_KEY = QStringLiteral("cosinusType");
7 const QVariant COSINUS_TYPE_DEFAULT_VALUE = QStringLiteral("scalar");
@@ -1,36 +1,36
1 #ifndef SCIQLOP_COSINUSPROVIDER_H
1 #ifndef SCIQLOP_COSINUSPROVIDER_H
2 #define SCIQLOP_COSINUSPROVIDER_H
2 #define SCIQLOP_COSINUSPROVIDER_H
3
3
4 #include "MockPluginGlobal.h"
4 #include "MockPluginGlobal.h"
5
5
6 #include <Data/IDataProvider.h>
6 #include <Data/IDataProvider.h>
7
7
8 #include <QLoggingCategory>
8 #include <QLoggingCategory>
9 #include <QUuid>
9 #include <QUuid>
10
10
11 #include <QHash>
11 #include <QHash>
12 Q_DECLARE_LOGGING_CATEGORY(LOG_CosinusProvider)
12 Q_DECLARE_LOGGING_CATEGORY(LOG_CosinusProvider)
13
13
14 /**
14 /**
15 * @brief The CosinusProvider class is an example of how a data provider can generate data
15 * @brief The CosinusProvider class is an example of how a data provider can generate data
16 */
16 */
17 class SCIQLOP_MOCKPLUGIN_EXPORT CosinusProvider : public IDataProvider {
17 class SCIQLOP_MOCKPLUGIN_EXPORT CosinusProvider : public IDataProvider {
18 public:
18 public:
19 std::shared_ptr<IDataProvider> clone() const override;
19 std::shared_ptr<IDataProvider> clone() const override;
20
20
21 /// @sa IDataProvider::requestDataLoading(). The current impl isn't thread safe.
21 /// @sa IDataProvider::requestDataLoading(). The current impl isn't thread safe.
22 void requestDataLoading(QUuid acqIdentifier, const DataProviderParameters &parameters) override;
22 void requestDataLoading(QUuid acqIdentifier, const DataProviderParameters &parameters) override;
23
23
24
24
25 /// @sa IDataProvider::requestDataAborting(). The current impl isn't thread safe.
25 /// @sa IDataProvider::requestDataAborting(). The current impl isn't thread safe.
26 void requestDataAborting(QUuid acqIdentifier) override;
26 void requestDataAborting(QUuid acqIdentifier) override;
27
27
28
28
29 private:
29 private:
30 std::shared_ptr<IDataSeries> retrieveData(QUuid acqIdentifier,
30 std::shared_ptr<IDataSeries>
31 const SqpRange &dataRangeRequested);
31 retrieveData(QUuid acqIdentifier, const SqpRange &dataRangeRequested, const QVariantHash &data);
32
32
33 QHash<QUuid, bool> m_VariableToEnableProvider;
33 QHash<QUuid, bool> m_VariableToEnableProvider;
34 };
34 };
35
35
36 #endif // SCIQLOP_COSINUSPROVIDER_H
36 #endif // SCIQLOP_COSINUSPROVIDER_H
@@ -1,115 +1,201
1 #include "CosinusProvider.h"
1 #include "CosinusProvider.h"
2 #include "MockDefs.h"
2
3
3 #include <Data/DataProviderParameters.h>
4 #include <Data/DataProviderParameters.h>
4 #include <Data/ScalarSeries.h>
5 #include <Data/ScalarSeries.h>
6 #include <Data/VectorSeries.h>
5
7
6 #include <cmath>
8 #include <cmath>
7
9
8 #include <QFuture>
10 #include <QFuture>
9 #include <QThread>
11 #include <QThread>
10 #include <QtConcurrent/QtConcurrent>
12 #include <QtConcurrent/QtConcurrent>
11
13
12 Q_LOGGING_CATEGORY(LOG_CosinusProvider, "CosinusProvider")
14 Q_LOGGING_CATEGORY(LOG_CosinusProvider, "CosinusProvider")
13
15
16 namespace {
17
18 /// Abstract cosinus type
19 struct ICosinusType {
20 virtual ~ICosinusType() = default;
21 /// @return the number of components generated for the type
22 virtual int componentCount() const = 0;
23 /// @return the data series created for the type
24 virtual std::shared_ptr<IDataSeries> createDataSeries(std::vector<double> xAxisData,
25 std::vector<double> valuesData,
26 Unit xAxisUnit,
27 Unit valuesUnit) const = 0;
28 };
29
30 struct ScalarCosinus : public ICosinusType {
31 int componentCount() const override { return 1; }
32
33 std::shared_ptr<IDataSeries> createDataSeries(std::vector<double> xAxisData,
34 std::vector<double> valuesData, Unit xAxisUnit,
35 Unit valuesUnit) const override
36 {
37 return std::make_shared<ScalarSeries>(std::move(xAxisData), std::move(valuesData),
38 xAxisUnit, valuesUnit);
39 }
40 };
41 struct VectorCosinus : public ICosinusType {
42 int componentCount() const override { return 3; }
43
44 std::shared_ptr<IDataSeries> createDataSeries(std::vector<double> xAxisData,
45 std::vector<double> valuesData, Unit xAxisUnit,
46 Unit valuesUnit) const override
47 {
48 return std::make_shared<VectorSeries>(std::move(xAxisData), std::move(valuesData),
49 xAxisUnit, valuesUnit);
50 }
51 };
52
53 /// Converts string to cosinus type
54 /// @return the cosinus type if the string could be converted, nullptr otherwise
55 std::unique_ptr<ICosinusType> cosinusType(const QString &type) noexcept
56 {
57 if (type.compare(QStringLiteral("scalar"), Qt::CaseInsensitive) == 0) {
58 return std::make_unique<ScalarCosinus>();
59 }
60 else if (type.compare(QStringLiteral("vector"), Qt::CaseInsensitive) == 0) {
61 return std::make_unique<VectorCosinus>();
62 }
63 else {
64 return nullptr;
65 }
66 }
67
68 } // namespace
69
14 std::shared_ptr<IDataProvider> CosinusProvider::clone() const
70 std::shared_ptr<IDataProvider> CosinusProvider::clone() const
15 {
71 {
16 // No copy is made in clone
72 // No copy is made in clone
17 return std::make_shared<CosinusProvider>();
73 return std::make_shared<CosinusProvider>();
18 }
74 }
19
75
20 std::shared_ptr<IDataSeries> CosinusProvider::retrieveData(QUuid acqIdentifier,
76 std::shared_ptr<IDataSeries> CosinusProvider::retrieveData(QUuid acqIdentifier,
21 const SqpRange &dataRangeRequested)
77 const SqpRange &dataRangeRequested,
78 const QVariantHash &data)
22 {
79 {
23 // TODO: Add Mutex
80 // TODO: Add Mutex
24 auto dataIndex = 0;
81 auto dataIndex = 0;
25
82
83 // Retrieves cosinus type
84 auto typeVariant = data.value(COSINUS_TYPE_KEY, COSINUS_TYPE_DEFAULT_VALUE);
85 if (!typeVariant.canConvert<QString>()) {
86 qCCritical(LOG_CosinusProvider()) << tr("Can't retrieve data: invalid type");
87 return nullptr;
88 }
89
90 auto type = cosinusType(typeVariant.toString());
91 if (!type) {
92 qCCritical(LOG_CosinusProvider()) << tr("Can't retrieve data: unknown type");
93 return nullptr;
94 }
95
96 // Retrieves frequency
97 auto freqVariant = data.value(COSINUS_FREQUENCY_KEY, COSINUS_FREQUENCY_DEFAULT_VALUE);
98 if (!freqVariant.canConvert<double>()) {
99 qCCritical(LOG_CosinusProvider()) << tr("Can't retrieve data: invalid frequency");
100 return nullptr;
101 }
102
26 // Gets the timerange from the parameters
103 // Gets the timerange from the parameters
27 double freq = 100.0;
104 double freq = freqVariant.toDouble();
28 double start = std::ceil(dataRangeRequested.m_TStart * freq); // 100 htz
105 double start = std::ceil(dataRangeRequested.m_TStart * freq);
29 double end = std::floor(dataRangeRequested.m_TEnd * freq); // 100 htz
106 double end = std::floor(dataRangeRequested.m_TEnd * freq);
30
107
31 // We assure that timerange is valid
108 // We assure that timerange is valid
32 if (end < start) {
109 if (end < start) {
33 std::swap(start, end);
110 std::swap(start, end);
34 }
111 }
35
112
36 // Generates scalar series containing cosinus values (one value per second, end value is
113 // Generates scalar series containing cosinus values (one value per second, end value is
37 // included)
114 // included)
38 auto dataCount = end - start + 1;
115 auto dataCount = end - start + 1;
39
116
117 // Number of components (depending on the cosinus type)
118 auto componentCount = type->componentCount();
119
40 auto xAxisData = std::vector<double>{};
120 auto xAxisData = std::vector<double>{};
41 xAxisData.resize(dataCount);
121 xAxisData.resize(dataCount);
42
122
43 auto valuesData = std::vector<double>{};
123 auto valuesData = std::vector<double>{};
44 valuesData.resize(dataCount);
124 valuesData.resize(dataCount * componentCount);
45
125
46 int progress = 0;
126 int progress = 0;
47 auto progressEnd = dataCount;
127 auto progressEnd = dataCount;
48 for (auto time = start; time <= end; ++time, ++dataIndex) {
128 for (auto time = start; time <= end; ++time, ++dataIndex) {
49 auto it = m_VariableToEnableProvider.find(acqIdentifier);
129 auto it = m_VariableToEnableProvider.find(acqIdentifier);
50 if (it != m_VariableToEnableProvider.end() && it.value()) {
130 if (it != m_VariableToEnableProvider.end() && it.value()) {
51 const auto timeOnFreq = time / freq;
131 const auto timeOnFreq = time / freq;
52
132
53 xAxisData[dataIndex] = timeOnFreq;
133 xAxisData[dataIndex] = timeOnFreq;
54 valuesData[dataIndex] = std::cos(timeOnFreq);
134
135 // Generates all components' values
136 // Example: for a vector, values will be : cos(x), cos(x)/2, cos(x)/3
137 auto value = std::cos(timeOnFreq);
138 for (auto i = 0; i < componentCount; ++i) {
139 valuesData[componentCount * dataIndex + i] = value / (i + 1);
140 }
55
141
56 // progression
142 // progression
57 int currentProgress = (time - start) * 100.0 / progressEnd;
143 int currentProgress = (time - start) * 100.0 / progressEnd;
58 if (currentProgress != progress) {
144 if (currentProgress != progress) {
59 progress = currentProgress;
145 progress = currentProgress;
60
146
61 emit dataProvidedProgress(acqIdentifier, progress);
147 emit dataProvidedProgress(acqIdentifier, progress);
62 qCInfo(LOG_CosinusProvider()) << "TORM: CosinusProvider::retrieveData"
148 qCInfo(LOG_CosinusProvider()) << "TORM: CosinusProvider::retrieveData"
63 << QThread::currentThread()->objectName() << progress;
149 << QThread::currentThread()->objectName() << progress;
64 // NOTE: Try to use multithread if possible
150 // NOTE: Try to use multithread if possible
65 }
151 }
66 }
152 }
67 else {
153 else {
68 if (!it.value()) {
154 if (!it.value()) {
69 qCDebug(LOG_CosinusProvider())
155 qCDebug(LOG_CosinusProvider())
70 << "CosinusProvider::retrieveData: ARRET De l'acquisition detectΓ©"
156 << "CosinusProvider::retrieveData: ARRET De l'acquisition detectΓ©"
71 << end - time;
157 << end - time;
72 }
158 }
73 }
159 }
74 }
160 }
75 if (progress != 100) {
161 if (progress != 100) {
76 // We can close progression beacause all data has been retrieved
162 // We can close progression beacause all data has been retrieved
77 emit dataProvidedProgress(acqIdentifier, 100);
163 emit dataProvidedProgress(acqIdentifier, 100);
78 }
164 }
79 return std::make_shared<ScalarSeries>(std::move(xAxisData), std::move(valuesData),
165 return type->createDataSeries(std::move(xAxisData), std::move(valuesData),
80 Unit{QStringLiteral("t"), true}, Unit{});
166 Unit{QStringLiteral("t"), true}, Unit{});
81 }
167 }
82
168
83 void CosinusProvider::requestDataLoading(QUuid acqIdentifier,
169 void CosinusProvider::requestDataLoading(QUuid acqIdentifier,
84 const DataProviderParameters &parameters)
170 const DataProviderParameters &parameters)
85 {
171 {
86 // TODO: Add Mutex
172 // TODO: Add Mutex
87 m_VariableToEnableProvider[acqIdentifier] = true;
173 m_VariableToEnableProvider[acqIdentifier] = true;
88 qCDebug(LOG_CosinusProvider()) << "TORM: CosinusProvider::requestDataLoading"
174 qCDebug(LOG_CosinusProvider()) << "TORM: CosinusProvider::requestDataLoading"
89 << QThread::currentThread()->objectName();
175 << QThread::currentThread()->objectName();
90 // NOTE: Try to use multithread if possible
176 // NOTE: Try to use multithread if possible
91 const auto times = parameters.m_Times;
177 const auto times = parameters.m_Times;
92
178
93 for (const auto &dateTime : qAsConst(times)) {
179 for (const auto &dateTime : qAsConst(times)) {
94 if (m_VariableToEnableProvider[acqIdentifier]) {
180 if (m_VariableToEnableProvider[acqIdentifier]) {
95 auto scalarSeries = this->retrieveData(acqIdentifier, dateTime);
181 auto scalarSeries = this->retrieveData(acqIdentifier, dateTime, parameters.m_Data);
96 qCDebug(LOG_CosinusProvider()) << "TORM: CosinusProvider::dataProvided";
182 qCDebug(LOG_CosinusProvider()) << "TORM: CosinusProvider::dataProvided";
97 emit dataProvided(acqIdentifier, scalarSeries, dateTime);
183 emit dataProvided(acqIdentifier, scalarSeries, dateTime);
98 }
184 }
99 }
185 }
100 }
186 }
101
187
102 void CosinusProvider::requestDataAborting(QUuid acqIdentifier)
188 void CosinusProvider::requestDataAborting(QUuid acqIdentifier)
103 {
189 {
104 // TODO: Add Mutex
190 // TODO: Add Mutex
105 qCDebug(LOG_CosinusProvider()) << "CosinusProvider::requestDataAborting" << acqIdentifier
191 qCDebug(LOG_CosinusProvider()) << "CosinusProvider::requestDataAborting" << acqIdentifier
106 << QThread::currentThread()->objectName();
192 << QThread::currentThread()->objectName();
107 auto it = m_VariableToEnableProvider.find(acqIdentifier);
193 auto it = m_VariableToEnableProvider.find(acqIdentifier);
108 if (it != m_VariableToEnableProvider.end()) {
194 if (it != m_VariableToEnableProvider.end()) {
109 it.value() = false;
195 it.value() = false;
110 }
196 }
111 else {
197 else {
112 qCWarning(LOG_CosinusProvider())
198 qCWarning(LOG_CosinusProvider())
113 << tr("Aborting progression of inexistant identifier detected !!!");
199 << tr("Aborting progression of inexistant identifier detected !!!");
114 }
200 }
115 }
201 }
@@ -1,79 +1,109
1 #include "MockPlugin.h"
1 #include "MockPlugin.h"
2 #include "CosinusProvider.h"
2 #include "CosinusProvider.h"
3 #include "MockDefs.h"
3
4
4 #include <DataSource/DataSourceController.h>
5 #include <DataSource/DataSourceController.h>
5 #include <DataSource/DataSourceItem.h>
6 #include <DataSource/DataSourceItem.h>
6 #include <DataSource/DataSourceItemAction.h>
7 #include <DataSource/DataSourceItemAction.h>
7
8
8 #include <SqpApplication.h>
9 #include <SqpApplication.h>
9
10
10 Q_LOGGING_CATEGORY(LOG_MockPlugin, "MockPlugin")
11 Q_LOGGING_CATEGORY(LOG_MockPlugin, "MockPlugin")
11
12
12 namespace {
13 namespace {
13
14
14 /// Name of the data source
15 /// Name of the data source
15 const auto DATA_SOURCE_NAME = QStringLiteral("MMS");
16 const auto DATA_SOURCE_NAME = QStringLiteral("MMS");
16
17
17 /// Creates the data provider relative to the plugin
18 /// Creates the data provider relative to the plugin
18 std::unique_ptr<IDataProvider> createDataProvider() noexcept
19 std::unique_ptr<IDataProvider> createDataProvider() noexcept
19 {
20 {
20 return std::make_unique<CosinusProvider>();
21 return std::make_unique<CosinusProvider>();
21 }
22 }
22
23
23 std::unique_ptr<DataSourceItem> createProductItem(const QString &productName,
24 std::unique_ptr<DataSourceItem> createProductItem(const QVariantHash &data,
24 const QUuid &dataSourceUid)
25 const QUuid &dataSourceUid)
25 {
26 {
26 auto result = std::make_unique<DataSourceItem>(DataSourceItemType::PRODUCT, productName);
27 auto result = std::make_unique<DataSourceItem>(DataSourceItemType::PRODUCT, data);
28 auto productName = data.value(DataSourceItem::NAME_DATA_KEY).toString();
27
29
28 // Add action to load product from DataSourceController
30 // Add action to load product from DataSourceController
29 result->addAction(std::make_unique<DataSourceItemAction>(
31 result->addAction(std::make_unique<DataSourceItemAction>(
30 QObject::tr("Load %1 product").arg(productName),
32 QObject::tr("Load %1 product").arg(productName),
31 [productName, dataSourceUid](DataSourceItem &item) {
33 [productName, dataSourceUid](DataSourceItem &item) {
32 if (auto app = sqpApp) {
34 if (auto app = sqpApp) {
33 app->dataSourceController().loadProductItem(dataSourceUid, item);
35 app->dataSourceController().loadProductItem(dataSourceUid, item);
34 }
36 }
35 }));
37 }));
36
38
37 return result;
39 return result;
38 }
40 }
39
41
40 /// Creates the data source item relative to the plugin
42 /// Creates the data source item relative to the plugin
41 std::unique_ptr<DataSourceItem> createDataSourceItem(const QUuid &dataSourceUid) noexcept
43 std::unique_ptr<DataSourceItem> createDataSourceItem(const QUuid &dataSourceUid) noexcept
42 {
44 {
43 // Magnetic field products
45 // Magnetic field products
44 auto magneticFieldFolder = std::make_unique<DataSourceItem>(DataSourceItemType::NODE,
46 auto magneticFieldFolder = std::make_unique<DataSourceItem>(DataSourceItemType::NODE,
45 QStringLiteral("Magnetic field"));
47 QStringLiteral("Magnetic field"));
46 magneticFieldFolder->appendChild(createProductItem(QStringLiteral("FGM"), dataSourceUid));
48 magneticFieldFolder->appendChild(
47 magneticFieldFolder->appendChild(createProductItem(QStringLiteral("SC"), dataSourceUid));
49 createProductItem({{DataSourceItem::NAME_DATA_KEY, QStringLiteral("Scalar 10 Hz")},
50 {COSINUS_TYPE_KEY, "scalar"},
51 {COSINUS_FREQUENCY_KEY, 10.}},
52 dataSourceUid));
53 magneticFieldFolder->appendChild(
54 createProductItem({{DataSourceItem::NAME_DATA_KEY, QStringLiteral("Scalar 60 Hz")},
55 {COSINUS_TYPE_KEY, "scalar"},
56 {COSINUS_FREQUENCY_KEY, 60.}},
57 dataSourceUid));
58 magneticFieldFolder->appendChild(
59 createProductItem({{DataSourceItem::NAME_DATA_KEY, QStringLiteral("Scalar 100 Hz")},
60 {COSINUS_TYPE_KEY, "scalar"},
61 {COSINUS_FREQUENCY_KEY, 100.}},
62 dataSourceUid));
63 magneticFieldFolder->appendChild(
64 createProductItem({{DataSourceItem::NAME_DATA_KEY, QStringLiteral("Vector 10 Hz")},
65 {COSINUS_TYPE_KEY, "vector"},
66 {COSINUS_FREQUENCY_KEY, 10.}},
67 dataSourceUid));
68 magneticFieldFolder->appendChild(
69 createProductItem({{DataSourceItem::NAME_DATA_KEY, QStringLiteral("Vector 60 Hz")},
70 {COSINUS_TYPE_KEY, "vector"},
71 {COSINUS_FREQUENCY_KEY, 60.}},
72 dataSourceUid));
73 magneticFieldFolder->appendChild(
74 createProductItem({{DataSourceItem::NAME_DATA_KEY, QStringLiteral("Vector 100 Hz")},
75 {COSINUS_TYPE_KEY, "vector"},
76 {COSINUS_FREQUENCY_KEY, 100.}},
77 dataSourceUid));
48
78
49 // Electric field products
79 // Electric field products
50 auto electricFieldFolder = std::make_unique<DataSourceItem>(DataSourceItemType::NODE,
80 auto electricFieldFolder = std::make_unique<DataSourceItem>(DataSourceItemType::NODE,
51 QStringLiteral("Electric field"));
81 QStringLiteral("Electric field"));
52
82
53 // Root
83 // Root
54 auto root = std::make_unique<DataSourceItem>(DataSourceItemType::NODE, DATA_SOURCE_NAME);
84 auto root = std::make_unique<DataSourceItem>(DataSourceItemType::NODE, DATA_SOURCE_NAME);
55 root->appendChild(std::move(magneticFieldFolder));
85 root->appendChild(std::move(magneticFieldFolder));
56 root->appendChild(std::move(electricFieldFolder));
86 root->appendChild(std::move(electricFieldFolder));
57
87
58 return root;
88 return root;
59 }
89 }
60
90
61 } // namespace
91 } // namespace
62
92
63 void MockPlugin::initialize()
93 void MockPlugin::initialize()
64 {
94 {
65 if (auto app = sqpApp) {
95 if (auto app = sqpApp) {
66 // Registers to the data source controller
96 // Registers to the data source controller
67 auto &dataSourceController = app->dataSourceController();
97 auto &dataSourceController = app->dataSourceController();
68 auto dataSourceUid = dataSourceController.registerDataSource(DATA_SOURCE_NAME);
98 auto dataSourceUid = dataSourceController.registerDataSource(DATA_SOURCE_NAME);
69
99
70 // Sets data source tree
100 // Sets data source tree
71 dataSourceController.setDataSourceItem(dataSourceUid, createDataSourceItem(dataSourceUid));
101 dataSourceController.setDataSourceItem(dataSourceUid, createDataSourceItem(dataSourceUid));
72
102
73 // Sets data provider
103 // Sets data provider
74 dataSourceController.setDataProvider(dataSourceUid, createDataProvider());
104 dataSourceController.setDataProvider(dataSourceUid, createDataProvider());
75 }
105 }
76 else {
106 else {
77 qCWarning(LOG_MockPlugin()) << tr("Can't access to SciQlop application");
107 qCWarning(LOG_MockPlugin()) << tr("Can't access to SciQlop application");
78 }
108 }
79 }
109 }
@@ -1,191 +1,193
1 #include "CosinusProvider.h"
1 #include "CosinusProvider.h"
2 #include "MockDefs.h"
2
3
3 #include <Data/DataProviderParameters.h>
4 #include <Data/DataProviderParameters.h>
4 #include <Data/ScalarSeries.h>
5 #include <Data/ScalarSeries.h>
5 #include <SqpApplication.h>
6 #include <SqpApplication.h>
6 #include <Time/TimeController.h>
7 #include <Time/TimeController.h>
7 #include <Variable/Variable.h>
8 #include <Variable/Variable.h>
8 #include <Variable/VariableController.h>
9 #include <Variable/VariableController.h>
9
10
10 #include <QObject>
11 #include <QObject>
11 #include <QtTest>
12 #include <QtTest>
12
13
13 #include <cmath>
14 #include <cmath>
14 #include <memory>
15 #include <memory>
15
16
16 namespace {
17 namespace {
17
18
18 /// Path for the tests
19 /// Path for the tests
19 const auto TESTS_RESOURCES_PATH = QFileInfo{
20 const auto TESTS_RESOURCES_PATH = QFileInfo{
20 QString{MOCKPLUGIN_TESTS_RESOURCES_DIR},
21 QString{MOCKPLUGIN_TESTS_RESOURCES_DIR},
21 "TestCosinusAcquisition"}.absoluteFilePath();
22 "TestCosinusAcquisition"}.absoluteFilePath();
22
23
23 /// Format of dates in data files
24 /// Format of dates in data files
24 const auto DATETIME_FORMAT = QStringLiteral("yyyy/MM/dd hh:mm:ss:zzz");
25 const auto DATETIME_FORMAT = QStringLiteral("yyyy/MM/dd hh:mm:ss:zzz");
25
26
26 /// Delay after each operation on the variable before validating it (in ms)
27 /// Delay after each operation on the variable before validating it (in ms)
27 const auto OPERATION_DELAY = 250;
28 const auto OPERATION_DELAY = 250;
28
29
29 /**
30 /**
30 * Verifies that the data in the candidate series are identical to the data in the reference series
31 * Verifies that the data in the candidate series are identical to the data in the reference series
31 * in a specific range
32 * in a specific range
32 * @param candidate the candidate data series
33 * @param candidate the candidate data series
33 * @param range the range to check
34 * @param range the range to check
34 * @param reference the reference data series
35 * @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 * @return true if the data of the candidate series and the reference series are identical in the
36 * range, false otherwise
37 * range, false otherwise
37 */
38 */
38 bool checkDataSeries(std::shared_ptr<IDataSeries> candidate, const SqpRange &range,
39 bool checkDataSeries(std::shared_ptr<IDataSeries> candidate, const SqpRange &range,
39 std::shared_ptr<IDataSeries> reference)
40 std::shared_ptr<IDataSeries> reference)
40 {
41 {
41 if (candidate == nullptr || reference == nullptr) {
42 if (candidate == nullptr || reference == nullptr) {
42 return candidate == reference;
43 return candidate == reference;
43 }
44 }
44
45
45 auto referenceIt = reference->xAxisRange(range.m_TStart, range.m_TEnd);
46 auto referenceIt = reference->xAxisRange(range.m_TStart, range.m_TEnd);
46
47
47 return std::equal(candidate->cbegin(), candidate->cend(), referenceIt.first, referenceIt.second,
48 return std::equal(candidate->cbegin(), candidate->cend(), referenceIt.first, referenceIt.second,
48 [](const auto &it1, const auto &it2) {
49 [](const auto &it1, const auto &it2) {
49 // - milliseconds precision for time
50 // - milliseconds precision for time
50 // - 1e-6 precision for value
51 // - 1e-6 precision for value
51 return std::abs(it1.x() - it2.x()) < 1e-3
52 return std::abs(it1.x() - it2.x()) < 1e-3
52 && std::abs(it1.value() - it2.value()) < 1e-6;
53 && std::abs(it1.value() - it2.value()) < 1e-6;
53 });
54 });
54 }
55 }
55
56
56 /// Generates the data series from the reading of a data stream
57 /// Generates the data series from the reading of a data stream
57 std::shared_ptr<IDataSeries> readDataStream(QTextStream &stream)
58 std::shared_ptr<IDataSeries> readDataStream(QTextStream &stream)
58 {
59 {
59 std::vector<double> xAxisData, valuesData;
60 std::vector<double> xAxisData, valuesData;
60
61
61 QString line{};
62 QString line{};
62 while (stream.readLineInto(&line)) {
63 while (stream.readLineInto(&line)) {
63 // Separates date (x-axis data) to value data
64 // Separates date (x-axis data) to value data
64 auto splitLine = line.split('\t');
65 auto splitLine = line.split('\t');
65 if (splitLine.size() == 2) {
66 if (splitLine.size() == 2) {
66 // Converts datetime to double
67 // Converts datetime to double
67 auto dateTime = QDateTime::fromString(splitLine[0], DATETIME_FORMAT);
68 auto dateTime = QDateTime::fromString(splitLine[0], DATETIME_FORMAT);
68 dateTime.setTimeSpec(Qt::UTC);
69 dateTime.setTimeSpec(Qt::UTC);
69 xAxisData.push_back(DateUtils::secondsSinceEpoch(dateTime));
70 xAxisData.push_back(DateUtils::secondsSinceEpoch(dateTime));
70
71
71 valuesData.push_back(splitLine[1].toDouble());
72 valuesData.push_back(splitLine[1].toDouble());
72 }
73 }
73 }
74 }
74
75
75 return std::make_shared<ScalarSeries>(std::move(xAxisData), std::move(valuesData),
76 return std::make_shared<ScalarSeries>(std::move(xAxisData), std::move(valuesData),
76 Unit{{}, true}, Unit{});
77 Unit{{}, true}, Unit{});
77 }
78 }
78
79
79 } // namespace
80 } // namespace
80
81
81 /**
82 /**
82 * @brief The TestCosinusAcquisition class tests acquisition in SciQlop (operations like zooms in,
83 * @brief The TestCosinusAcquisition class tests acquisition in SciQlop (operations like zooms in,
83 * zooms out, pans) of data from CosinusProvider
84 * zooms out, pans) of data from CosinusProvider
84 * @sa CosinusProvider
85 * @sa CosinusProvider
85 */
86 */
86 class TestCosinusAcquisition : public QObject {
87 class TestCosinusAcquisition : public QObject {
87 Q_OBJECT
88 Q_OBJECT
88
89
89 private slots:
90 private slots:
90 /// Input data for @sa testAcquisition()
91 /// Input data for @sa testAcquisition()
91 void testAcquisition_data();
92 void testAcquisition_data();
92 void testAcquisition();
93 void testAcquisition();
93 };
94 };
94
95
95 void TestCosinusAcquisition::testAcquisition_data()
96 void TestCosinusAcquisition::testAcquisition_data()
96 {
97 {
97 // ////////////// //
98 // ////////////// //
98 // Test structure //
99 // Test structure //
99 // ////////////// //
100 // ////////////// //
100
101
101 QTest::addColumn<QString>("dataFilename"); // File containing expected data of acquisitions
102 QTest::addColumn<QString>("dataFilename"); // File containing expected data of acquisitions
102 QTest::addColumn<SqpRange>("initialRange"); // First acquisition
103 QTest::addColumn<SqpRange>("initialRange"); // First acquisition
103 QTest::addColumn<std::vector<SqpRange> >("operations"); // Acquisitions to make
104 QTest::addColumn<std::vector<SqpRange> >("operations"); // Acquisitions to make
104
105
105 // ////////// //
106 // ////////// //
106 // Test cases //
107 // Test cases //
107 // ////////// //
108 // ////////// //
108
109
109 auto dateTime = [](int year, int month, int day, int hours, int minutes, int seconds) {
110 auto dateTime = [](int year, int month, int day, int hours, int minutes, int seconds) {
110 return DateUtils::secondsSinceEpoch(
111 return DateUtils::secondsSinceEpoch(
111 QDateTime{{year, month, day}, {hours, minutes, seconds}, Qt::UTC});
112 QDateTime{{year, month, day}, {hours, minutes, seconds}, Qt::UTC});
112 };
113 };
113
114
114 QTest::newRow("cosinus")
115 QTest::newRow("cosinus")
115 << "Cosinus_100Hz_20170101_1200_20170101_1300.txt"
116 << "Cosinus_100Hz_20170101_1200_20170101_1300.txt"
116 << SqpRange{dateTime(2017, 1, 1, 12, 30, 0), dateTime(2017, 1, 1, 12, 35, 1)}
117 << SqpRange{dateTime(2017, 1, 1, 12, 30, 0), dateTime(2017, 1, 1, 12, 35, 1)}
117 << std::vector<SqpRange>{
118 << std::vector<SqpRange>{
118 // Pan (jump) left
119 // Pan (jump) left
119 SqpRange{dateTime(2017, 1, 1, 12, 45, 0), dateTime(2017, 1, 1, 12, 50, 0)},
120 SqpRange{dateTime(2017, 1, 1, 12, 45, 0), dateTime(2017, 1, 1, 12, 50, 0)},
120 // Pan (jump) right
121 // Pan (jump) right
121 SqpRange{dateTime(2017, 1, 1, 12, 15, 0), dateTime(2017, 1, 1, 12, 20, 0)},
122 SqpRange{dateTime(2017, 1, 1, 12, 15, 0), dateTime(2017, 1, 1, 12, 20, 0)},
122 // Pan (overlay) right
123 // Pan (overlay) right
123 SqpRange{dateTime(2017, 1, 1, 12, 14, 0), dateTime(2017, 1, 1, 12, 19, 0)},
124 SqpRange{dateTime(2017, 1, 1, 12, 14, 0), dateTime(2017, 1, 1, 12, 19, 0)},
124 // Pan (overlay) left
125 // Pan (overlay) left
125 SqpRange{dateTime(2017, 1, 1, 12, 15, 0), dateTime(2017, 1, 1, 12, 20, 0)},
126 SqpRange{dateTime(2017, 1, 1, 12, 15, 0), dateTime(2017, 1, 1, 12, 20, 0)},
126 // Pan (overlay) left
127 // Pan (overlay) left
127 SqpRange{dateTime(2017, 1, 1, 12, 16, 0), dateTime(2017, 1, 1, 12, 21, 0)},
128 SqpRange{dateTime(2017, 1, 1, 12, 16, 0), dateTime(2017, 1, 1, 12, 21, 0)},
128 // Zoom in
129 // Zoom in
129 SqpRange{dateTime(2017, 1, 1, 12, 17, 30), dateTime(2017, 1, 1, 12, 19, 30)},
130 SqpRange{dateTime(2017, 1, 1, 12, 17, 30), dateTime(2017, 1, 1, 12, 19, 30)},
130 // Zoom out
131 // Zoom out
131 SqpRange{dateTime(2017, 1, 1, 12, 12, 30), dateTime(2017, 1, 1, 12, 24, 30)}};
132 SqpRange{dateTime(2017, 1, 1, 12, 12, 30), dateTime(2017, 1, 1, 12, 24, 30)}};
132 }
133 }
133
134
134 void TestCosinusAcquisition::testAcquisition()
135 void TestCosinusAcquisition::testAcquisition()
135 {
136 {
136 // Retrieves data file
137 // Retrieves data file
137 QFETCH(QString, dataFilename);
138 QFETCH(QString, dataFilename);
138
139
139 auto dataFilePath = QFileInfo{TESTS_RESOURCES_PATH, dataFilename}.absoluteFilePath();
140 auto dataFilePath = QFileInfo{TESTS_RESOURCES_PATH, dataFilename}.absoluteFilePath();
140 QFile dataFile{dataFilePath};
141 QFile dataFile{dataFilePath};
141
142
142 if (dataFile.open(QFile::ReadOnly)) {
143 if (dataFile.open(QFile::ReadOnly)) {
143 // Generates data series to compare with
144 // Generates data series to compare with
144 QTextStream dataStream{&dataFile};
145 QTextStream dataStream{&dataFile};
145 auto dataSeries = readDataStream(dataStream);
146 auto dataSeries = readDataStream(dataStream);
146
147
147 /// Lambda used to validate a variable at each step
148 /// Lambda used to validate a variable at each step
148 auto validateVariable = [dataSeries](std::shared_ptr<Variable> variable,
149 auto validateVariable = [dataSeries](std::shared_ptr<Variable> variable,
149 const SqpRange &range) {
150 const SqpRange &range) {
150 // Checks that the variable's range has changed
151 // Checks that the variable's range has changed
151 QCOMPARE(variable->range(), range);
152 QCOMPARE(variable->range(), range);
152
153
153 // Checks the variable's data series
154 // Checks the variable's data series
154 QVERIFY(checkDataSeries(variable->dataSeries(), variable->cacheRange(), dataSeries));
155 QVERIFY(checkDataSeries(variable->dataSeries(), variable->cacheRange(), dataSeries));
155 };
156 };
156
157
157 // Creates variable
158 // Creates variable
158 QFETCH(SqpRange, initialRange);
159 QFETCH(SqpRange, initialRange);
159 sqpApp->timeController().onTimeToUpdate(initialRange);
160 sqpApp->timeController().onTimeToUpdate(initialRange);
160 auto provider = std::make_shared<CosinusProvider>();
161 auto provider = std::make_shared<CosinusProvider>();
161 auto variable = sqpApp->variableController().createVariable("MMS", {}, provider);
162 auto variable = sqpApp->variableController().createVariable(
163 "MMS", {{COSINUS_TYPE_KEY, "scalar"}, {COSINUS_FREQUENCY_KEY, 100.}}, provider);
162
164
163 QTest::qWait(OPERATION_DELAY);
165 QTest::qWait(OPERATION_DELAY);
164 validateVariable(variable, initialRange);
166 validateVariable(variable, initialRange);
165
167
166 // Makes operations on the variable
168 // Makes operations on the variable
167 QFETCH(std::vector<SqpRange>, operations);
169 QFETCH(std::vector<SqpRange>, operations);
168 for (const auto &operation : operations) {
170 for (const auto &operation : operations) {
169 // Asks request on the variable and waits during its execution
171 // Asks request on the variable and waits during its execution
170 sqpApp->variableController().onRequestDataLoading({variable}, operation,
172 sqpApp->variableController().onRequestDataLoading({variable}, operation,
171 variable->range(), true);
173 variable->range(), true);
172
174
173 QTest::qWait(OPERATION_DELAY);
175 QTest::qWait(OPERATION_DELAY);
174 validateVariable(variable, operation);
176 validateVariable(variable, operation);
175 }
177 }
176 }
178 }
177 else {
179 else {
178 QFAIL("Can't read input data file");
180 QFAIL("Can't read input data file");
179 }
181 }
180 }
182 }
181
183
182 int main(int argc, char *argv[])
184 int main(int argc, char *argv[])
183 {
185 {
184 SqpApplication app{argc, argv};
186 SqpApplication app{argc, argv};
185 app.setAttribute(Qt::AA_Use96Dpi, true);
187 app.setAttribute(Qt::AA_Use96Dpi, true);
186 TestCosinusAcquisition testObject{};
188 TestCosinusAcquisition testObject{};
187 QTEST_SET_MAIN_SOURCE_PATH
189 QTEST_SET_MAIN_SOURCE_PATH
188 return QTest::qExec(&testObject, argc, argv);
190 return QTest::qExec(&testObject, argc, argv);
189 }
191 }
190
192
191 #include "TestCosinusAcquisition.moc"
193 #include "TestCosinusAcquisition.moc"
General Comments 0
You need to be logged in to leave comments. Login now