414 lines
13 KiB
C++
Executable File
414 lines
13 KiB
C++
Executable File
/**
|
|
* AES module test fire automaton
|
|
* $Id$
|
|
* $HeadURL$
|
|
* $Author$
|
|
*/
|
|
|
|
|
|
#include <QCoreApplication>
|
|
#include <QTimer>
|
|
#include <QDateTime>
|
|
#include <QTest>
|
|
#include <QVector>
|
|
#include <QSignalSpy>
|
|
|
|
#include <nglapplication/nglcoreapplication.h>
|
|
#include <AreaEffectSimulation/Utils/fire_automaton.h>
|
|
#include <AreaEffectSimulation/logger.h>
|
|
|
|
#include "aes_test_fire_automaton.h"
|
|
|
|
using namespace AreaEffectSimulation;
|
|
|
|
void TestFireAutomaton::initTestCase()
|
|
{ }
|
|
|
|
void TestFireAutomaton::init()
|
|
{
|
|
m_receivedFire.clear();
|
|
m_finishedTime = 0;
|
|
}
|
|
|
|
void TestFireAutomaton::fireReceived(int32_t id)
|
|
{
|
|
m_receivedFire.append({QDateTime::currentMSecsSinceEpoch(), id});
|
|
}
|
|
|
|
/*
|
|
Test basic pattern with fire slots = rounds
|
|
*/
|
|
void TestFireAutomaton::testSchedule_0()
|
|
{
|
|
int32_t effectDurationMSecs = 500;
|
|
int32_t cadence = 100;
|
|
int32_t numberOfRounds = 6;
|
|
QVector<int32_t> effectorIds = {1};
|
|
QString pattern = QStringLiteral("all, next, all, next, all, next");
|
|
|
|
QVector<qint64> expectedDelays = {0, 100, 200, 300, 400, 500};
|
|
QVector<QVector<int32_t>> expectedSchedule = {{1}, {1}, {1}, {1}, {1}, {1}};
|
|
|
|
testScheduling(effectDurationMSecs, FireAutomaton::TimeType::Duration, numberOfRounds, effectorIds, pattern, expectedDelays, expectedSchedule);
|
|
testScheduling(cadence, FireAutomaton::TimeType::Cadence, numberOfRounds, effectorIds, pattern, expectedDelays, expectedSchedule);
|
|
testStepping(numberOfRounds, effectorIds, pattern, expectedSchedule);
|
|
}
|
|
|
|
/*
|
|
Test pattern with fill element
|
|
*/
|
|
void TestFireAutomaton::testSchedule_1()
|
|
{
|
|
int32_t effectDurationMSecs = 800;
|
|
int32_t cadence = 100;
|
|
int32_t numberOfRounds = 13;
|
|
QVector<int32_t> effectorIds = {1, 2, 3};
|
|
QString pattern = QStringLiteral("all,next*,all");
|
|
|
|
QVector<qint64> expectedDelays = {0, 0, 0, 100, 200, 300, 400, 500, 600, 700, 800, 800, 800};
|
|
QVector<QVector<int32_t>> expectedSchedule = {{1, 2, 3}, {1}, {2}, {3}, {1}, {2}, {3}, {1}, {1, 2, 3}};
|
|
|
|
testScheduling(effectDurationMSecs, FireAutomaton::TimeType::Duration, numberOfRounds, effectorIds, pattern, expectedDelays, expectedSchedule);
|
|
testScheduling(cadence, FireAutomaton::TimeType::Cadence, numberOfRounds, effectorIds, pattern, expectedDelays, expectedSchedule);
|
|
testStepping(numberOfRounds, effectorIds, pattern, expectedSchedule);
|
|
}
|
|
|
|
/*
|
|
Test fill pattern element with 0 fill
|
|
*/
|
|
void TestFireAutomaton::testSchedule_2()
|
|
{
|
|
int32_t effectDurationMSecs = 200;
|
|
int32_t cadence = 200;
|
|
int32_t numberOfRounds = 6;
|
|
QVector<int32_t> effectorIds = {1, 2, 3};
|
|
QString pattern = QStringLiteral("all,all*,all");
|
|
|
|
QVector<qint64> expectedDelays = {0, 0, 0, 200, 200, 200};
|
|
QVector<QVector<int32_t>> expectedSchedule = {{1,2,3}, {1,2,3}};
|
|
|
|
testScheduling(effectDurationMSecs, FireAutomaton::TimeType::Duration, numberOfRounds, effectorIds, pattern, expectedDelays, expectedSchedule);
|
|
testScheduling(cadence, FireAutomaton::TimeType::Cadence, numberOfRounds, effectorIds, pattern, expectedDelays, expectedSchedule);
|
|
testStepping(numberOfRounds, effectorIds, pattern, expectedSchedule);
|
|
}
|
|
|
|
/*
|
|
Test pattern with fire slots > rounds
|
|
*/
|
|
void TestFireAutomaton::testSchedule_3()
|
|
{
|
|
int32_t effectDurationMSecs = 200;
|
|
int32_t cadence = 200;
|
|
int32_t numberOfRounds = 5;
|
|
QVector<int32_t> effectorIds = {1, 2, 3, 4};
|
|
QString pattern = QStringLiteral("all,all");
|
|
|
|
QVector<qint64> expectedDelays = {0, 0, 0, 0, 200};
|
|
QVector<QVector<int32_t>> expectedSchedule = {{1, 2, 3, 4}, {1}};
|
|
|
|
testScheduling(effectDurationMSecs, FireAutomaton::TimeType::Duration, numberOfRounds, effectorIds, pattern, expectedDelays, expectedSchedule);
|
|
testScheduling(cadence, FireAutomaton::TimeType::Cadence, numberOfRounds, effectorIds, pattern, expectedDelays, expectedSchedule);
|
|
testStepping(numberOfRounds, effectorIds, pattern, expectedSchedule);
|
|
}
|
|
|
|
/*
|
|
Test pattern with rounds > fire slots
|
|
*/
|
|
void TestFireAutomaton::testSchedule_4()
|
|
{
|
|
int32_t effectDurationMSecs = 100;
|
|
int32_t numberOfRounds = 5;
|
|
QVector<int32_t> effectorIds = {1};
|
|
QString pattern = QStringLiteral("next, next");
|
|
|
|
QVector<qint64> expectedDelays = {0, 100};
|
|
QVector<QVector<int32_t>> expectedSchedule = {{1}, {1}};
|
|
|
|
FireAutomaton automaton;
|
|
QVERIFY(!automaton.init(effectDurationMSecs, FireAutomaton::TimeType::Duration, numberOfRounds, effectorIds, pattern));
|
|
}
|
|
|
|
void TestFireAutomaton::testScheduling(int32_t time, FireAutomaton::TimeType type, int32_t numberOfRounds, const QVector<int32_t>& effectorIds,
|
|
const QString& pattern, QVector<qint64> expectedDelays, QVector<QVector<int32_t>> expectedSchedule)
|
|
{
|
|
FireAutomaton automaton;
|
|
QVERIFY(automaton.init(time, type, numberOfRounds, effectorIds, pattern));
|
|
|
|
QSignalSpy spyFire(&automaton, SIGNAL(fire(int32_t)));
|
|
QVERIFY(spyFire.isValid());
|
|
|
|
QSignalSpy spyFinished(&automaton, SIGNAL(finished()));
|
|
QVERIFY(spyFinished.isValid());
|
|
|
|
connect(&automaton, &FireAutomaton::fire, this, &TestFireAutomaton::fireReceived);
|
|
|
|
qint64 startTimeMSecs = QDateTime::currentMSecsSinceEpoch();
|
|
automaton.start();
|
|
|
|
QVERIFY(spyFinished.wait(1000));
|
|
QVERIFY(withinTolerance(QDateTime::currentMSecsSinceEpoch() - startTimeMSecs, expectedDelays.last(), 50));
|
|
|
|
int32_t expectedShots = 0;
|
|
for(const auto& tick : expectedSchedule)
|
|
expectedShots += tick.size();
|
|
|
|
QCOMPARE(spyFire.count(), expectedShots);
|
|
|
|
for(int32_t i=0; i < numberOfRounds; i++) {
|
|
withinTolerance(QDateTime::currentMSecsSinceEpoch() - startTimeMSecs, expectedDelays.last(), 50);
|
|
}
|
|
|
|
QVector<QVector<int32_t>> schedule;
|
|
QVector<int32_t> tickIds;
|
|
qint64 firstFireTime = m_receivedFire[0].time;
|
|
|
|
if(expectedDelays.size() != m_receivedFire.size())
|
|
{
|
|
QVERIFY(false);
|
|
return;
|
|
}
|
|
|
|
// first fire time is basis for delays
|
|
for(int i=0; i < m_receivedFire.size(); i++)
|
|
{
|
|
m_receivedFire[i].time = m_receivedFire[i].time - firstFireTime;
|
|
QVERIFY(withinTolerance(m_receivedFire[i].time, expectedDelays[i], 50));
|
|
}
|
|
|
|
tickIds.clear();
|
|
tickIds.append(m_receivedFire[0].id);
|
|
|
|
for(int i=1; i < m_receivedFire.size(); i++)
|
|
{
|
|
if(withinTolerance(m_receivedFire[i - 1].time, m_receivedFire[i].time, 50))
|
|
{
|
|
tickIds.append(m_receivedFire[i].id);
|
|
} else {
|
|
schedule.append(tickIds);
|
|
tickIds.clear();
|
|
tickIds.append(m_receivedFire[i].id);
|
|
}
|
|
}
|
|
|
|
schedule.append(tickIds);
|
|
|
|
QVERIFY(schedule.size() == expectedSchedule.size());
|
|
|
|
for(int i=0; i < schedule.size(); i++)
|
|
{
|
|
QVERIFY(schedule[i] == expectedSchedule[i]);
|
|
}
|
|
|
|
m_receivedFire.clear();
|
|
}
|
|
|
|
void TestFireAutomaton::testStepping(int32_t numberOfRounds, const QVector<int32_t>& effectorIds,
|
|
const QString& pattern, QVector<QVector<int32_t>> expectedSchedule)
|
|
{
|
|
FireAutomaton automaton;
|
|
QVERIFY(automaton.init(0, FireAutomaton::TimeType::Cadence, numberOfRounds, effectorIds, pattern));
|
|
QSignalSpy spyFire(&automaton, SIGNAL(fire(int32_t)));
|
|
QVERIFY(spyFire.isValid());
|
|
QSignalSpy spyFinished(&automaton, SIGNAL(finished()));
|
|
QVERIFY(spyFinished.isValid());
|
|
connect(&automaton, &FireAutomaton::fire, this, &TestFireAutomaton::fireReceived);
|
|
|
|
for(int i=0; i < expectedSchedule.size(); i++)
|
|
{
|
|
QVERIFY(automaton.performStep());
|
|
QTest::qWait(100);
|
|
}
|
|
|
|
QVERIFY(spyFinished.count() == 1);
|
|
|
|
QVector<QVector<int32_t>> schedule;
|
|
QVector<int32_t> tickIds;
|
|
qint64 firstFireTime = m_receivedFire[0].time;
|
|
|
|
// first fire time is basis for delays
|
|
for(int i=0; i < m_receivedFire.size(); i++)
|
|
{
|
|
m_receivedFire[i].time = m_receivedFire[i].time - firstFireTime;
|
|
}
|
|
|
|
tickIds.clear();
|
|
tickIds.append(m_receivedFire[0].id);
|
|
|
|
for(int i=1; i < m_receivedFire.size(); i++)
|
|
{
|
|
if(withinTolerance(m_receivedFire[i - 1].time, m_receivedFire[i].time, 50))
|
|
{
|
|
tickIds.append(m_receivedFire[i].id);
|
|
} else {
|
|
schedule.append(tickIds);
|
|
tickIds.clear();
|
|
tickIds.append(m_receivedFire[i].id);
|
|
}
|
|
}
|
|
|
|
schedule.append(tickIds);
|
|
|
|
QVERIFY(schedule.size() == expectedSchedule.size());
|
|
|
|
for(int i=0; i < schedule.size(); i++)
|
|
{
|
|
QVERIFY(schedule[i] == expectedSchedule[i]);
|
|
}
|
|
|
|
m_receivedFire.clear();
|
|
}
|
|
|
|
|
|
void TestFireAutomaton::testResumePaused()
|
|
{
|
|
QVector<int32_t> effectorIds = {1};
|
|
int32_t effectDurationMSecs = 1000;
|
|
int32_t numberOfRounds = 2;
|
|
|
|
FireAutomaton automaton;
|
|
QVERIFY(automaton.init(effectDurationMSecs, FireAutomaton::TimeType::Duration, numberOfRounds, effectorIds, QStringLiteral("all*")));
|
|
|
|
QSignalSpy spyFire(&automaton, SIGNAL(fire(int32_t)));
|
|
QVERIFY(spyFire.isValid());
|
|
|
|
QSignalSpy spyFinished(&automaton, SIGNAL(finished()));
|
|
QVERIFY(spyFinished.isValid());
|
|
|
|
qint64 startTimeMSecs = QDateTime::currentMSecsSinceEpoch();
|
|
QVERIFY(automaton.start());
|
|
|
|
QTest::qWait(100);
|
|
|
|
automaton.pause();
|
|
QCOMPARE(automaton.getState(), FireAutomaton::State::Paused);
|
|
qint64 pauseTimeMSecs = QDateTime::currentMSecsSinceEpoch();
|
|
QVERIFY(spyFire.count() == 1);
|
|
|
|
QTest::qWait(100);
|
|
|
|
qint64 resumeTimeMSecs = QDateTime::currentMSecsSinceEpoch();
|
|
automaton.resume();
|
|
|
|
QCOMPARE(automaton.getState(), FireAutomaton::State::Running);
|
|
QVERIFY(spyFinished.wait(2000));
|
|
|
|
qint64 measuredDuration = (QDateTime::currentMSecsSinceEpoch() - startTimeMSecs) - resumeTimeMSecs + pauseTimeMSecs;
|
|
|
|
QVERIFY(spyFinished.count() == 1);
|
|
QVERIFY(withinTolerance(measuredDuration, effectDurationMSecs, 100));
|
|
QVERIFY(spyFire.count() == numberOfRounds);
|
|
}
|
|
|
|
void TestFireAutomaton::testStop()
|
|
{
|
|
QVector<int32_t> effectorIds = {1, 2, 3, 4, 5, 6};
|
|
int32_t effectDurationMSecs = 500;
|
|
int32_t numberOfRounds = 10;
|
|
|
|
FireAutomaton automaton;
|
|
QVERIFY(automaton.init(effectDurationMSecs, FireAutomaton::TimeType::Duration, numberOfRounds, effectorIds, QStringLiteral("next*")));
|
|
|
|
QTest::qWait(10);
|
|
|
|
QSignalSpy spyFire(&automaton, SIGNAL(fire(int32_t)));
|
|
QVERIFY(spyFire.isValid());
|
|
|
|
QSignalSpy spyFinished(&automaton, SIGNAL(finished()));
|
|
QVERIFY(spyFinished.isValid());
|
|
|
|
QVERIFY(automaton.start());
|
|
|
|
QTest::qWait(100);
|
|
|
|
automaton.stop();
|
|
|
|
int32_t fireCount = spyFire.count();
|
|
QVERIFY(!spyFinished.wait(1000)); // expected to timeout
|
|
QCOMPARE(spyFire.count(), fireCount); // expected to not have changed
|
|
QVERIFY(spyFire.count() < numberOfRounds);
|
|
|
|
// start to finish
|
|
qint64 startTimeMSecs = QDateTime::currentMSecsSinceEpoch();
|
|
QVERIFY(automaton.start());
|
|
|
|
QVERIFY(spyFinished.wait(1000));
|
|
QVERIFY(spyFire.count() - fireCount == numberOfRounds);
|
|
QVERIFY(withinTolerance(QDateTime::currentMSecsSinceEpoch() - startTimeMSecs, effectDurationMSecs, 50));
|
|
}
|
|
|
|
void TestFireAutomaton::testStates()
|
|
{
|
|
QVector<int32_t> effectorIds = {11, 10};
|
|
int32_t effectDurationMSecs = 500;
|
|
int32_t numberOfRounds = 10;
|
|
|
|
FireAutomaton automaton;
|
|
|
|
QSignalSpy spyFinished(&automaton, SIGNAL(finished()));
|
|
QVERIFY(spyFinished.isValid());
|
|
|
|
// init
|
|
QCOMPARE(automaton.getState(), FireAutomaton::State::Uninitialized);
|
|
QVERIFY(!automaton.start());
|
|
QVERIFY(!automaton.pause());
|
|
QVERIFY(!automaton.resume());
|
|
|
|
QVERIFY(automaton.init(effectDurationMSecs, FireAutomaton::TimeType::Duration, numberOfRounds, effectorIds, QStringLiteral("all*")));
|
|
QCOMPARE(automaton.getState(), FireAutomaton::State::Stopped);
|
|
QVERIFY(!automaton.pause());
|
|
QVERIFY(!automaton.resume());
|
|
|
|
// start -> pause -> resume -> stop
|
|
QVERIFY(automaton.start());
|
|
QCOMPARE(automaton.getState(), FireAutomaton::State::Running);
|
|
QVERIFY(!automaton.start());
|
|
QVERIFY(!automaton.resume());
|
|
|
|
QVERIFY(automaton.pause());
|
|
QCOMPARE(automaton.getState(), FireAutomaton::State::Paused);
|
|
QVERIFY(!automaton.start());
|
|
QVERIFY(!automaton.pause());
|
|
|
|
QVERIFY(automaton.resume());
|
|
QCOMPARE(automaton.getState(), FireAutomaton::State::Running);
|
|
|
|
QVERIFY(spyFinished.wait(1000));
|
|
|
|
QCOMPARE(automaton.getState(), FireAutomaton::State::Stopped);
|
|
QVERIFY(!automaton.pause());
|
|
QCOMPARE(automaton.getState(), FireAutomaton::State::Stopped);
|
|
QVERIFY(!automaton.resume());
|
|
QCOMPARE(automaton.getState(), FireAutomaton::State::Stopped);
|
|
|
|
// start -> stop
|
|
QVERIFY(automaton.start());
|
|
QCOMPARE(automaton.getState(), FireAutomaton::State::Running);
|
|
QVERIFY(!automaton.start());
|
|
QVERIFY(!automaton.resume());
|
|
|
|
QVERIFY(spyFinished.wait(1000));
|
|
|
|
QCOMPARE(automaton.getState(), FireAutomaton::State::Stopped);
|
|
|
|
// start -> finish
|
|
QVERIFY(automaton.start());
|
|
QCOMPARE(automaton.getState(), FireAutomaton::State::Running);
|
|
QVERIFY(!automaton.start());
|
|
QVERIFY(!automaton.resume());
|
|
|
|
QVERIFY(spyFinished.wait(1000));
|
|
QCOMPARE(automaton.getState(), FireAutomaton::State::Stopped);
|
|
}
|
|
|
|
|
|
int main(int argc, char *argv[])
|
|
{
|
|
qRegisterMetaType<int32_t>("int32_t");
|
|
|
|
NGLCoreApplication app(argc, argv);
|
|
app.createLogger("UnitTest_FireAutomaton", "log4cxx_aes.props");
|
|
|
|
TestFireAutomaton testCase;
|
|
return QTest::qExec(&testCase, argc, argv);
|
|
}
|