##// END OF EJS Templates
Reads variable's metadata to retrieve the type of data series (scalar, vector, spectrogram)
Reads variable's metadata to retrieve the type of data series (scalar, vector, spectrogram)

File last commit:

r892:cf668dfc6929
r1279:88939ef97b8f
Show More
TestVariableSync.cpp
508 lines | 18.7 KiB | text/x-c | CppLexer
/ core / tests / Variable / TestVariableSync.cpp
Alexandre Leroux
Makes unit tests for variables sync
r772 #include <QObject>
#include <QtTest>
#include <memory>
#include <Data/DataProviderParameters.h>
#include <Data/IDataProvider.h>
#include <Data/ScalarSeries.h>
#include <Time/TimeController.h>
#include <Variable/Variable.h>
#include <Variable/VariableController.h>
#include <Variable/VariableModel.h>
namespace {
/// Delay after each operation on the variable before validating it (in ms)
const auto OPERATION_DELAY = 100;
/**
* Generates values according to a range. The value generated for a time t is the number of seconds
* of difference between t and a reference value (which is midnight -> 00:00:00)
*
* Example: For a range between 00:00:10 and 00:00:20, the generated values are
* {10,11,12,13,14,15,16,17,18,19,20}
*/
std::vector<double> values(const SqpRange &range)
{
QTime referenceTime{0, 0};
std::vector<double> result{};
for (auto i = range.m_TStart; i <= range.m_TEnd; ++i) {
auto time = DateUtils::dateTime(i).time();
result.push_back(referenceTime.secsTo(time));
}
return result;
}
Add test for one variable acquisition in TestVariableSync
r833 void validateRanges(VariableController &variableController,
const std::map<int, SqpRange> &expectedRanges)
{
for (const auto &expectedRangeEntry : expectedRanges) {
auto variableIndex = expectedRangeEntry.first;
auto expectedRange = expectedRangeEntry.second;
// Gets the variable in the controller
auto variable = variableController.variableModel()->variable(variableIndex);
// Compares variable's range to the expected range
QVERIFY(variable != nullptr);
auto range = variable->range();
qInfo() << "range vs expected range" << range << expectedRange;
QCOMPARE(range, expectedRange);
// Compares variable's data with values expected for its range
auto dataSeries = variable->dataSeries();
QVERIFY(dataSeries != nullptr);
auto it = dataSeries->xAxisRange(range.m_TStart, range.m_TEnd);
auto expectedValues = values(range);
qInfo() << std::distance(it.first, it.second) << expectedValues.size();
QVERIFY(std::equal(it.first, it.second, expectedValues.cbegin(), expectedValues.cend(),
[](const auto &dataSeriesIt, const auto &expectedValue) {
return dataSeriesIt.value() == expectedValue;
}));
}
}
Alexandre Leroux
Makes unit tests for variables sync
r772 /// Provider used for the tests
class TestProvider : public IDataProvider {
std::shared_ptr<IDataProvider> clone() const { return std::make_shared<TestProvider>(); }
void requestDataLoading(QUuid acqIdentifier, const DataProviderParameters &parameters) override
{
const auto &ranges = parameters.m_Times;
for (const auto &range : ranges) {
// Generates data series
auto valuesData = values(range);
std::vector<double> xAxisData{};
for (auto i = range.m_TStart; i <= range.m_TEnd; ++i) {
xAxisData.push_back(i);
}
auto dataSeries = std::make_shared<ScalarSeries>(
std::move(xAxisData), std::move(valuesData), Unit{"t", true}, Unit{});
emit dataProvided(acqIdentifier, dataSeries, range);
}
}
void requestDataAborting(QUuid acqIdentifier) override
{
// Does nothing
}
};
/**
* Interface representing an operation performed on a variable controller.
* This interface is used in tests to apply a set of operations and check the status of the
* controller after each operation
*/
struct IOperation {
virtual ~IOperation() = default;
/// Executes the operation on the variable controller
virtual void exec(VariableController &variableController) const = 0;
};
/**
*Variable creation operation in the controller
*/
struct Create : public IOperation {
explicit Create(int index) : m_Index{index} {}
void exec(VariableController &variableController) const override
{
auto variable = variableController.createVariable(QString::number(m_Index), {},
std::make_unique<TestProvider>());
}
int m_Index; ///< The index of the variable to create in the controller
};
/**
* Variable move/shift operation in the controller
*/
struct Move : public IOperation {
Add test for one variable acquisition in TestVariableSync
r833 explicit Move(int index, const SqpRange &newRange, bool shift = false, int delayMS = 10)
: m_Index{index}, m_NewRange{newRange}, m_Shift{shift}, m_DelayMs{delayMS}
Alexandre Leroux
Makes unit tests for variables sync
r772 {
}
void exec(VariableController &variableController) const override
{
if (auto variable = variableController.variableModel()->variable(m_Index)) {
Implémentation timewidget
r811 variableController.onRequestDataLoading({variable}, m_NewRange, !m_Shift);
Add test for one variable acquisition in TestVariableSync
r833 QTest::qWait(m_DelayMs);
Alexandre Leroux
Makes unit tests for variables sync
r772 }
}
int m_Index; ///< The index of the variable to move
SqpRange m_NewRange; ///< The new range of the variable
bool m_Shift; ///< Performs a shift (
Add test for one variable acquisition in TestVariableSync
r833 int m_DelayMs; ///< wait the delay after running the request (
Alexandre Leroux
Makes unit tests for variables sync
r772 };
/**
* Variable synchronization/desynchronization operation in the controller
*/
struct Synchronize : public IOperation {
explicit Synchronize(int index, QUuid syncId, bool synchronize = true)
: m_Index{index}, m_SyncId{syncId}, m_Synchronize{synchronize}
{
}
void exec(VariableController &variableController) const override
{
if (auto variable = variableController.variableModel()->variable(m_Index)) {
if (m_Synchronize) {
variableController.onAddSynchronized(variable, m_SyncId);
}
else {
variableController.desynchronize(variable, m_SyncId);
}
}
}
int m_Index; ///< The index of the variable to sync/desync
QUuid m_SyncId; ///< The synchronization group of the variable
bool m_Synchronize; ///< Performs sync or desync operation
};
/**
* Test Iteration
*
* A test iteration includes an operation to be performed, and a set of expected ranges after each
* operation. Each range is tested after the operation to ensure that:
* - the range of the variable is the expected range
* - the data of the variable are those generated for the expected range
*/
struct Iteration {
std::shared_ptr<IOperation> m_Operation; ///< Operation to perform
std::map<int, SqpRange> m_ExpectedRanges; ///< Expected ranges (by variable index)
};
using Iterations = std::vector<Iteration>;
} // namespace
Q_DECLARE_METATYPE(Iterations)
class TestVariableSync : public QObject {
Q_OBJECT
private slots:
Alexandre Leroux
SkipsTestVariableSync tests
r892 void initTestCase() { QSKIP("Temporarily disables TestVariableSync"); }
Alexandre Leroux
Makes unit tests for variables sync
r772 /// Input data for @sa testSync()
void testSync_data();
Add test for one variable acquisition in TestVariableSync
r833 /// Input data for @sa testSyncOneVar()
void testSyncOneVar_data();
Alexandre Leroux
Makes unit tests for variables sync
r772 /// Tests synchronization between variables through several operations
void testSync();
Add test for one variable acquisition in TestVariableSync
r833
/// Tests synchronization between variables through several operations
void testSyncOneVar();
Alexandre Leroux
Makes unit tests for variables sync
r772 };
Fix bug in synchro for operation (jump + rescaling)
r809 namespace {
Alexandre Leroux
Makes unit tests for variables sync
r772
Fix bug in synchro for operation (jump + rescaling)
r809 void testSyncCase1()
{
Alexandre Leroux
Makes unit tests for variables sync
r772 // Id used to synchronize variables in the controller
auto syncId = QUuid::createUuid();
/// Generates a range according to a start time and a end time (the date is the same)
auto range = [](const QTime &startTime, const QTime &endTime) {
return SqpRange{DateUtils::secondsSinceEpoch(QDateTime{{2017, 1, 1}, startTime, Qt::UTC}),
DateUtils::secondsSinceEpoch(QDateTime{{2017, 1, 1}, endTime, Qt::UTC})};
};
auto initialRange = range({12, 0}, {13, 0});
Iterations iterations{};
// Creates variables var0, var1 and var2
iterations.push_back({std::make_shared<Create>(0), {{0, initialRange}}});
iterations.push_back({std::make_shared<Create>(1), {{0, initialRange}, {1, initialRange}}});
iterations.push_back(
{std::make_shared<Create>(2), {{0, initialRange}, {1, initialRange}, {2, initialRange}}});
// Adds variables into the sync group (ranges don't need to be tested here)
iterations.push_back({std::make_shared<Synchronize>(0, syncId)});
iterations.push_back({std::make_shared<Synchronize>(1, syncId)});
iterations.push_back({std::make_shared<Synchronize>(2, syncId)});
// Moves var0: ranges of var0, var1 and var2 change
auto newRange = range({12, 30}, {13, 30});
iterations.push_back(
{std::make_shared<Move>(0, newRange), {{0, newRange}, {1, newRange}, {2, newRange}}});
// Moves var1: ranges of var0, var1 and var2 change
newRange = range({13, 0}, {14, 0});
iterations.push_back(
{std::make_shared<Move>(0, newRange), {{0, newRange}, {1, newRange}, {2, newRange}}});
// Moves var2: ranges of var0, var1 and var2 change
newRange = range({13, 30}, {14, 30});
iterations.push_back(
{std::make_shared<Move>(0, newRange), {{0, newRange}, {1, newRange}, {2, newRange}}});
// Desyncs var2 and moves var0:
// - ranges of var0 and var1 change
// - range of var2 doesn't change anymore
auto var2Range = newRange;
newRange = range({13, 45}, {14, 45});
iterations.push_back({std::make_shared<Synchronize>(2, syncId, false)});
iterations.push_back(
{std::make_shared<Move>(0, newRange), {{0, newRange}, {1, newRange}, {2, var2Range}}});
// Shifts var0: although var1 is synchronized with var0, its range doesn't change
auto var1Range = newRange;
newRange = range({14, 45}, {15, 45});
iterations.push_back({std::make_shared<Move>(0, newRange, true),
{{0, newRange}, {1, var1Range}, {2, var2Range}}});
// Moves var0 through several operations:
// - range of var0 changes
// - range or var1 changes according to the previous shift (one hour)
auto moveVar0 = [&iterations](const auto &var0NewRange, const auto &var1ExpectedRange) {
iterations.push_back(
{std::make_shared<Move>(0, var0NewRange), {{0, var0NewRange}, {1, var1ExpectedRange}}});
};
Improve TestVariable test
r824
Alexandre Leroux
Makes unit tests for variables sync
r772 // Pan left
moveVar0(range({14, 30}, {15, 30}), range({13, 30}, {14, 30}));
// Pan right
moveVar0(range({16, 0}, {17, 0}), range({15, 0}, {16, 0}));
// Zoom in
moveVar0(range({16, 30}, {16, 45}), range({15, 30}, {15, 45}));
// Zoom out
Implementation of varRequestId aborting to permit to cancel a request...
r822 moveVar0(range({16, 15}, {17, 0}), range({15, 15}, {16, 0}));
Alexandre Leroux
Makes unit tests for variables sync
r772
Fix bug in synchro for operation (jump + rescaling)
r809 QTest::newRow("sync1") << syncId << initialRange << std::move(iterations) << 200;
}
void testSyncCase2()
{
// Id used to synchronize variables in the controller
auto syncId = QUuid::createUuid();
/// Generates a range according to a start time and a end time (the date is the same)
auto dateTime = [](int year, int month, int day, int hours, int minutes, int seconds) {
return DateUtils::secondsSinceEpoch(
QDateTime{{year, month, day}, QTime{hours, minutes, seconds}, Qt::UTC});
};
auto initialRange = SqpRange{dateTime(2017, 1, 1, 12, 0, 0), dateTime(2017, 1, 1, 13, 0, 0)};
Iterations iterations{};
// Creates variables var0 and var1
iterations.push_back({std::make_shared<Create>(0), {{0, initialRange}}});
iterations.push_back({std::make_shared<Create>(1), {{0, initialRange}, {1, initialRange}}});
// Adds variables into the sync group (ranges don't need to be tested here)
iterations.push_back({std::make_shared<Synchronize>(0, syncId)});
iterations.push_back({std::make_shared<Synchronize>(1, syncId)});
// Moves var0 through several operations:
// - range of var0 changes
// - range or var1 changes according to the previous shift (one hour)
auto moveVar0 = [&iterations](const auto &var0NewRange) {
iterations.push_back(
{std::make_shared<Move>(0, var0NewRange), {{0, var0NewRange}, {1, var0NewRange}}});
};
moveVar0(SqpRange{dateTime(2017, 1, 1, 12, 0, 0), dateTime(2017, 1, 1, 13, 0, 0)});
moveVar0(SqpRange{dateTime(2017, 1, 1, 14, 0, 0), dateTime(2017, 1, 1, 15, 0, 0)});
moveVar0(SqpRange{dateTime(2017, 1, 1, 8, 0, 0), dateTime(2017, 1, 1, 9, 0, 0)});
// moveVar0(SqpRange{dateTime(2017, 1, 1, 7, 30, 0), dateTime(2017, 1, 1, 9, 30, 0)});
moveVar0(SqpRange{dateTime(2017, 1, 1, 2, 0, 0), dateTime(2017, 1, 1, 4, 0, 0)});
moveVar0(SqpRange{dateTime(2017, 1, 1, 6, 0, 0), dateTime(2017, 1, 1, 8, 0, 0)});
moveVar0(SqpRange{dateTime(2017, 1, 10, 6, 0, 0), dateTime(2017, 1, 15, 8, 0, 0)});
moveVar0(SqpRange{dateTime(2017, 1, 17, 6, 0, 0), dateTime(2017, 1, 25, 8, 0, 0)});
moveVar0(SqpRange{dateTime(2017, 1, 2, 6, 0, 0), dateTime(2017, 1, 8, 8, 0, 0)});
moveVar0(SqpRange{dateTime(2017, 4, 10, 6, 0, 0), dateTime(2017, 6, 15, 8, 0, 0)});
moveVar0(SqpRange{dateTime(2017, 1, 17, 6, 0, 0), dateTime(2017, 2, 25, 8, 0, 0)});
moveVar0(SqpRange{dateTime(2017, 7, 2, 6, 0, 0), dateTime(2017, 10, 8, 8, 0, 0)});
moveVar0(SqpRange{dateTime(2017, 4, 10, 6, 0, 0), dateTime(2017, 6, 15, 8, 0, 0)});
moveVar0(SqpRange{dateTime(2017, 1, 17, 6, 0, 0), dateTime(2017, 2, 25, 8, 0, 0)});
moveVar0(SqpRange{dateTime(2017, 7, 2, 6, 0, 0), dateTime(2017, 10, 8, 8, 0, 0)});
moveVar0(SqpRange{dateTime(2017, 4, 10, 6, 0, 0), dateTime(2017, 6, 15, 8, 0, 0)});
moveVar0(SqpRange{dateTime(2017, 1, 17, 6, 0, 0), dateTime(2017, 2, 25, 8, 0, 0)});
moveVar0(SqpRange{dateTime(2017, 7, 2, 6, 0, 0), dateTime(2017, 10, 8, 8, 0, 0)});
moveVar0(SqpRange{dateTime(2017, 4, 10, 6, 0, 0), dateTime(2017, 6, 15, 8, 0, 0)});
moveVar0(SqpRange{dateTime(2017, 1, 17, 6, 0, 0), dateTime(2017, 2, 25, 8, 0, 0)});
moveVar0(SqpRange{dateTime(2017, 7, 2, 6, 0, 0), dateTime(2017, 10, 8, 8, 0, 0)});
QTest::newRow("sync2") << syncId << initialRange << iterations << 4000;
// QTest::newRow("sync3") << syncId << initialRange << iterations << 5000;
}
Add test for one variable acquisition in TestVariableSync
r833
void testSyncOnVarCase1()
{
// Id used to synchronize variables in the controller
auto syncId = QUuid::createUuid();
/// Generates a range according to a start time and a end time (the date is the same)
auto range = [](const QTime &startTime, const QTime &endTime) {
return SqpRange{DateUtils::secondsSinceEpoch(QDateTime{{2017, 1, 1}, startTime, Qt::UTC}),
DateUtils::secondsSinceEpoch(QDateTime{{2017, 1, 1}, endTime, Qt::UTC})};
};
auto initialRange = range({12, 0}, {13, 0});
Iterations creations{};
// Creates variables var0, var1 and var2
creations.push_back({std::make_shared<Create>(0), {{0, initialRange}}});
Iterations synchronization{};
// Adds variables into the sync group (ranges don't need to be tested here)
synchronization.push_back({std::make_shared<Synchronize>(0, syncId)});
Iterations iterations{};
// Moves var0 through several operations
auto moveOp = [&iterations](const auto &requestedRange, const auto &expectedRange, auto delay) {
iterations.push_back(
{std::make_shared<Move>(0, requestedRange, true, delay), {{0, expectedRange}}});
};
// we assume here 300 ms is enough to finsh a operation
int delayToFinish = 300;
// jump to right, let's the operation time to finish
moveOp(range({14, 30}, {15, 30}), range({14, 30}, {15, 30}), delayToFinish);
// pan to right, let's the operation time to finish
moveOp(range({14, 45}, {15, 45}), range({14, 45}, {15, 45}), delayToFinish);
// jump to left, let's the operation time to finish
moveOp(range({03, 30}, {04, 30}), range({03, 30}, {04, 30}), delayToFinish);
// Pan to left, let's the operation time to finish
moveOp(range({03, 10}, {04, 10}), range({03, 10}, {04, 10}), delayToFinish);
// Zoom in, let's the operation time to finish
moveOp(range({03, 30}, {04, 00}), range({03, 30}, {04, 00}), delayToFinish);
// Zoom out left, let's the operation time to finish
moveOp(range({01, 10}, {18, 10}), range({01, 10}, {18, 10}), delayToFinish);
// Go back to initial range
moveOp(initialRange, initialRange, delayToFinish);
// jump to right, let's the operation time to finish
// moveOp(range({14, 30}, {15, 30}), initialRange, delayToFinish);
// Zoom out left, let's the operation time to finish
moveOp(range({01, 10}, {18, 10}), initialRange, delayToFinish);
// Go back to initial range
moveOp(initialRange, initialRange, 300);
QTest::newRow("syncOnVarCase1") << syncId << initialRange << std::move(creations)
<< std::move(iterations);
}
Fix bug in synchro for operation (jump + rescaling)
r809 }
void TestVariableSync::testSync_data()
{
// ////////////// //
// Test structure //
// ////////////// //
QTest::addColumn<QUuid>("syncId");
QTest::addColumn<SqpRange>("initialRange");
QTest::addColumn<Iterations>("iterations");
QTest::addColumn<int>("operationDelay");
// ////////// //
// Test cases //
// ////////// //
testSyncCase1();
Improve TestVariable test
r824 testSyncCase2();
}
Add test for one variable acquisition in TestVariableSync
r833 void TestVariableSync::testSyncOneVar_data()
Alexandre Leroux
Makes unit tests for variables sync
r772 {
Add test for one variable acquisition in TestVariableSync
r833 // ////////////// //
// Test structure //
// ////////////// //
QTest::addColumn<QUuid>("syncId");
QTest::addColumn<SqpRange>("initialRange");
QTest::addColumn<Iterations>("creations");
QTest::addColumn<Iterations>("iterations");
Improve TestVariable test
r824
Add test for one variable acquisition in TestVariableSync
r833 // ////////// //
// Test cases //
// ////////// //
testSyncOnVarCase1();
}
void TestVariableSync::testSync()
{
Alexandre Leroux
Makes unit tests for variables sync
r772 // Inits controllers
TimeController timeController{};
VariableController variableController{};
variableController.setTimeController(&timeController);
QFETCH(QUuid, syncId);
QFETCH(SqpRange, initialRange);
timeController.onTimeToUpdate(initialRange);
// Synchronization group used
variableController.onAddSynchronizationGroupId(syncId);
Fix bug in synchro for operation (jump + rescaling)
r809 // For each iteration:
// - execute operation
// - compare the variables' state to the expected states
QFETCH(Iterations, iterations);
QFETCH(int, operationDelay);
for (const auto &iteration : iterations) {
iteration.m_Operation->exec(variableController);
QTest::qWait(operationDelay);
Add test for one variable acquisition in TestVariableSync
r833 validateRanges(variableController, iteration.m_ExpectedRanges);
Fix bug in synchro for operation (jump + rescaling)
r809 }
Improve TestVariable test
r824 }
Add test for one variable acquisition in TestVariableSync
r833 void TestVariableSync::testSyncOneVar()
{
// Inits controllers
TimeController timeController{};
VariableController variableController{};
variableController.setTimeController(&timeController);
QFETCH(QUuid, syncId);
QFETCH(SqpRange, initialRange);
timeController.onTimeToUpdate(initialRange);
// Synchronization group used
variableController.onAddSynchronizationGroupId(syncId);
// For each iteration:
// - execute operation
// - compare the variables' state to the expected states
QFETCH(Iterations, iterations);
QFETCH(Iterations, creations);
for (const auto &creation : creations) {
creation.m_Operation->exec(variableController);
QTest::qWait(300);
}
for (const auto &iteration : iterations) {
iteration.m_Operation->exec(variableController);
}
if (!iterations.empty()) {
validateRanges(variableController, iterations.back().m_ExpectedRanges);
}
}
Improve TestVariable test
r824
Alexandre Leroux
Makes unit tests for variables sync
r772 QTEST_MAIN(TestVariableSync)
#include "TestVariableSync.moc"