flightgear/test_suite/simgear_tests/structure/test_event.cxx
2022-10-20 20:29:11 +08:00

143 lines
3.8 KiB
C++

/*
* Copyright (C) 2016 Edward d'Auvergne
*
* This file is part of the program FlightGear.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <algorithm>
#include <memory>
#include "test_event.hxx"
using namespace std;
namespace {
SGEventMgr* global_eventManager = nullptr;
double global_realTime = 0.0;
// class which behaves similarly to TimerObj in NasalSys
class FakeNasalTimer
{
public:
FakeNasalTimer(string n) : _name(n)
{
}
void invoke()
{
++_invokeCount;
if (_expectedTime > 0.0) {
CPPUNIT_ASSERT_DOUBLES_EQUAL(_expectedTime, global_realTime, 0.1);
}
// rescheudle base don the next time
if (!_rescheduleTimes.empty()) {
const auto t = _rescheduleTimes.front();
_rescheduleTimes.pop_front();
// TimerObj does this, eugh
if (global_eventManager) {
global_eventManager->removeTask(_name);
start(t);
}
}
}
void start(double interval)
{
if (!global_eventManager)
return;
global_eventManager->addTask(_name, [this](){ this->invoke(); },
interval, interval /* delay */, false);
_expectedTime = global_realTime + interval;
}
string _name;
deque<double> _rescheduleTimes;
int _invokeCount = 0;
double _expectedTime = 0.0;
};
} // namespace
// Set up function for each test.
void SimgearEventTests::setUp()
{
_eventManager = new SGEventMgr;
global_eventManager = _eventManager;
_eventManager->init();
_realTimeProp = new SGPropertyNode{};
_eventManager->setRealtimeProperty(_realTimeProp);
}
// Clean up after each test.
void SimgearEventTests::tearDown()
{
global_eventManager = nullptr;
}
void SimgearEventTests::runForTestTime(double totalTime, double updateHz, double simTimeScaling)
{
const double dt = 1.0 / updateHz;
const int updateCount = static_cast<int>(totalTime * updateHz);
const double simDt = dt * simTimeScaling;
_realTimeProp->setDoubleValue(dt);
global_realTime = 0.0;
for (int c = 0; c < updateCount; ++c) {
const double newRealTime = global_realTime + dt;
global_realTime = newRealTime;
_eventManager->update(simDt);
}
}
void SimgearEventTests::testTaskRescheduleDuringRun()
{
auto t1 = std::make_unique<FakeNasalTimer>("timer_aaa");
t1->_rescheduleTimes.resize(10);
fill(t1->_rescheduleTimes.begin(), t1->_rescheduleTimes.end(), 0.5);
t1->_rescheduleTimes.push_back(30.0); // large final value
global_realTime = 0.0;
t1->start(1.0);
runForTestTime(8.0, 20);
CPPUNIT_ASSERT_EQUAL(11, t1->_invokeCount);
}
void SimgearEventTests::testTaskRescheduleDuringRun2()
{
auto t1 = std::make_unique<FakeNasalTimer>("timer_bbb");
const std::initializer_list<double> times = {
0.02, 0.05, 0.02, 0.1, 0.02, 0.125, 0.05, 0.02};
t1->_rescheduleTimes = times;
t1->_rescheduleTimes.push_back(30.0); // large final value
global_realTime = 0.0;
t1->start(1.0);
// running at 60Hz, check we don't miss any
runForTestTime(8.0, 60);
CPPUNIT_ASSERT_EQUAL(9, t1->_invokeCount);
}