c1e5cc3074
Improve argument parsing for createViaTo, createViaFromTo to handle Airway ghosts as well as strings. As part of this, allow specification of the airway level explicitly when looking up an airway. SF-ID: https://sourceforge.net/p/flightgear/codetickets/2686/
467 lines
16 KiB
C++
467 lines
16 KiB
C++
#include "test_fpNasal.hxx"
|
|
|
|
#include "test_suite/FGTestApi/testGlobals.hxx"
|
|
#include "test_suite/FGTestApi/NavDataCache.hxx"
|
|
|
|
#include <simgear/misc/strutils.hxx>
|
|
|
|
#include <Navaids/FlightPlan.hxx>
|
|
#include <Navaids/routePath.hxx>
|
|
#include <Navaids/NavDataCache.hxx>
|
|
#include <Navaids/waypoint.hxx>
|
|
#include <Navaids/navlist.hxx>
|
|
#include <Navaids/navrecord.hxx>
|
|
#include <Navaids/airways.hxx>
|
|
#include <Navaids/fix.hxx>
|
|
|
|
#include <Airports/airport.hxx>
|
|
#include <Autopilot/route_mgr.hxx>
|
|
|
|
using namespace flightgear;
|
|
|
|
static bool static_haveProcedures = false;
|
|
|
|
// Set up function for each test.
|
|
void FPNasalTests::setUp()
|
|
{
|
|
FGTestApi::setUp::initTestGlobals("flightplan");
|
|
FGTestApi::setUp::initNavDataCache();
|
|
|
|
SGPath proceduresPath = SGPath::fromEnv("FG_PROCEDURES_PATH");
|
|
if (proceduresPath.exists()) {
|
|
static_haveProcedures = true;
|
|
globals->append_fg_scenery(proceduresPath);
|
|
}
|
|
|
|
// flightplan() acces needs the route manager
|
|
globals->add_new_subsystem<FGRouteMgr>(SGSubsystemMgr::GENERAL);
|
|
|
|
globals->get_subsystem_mgr()->bind();
|
|
globals->get_subsystem_mgr()->init();
|
|
|
|
FGTestApi::setUp::initStandardNasal();
|
|
globals->get_subsystem_mgr()->postinit();
|
|
}
|
|
|
|
|
|
// Clean up after each test.
|
|
void FPNasalTests::tearDown()
|
|
{
|
|
FGTestApi::tearDown::shutdownTestGlobals();
|
|
}
|
|
|
|
static FlightPlanRef makeTestFP(const std::string& depICAO, const std::string& depRunway,
|
|
const std::string& destICAO, const std::string& destRunway,
|
|
const std::string& waypoints)
|
|
{
|
|
FlightPlanRef f = new FlightPlan;
|
|
FGTestApi::setUp::populateFPWithNasal(f, depICAO, depRunway, destICAO, destRunway, waypoints);
|
|
return f;
|
|
}
|
|
|
|
void FPNasalTests::testBasic()
|
|
{
|
|
|
|
FlightPlanRef fp1 = makeTestFP("EGCC", "23L", "EHAM", "24",
|
|
"TNT CLN");
|
|
fp1->setIdent("testplan");
|
|
|
|
// setup the FP on the route-manager, so flightplan() call works
|
|
auto rm = globals->get_subsystem<FGRouteMgr>();
|
|
rm->setFlightPlan(fp1);
|
|
rm->activate();
|
|
|
|
// modify leg data dfrom Nasal
|
|
bool ok = FGTestApi::executeNasal(R"(
|
|
var fp = flightplan(); # retrieve the global flightplan
|
|
var leg = fp.getWP(3);
|
|
leg.setAltitude(6000, 'AT');
|
|
)");
|
|
CPPUNIT_ASSERT(ok);
|
|
|
|
// check the value updated in the leg
|
|
CPPUNIT_ASSERT_EQUAL(RESTRICT_AT, fp1->legAtIndex(3)->altitudeRestriction());
|
|
CPPUNIT_ASSERT_EQUAL(6000, fp1->legAtIndex(3)->altitudeFt());
|
|
|
|
// insert some waypoints from Nasal
|
|
|
|
ok = FGTestApi::executeNasal(R"(
|
|
var fp = flightplan();
|
|
var leg = fp.getWP(2);
|
|
var newWP = createWPFrom(navinfo(leg.lat, leg.lon, 'COA')[0]);
|
|
fp.insertWPAfter(newWP, 2);
|
|
)");
|
|
CPPUNIT_ASSERT(ok);
|
|
|
|
CPPUNIT_ASSERT_EQUAL(string{"COSTA VOR-DME"}, fp1->legAtIndex(3)->waypoint()->source()->name());
|
|
|
|
ok = FGTestApi::executeNasal(R"(
|
|
var fp = flightplan();
|
|
fp.clearAll();
|
|
unitTest.assert_equal(fp.getPlanSize(), 0);
|
|
unitTest.assert_equal(fp.current, -1);
|
|
unitTest.assert_equal(fp.departure, nil);
|
|
unitTest.assert_equal(fp.sid, nil);
|
|
unitTest.assert_equal(fp.cruiseSpeedKt, 0);
|
|
)");
|
|
CPPUNIT_ASSERT(ok);
|
|
}
|
|
|
|
void FPNasalTests::testRestrictions()
|
|
{
|
|
FlightPlanRef fp1 = makeTestFP("EGCC", "23L", "EHAM", "24",
|
|
"TNT CLN");
|
|
fp1->setIdent("testplan");
|
|
|
|
// setup the FP on the route-manager, so flightplan() call works
|
|
auto rm = globals->get_subsystem<FGRouteMgr>();
|
|
rm->setFlightPlan(fp1);
|
|
rm->activate();
|
|
|
|
// modify leg data dfrom Nasal
|
|
bool ok = FGTestApi::executeNasal(R"(
|
|
var fp = flightplan(); # retrieve the global flightplan
|
|
var leg = fp.getWP(3);
|
|
leg.setAltitude(6000, 'AT');
|
|
)");
|
|
CPPUNIT_ASSERT(ok);
|
|
|
|
// check the value updated in the leg
|
|
CPPUNIT_ASSERT_EQUAL(RESTRICT_AT, fp1->legAtIndex(3)->altitudeRestriction());
|
|
CPPUNIT_ASSERT_EQUAL(6000, fp1->legAtIndex(3)->altitudeFt());
|
|
|
|
ok = FGTestApi::executeNasal(R"(
|
|
var fp = flightplan(); # retrieve the global flightplan
|
|
var leg = fp.getWP(3);
|
|
leg.setAltitude(6000, 'above');
|
|
)");
|
|
CPPUNIT_ASSERT(ok);
|
|
|
|
CPPUNIT_ASSERT_EQUAL(RESTRICT_ABOVE, fp1->legAtIndex(3)->altitudeRestriction());
|
|
CPPUNIT_ASSERT_EQUAL(6000, fp1->legAtIndex(3)->altitudeFt());
|
|
|
|
ok = FGTestApi::executeNasal(R"(
|
|
var fp = flightplan(); # retrieve the global flightplan
|
|
var leg = fp.getWP(3);
|
|
leg.setAltitude(6000, 'below');
|
|
)");
|
|
CPPUNIT_ASSERT(ok);
|
|
|
|
CPPUNIT_ASSERT_EQUAL(RESTRICT_BELOW, fp1->legAtIndex(3)->altitudeRestriction());
|
|
CPPUNIT_ASSERT_EQUAL(6000, fp1->legAtIndex(3)->altitudeFt());
|
|
|
|
ok = FGTestApi::executeNasal(R"(
|
|
var fp = flightplan(); # retrieve the global flightplan
|
|
var leg = fp.getWP(3);
|
|
leg.setAltitude(6000, 'delete');
|
|
)");
|
|
CPPUNIT_ASSERT(ok);
|
|
|
|
CPPUNIT_ASSERT_EQUAL(RESTRICT_DELETE, fp1->legAtIndex(3)->altitudeRestriction());
|
|
|
|
ok = FGTestApi::executeNasal(R"(
|
|
var fp = flightplan(); # retrieve the global flightplan
|
|
var leg = fp.getWP(3);
|
|
leg.setSpeed(250, 'at');
|
|
)");
|
|
CPPUNIT_ASSERT(ok);
|
|
|
|
CPPUNIT_ASSERT_EQUAL(RESTRICT_AT, fp1->legAtIndex(3)->speedRestriction());
|
|
CPPUNIT_ASSERT_EQUAL(250, fp1->legAtIndex(3)->speedKts());
|
|
|
|
ok = FGTestApi::executeNasal(R"(
|
|
var fp = flightplan(); # retrieve the global flightplan
|
|
var leg = fp.getWP(3);
|
|
leg.setSpeed(250, 'above');
|
|
)");
|
|
CPPUNIT_ASSERT(ok);
|
|
|
|
CPPUNIT_ASSERT_EQUAL(RESTRICT_ABOVE, fp1->legAtIndex(3)->speedRestriction());
|
|
CPPUNIT_ASSERT_EQUAL(250, fp1->legAtIndex(3)->speedKts());
|
|
|
|
ok = FGTestApi::executeNasal(R"(
|
|
var fp = flightplan(); # retrieve the global flightplan
|
|
var leg = fp.getWP(3);
|
|
leg.setSpeed(250, 'below');
|
|
)");
|
|
CPPUNIT_ASSERT(ok);
|
|
|
|
CPPUNIT_ASSERT_EQUAL(RESTRICT_BELOW, fp1->legAtIndex(3)->speedRestriction());
|
|
CPPUNIT_ASSERT_EQUAL(250, fp1->legAtIndex(3)->speedKts());
|
|
|
|
ok = FGTestApi::executeNasal(R"(
|
|
var fp = flightplan(); # retrieve the global flightplan
|
|
var leg = fp.getWP(3);
|
|
leg.setSpeed(250, 'delete');
|
|
)");
|
|
CPPUNIT_ASSERT(ok);
|
|
|
|
CPPUNIT_ASSERT_EQUAL(RESTRICT_DELETE, fp1->legAtIndex(3)->speedRestriction());
|
|
}
|
|
|
|
void FPNasalTests::testSegfaultWaypointGhost()
|
|
{
|
|
// checking for a segfault here, no segfault indicates success. A runtime error in the log is acceptable here.
|
|
bool ok = FGTestApi::executeNasal(R"(
|
|
var fp = createFlightplan();
|
|
fp.departure = airportinfo("BIKF");
|
|
fp.destination = airportinfo("EGLL");
|
|
var wp = fp.getWP(1);
|
|
fp.deleteWP(1);
|
|
print(wp.wp_name);
|
|
)");
|
|
CPPUNIT_ASSERT(ok);
|
|
}
|
|
|
|
void FPNasalTests::testSIDTransitionAPI()
|
|
{
|
|
if (!static_haveProcedures) {
|
|
return;
|
|
}
|
|
|
|
auto rm = globals->get_subsystem<FGRouteMgr>();
|
|
|
|
bool ok = FGTestApi::executeNasal(R"(
|
|
var fp = flightplan();
|
|
fp.departure = airportinfo("KJFK");
|
|
fp.destination = airportinfo("EGLL");
|
|
|
|
var sid = fp.departure.getSid("DEEZZ5.13L");
|
|
|
|
unitTest.assert(sid != nil, "SID not found");
|
|
unitTest.assert_equal(sid.id, "DEEZZ5.13L", "Incorrect SID loaded");
|
|
|
|
var trans = sid.transition('CANDR');
|
|
unitTest.assert_equal(trans.id, "CANDR", "Couldn't find transition");
|
|
unitTest.assert_equal(trans.tp_type, "transition", "Procedure type incorrect");
|
|
|
|
fp.sid = trans;
|
|
fp.departure_runway = fp.departure.runway('13L')
|
|
)");
|
|
|
|
CPPUNIT_ASSERT(ok);
|
|
|
|
auto fp = rm->flightPlan();
|
|
|
|
CPPUNIT_ASSERT(fp->departureRunway());
|
|
CPPUNIT_ASSERT(fp->sid());
|
|
CPPUNIT_ASSERT(fp->sidTransition());
|
|
|
|
CPPUNIT_ASSERT_EQUAL(fp->departureRunway()->ident(), string{"13L"});
|
|
CPPUNIT_ASSERT_EQUAL(fp->sid()->ident(), string{"DEEZZ5.13L"});
|
|
CPPUNIT_ASSERT_EQUAL(fp->sidTransition()->ident(), string{"CANDR"});
|
|
|
|
// test specify SID via transition in Nasal
|
|
rm->setFlightPlan(new FlightPlan{});
|
|
|
|
ok = FGTestApi::executeNasal(R"(
|
|
var fp = flightplan();
|
|
fp.departure = airportinfo("KJFK");
|
|
fp.destination = airportinfo("EGLL");
|
|
fp.departure_runway = airportinfo("KJFK").runways["13L"];
|
|
fp.sid = airportinfo("KJFK").getSid("DEEZZ5.13L");
|
|
fp.sid_trans = "CANDR";
|
|
|
|
)");
|
|
|
|
CPPUNIT_ASSERT(ok);
|
|
|
|
fp = rm->flightPlan();
|
|
|
|
CPPUNIT_ASSERT(fp->departureRunway());
|
|
CPPUNIT_ASSERT(fp->sid());
|
|
CPPUNIT_ASSERT(fp->sidTransition());
|
|
|
|
CPPUNIT_ASSERT_EQUAL(fp->departureRunway()->ident(), string{"13L"});
|
|
CPPUNIT_ASSERT_EQUAL(fp->sid()->ident(), string{"DEEZZ5.13L"});
|
|
CPPUNIT_ASSERT_EQUAL(fp->sidTransition()->ident(), string{"CANDR"});
|
|
|
|
|
|
}
|
|
|
|
void FPNasalTests::testSTARTransitionAPI()
|
|
{
|
|
if (!static_haveProcedures) {
|
|
return;
|
|
}
|
|
|
|
auto rm = globals->get_subsystem<FGRouteMgr>();
|
|
|
|
bool ok = FGTestApi::executeNasal(R"(
|
|
var fp = flightplan();
|
|
fp.departure = airportinfo("EGLL");
|
|
fp.destination = airportinfo("EDDM");
|
|
|
|
var star = fp.destination.getStar("RIXE3A.26L");
|
|
|
|
unitTest.assert(star != nil, "STAR not found");
|
|
unitTest.assert_equal(star.id, "RIXE3A.26L", "Incorrect STAR loaded");
|
|
|
|
|
|
fp.star = star;
|
|
fp.destination_runway = fp.destination.runway('26L')
|
|
)");
|
|
|
|
CPPUNIT_ASSERT(ok);
|
|
|
|
auto fp = rm->flightPlan();
|
|
|
|
CPPUNIT_ASSERT(fp->star());
|
|
CPPUNIT_ASSERT(fp->starTransition() == nullptr);
|
|
|
|
CPPUNIT_ASSERT_EQUAL(fp->star()->ident(), string{"RIXE3A.26L"});
|
|
}
|
|
|
|
void FPNasalTests::testApproachTransitionAPI()
|
|
{
|
|
if (!static_haveProcedures) {
|
|
return;
|
|
}
|
|
|
|
auto rm = globals->get_subsystem<FGRouteMgr>();
|
|
|
|
bool ok = FGTestApi::executeNasal(R"(
|
|
var fp = flightplan();
|
|
fp.departure = airportinfo("EGLL");
|
|
fp.destination = airportinfo("EDDM");
|
|
|
|
var star = fp.destination.getStar("RIXE3A.08L");
|
|
|
|
unitTest.assert(star != nil, "STAR not found");
|
|
unitTest.assert_equal(star.id, "RIXE3A.08L", "Incorrect STAR loaded");
|
|
|
|
fp.star = star;
|
|
fp.destination_runway = fp.destination.runway('08L');
|
|
|
|
var approach = fp.destination.getApproach("ILS08L");
|
|
unitTest.assert(approach != nil, "No approach loaded");
|
|
|
|
var trans = approach.transition('LUL1C');
|
|
|
|
unitTest.assert(trans != nil, "approach transition not found");
|
|
unitTest.assert_equal(trans.id, "LUL1C", "Incorrect approach transition loaded");
|
|
unitTest.assert_equal(trans.tp_type, "transition", "Procedure type incorrect");
|
|
|
|
fp.approach = trans;
|
|
|
|
unitTest.assert_equal(fp.approach.id, "ILS08L", "Incorrect approach returned");
|
|
unitTest.assert_equal(fp.approach_trans.id, "LUL1C", "Incorrect transition returned");
|
|
unitTest.assert_equal(fp.approach_trans.tp_type, "transition", "Procedure type incorrect");
|
|
)");
|
|
|
|
CPPUNIT_ASSERT(ok);
|
|
|
|
auto fp = rm->flightPlan();
|
|
|
|
CPPUNIT_ASSERT(fp->approach());
|
|
CPPUNIT_ASSERT_EQUAL(string{"LUL1C"}, fp->approachTransition()->ident());
|
|
CPPUNIT_ASSERT_EQUAL(string{"ILS08L"}, fp->approach()->ident());
|
|
}
|
|
|
|
void FPNasalTests::testApproachTransitionAPIWithCloning()
|
|
{
|
|
if (!static_haveProcedures) {
|
|
return;
|
|
}
|
|
|
|
auto rm = globals->get_subsystem<FGRouteMgr>();
|
|
|
|
bool ok = FGTestApi::executeNasal(R"(
|
|
var fp = flightplan();
|
|
fp.departure = airportinfo("EGLL");
|
|
fp.destination = airportinfo("EHAM");
|
|
fp.star = fp.destination.getStar("REDF1A");
|
|
fp.destination_runway = fp.destination.runway('06');
|
|
|
|
var approach = fp.destination.getApproach("ILS06");
|
|
unitTest.assert(approach != nil, "No approach loaded");
|
|
|
|
var trans = approach.transition('SUG2A');
|
|
unitTest.assert(trans != nil, "approach transition not found");
|
|
|
|
fp.approach = trans;
|
|
|
|
unitTest.assert_equal(fp.approach.id, "ILS06", "Incorrect approach returned");
|
|
unitTest.assert_equal(fp.approach_trans.id, "SUG2A", "Incorrect transition returned");
|
|
unitTest.assert_equal(fp.approach_trans.tp_type, "transition", "Procedure type incorrect");
|
|
)");
|
|
|
|
CPPUNIT_ASSERT(ok);
|
|
|
|
auto fp = rm->flightPlan();
|
|
|
|
CPPUNIT_ASSERT(fp->approach());
|
|
CPPUNIT_ASSERT_EQUAL(string{"SUG2A"}, fp->approachTransition()->ident());
|
|
CPPUNIT_ASSERT_EQUAL(string{"ILS06"}, fp->approach()->ident());
|
|
|
|
auto fp2 = fp->clone("testplan2");
|
|
CPPUNIT_ASSERT_EQUAL(string{"ILS06"}, fp2->approach()->ident());
|
|
CPPUNIT_ASSERT_EQUAL(string{"SUG2A"}, fp2->approachTransition()->ident());
|
|
}
|
|
|
|
void FPNasalTests::testAirwaysAPI()
|
|
{
|
|
bool ok = FGTestApi::executeNasal(R"(
|
|
var airwayIdent = "L620";
|
|
var airwayStore = airway(airwayIdent, "low");
|
|
unitTest.assert(airwayStore != nil, "Airway " ~ airwayIdent ~ " not found");
|
|
unitTest.assert(airwayStore.id == airwayIdent, "Incorrect airway found");
|
|
unitTest.assert_equal(airwayStore.level, 'low', "Incorrect airway found");
|
|
unitTest.assert_equal(airwayStore.level_code, Airway.LOW, "Incorrect airway found");
|
|
|
|
airwayIdent = "UL620";
|
|
var cln = findNavaidsByID("CLN", "VOR")[0];
|
|
airwayStore = airway(airwayIdent, cln);
|
|
unitTest.assert(airwayStore != nil, "Airway " ~ airwayIdent ~ " not found");
|
|
unitTest.assert(airwayStore.id == airwayIdent, "Incorrect airway found");
|
|
unitTest.assert_equal(airwayStore.level_code, Airway.HIGH, "Incorrect airway found");
|
|
|
|
airwayIdent = "J547";
|
|
airwayStore = airway(airwayIdent);
|
|
unitTest.assert(airwayStore != nil, "Airway " ~ airwayIdent ~ " not found");
|
|
unitTest.assert(airwayStore.id == airwayIdent, "Incorrect airway found");
|
|
)");
|
|
|
|
CPPUNIT_ASSERT(ok);
|
|
|
|
ok = FGTestApi::executeNasal(R"(
|
|
|
|
var airwayIdent = "L620";
|
|
var airwayStore = airway(airwayIdent, Airway.LOW);
|
|
var cln = findNavaidsByID("CLN", "VOR")[0];
|
|
|
|
var v1 = createViaTo(airwayIdent, "CLN");
|
|
unitTest.assert_equal(v1.wp_type, "via");
|
|
unitTest.assert_equal(v1.airway.id, 'L620');
|
|
unitTest.assert_equal(v1.airway.level_code, Airway.LOW);
|
|
|
|
var v2 = createViaTo(airwayStore, "TULIP");
|
|
unitTest.assert_equal(v2.wp_type, "via");
|
|
unitTest.assert_equal(v2.airway.id, airwayIdent);
|
|
|
|
var v3 = createViaFromTo(cln, "L620", 'low', "TULIP");
|
|
unitTest.assert_equal(v3.airway.id, 'L620');
|
|
|
|
var v4 = createViaFromTo(cln, "L620", "REDFA");
|
|
unitTest.assert_equal(v4.airway.level_code, Airway.LOW);
|
|
)");
|
|
|
|
CPPUNIT_ASSERT(ok);
|
|
}
|
|
|
|
void FPNasalTests::testTotalDistanceAPI()
|
|
{
|
|
auto rm = globals->get_subsystem<FGRouteMgr>();
|
|
|
|
bool ok = FGTestApi::executeNasal(R"(
|
|
var fp = flightplan();
|
|
fp.departure = airportinfo("BIKF");
|
|
fp.destination = airportinfo("EGLL");
|
|
unitTest.assert_doubles_equal(1025.9, fp.totalDistanceNm, 0.1, "Distance assertion failed");
|
|
)");
|
|
|
|
CPPUNIT_ASSERT(ok);
|
|
|
|
auto fp = rm->flightPlan();
|
|
CPPUNIT_ASSERT_DOUBLES_EQUAL(fp->totalDistanceNm(), 1025.9, 0.1);
|
|
}
|