Auto status change to "Under Review"
@@ -1,553 +1,637 | |||
|
1 | 1 | #include <QObject> |
|
2 | 2 | #include <QtTest> |
|
3 | 3 | |
|
4 | 4 | #include <memory> |
|
5 | 5 | |
|
6 | 6 | #include <Data/DataProviderParameters.h> |
|
7 | 7 | #include <Data/IDataProvider.h> |
|
8 | 8 | #include <Data/ScalarSeries.h> |
|
9 | 9 | #include <Time/TimeController.h> |
|
10 | 10 | #include <Variable/Variable.h> |
|
11 | 11 | #include <Variable/VariableController.h> |
|
12 | 12 | #include <Variable/VariableModel.h> |
|
13 | 13 | |
|
14 | 14 | namespace { |
|
15 | 15 | |
|
16 | 16 | /// Delay after each operation on the variable before validating it (in ms) |
|
17 | 17 | const auto OPERATION_DELAY = 100; |
|
18 | 18 | |
|
19 | 19 | /** |
|
20 | 20 | * Generates values according to a range. The value generated for a time t is the number of seconds |
|
21 | 21 | * of difference between t and a reference value (which is midnight -> 00:00:00) |
|
22 | 22 | * |
|
23 | 23 | * Example: For a range between 00:00:10 and 00:00:20, the generated values are |
|
24 | 24 | * {10,11,12,13,14,15,16,17,18,19,20} |
|
25 | 25 | */ |
|
26 | 26 | std::vector<double> values(const SqpRange &range) |
|
27 | 27 | { |
|
28 | 28 | QTime referenceTime{0, 0}; |
|
29 | 29 | |
|
30 | 30 | std::vector<double> result{}; |
|
31 | 31 | |
|
32 | 32 | for (auto i = range.m_TStart; i <= range.m_TEnd; ++i) { |
|
33 | 33 | auto time = DateUtils::dateTime(i).time(); |
|
34 | 34 | result.push_back(referenceTime.secsTo(time)); |
|
35 | 35 | } |
|
36 | 36 | |
|
37 | 37 | return result; |
|
38 | 38 | } |
|
39 | 39 | |
|
40 | void validateRanges(VariableController &variableController, | |
|
41 | const std::map<int, SqpRange> &expectedRanges) | |
|
42 | { | |
|
43 | for (const auto &expectedRangeEntry : expectedRanges) { | |
|
44 | auto variableIndex = expectedRangeEntry.first; | |
|
45 | auto expectedRange = expectedRangeEntry.second; | |
|
46 | ||
|
47 | // Gets the variable in the controller | |
|
48 | auto variable = variableController.variableModel()->variable(variableIndex); | |
|
49 | ||
|
50 | // Compares variable's range to the expected range | |
|
51 | QVERIFY(variable != nullptr); | |
|
52 | auto range = variable->range(); | |
|
53 | qInfo() << "range vs expected range" << range << expectedRange; | |
|
54 | QCOMPARE(range, expectedRange); | |
|
55 | ||
|
56 | // Compares variable's data with values expected for its range | |
|
57 | auto dataSeries = variable->dataSeries(); | |
|
58 | QVERIFY(dataSeries != nullptr); | |
|
59 | ||
|
60 | auto it = dataSeries->xAxisRange(range.m_TStart, range.m_TEnd); | |
|
61 | auto expectedValues = values(range); | |
|
62 | qInfo() << std::distance(it.first, it.second) << expectedValues.size(); | |
|
63 | QVERIFY(std::equal(it.first, it.second, expectedValues.cbegin(), expectedValues.cend(), | |
|
64 | [](const auto &dataSeriesIt, const auto &expectedValue) { | |
|
65 | return dataSeriesIt.value() == expectedValue; | |
|
66 | })); | |
|
67 | } | |
|
68 | } | |
|
69 | ||
|
40 | 70 | /// Provider used for the tests |
|
41 | 71 | class TestProvider : public IDataProvider { |
|
42 | 72 | std::shared_ptr<IDataProvider> clone() const { return std::make_shared<TestProvider>(); } |
|
43 | 73 | |
|
44 | 74 | void requestDataLoading(QUuid acqIdentifier, const DataProviderParameters ¶meters) override |
|
45 | 75 | { |
|
46 | 76 | const auto &ranges = parameters.m_Times; |
|
47 | 77 | |
|
48 | 78 | for (const auto &range : ranges) { |
|
49 | 79 | // Generates data series |
|
50 | 80 | auto valuesData = values(range); |
|
51 | 81 | |
|
52 | 82 | std::vector<double> xAxisData{}; |
|
53 | 83 | for (auto i = range.m_TStart; i <= range.m_TEnd; ++i) { |
|
54 | 84 | xAxisData.push_back(i); |
|
55 | 85 | } |
|
56 | 86 | |
|
57 | 87 | auto dataSeries = std::make_shared<ScalarSeries>( |
|
58 | 88 | std::move(xAxisData), std::move(valuesData), Unit{"t", true}, Unit{}); |
|
59 | 89 | |
|
60 | 90 | emit dataProvided(acqIdentifier, dataSeries, range); |
|
61 | 91 | } |
|
62 | 92 | } |
|
63 | 93 | |
|
64 | 94 | void requestDataAborting(QUuid acqIdentifier) override |
|
65 | 95 | { |
|
66 | 96 | // Does nothing |
|
67 | 97 | } |
|
68 | 98 | }; |
|
69 | 99 | |
|
70 | 100 | /** |
|
71 | 101 | * Interface representing an operation performed on a variable controller. |
|
72 | 102 | * This interface is used in tests to apply a set of operations and check the status of the |
|
73 | 103 | * controller after each operation |
|
74 | 104 | */ |
|
75 | 105 | struct IOperation { |
|
76 | 106 | virtual ~IOperation() = default; |
|
77 | 107 | /// Executes the operation on the variable controller |
|
78 | 108 | virtual void exec(VariableController &variableController) const = 0; |
|
79 | 109 | }; |
|
80 | 110 | |
|
81 | 111 | /** |
|
82 | 112 | *Variable creation operation in the controller |
|
83 | 113 | */ |
|
84 | 114 | struct Create : public IOperation { |
|
85 | 115 | explicit Create(int index) : m_Index{index} {} |
|
86 | 116 | |
|
87 | 117 | void exec(VariableController &variableController) const override |
|
88 | 118 | { |
|
89 | 119 | auto variable = variableController.createVariable(QString::number(m_Index), {}, |
|
90 | 120 | std::make_unique<TestProvider>()); |
|
91 | 121 | } |
|
92 | 122 | |
|
93 | 123 | int m_Index; ///< The index of the variable to create in the controller |
|
94 | 124 | }; |
|
95 | 125 | |
|
96 | 126 | /** |
|
97 | 127 | * Variable move/shift operation in the controller |
|
98 | 128 | */ |
|
99 | 129 | struct Move : public IOperation { |
|
100 | explicit Move(int index, const SqpRange &newRange, bool shift = false) | |
|
101 | : m_Index{index}, m_NewRange{newRange}, m_Shift{shift} | |
|
130 | explicit Move(int index, const SqpRange &newRange, bool shift = false, int delayMS = 10) | |
|
131 | : m_Index{index}, m_NewRange{newRange}, m_Shift{shift}, m_DelayMs{delayMS} | |
|
102 | 132 | { |
|
103 | 133 | } |
|
104 | 134 | |
|
105 | 135 | void exec(VariableController &variableController) const override |
|
106 | 136 | { |
|
107 | 137 | if (auto variable = variableController.variableModel()->variable(m_Index)) { |
|
108 | 138 | variableController.onRequestDataLoading({variable}, m_NewRange, !m_Shift); |
|
139 | QTest::qWait(m_DelayMs); | |
|
109 | 140 | } |
|
110 | 141 | } |
|
111 | 142 | |
|
112 | 143 | int m_Index; ///< The index of the variable to move |
|
113 | 144 | SqpRange m_NewRange; ///< The new range of the variable |
|
114 | 145 | bool m_Shift; ///< Performs a shift ( |
|
146 | int m_DelayMs; ///< wait the delay after running the request ( | |
|
115 | 147 | }; |
|
116 | 148 | |
|
117 | 149 | /** |
|
118 | 150 | * Variable synchronization/desynchronization operation in the controller |
|
119 | 151 | */ |
|
120 | 152 | struct Synchronize : public IOperation { |
|
121 | 153 | explicit Synchronize(int index, QUuid syncId, bool synchronize = true) |
|
122 | 154 | : m_Index{index}, m_SyncId{syncId}, m_Synchronize{synchronize} |
|
123 | 155 | { |
|
124 | 156 | } |
|
125 | 157 | |
|
126 | 158 | void exec(VariableController &variableController) const override |
|
127 | 159 | { |
|
128 | 160 | if (auto variable = variableController.variableModel()->variable(m_Index)) { |
|
129 | 161 | if (m_Synchronize) { |
|
130 | 162 | variableController.onAddSynchronized(variable, m_SyncId); |
|
131 | 163 | } |
|
132 | 164 | else { |
|
133 | 165 | variableController.desynchronize(variable, m_SyncId); |
|
134 | 166 | } |
|
135 | 167 | } |
|
136 | 168 | } |
|
137 | 169 | |
|
138 | 170 | int m_Index; ///< The index of the variable to sync/desync |
|
139 | 171 | QUuid m_SyncId; ///< The synchronization group of the variable |
|
140 | 172 | bool m_Synchronize; ///< Performs sync or desync operation |
|
141 | 173 | }; |
|
142 | 174 | |
|
143 | 175 | /** |
|
144 | 176 | * Test Iteration |
|
145 | 177 | * |
|
146 | 178 | * A test iteration includes an operation to be performed, and a set of expected ranges after each |
|
147 | 179 | * operation. Each range is tested after the operation to ensure that: |
|
148 | 180 | * - the range of the variable is the expected range |
|
149 | 181 | * - the data of the variable are those generated for the expected range |
|
150 | 182 | */ |
|
151 | 183 | struct Iteration { |
|
152 | 184 | std::shared_ptr<IOperation> m_Operation; ///< Operation to perform |
|
153 | 185 | std::map<int, SqpRange> m_ExpectedRanges; ///< Expected ranges (by variable index) |
|
154 | 186 | }; |
|
155 | 187 | |
|
156 | 188 | using Iterations = std::vector<Iteration>; |
|
157 | 189 | |
|
158 | 190 | } // namespace |
|
159 | 191 | |
|
160 | 192 | Q_DECLARE_METATYPE(Iterations) |
|
161 | 193 | |
|
162 | 194 | class TestVariableSync : public QObject { |
|
163 | 195 | Q_OBJECT |
|
164 | 196 | |
|
165 | 197 | private slots: |
|
166 | 198 | /// Input data for @sa testSync() |
|
167 | 199 | void testSync_data(); |
|
168 | 200 | |
|
169 | 201 | /// Input data for @sa testSyncWithAborting() |
|
170 | 202 | void testSyncWithAborting_data(); |
|
171 | 203 | |
|
172 | /// Tests synchronization between variables through several operations with aborting | |
|
204 | /// Input data for @sa testSyncOneVar() | |
|
205 | void testSyncOneVar_data(); | |
|
206 | ||
|
207 | /// Tests synchronization between variables through several operations with automatic aborting | |
|
173 | 208 | void testSyncWithAborting(); |
|
174 | 209 | |
|
175 | 210 | /// Tests synchronization between variables through several operations |
|
176 | 211 | void testSync(); |
|
212 | ||
|
213 | /// Tests synchronization between variables through several operations | |
|
214 | void testSyncOneVar(); | |
|
177 | 215 | }; |
|
178 | 216 | |
|
179 | 217 | namespace { |
|
180 | 218 | |
|
181 | 219 | void testSyncCase1() |
|
182 | 220 | { |
|
183 | 221 | // Id used to synchronize variables in the controller |
|
184 | 222 | auto syncId = QUuid::createUuid(); |
|
185 | 223 | |
|
186 | 224 | /// Generates a range according to a start time and a end time (the date is the same) |
|
187 | 225 | auto range = [](const QTime &startTime, const QTime &endTime) { |
|
188 | 226 | return SqpRange{DateUtils::secondsSinceEpoch(QDateTime{{2017, 1, 1}, startTime, Qt::UTC}), |
|
189 | 227 | DateUtils::secondsSinceEpoch(QDateTime{{2017, 1, 1}, endTime, Qt::UTC})}; |
|
190 | 228 | }; |
|
191 | 229 | |
|
192 | 230 | auto initialRange = range({12, 0}, {13, 0}); |
|
193 | 231 | |
|
194 | 232 | Iterations iterations{}; |
|
195 | 233 | // Creates variables var0, var1 and var2 |
|
196 | 234 | iterations.push_back({std::make_shared<Create>(0), {{0, initialRange}}}); |
|
197 | 235 | iterations.push_back({std::make_shared<Create>(1), {{0, initialRange}, {1, initialRange}}}); |
|
198 | 236 | iterations.push_back( |
|
199 | 237 | {std::make_shared<Create>(2), {{0, initialRange}, {1, initialRange}, {2, initialRange}}}); |
|
200 | 238 | |
|
201 | 239 | // Adds variables into the sync group (ranges don't need to be tested here) |
|
202 | 240 | iterations.push_back({std::make_shared<Synchronize>(0, syncId)}); |
|
203 | 241 | iterations.push_back({std::make_shared<Synchronize>(1, syncId)}); |
|
204 | 242 | iterations.push_back({std::make_shared<Synchronize>(2, syncId)}); |
|
205 | 243 | |
|
206 | 244 | // Moves var0: ranges of var0, var1 and var2 change |
|
207 | 245 | auto newRange = range({12, 30}, {13, 30}); |
|
208 | 246 | iterations.push_back( |
|
209 | 247 | {std::make_shared<Move>(0, newRange), {{0, newRange}, {1, newRange}, {2, newRange}}}); |
|
210 | 248 | |
|
211 | 249 | // Moves var1: ranges of var0, var1 and var2 change |
|
212 | 250 | newRange = range({13, 0}, {14, 0}); |
|
213 | 251 | iterations.push_back( |
|
214 | 252 | {std::make_shared<Move>(0, newRange), {{0, newRange}, {1, newRange}, {2, newRange}}}); |
|
215 | 253 | |
|
216 | 254 | // Moves var2: ranges of var0, var1 and var2 change |
|
217 | 255 | newRange = range({13, 30}, {14, 30}); |
|
218 | 256 | iterations.push_back( |
|
219 | 257 | {std::make_shared<Move>(0, newRange), {{0, newRange}, {1, newRange}, {2, newRange}}}); |
|
220 | 258 | |
|
221 | 259 | // Desyncs var2 and moves var0: |
|
222 | 260 | // - ranges of var0 and var1 change |
|
223 | 261 | // - range of var2 doesn't change anymore |
|
224 | 262 | auto var2Range = newRange; |
|
225 | 263 | newRange = range({13, 45}, {14, 45}); |
|
226 | 264 | iterations.push_back({std::make_shared<Synchronize>(2, syncId, false)}); |
|
227 | 265 | iterations.push_back( |
|
228 | 266 | {std::make_shared<Move>(0, newRange), {{0, newRange}, {1, newRange}, {2, var2Range}}}); |
|
229 | 267 | |
|
230 | 268 | // Shifts var0: although var1 is synchronized with var0, its range doesn't change |
|
231 | 269 | auto var1Range = newRange; |
|
232 | 270 | newRange = range({14, 45}, {15, 45}); |
|
233 | 271 | iterations.push_back({std::make_shared<Move>(0, newRange, true), |
|
234 | 272 | {{0, newRange}, {1, var1Range}, {2, var2Range}}}); |
|
235 | 273 | |
|
236 | 274 | // Moves var0 through several operations: |
|
237 | 275 | // - range of var0 changes |
|
238 | 276 | // - range or var1 changes according to the previous shift (one hour) |
|
239 | 277 | auto moveVar0 = [&iterations](const auto &var0NewRange, const auto &var1ExpectedRange) { |
|
240 | 278 | iterations.push_back( |
|
241 | 279 | {std::make_shared<Move>(0, var0NewRange), {{0, var0NewRange}, {1, var1ExpectedRange}}}); |
|
242 | 280 | }; |
|
243 | 281 | |
|
244 | 282 | // Pan left |
|
245 | 283 | moveVar0(range({14, 30}, {15, 30}), range({13, 30}, {14, 30})); |
|
246 | 284 | // Pan right |
|
247 | 285 | moveVar0(range({16, 0}, {17, 0}), range({15, 0}, {16, 0})); |
|
248 | 286 | // Zoom in |
|
249 | 287 | moveVar0(range({16, 30}, {16, 45}), range({15, 30}, {15, 45})); |
|
250 | 288 | // Zoom out |
|
251 | 289 | moveVar0(range({16, 15}, {17, 0}), range({15, 15}, {16, 0})); |
|
252 | 290 | |
|
253 | 291 | QTest::newRow("sync1") << syncId << initialRange << std::move(iterations) << 200; |
|
254 | 292 | } |
|
255 | 293 | |
|
256 | 294 | void testSyncCase1WithAborting() |
|
257 | 295 | { |
|
258 | 296 | // Id used to synchronize variables in the controller |
|
259 | 297 | auto syncId = QUuid::createUuid(); |
|
260 | 298 | |
|
261 | 299 | /// Generates a range according to a start time and a end time (the date is the same) |
|
262 | 300 | auto range = [](const QTime &startTime, const QTime &endTime) { |
|
263 | 301 | return SqpRange{DateUtils::secondsSinceEpoch(QDateTime{{2017, 1, 1}, startTime, Qt::UTC}), |
|
264 | 302 | DateUtils::secondsSinceEpoch(QDateTime{{2017, 1, 1}, endTime, Qt::UTC})}; |
|
265 | 303 | }; |
|
266 | 304 | |
|
267 | 305 | auto initialRange = range({12, 0}, {13, 0}); |
|
268 | 306 | |
|
269 | 307 | Iterations creations{}; |
|
270 | 308 | // Creates variables var0, var1 and var2 |
|
271 | 309 | creations.push_back({std::make_shared<Create>(0), {{0, initialRange}}}); |
|
272 | 310 | creations.push_back({std::make_shared<Create>(1), {{0, initialRange}, {1, initialRange}}}); |
|
273 | 311 | |
|
274 | 312 | // Adds variables into the sync group (ranges don't need to be tested here) |
|
275 | 313 | Iterations iterations{}; |
|
276 | 314 | iterations.push_back({std::make_shared<Synchronize>(0, syncId)}); |
|
277 | 315 | iterations.push_back({std::make_shared<Synchronize>(1, syncId)}); |
|
278 | 316 | |
|
279 | 317 | // Moves var0: ranges of var0, var1 |
|
280 | 318 | auto currentRange = range({12, 30}, {13, 30}); |
|
281 | 319 | iterations.push_back( |
|
282 | 320 | {std::make_shared<Move>(0, currentRange), {{0, currentRange}, {1, currentRange}}}); |
|
283 | 321 | |
|
284 | 322 | // Moves var0: ranges of var0, var1 |
|
285 | 323 | auto pendingRange = range({13, 0}, {14, 0}); |
|
286 | 324 | iterations.push_back( |
|
287 | 325 | {std::make_shared<Move>(0, pendingRange), {{0, pendingRange}, {1, pendingRange}}}); |
|
288 | 326 | |
|
289 | 327 | // Moves var0: ranges of var0, var1 |
|
290 | 328 | pendingRange = range({13, 30}, {14, 30}); |
|
291 | 329 | iterations.push_back( |
|
292 | 330 | {std::make_shared<Move>(0, pendingRange), {{0, pendingRange}, {1, pendingRange}}}); |
|
293 | 331 | |
|
294 | 332 | // moves var0: |
|
295 | 333 | // - ranges of var0 and var1 change |
|
296 | 334 | auto var2Range = pendingRange; |
|
297 | 335 | pendingRange = range({13, 45}, {14, 45}); |
|
298 | 336 | iterations.push_back( |
|
299 | 337 | {std::make_shared<Move>(0, pendingRange), {{0, pendingRange}, {1, pendingRange}}}); |
|
300 | 338 | |
|
301 | 339 | // Shifts var0: although var1 is synchronized with var0, its range doesn't change |
|
302 | 340 | auto var1Range = pendingRange; |
|
303 | 341 | pendingRange = range({14, 45}, {15, 45}); |
|
304 | 342 | iterations.push_back( |
|
305 | 343 | {std::make_shared<Move>(0, pendingRange, false), {{0, pendingRange}, {1, pendingRange}}}); |
|
306 | 344 | |
|
307 | 345 | // Moves var0 through several operations: |
|
308 | 346 | // - range of var0 changes |
|
309 | 347 | // - range or var1 changes according to the previous shift (one hour) |
|
310 | 348 | auto moveVar0 = [&iterations](const auto &var0NewRange, const auto &var1ExpectedRange) { |
|
311 | 349 | iterations.push_back( |
|
312 | 350 | {std::make_shared<Move>(0, var0NewRange), {{0, var0NewRange}, {1, var1ExpectedRange}}}); |
|
313 | 351 | }; |
|
314 | 352 | |
|
315 | // auto oldRange = newRange; | |
|
316 | // newRange = range({14, 30}, {15, 30}); | |
|
317 | // auto expectedRange = oldRange; | |
|
318 | // iterations.push_back( | |
|
319 | // {std::make_shared<Move>(0, newRange), {{0, oldRange}, {1, expectedRange}}}); | |
|
320 | ||
|
321 | 353 | // Pan left |
|
322 | 354 | moveVar0(range({14, 30}, {15, 30}), range({14, 30}, {15, 30})); |
|
323 | 355 | // Pan right |
|
324 | 356 | moveVar0(range({16, 0}, {17, 0}), range({16, 0}, {17, 0})); |
|
325 | 357 | // Zoom in |
|
326 | 358 | moveVar0(range({16, 30}, {16, 45}), range({16, 30}, {16, 45})); |
|
327 | 359 | // Zoom out |
|
328 | 360 | moveVar0(range({16, 15}, {17, 0}), range({16, 15}, {17, 0})); |
|
329 | 361 | |
|
330 | 362 | QTest::newRow("syncWithAborting1") << syncId << currentRange << std::move(creations) |
|
331 | 363 | << std::move(iterations) << 200; |
|
332 | 364 | } |
|
333 | 365 | |
|
334 | 366 | void testSyncCase2() |
|
335 | 367 | { |
|
336 | 368 | // Id used to synchronize variables in the controller |
|
337 | 369 | auto syncId = QUuid::createUuid(); |
|
338 | 370 | |
|
339 | 371 | /// Generates a range according to a start time and a end time (the date is the same) |
|
340 | 372 | auto dateTime = [](int year, int month, int day, int hours, int minutes, int seconds) { |
|
341 | 373 | return DateUtils::secondsSinceEpoch( |
|
342 | 374 | QDateTime{{year, month, day}, QTime{hours, minutes, seconds}, Qt::UTC}); |
|
343 | 375 | }; |
|
344 | 376 | |
|
345 | 377 | auto initialRange = SqpRange{dateTime(2017, 1, 1, 12, 0, 0), dateTime(2017, 1, 1, 13, 0, 0)}; |
|
346 | 378 | |
|
347 | 379 | Iterations iterations{}; |
|
348 | 380 | // Creates variables var0 and var1 |
|
349 | 381 | iterations.push_back({std::make_shared<Create>(0), {{0, initialRange}}}); |
|
350 | 382 | iterations.push_back({std::make_shared<Create>(1), {{0, initialRange}, {1, initialRange}}}); |
|
351 | 383 | |
|
352 | 384 | // Adds variables into the sync group (ranges don't need to be tested here) |
|
353 | 385 | iterations.push_back({std::make_shared<Synchronize>(0, syncId)}); |
|
354 | 386 | iterations.push_back({std::make_shared<Synchronize>(1, syncId)}); |
|
355 | 387 | |
|
356 | 388 | |
|
357 | 389 | // Moves var0 through several operations: |
|
358 | 390 | // - range of var0 changes |
|
359 | 391 | // - range or var1 changes according to the previous shift (one hour) |
|
360 | 392 | auto moveVar0 = [&iterations](const auto &var0NewRange) { |
|
361 | 393 | iterations.push_back( |
|
362 | 394 | {std::make_shared<Move>(0, var0NewRange), {{0, var0NewRange}, {1, var0NewRange}}}); |
|
363 | 395 | }; |
|
364 | 396 | moveVar0(SqpRange{dateTime(2017, 1, 1, 12, 0, 0), dateTime(2017, 1, 1, 13, 0, 0)}); |
|
365 | 397 | moveVar0(SqpRange{dateTime(2017, 1, 1, 14, 0, 0), dateTime(2017, 1, 1, 15, 0, 0)}); |
|
366 | 398 | moveVar0(SqpRange{dateTime(2017, 1, 1, 8, 0, 0), dateTime(2017, 1, 1, 9, 0, 0)}); |
|
367 | 399 | // moveVar0(SqpRange{dateTime(2017, 1, 1, 7, 30, 0), dateTime(2017, 1, 1, 9, 30, 0)}); |
|
368 | 400 | moveVar0(SqpRange{dateTime(2017, 1, 1, 2, 0, 0), dateTime(2017, 1, 1, 4, 0, 0)}); |
|
369 | 401 | moveVar0(SqpRange{dateTime(2017, 1, 1, 6, 0, 0), dateTime(2017, 1, 1, 8, 0, 0)}); |
|
370 | 402 | |
|
371 | 403 | moveVar0(SqpRange{dateTime(2017, 1, 10, 6, 0, 0), dateTime(2017, 1, 15, 8, 0, 0)}); |
|
372 | 404 | moveVar0(SqpRange{dateTime(2017, 1, 17, 6, 0, 0), dateTime(2017, 1, 25, 8, 0, 0)}); |
|
373 | 405 | moveVar0(SqpRange{dateTime(2017, 1, 2, 6, 0, 0), dateTime(2017, 1, 8, 8, 0, 0)}); |
|
374 | 406 | |
|
375 | 407 | moveVar0(SqpRange{dateTime(2017, 4, 10, 6, 0, 0), dateTime(2017, 6, 15, 8, 0, 0)}); |
|
376 | 408 | moveVar0(SqpRange{dateTime(2017, 1, 17, 6, 0, 0), dateTime(2017, 2, 25, 8, 0, 0)}); |
|
377 | 409 | moveVar0(SqpRange{dateTime(2017, 7, 2, 6, 0, 0), dateTime(2017, 10, 8, 8, 0, 0)}); |
|
378 | 410 | moveVar0(SqpRange{dateTime(2017, 4, 10, 6, 0, 0), dateTime(2017, 6, 15, 8, 0, 0)}); |
|
379 | 411 | moveVar0(SqpRange{dateTime(2017, 1, 17, 6, 0, 0), dateTime(2017, 2, 25, 8, 0, 0)}); |
|
380 | 412 | moveVar0(SqpRange{dateTime(2017, 7, 2, 6, 0, 0), dateTime(2017, 10, 8, 8, 0, 0)}); |
|
381 | 413 | moveVar0(SqpRange{dateTime(2017, 4, 10, 6, 0, 0), dateTime(2017, 6, 15, 8, 0, 0)}); |
|
382 | 414 | moveVar0(SqpRange{dateTime(2017, 1, 17, 6, 0, 0), dateTime(2017, 2, 25, 8, 0, 0)}); |
|
383 | 415 | moveVar0(SqpRange{dateTime(2017, 7, 2, 6, 0, 0), dateTime(2017, 10, 8, 8, 0, 0)}); |
|
384 | 416 | moveVar0(SqpRange{dateTime(2017, 4, 10, 6, 0, 0), dateTime(2017, 6, 15, 8, 0, 0)}); |
|
385 | 417 | moveVar0(SqpRange{dateTime(2017, 1, 17, 6, 0, 0), dateTime(2017, 2, 25, 8, 0, 0)}); |
|
386 | 418 | moveVar0(SqpRange{dateTime(2017, 7, 2, 6, 0, 0), dateTime(2017, 10, 8, 8, 0, 0)}); |
|
387 | 419 | |
|
388 | 420 | |
|
389 | 421 | QTest::newRow("sync2") << syncId << initialRange << iterations << 4000; |
|
390 | 422 | // QTest::newRow("sync3") << syncId << initialRange << iterations << 5000; |
|
391 | 423 | } |
|
424 | ||
|
425 | void testSyncOnVarCase1() | |
|
426 | { | |
|
427 | // Id used to synchronize variables in the controller | |
|
428 | auto syncId = QUuid::createUuid(); | |
|
429 | ||
|
430 | /// Generates a range according to a start time and a end time (the date is the same) | |
|
431 | auto range = [](const QTime &startTime, const QTime &endTime) { | |
|
432 | return SqpRange{DateUtils::secondsSinceEpoch(QDateTime{{2017, 1, 1}, startTime, Qt::UTC}), | |
|
433 | DateUtils::secondsSinceEpoch(QDateTime{{2017, 1, 1}, endTime, Qt::UTC})}; | |
|
434 | }; | |
|
435 | ||
|
436 | auto initialRange = range({12, 0}, {13, 0}); | |
|
437 | ||
|
438 | Iterations creations{}; | |
|
439 | // Creates variables var0, var1 and var2 | |
|
440 | creations.push_back({std::make_shared<Create>(0), {{0, initialRange}}}); | |
|
441 | ||
|
442 | Iterations synchronization{}; | |
|
443 | // Adds variables into the sync group (ranges don't need to be tested here) | |
|
444 | synchronization.push_back({std::make_shared<Synchronize>(0, syncId)}); | |
|
445 | ||
|
446 | Iterations iterations{}; | |
|
447 | ||
|
448 | // Moves var0 through several operations | |
|
449 | auto moveOp = [&iterations](const auto &requestedRange, const auto &expectedRange, auto delay) { | |
|
450 | iterations.push_back( | |
|
451 | {std::make_shared<Move>(0, requestedRange, true, delay), {{0, expectedRange}}}); | |
|
452 | }; | |
|
453 | ||
|
454 | // we assume here 300 ms is enough to finsh a operation | |
|
455 | int delayToFinish = 300; | |
|
456 | // jump to right, let's the operation time to finish | |
|
457 | moveOp(range({14, 30}, {15, 30}), range({14, 30}, {15, 30}), delayToFinish); | |
|
458 | // pan to right, let's the operation time to finish | |
|
459 | moveOp(range({14, 45}, {15, 45}), range({14, 45}, {15, 45}), delayToFinish); | |
|
460 | // jump to left, let's the operation time to finish | |
|
461 | moveOp(range({03, 30}, {04, 30}), range({03, 30}, {04, 30}), delayToFinish); | |
|
462 | // Pan to left, let's the operation time to finish | |
|
463 | moveOp(range({03, 10}, {04, 10}), range({03, 10}, {04, 10}), delayToFinish); | |
|
464 | // Zoom in, let's the operation time to finish | |
|
465 | moveOp(range({03, 30}, {04, 00}), range({03, 30}, {04, 00}), delayToFinish); | |
|
466 | // Zoom out left, let's the operation time to finish | |
|
467 | moveOp(range({01, 10}, {18, 10}), range({01, 10}, {18, 10}), delayToFinish); | |
|
468 | // Go back to initial range | |
|
469 | moveOp(initialRange, initialRange, delayToFinish); | |
|
470 | ||
|
471 | ||
|
472 | // jump to right, let's the operation time to finish | |
|
473 | // moveOp(range({14, 30}, {15, 30}), initialRange, delayToFinish); | |
|
474 | // Zoom out left, let's the operation time to finish | |
|
475 | moveOp(range({01, 10}, {18, 10}), initialRange, delayToFinish); | |
|
476 | // Go back to initial range | |
|
477 | moveOp(initialRange, initialRange, 300); | |
|
478 | ||
|
479 | QTest::newRow("syncOnVarCase1") << syncId << initialRange << std::move(creations) | |
|
480 | << std::move(iterations); | |
|
481 | } | |
|
392 | 482 | } |
|
393 | 483 | |
|
394 | 484 | void TestVariableSync::testSync_data() |
|
395 | 485 | { |
|
396 | 486 | // ////////////// // |
|
397 | 487 | // Test structure // |
|
398 | 488 | // ////////////// // |
|
399 | 489 | |
|
400 | 490 | QTest::addColumn<QUuid>("syncId"); |
|
401 | 491 | QTest::addColumn<SqpRange>("initialRange"); |
|
402 | 492 | QTest::addColumn<Iterations>("iterations"); |
|
403 | 493 | QTest::addColumn<int>("operationDelay"); |
|
404 | 494 | |
|
405 | 495 | // ////////// // |
|
406 | 496 | // Test cases // |
|
407 | 497 | // ////////// // |
|
408 | 498 | |
|
409 | 499 | testSyncCase1(); |
|
410 | 500 | testSyncCase2(); |
|
411 | 501 | } |
|
412 | 502 | |
|
413 | 503 | void TestVariableSync::testSyncWithAborting_data() |
|
414 | 504 | { |
|
415 | 505 | // ////////////// // |
|
416 | 506 | // Test structure // |
|
417 | 507 | // ////////////// // |
|
418 | 508 | |
|
419 | 509 | QTest::addColumn<QUuid>("syncId"); |
|
420 | 510 | QTest::addColumn<SqpRange>("initialRange"); |
|
421 | 511 | QTest::addColumn<Iterations>("creations"); |
|
422 | 512 | QTest::addColumn<Iterations>("iterations"); |
|
423 | 513 | QTest::addColumn<int>("operationDelay"); |
|
424 | 514 | |
|
425 | 515 | // ////////// // |
|
426 | 516 | // Test cases // |
|
427 | 517 | // ////////// // |
|
428 | 518 | |
|
429 | 519 | testSyncCase1WithAborting(); |
|
430 | 520 | } |
|
431 | 521 | |
|
432 | void TestVariableSync::testSync() | |
|
522 | void TestVariableSync::testSyncOneVar_data() | |
|
433 | 523 | { |
|
434 | return; | |
|
524 | // ////////////// // | |
|
525 | // Test structure // | |
|
526 | // ////////////// // | |
|
527 | ||
|
528 | QTest::addColumn<QUuid>("syncId"); | |
|
529 | QTest::addColumn<SqpRange>("initialRange"); | |
|
530 | QTest::addColumn<Iterations>("creations"); | |
|
531 | QTest::addColumn<Iterations>("iterations"); | |
|
435 | 532 | |
|
533 | // ////////// // | |
|
534 | // Test cases // | |
|
535 | // ////////// // | |
|
536 | ||
|
537 | testSyncOnVarCase1(); | |
|
538 | } | |
|
539 | ||
|
540 | void TestVariableSync::testSync() | |
|
541 | { | |
|
436 | 542 | // Inits controllers |
|
437 | 543 | TimeController timeController{}; |
|
438 | 544 | VariableController variableController{}; |
|
439 | 545 | variableController.setTimeController(&timeController); |
|
440 | 546 | |
|
441 | 547 | QFETCH(QUuid, syncId); |
|
442 | 548 | QFETCH(SqpRange, initialRange); |
|
443 | 549 | timeController.onTimeToUpdate(initialRange); |
|
444 | 550 | |
|
445 | 551 | // Synchronization group used |
|
446 | 552 | variableController.onAddSynchronizationGroupId(syncId); |
|
447 | 553 | |
|
448 | auto validateRanges = [&variableController](const auto &expectedRanges) { | |
|
449 | for (const auto &expectedRangeEntry : expectedRanges) { | |
|
450 | auto variableIndex = expectedRangeEntry.first; | |
|
451 | auto expectedRange = expectedRangeEntry.second; | |
|
452 | ||
|
453 | // Gets the variable in the controller | |
|
454 | auto variable = variableController.variableModel()->variable(variableIndex); | |
|
455 | ||
|
456 | // Compares variable's range to the expected range | |
|
457 | QVERIFY(variable != nullptr); | |
|
458 | auto range = variable->range(); | |
|
459 | QCOMPARE(range, expectedRange); | |
|
460 | ||
|
461 | // Compares variable's data with values expected for its range | |
|
462 | auto dataSeries = variable->dataSeries(); | |
|
463 | QVERIFY(dataSeries != nullptr); | |
|
464 | ||
|
465 | auto it = dataSeries->xAxisRange(range.m_TStart, range.m_TEnd); | |
|
466 | auto expectedValues = values(range); | |
|
467 | qInfo() << std::distance(it.first, it.second) << expectedValues.size(); | |
|
468 | QVERIFY(std::equal(it.first, it.second, expectedValues.cbegin(), expectedValues.cend(), | |
|
469 | [](const auto &dataSeriesIt, const auto &expectedValue) { | |
|
470 | return dataSeriesIt.value() == expectedValue; | |
|
471 | })); | |
|
472 | } | |
|
473 | }; | |
|
474 | ||
|
475 | 554 | // For each iteration: |
|
476 | 555 | // - execute operation |
|
477 | 556 | // - compare the variables' state to the expected states |
|
478 | 557 | QFETCH(Iterations, iterations); |
|
479 | 558 | QFETCH(int, operationDelay); |
|
480 | 559 | for (const auto &iteration : iterations) { |
|
481 | 560 | iteration.m_Operation->exec(variableController); |
|
482 | 561 | QTest::qWait(operationDelay); |
|
483 | 562 | |
|
484 | validateRanges(iteration.m_ExpectedRanges); | |
|
563 | validateRanges(variableController, iteration.m_ExpectedRanges); | |
|
485 | 564 | } |
|
486 | 565 | } |
|
487 | 566 | |
|
488 | 567 | void TestVariableSync::testSyncWithAborting() |
|
489 | 568 | { |
|
490 | 569 | // Inits controllers |
|
491 | 570 | TimeController timeController{}; |
|
492 | 571 | VariableController variableController{}; |
|
493 | 572 | variableController.setTimeController(&timeController); |
|
494 | 573 | |
|
495 | 574 | QFETCH(QUuid, syncId); |
|
496 | 575 | QFETCH(SqpRange, initialRange); |
|
497 | 576 | timeController.onTimeToUpdate(initialRange); |
|
498 | 577 | |
|
499 | 578 | // Synchronization group used |
|
500 | 579 | variableController.onAddSynchronizationGroupId(syncId); |
|
501 | 580 | |
|
502 | auto validateRanges = [&variableController](const auto &expectedRanges) { | |
|
503 | for (const auto &expectedRangeEntry : expectedRanges) { | |
|
504 | auto variableIndex = expectedRangeEntry.first; | |
|
505 | auto expectedRange = expectedRangeEntry.second; | |
|
506 | ||
|
507 | // Gets the variable in the controller | |
|
508 | auto variable = variableController.variableModel()->variable(variableIndex); | |
|
581 | // For each iteration: | |
|
582 | // - execute operation | |
|
583 | // - compare the variables' state to the expected states | |
|
584 | QFETCH(Iterations, iterations); | |
|
585 | QFETCH(Iterations, creations); | |
|
586 | QFETCH(int, operationDelay); | |
|
509 | 587 | |
|
510 | // Compares variable's range to the expected range | |
|
511 | QVERIFY(variable != nullptr); | |
|
512 | auto range = variable->range(); | |
|
513 | qInfo() << "range vs expected range" << range << variable->range(); | |
|
514 | QCOMPARE(range, expectedRange); | |
|
588 | for (const auto &creation : creations) { | |
|
589 | creation.m_Operation->exec(variableController); | |
|
590 | QTest::qWait(operationDelay); | |
|
591 | } | |
|
515 | 592 | |
|
516 | // Compares variable's data with values expected for its range | |
|
517 | auto dataSeries = variable->dataSeries(); | |
|
518 | QVERIFY(dataSeries != nullptr); | |
|
593 | for (const auto &iteration : iterations) { | |
|
594 | iteration.m_Operation->exec(variableController); | |
|
595 | } | |
|
519 | 596 | |
|
520 | auto it = dataSeries->xAxisRange(range.m_TStart, range.m_TEnd); | |
|
521 | auto expectedValues = values(range); | |
|
522 | qInfo() << std::distance(it.first, it.second) << expectedValues.size(); | |
|
523 | QVERIFY(std::equal(it.first, it.second, expectedValues.cbegin(), expectedValues.cend(), | |
|
524 | [](const auto &dataSeriesIt, const auto &expectedValue) { | |
|
525 | return dataSeriesIt.value() == expectedValue; | |
|
526 | })); | |
|
597 | QTest::qWait(operationDelay); | |
|
598 | validateRanges(variableController, iterations.back().m_ExpectedRanges); | |
|
527 | 599 | } |
|
528 | }; | |
|
600 | ||
|
601 | void TestVariableSync::testSyncOneVar() | |
|
602 | { | |
|
603 | // Inits controllers | |
|
604 | TimeController timeController{}; | |
|
605 | VariableController variableController{}; | |
|
606 | variableController.setTimeController(&timeController); | |
|
607 | ||
|
608 | QFETCH(QUuid, syncId); | |
|
609 | QFETCH(SqpRange, initialRange); | |
|
610 | timeController.onTimeToUpdate(initialRange); | |
|
611 | ||
|
612 | // Synchronization group used | |
|
613 | variableController.onAddSynchronizationGroupId(syncId); | |
|
529 | 614 | |
|
530 | 615 | // For each iteration: |
|
531 | 616 | // - execute operation |
|
532 | 617 | // - compare the variables' state to the expected states |
|
533 | 618 | QFETCH(Iterations, iterations); |
|
534 | 619 | QFETCH(Iterations, creations); |
|
535 | QFETCH(int, operationDelay); | |
|
536 | 620 | |
|
537 | 621 | for (const auto &creation : creations) { |
|
538 | 622 | creation.m_Operation->exec(variableController); |
|
539 |
QTest::qWait( |
|
|
623 | QTest::qWait(300); | |
|
540 | 624 | } |
|
541 | 625 | |
|
542 | 626 | for (const auto &iteration : iterations) { |
|
543 | 627 | iteration.m_Operation->exec(variableController); |
|
544 | 628 | } |
|
545 | 629 | |
|
546 | QTest::qWait(operationDelay); | |
|
547 | validateRanges(iterations.back().m_ExpectedRanges); | |
|
630 | if (!iterations.empty()) { | |
|
631 | validateRanges(variableController, iterations.back().m_ExpectedRanges); | |
|
632 | } | |
|
548 | 633 | } |
|
549 | ||
|
550 | 634 | |
|
551 | 635 | QTEST_MAIN(TestVariableSync) |
|
552 | 636 | |
|
553 | 637 | #include "TestVariableSync.moc" |
General Comments 3
Merge lasted acquisition developpement on main Sciqlop branch
You need to be logged in to leave comments.
Login now