##// END OF EJS Templates
Implements test case
Alexandre Leroux -
r717:daedfa2562d7
parent child
Show More
@@ -1,241 +1,310
1 #include <QObject>
1 #include <QObject>
2 #include <QtTest>
2 #include <QtTest>
3
3
4 #include <memory>
4 #include <memory>
5
5
6 #include <Data/DataProviderParameters.h>
6 #include <Data/DataProviderParameters.h>
7 #include <Data/IDataProvider.h>
7 #include <Data/IDataProvider.h>
8 #include <Data/ScalarSeries.h>
8 #include <Data/ScalarSeries.h>
9 #include <Time/TimeController.h>
9 #include <Time/TimeController.h>
10 #include <Variable/Variable.h>
10 #include <Variable/Variable.h>
11 #include <Variable/VariableController.h>
11 #include <Variable/VariableController.h>
12 #include <Variable/VariableModel.h>
12 #include <Variable/VariableModel.h>
13
13
14 namespace {
14 namespace {
15
15
16 /// Delay after each operation on the variable before validating it (in ms)
16 /// Delay after each operation on the variable before validating it (in ms)
17 const auto OPERATION_DELAY = 100;
17 const auto OPERATION_DELAY = 100;
18
18
19 /**
19 /**
20 * Generates values according to a range. The value generated for a time t is the number of seconds
20 * Generates values according to a range. The value generated for a time t is the number of seconds
21 * of difference between t and a reference value (which is midnight -> 00:00:00)
21 * of difference between t and a reference value (which is midnight -> 00:00:00)
22 *
22 *
23 * Example: For a range between 00:00:10 and 00:00:20, the generated values are
23 * Example: For a range between 00:00:10 and 00:00:20, the generated values are
24 * {10,11,12,13,14,15,16,17,18,19,20}
24 * {10,11,12,13,14,15,16,17,18,19,20}
25 */
25 */
26 std::vector<double> values(const SqpRange &range)
26 std::vector<double> values(const SqpRange &range)
27 {
27 {
28 QTime referenceTime{0, 0};
28 QTime referenceTime{0, 0};
29
29
30 std::vector<double> result{};
30 std::vector<double> result{};
31
31
32 for (auto i = range.m_TStart; i <= range.m_TEnd; ++i) {
32 for (auto i = range.m_TStart; i <= range.m_TEnd; ++i) {
33 auto time = DateUtils::dateTime(i).time();
33 auto time = DateUtils::dateTime(i).time();
34 result.push_back(referenceTime.secsTo(time));
34 result.push_back(referenceTime.secsTo(time));
35 }
35 }
36
36
37 return result;
37 return result;
38 }
38 }
39
39
40 /// Provider used for the tests
40 /// Provider used for the tests
41 class TestProvider : public IDataProvider {
41 class TestProvider : public IDataProvider {
42 std::shared_ptr<IDataProvider> clone() const { return std::make_shared<TestProvider>(); }
42 std::shared_ptr<IDataProvider> clone() const { return std::make_shared<TestProvider>(); }
43
43
44 void requestDataLoading(QUuid acqIdentifier, const DataProviderParameters &parameters) override
44 void requestDataLoading(QUuid acqIdentifier, const DataProviderParameters &parameters) override
45 {
45 {
46 const auto &ranges = parameters.m_Times;
46 const auto &ranges = parameters.m_Times;
47
47
48 for (const auto &range : ranges) {
48 for (const auto &range : ranges) {
49 // Generates data series
49 // Generates data series
50 auto valuesData = values(range);
50 auto valuesData = values(range);
51
51
52 std::vector<double> xAxisData{};
52 std::vector<double> xAxisData{};
53 for (auto i = range.m_TStart; i <= range.m_TEnd; ++i) {
53 for (auto i = range.m_TStart; i <= range.m_TEnd; ++i) {
54 xAxisData.push_back(i);
54 xAxisData.push_back(i);
55 }
55 }
56
56
57 auto dataSeries = std::make_shared<ScalarSeries>(
57 auto dataSeries = std::make_shared<ScalarSeries>(
58 std::move(xAxisData), std::move(valuesData), Unit{"t", true}, Unit{});
58 std::move(xAxisData), std::move(valuesData), Unit{"t", true}, Unit{});
59
59
60 emit dataProvided(acqIdentifier, dataSeries, range);
60 emit dataProvided(acqIdentifier, dataSeries, range);
61 }
61 }
62 }
62 }
63
63
64 void requestDataAborting(QUuid acqIdentifier) override
64 void requestDataAborting(QUuid acqIdentifier) override
65 {
65 {
66 // Does nothing
66 // Does nothing
67 }
67 }
68 };
68 };
69
69
70 /**
70 /**
71 * Interface representing an operation performed on a variable controller.
71 * Interface representing an operation performed on a variable controller.
72 * This interface is used in tests to apply a set of operations and check the status of the
72 * This interface is used in tests to apply a set of operations and check the status of the
73 * controller after each operation
73 * controller after each operation
74 */
74 */
75 struct IOperation {
75 struct IOperation {
76 virtual ~IOperation() = default;
76 virtual ~IOperation() = default;
77 /// Executes the operation on the variable controller
77 /// Executes the operation on the variable controller
78 virtual void exec(VariableController &variableController) const = 0;
78 virtual void exec(VariableController &variableController) const = 0;
79 };
79 };
80
80
81 /**
81 /**
82 *Variable creation operation in the controller
82 *Variable creation operation in the controller
83 */
83 */
84 struct Create : public IOperation {
84 struct Create : public IOperation {
85 explicit Create(int index) : m_Index{index} {}
85 explicit Create(int index) : m_Index{index} {}
86
86
87 void exec(VariableController &variableController) const override
87 void exec(VariableController &variableController) const override
88 {
88 {
89 auto variable = variableController.createVariable(QString::number(m_Index), {},
89 auto variable = variableController.createVariable(QString::number(m_Index), {},
90 std::make_unique<TestProvider>());
90 std::make_unique<TestProvider>());
91 }
91 }
92
92
93 int m_Index; ///< The index of the variable to create in the controller
93 int m_Index; ///< The index of the variable to create in the controller
94 };
94 };
95
95
96 /**
96 /**
97 * Variable move/shift operation in the controller
97 * Variable move/shift operation in the controller
98 */
98 */
99 struct Move : public IOperation {
99 struct Move : public IOperation {
100 explicit Move(int index, const SqpRange &newRange, bool shift = false)
100 explicit Move(int index, const SqpRange &newRange, bool shift = false)
101 : m_Index{index}, m_NewRange{newRange}, m_Shift{shift}
101 : m_Index{index}, m_NewRange{newRange}, m_Shift{shift}
102 {
102 {
103 }
103 }
104
104
105 void exec(VariableController &variableController) const override
105 void exec(VariableController &variableController) const override
106 {
106 {
107 if (auto variable = variableController.variableModel()->variable(m_Index)) {
107 if (auto variable = variableController.variableModel()->variable(m_Index)) {
108 variableController.onRequestDataLoading({variable}, m_NewRange, variable->range(),
108 variableController.onRequestDataLoading({variable}, m_NewRange, variable->range(),
109 !m_Shift);
109 !m_Shift);
110 }
110 }
111 }
111 }
112
112
113 int m_Index; ///< The index of the variable to move
113 int m_Index; ///< The index of the variable to move
114 SqpRange m_NewRange; ///< The new range of the variable
114 SqpRange m_NewRange; ///< The new range of the variable
115 bool m_Shift; ///< Performs a shift (
115 bool m_Shift; ///< Performs a shift (
116 };
116 };
117
117
118 /**
118 /**
119 * Variable synchronization/desynchronization operation in the controller
119 * Variable synchronization/desynchronization operation in the controller
120 */
120 */
121 struct Synchronize : public IOperation {
121 struct Synchronize : public IOperation {
122 explicit Synchronize(int index, QUuid syncId, bool synchronize = true)
122 explicit Synchronize(int index, QUuid syncId, bool synchronize = true)
123 : m_Index{index}, m_SyncId{syncId}, m_Synchronize{synchronize}
123 : m_Index{index}, m_SyncId{syncId}, m_Synchronize{synchronize}
124 {
124 {
125 }
125 }
126
126
127 void exec(VariableController &variableController) const override
127 void exec(VariableController &variableController) const override
128 {
128 {
129 if (auto variable = variableController.variableModel()->variable(m_Index)) {
129 if (auto variable = variableController.variableModel()->variable(m_Index)) {
130 if (m_Synchronize) {
130 if (m_Synchronize) {
131 variableController.onAddSynchronized(variable, m_SyncId);
131 variableController.onAddSynchronized(variable, m_SyncId);
132 }
132 }
133 else {
133 else {
134 variableController.desynchronize(variable, m_SyncId);
134 variableController.desynchronize(variable, m_SyncId);
135 }
135 }
136 }
136 }
137 }
137 }
138
138
139 int m_Index; ///< The index of the variable to sync/desync
139 int m_Index; ///< The index of the variable to sync/desync
140 QUuid m_SyncId; ///< The synchronization group of the variable
140 QUuid m_SyncId; ///< The synchronization group of the variable
141 bool m_Synchronize; ///< Performs sync or desync operation
141 bool m_Synchronize; ///< Performs sync or desync operation
142 };
142 };
143
143
144 /**
144 /**
145 * Test Iteration
145 * Test Iteration
146 *
146 *
147 * A test iteration includes an operation to be performed, and a set of expected ranges after each
147 * A test iteration includes an operation to be performed, and a set of expected ranges after each
148 * operation. Each range is tested after the operation to ensure that:
148 * operation. Each range is tested after the operation to ensure that:
149 * - the range of the variable is the expected range
149 * - the range of the variable is the expected range
150 * - the data of the variable are those generated for the expected range
150 * - the data of the variable are those generated for the expected range
151 */
151 */
152 struct Iteration {
152 struct Iteration {
153 std::shared_ptr<IOperation> m_Operation; ///< Operation to perform
153 std::shared_ptr<IOperation> m_Operation; ///< Operation to perform
154 std::map<int, SqpRange> m_ExpectedRanges; ///< Expected ranges (by variable index)
154 std::map<int, SqpRange> m_ExpectedRanges; ///< Expected ranges (by variable index)
155 };
155 };
156
156
157 using Iterations = std::vector<Iteration>;
157 using Iterations = std::vector<Iteration>;
158
158
159 } // namespace
159 } // namespace
160
160
161 Q_DECLARE_METATYPE(Iterations)
161 Q_DECLARE_METATYPE(Iterations)
162
162
163 class TestVariableSync : public QObject {
163 class TestVariableSync : public QObject {
164 Q_OBJECT
164 Q_OBJECT
165
165
166 private slots:
166 private slots:
167 /// Input data for @sa testSync()
167 /// Input data for @sa testSync()
168 void testSync_data();
168 void testSync_data();
169
169
170 /// Tests synchronization between variables through several operations
170 /// Tests synchronization between variables through several operations
171 void testSync();
171 void testSync();
172 };
172 };
173
173
174 void TestVariableSync::testSync_data()
174 void TestVariableSync::testSync_data()
175 {
175 {
176 // ////////////// //
176 // ////////////// //
177 // Test structure //
177 // Test structure //
178 // ////////////// //
178 // ////////////// //
179
179
180 QTest::addColumn<QUuid>("syncId");
180 QTest::addColumn<QUuid>("syncId");
181 QTest::addColumn<SqpRange>("initialRange");
181 QTest::addColumn<SqpRange>("initialRange");
182 QTest::addColumn<Iterations>("iterations");
182 QTest::addColumn<Iterations>("iterations");
183
183
184 // ////////// //
184 // ////////// //
185 // Test cases //
185 // Test cases //
186 // ////////// //
186 // ////////// //
187
187
188 /// @todo
188 // Id used to synchronize variables in the controller
189 auto syncId = QUuid::createUuid();
190
191 /// Generates a range according to a start time and a end time (the date is the same)
192 auto range = [](const QTime &startTime, const QTime &endTime) {
193 return SqpRange{DateUtils::secondsSinceEpoch(QDateTime{{2017, 1, 1}, startTime, Qt::UTC}),
194 DateUtils::secondsSinceEpoch(QDateTime{{2017, 1, 1}, endTime, Qt::UTC})};
195 };
196
197 auto initialRange = range({12, 0}, {13, 0});
198
199 Iterations iterations{};
200 // Creates variables var0, var1 and var2
201 iterations.push_back({std::make_shared<Create>(0), {{0, initialRange}}});
202 iterations.push_back({std::make_shared<Create>(1), {{0, initialRange}, {1, initialRange}}});
203 iterations.push_back(
204 {std::make_shared<Create>(2), {{0, initialRange}, {1, initialRange}, {2, initialRange}}});
205
206 // Adds variables into the sync group (ranges don't need to be tested here)
207 iterations.push_back({std::make_shared<Synchronize>(0, syncId)});
208 iterations.push_back({std::make_shared<Synchronize>(1, syncId)});
209 iterations.push_back({std::make_shared<Synchronize>(2, syncId)});
210
211 // Moves var0: ranges of var0, var1 and var2 change
212 auto newRange = range({12, 30}, {13, 30});
213 iterations.push_back(
214 {std::make_shared<Move>(0, newRange), {{0, newRange}, {1, newRange}, {2, newRange}}});
215
216 // Moves var1: ranges of var0, var1 and var2 change
217 newRange = range({13, 0}, {14, 0});
218 iterations.push_back(
219 {std::make_shared<Move>(0, newRange), {{0, newRange}, {1, newRange}, {2, newRange}}});
220
221 // Moves var2: ranges of var0, var1 and var2 change
222 newRange = range({13, 30}, {14, 30});
223 iterations.push_back(
224 {std::make_shared<Move>(0, newRange), {{0, newRange}, {1, newRange}, {2, newRange}}});
225
226 // Desyncs var2 and moves var0:
227 // - ranges of var0 and var1 change
228 // - range of var2 doesn't change anymore
229 auto var2Range = newRange;
230 newRange = range({13, 45}, {14, 45});
231 iterations.push_back({std::make_shared<Synchronize>(2, syncId, false)});
232 iterations.push_back(
233 {std::make_shared<Move>(0, newRange), {{0, newRange}, {1, newRange}, {2, var2Range}}});
234
235 // Shifts var0: although var1 is synchronized with var0, its range doesn't change
236 auto var1Range = newRange;
237 newRange = range({14, 45}, {15, 45});
238 iterations.push_back({std::make_shared<Move>(0, newRange, true),
239 {{0, newRange}, {1, var1Range}, {2, var2Range}}});
240
241 // Moves var0 through several operations:
242 // - range of var0 changes
243 // - range or var1 changes according to the previous shift (one hour)
244 auto moveVar0 = [&iterations](const auto &var0NewRange, const auto &var1ExpectedRange) {
245 iterations.push_back(
246 {std::make_shared<Move>(0, var0NewRange), {{0, var0NewRange}, {1, var1ExpectedRange}}});
247 };
248 // Pan left
249 moveVar0(range({14, 30}, {15, 30}), range({13, 30}, {14, 30}));
250 // Pan right
251 moveVar0(range({16, 0}, {17, 0}), range({15, 0}, {16, 0}));
252 // Zoom in
253 moveVar0(range({16, 30}, {16, 45}), range({15, 30}, {15, 45}));
254 // Zoom out
255 moveVar0(range({12, 0}, {18, 0}), range({11, 0}, {17, 0}));
256
257 QTest::newRow("sync1") << syncId << initialRange << std::move(iterations);
189 }
258 }
190
259
191 void TestVariableSync::testSync()
260 void TestVariableSync::testSync()
192 {
261 {
193 // Inits controllers
262 // Inits controllers
194 TimeController timeController{};
263 TimeController timeController{};
195 VariableController variableController{};
264 VariableController variableController{};
196 variableController.setTimeController(&timeController);
265 variableController.setTimeController(&timeController);
197
266
198 QFETCH(QUuid, syncId);
267 QFETCH(QUuid, syncId);
199 QFETCH(SqpRange, initialRange);
268 QFETCH(SqpRange, initialRange);
200 timeController.onTimeToUpdate(initialRange);
269 timeController.onTimeToUpdate(initialRange);
201
270
202 // Synchronization group used
271 // Synchronization group used
203 variableController.onAddSynchronizationGroupId(syncId);
272 variableController.onAddSynchronizationGroupId(syncId);
204
273
205 // For each iteration:
274 // For each iteration:
206 // - execute operation
275 // - execute operation
207 // - compare the variables' state to the expected states
276 // - compare the variables' state to the expected states
208 QFETCH(Iterations, iterations);
277 QFETCH(Iterations, iterations);
209 for (const auto &iteration : iterations) {
278 for (const auto &iteration : iterations) {
210 iteration.m_Operation->exec(variableController);
279 iteration.m_Operation->exec(variableController);
211 QTest::qWait(OPERATION_DELAY);
280 QTest::qWait(OPERATION_DELAY);
212
281
213 for (const auto &expectedRangeEntry : iteration.m_ExpectedRanges) {
282 for (const auto &expectedRangeEntry : iteration.m_ExpectedRanges) {
214 auto variableIndex = expectedRangeEntry.first;
283 auto variableIndex = expectedRangeEntry.first;
215 auto expectedRange = expectedRangeEntry.second;
284 auto expectedRange = expectedRangeEntry.second;
216
285
217 // Gets the variable in the controller
286 // Gets the variable in the controller
218 auto variable = variableController.variableModel()->variable(variableIndex);
287 auto variable = variableController.variableModel()->variable(variableIndex);
219
288
220 // Compares variable's range to the expected range
289 // Compares variable's range to the expected range
221 QVERIFY(variable != nullptr);
290 QVERIFY(variable != nullptr);
222 auto range = variable->range();
291 auto range = variable->range();
223 QCOMPARE(range, expectedRange);
292 QCOMPARE(range, expectedRange);
224
293
225 // Compares variable's data with values expected for its range
294 // Compares variable's data with values expected for its range
226 auto dataSeries = variable->dataSeries();
295 auto dataSeries = variable->dataSeries();
227 QVERIFY(dataSeries != nullptr);
296 QVERIFY(dataSeries != nullptr);
228
297
229 auto it = dataSeries->xAxisRange(range.m_TStart, range.m_TEnd);
298 auto it = dataSeries->xAxisRange(range.m_TStart, range.m_TEnd);
230 auto expectedValues = values(range);
299 auto expectedValues = values(range);
231 QVERIFY(std::equal(it.first, it.second, expectedValues.cbegin(), expectedValues.cend(),
300 QVERIFY(std::equal(it.first, it.second, expectedValues.cbegin(), expectedValues.cend(),
232 [](const auto &dataSeriesIt, const auto &expectedValue) {
301 [](const auto &dataSeriesIt, const auto &expectedValue) {
233 return dataSeriesIt.value() == expectedValue;
302 return dataSeriesIt.value() == expectedValue;
234 }));
303 }));
235 }
304 }
236 }
305 }
237 }
306 }
238
307
239 QTEST_MAIN(TestVariableSync)
308 QTEST_MAIN(TestVariableSync)
240
309
241 #include "TestVariableSync.moc"
310 #include "TestVariableSync.moc"
General Comments 0
You need to be logged in to leave comments. Login now