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