1
0
Fork 0

Partial testing framework.

Compile a useful subset of FG as a shared library, and add two basic
uses of this to exercise some Flightplan / RoutePath / navaid
functions.

The test framework can/will be expanded incrementally from here, this
is just a starting point.
This commit is contained in:
James Turner 2017-03-21 21:43:42 +01:00
parent 7adb2fa851
commit 9e122eaf81
25 changed files with 1499 additions and 113 deletions

View file

@ -512,6 +512,22 @@ add_subdirectory(utils)
add_subdirectory(src)
add_subdirectory(man)
if(ENABLE_TESTS)
# enable CTest / make test target
message(STATUS "Tests: ENABLED")
include (Dart)
enable_testing()
if(WIN32)
# tests disabled until shared library export is fixed on Windows
message(STATUS "Tests disabled on Windows for the moment")
else()
add_subdirectory(tests)
endif()
else()
message(STATUS "Tests: DISABLED")
endif(ENABLE_TESTS)
#-----------------------------------------------------------------------------
### uninstall target
#-----------------------------------------------------------------------------

View file

@ -26,8 +26,13 @@
#include <simgear/constants.h>
#include <simgear/debug/logstream.hxx>
#ifdef FG_TESTLIB
#include <tests/fake_sgSky.hxx>
#else
#include <simgear/scene/sky/sky.hxx>
#include <simgear/scene/model/particles.hxx>
#endif
#include <simgear/structure/event_mgr.hxx>
#include <Main/main.hxx>
@ -47,6 +52,7 @@
#include "gravity.hxx"
#include "magvarmanager.hxx"
#ifndef FG_TESTLIB
class FG3DCloudsListener : public SGPropertyChangeListener {
public:
FG3DCloudsListener( FGClouds * fgClouds );
@ -77,19 +83,26 @@ void FG3DCloudsListener::valueChanged( SGPropertyNode * node )
{
_fgClouds->set_3dClouds( _enableNode->getBoolValue() );
}
#endif
FGEnvironmentMgr::FGEnvironmentMgr () :
_environment(new FGEnvironment()),
fgClouds(new FGClouds()),
fgClouds(nullptr),
_cloudLayersDirty(true),
_3dCloudsEnableListener(new FG3DCloudsListener(fgClouds) ),
_3dCloudsEnableListener(nullptr),
_sky(globals->get_renderer()->getSky())
{
#ifndef FG_TESTLIB
fgClouds = new FGClouds;
_3dCloudsEnableListener = new FG3DCloudsListener(fgClouds);
#endif
set_subsystem("controller", Environment::LayerInterpolateController::createInstance( fgGetNode("/environment/config", true ) ));
set_subsystem("realwx", Environment::RealWxController::createInstance( fgGetNode("/environment/realwx", true ) ), 1.0 );
set_subsystem("precipitation", new FGPrecipitationMgr);
#ifndef FG_TESTLIB
set_subsystem("realwx", Environment::RealWxController::createInstance( fgGetNode("/environment/realwx", true ) ), 1.0 );
set_subsystem("terrainsampler", Environment::TerrainSampler::createInstance( fgGetNode("/environment/terrain", true ) ));
#endif
set_subsystem("ridgelift", new FGRidgeLift);
set_subsystem("magvar", new FGMagVarManager);
@ -104,10 +117,11 @@ FGEnvironmentMgr::~FGEnvironmentMgr ()
remove_subsystem("controller");
remove_subsystem("magvar");
#ifndef FG_TESTLIB
delete fgClouds;
delete _environment;
delete _3dCloudsEnableListener;
#endif
delete _environment;
}
SGSubsystem::InitStatus FGEnvironmentMgr::incrementalInit()
@ -115,7 +129,9 @@ SGSubsystem::InitStatus FGEnvironmentMgr::incrementalInit()
InitStatus r = SGSubsystemGroup::incrementalInit();
if (r == INIT_DONE) {
#ifndef FG_TESTLIB
fgClouds->Init();
#endif
globals->get_event_mgr()->addTask("updateClosestAirport", this,
&FGEnvironmentMgr::updateClosestAirport, 30 );
}
@ -148,10 +164,11 @@ FGEnvironmentMgr::bind ()
_tiedProperties.Tie( "effective-visibility-m", _sky,
&SGSky::get_visibility );
#ifndef FG_TESTLIB
_tiedProperties.Tie("rebuild-layers", fgClouds,
&FGClouds::get_update_event,
&FGClouds::set_update_event);
#endif
// _tiedProperties.Tie("turbulence/use-cloud-turbulence", &sgEnviro,
// &SGEnviro::get_turbulence_enable_state,
// &SGEnviro::set_turbulence_enable_state);
@ -221,7 +238,6 @@ FGEnvironmentMgr::bind ()
_tiedProperties.Tie("clouds3d-use-impostors", _sky,
&SGSky::get_3dCloudUseImpostors,
&SGSky::set_3dCloudUseImpostors);
}
void
@ -240,13 +256,14 @@ FGEnvironmentMgr::update (double dt)
SGGeod aircraftPos(globals->get_aircraft_position());
_environment->set_elevation_ft( aircraftPos.getElevationFt() );
#ifndef FG_TESTLIB
simgear::Particles::setWindFrom( _environment->get_wind_from_heading_deg(),
_environment->get_wind_speed_kt() );
if( _cloudLayersDirty ) {
_cloudLayersDirty = false;
fgClouds->set_update_event( fgClouds->get_update_event()+1 );
}
#endif
fgSetDouble( "/environment/gravitational-acceleration-mps2",
Environment::Gravity::instance()->getGravity(aircraftPos));

View file

@ -36,8 +36,10 @@
class FGPrecipitationMgr : public SGSubsystem
{
private:
#ifndef FG_TESTLIB
osg::ref_ptr<osg::MatrixTransform> transform;
osg::ref_ptr<SGPrecipitation> precipitation;
#endif
float getPrecipitationAtAltitudeMax(void);
simgear::TiedPropertyList _tiedProperties;
@ -56,4 +58,3 @@ public:
};
#endif

View file

@ -33,6 +33,7 @@
#cmakedefine ENABLE_JSBSIM
#define PKGLIBDIR "@FG_DATA_DIR@"
#define FGSRCDIR "@PROJECT_SOURCE_DIR@"
#define WEB_BROWSER "@WEB_BROWSER@"
// Ensure FG_HAVE_xxx always have a value

View file

@ -242,8 +242,10 @@ setFreeze (bool f)
}
}
#ifndef FG_TESTLIB
// Pause the particle system
simgear::Particles::setFrozen(f);
#endif
}

View file

@ -20,25 +20,25 @@
//
// $Id$
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include <config.h>
#include <boost/foreach.hpp>
#include <algorithm>
#ifndef FG_TESTLIB
#include <osgViewer/Viewer>
#include <osgDB/Registry>
#endif
#include <simgear/structure/commands.hxx>
#include <simgear/structure/exception.hxx>
#include <simgear/misc/sg_path.hxx>
#include <simgear/misc/sg_dir.hxx>
#include <simgear/timing/sg_time.hxx>
#include <simgear/ephemeris/ephemeris.hxx>
#include <simgear/scene/material/matlib.hxx>
#include <simgear/structure/subsystem_mgr.hxx>
#include <simgear/structure/event_mgr.hxx>
#include <simgear/sound/soundmgr.hxx>
#include <simgear/misc/ResourceManager.hxx>
#include <simgear/props/propertyObject.hxx>
#include <simgear/props/props_io.hxx>
@ -48,14 +48,21 @@
#include <Aircraft/controls.hxx>
#include <Airports/runways.hxx>
#include <Autopilot/route_mgr.hxx>
#include <Navaids/navlist.hxx>
#include <GUI/gui.h>
#include <Viewer/viewmgr.hxx>
#ifndef FG_TESTLIB
#include <Scenery/scenery.hxx>
#include <Scenery/tilemgr.hxx>
#include <Navaids/navlist.hxx>
#include <Viewer/renderer.hxx>
#include <Viewer/viewmgr.hxx>
#include <GUI/FGFontCache.hxx>
#include <simgear/sound/soundmgr.hxx>
#include <simgear/scene/material/matlib.hxx>
#endif
#include "globals.hxx"
#include "locale.hxx"
@ -147,7 +154,9 @@ FGGlobals *globals = NULL;
// Constructor
FGGlobals::FGGlobals() :
#ifndef FG_TESTLIB
renderer( new FGRenderer ),
#endif
subsystem_mgr( new SGSubsystemMgr ),
event_mgr( new SGEventMgr ),
sim_time_sec( 0.0 ),
@ -195,7 +204,7 @@ FGGlobals::~FGGlobals()
// stop OSG threading first, to avoid thread races while we tear down
// scene-graph pieces
#ifndef FG_TESTLIB
osg::ref_ptr<osgViewer::Viewer> vw(renderer->getViewer());
if (vw) {
// https://code.google.com/p/flightgear-bugs/issues/detail?id=1291
@ -204,10 +213,11 @@ FGGlobals::~FGGlobals()
// GraphicsContext)
vw->stopThreading();
}
#endif
subsystem_mgr->shutdown();
subsystem_mgr->unbind();
#ifndef FG_TESTLIB
// don't cancel the pager until after shutdown, since AIModels (and
// potentially others) can queue delete requests on the pager.
if (vw && vw->getDatabasePager()) {
@ -223,21 +233,24 @@ FGGlobals::~FGGlobals()
FGFontCache::shutdown();
fgCancelSnapShot();
#endif
delete subsystem_mgr;
subsystem_mgr = NULL; // important so ::get_subsystem returns NULL
vw = 0; // don't delete the viewer until now
#ifndef FG_TESTLIB
vw = nullptr; // don't delete the viewer until now
set_matlib(NULL);
#endif
delete time_params;
set_matlib(NULL);
delete channel_options_list;
delete initial_waypoints;
delete channellist;
simgear::PropertyObjectBase::setDefaultRoot(NULL);
#ifndef FG_TESTLIB
simgear::SGModelLib::resetPropertyRoot();
#endif
delete locale;
locale = NULL;
@ -509,12 +522,14 @@ FGGlobals::get_renderer () const
void FGGlobals::set_renderer(FGRenderer *render)
{
#ifndef FG_TESTLIB
if (render == renderer) {
return;
}
delete renderer;
renderer = render;
#endif
}
SGSubsystemMgr *
@ -750,7 +765,11 @@ void FGGlobals::set_warp_delta( long int d )
FGScenery* FGGlobals::get_scenery () const
{
#ifdef FG_TESTLIB
return nullptr;
#else
return get_subsystem<FGScenery>();
#endif
}
FGViewMgr *FGGlobals::get_viewmgr() const
@ -766,7 +785,9 @@ flightgear::View* FGGlobals::get_current_view () const
void FGGlobals::set_matlib( SGMaterialLib *m )
{
#ifndef FG_TESTLIB
matlib = m;
#endif
}
FGControls *FGGlobals::get_controls() const

View file

@ -118,8 +118,10 @@ private:
// Time structure
SGTime *time_params;
#ifndef FG_TESTLIB
// Material properties library
SGSharedPtr<SGMaterialLib> matlib;
#endif
SGCommandMgr *commands;
@ -317,7 +319,14 @@ public:
inline SGTime *get_time_params() const { return time_params; }
inline void set_time_params( SGTime *t ) { time_params = t; }
inline SGMaterialLib *get_matlib() const { return matlib; }
inline SGMaterialLib *get_matlib() const
{
#ifdef FG_TESTLIB
return nullptr;
#else
return matlib;
#endif
}
void set_matlib( SGMaterialLib *m );
inline SGPropertyNode *get_props () { return props; }

View file

@ -58,7 +58,8 @@
#include <GUI/gui.h>
#include <GUI/MessageBox.hxx>
#if defined(HAVE_QT)
#if defined(HAVE_QT) && !defined(FG_TESTLIB)
#include <GUI/QtLauncher.hxx>
#include <GUI/SetupRootDialog.hxx>
#endif
@ -236,9 +237,11 @@ void fgSetDefaults ()
SGPropertyNode* v = globals->get_props()->getNode("/sim/version", true);
v->setValueReadOnly("flightgear", FLIGHTGEAR_VERSION);
v->setValueReadOnly("simgear", SG_STRINGIZE(SIMGEAR_VERSION));
#ifndef FG_TESTLIB
v->setValueReadOnly("openscenegraph", osgGetVersion());
v->setValueReadOnly("openscenegraph-thread-safe-reference-counting",
osg::Referenced::getThreadSafeReferenceCounting());
#endif
v->setValueReadOnly("revision", REVISION);
v->setValueReadOnly("build-number", HUDSON_BUILD_NUMBER);
v->setValueReadOnly("build-id", HUDSON_BUILD_ID);
@ -989,12 +992,14 @@ fgOptJpgHttpd( const char * arg )
static int
fgOptHttpd( const char * arg )
{
#ifndef FG_TESTLIB
// port may be any valid address:port notation
// like 127.0.0.1:8080
// or just the port 8080
string port = simgear::strutils::strip(string(arg));
if( port.empty() ) return FG_OPTIONS_ERROR;
fgSetString( string(flightgear::http::PROPERTY_ROOT).append("/options/listening-port").c_str(), port );
#endif
return FG_OPTIONS_OK;
}
@ -2650,7 +2655,9 @@ void Options::showVersion() const
PathList scn = globals->get_fg_scenery();
cout << SGPath::join(scn, &SGPath::pathListSep) << endl;
cout << "SimGear version: " << SG_STRINGIZE(SIMGEAR_VERSION) << endl;
#ifndef FG_TESTLIB
cout << "OSG version: " << osgGetVersion() << endl;
#endif
cout << "PLIB version: " << PLIB_VERSION << endl;
}
@ -2767,7 +2774,7 @@ void Options::setupRoot(int argc, char **argv)
root = SGPath::fromLocal8Bit(envp);
SG_LOG(SG_GENERAL, SG_INFO, "set from FG_ROOT env var: fg_root = " << root );
} else {
#if defined(HAVE_QT)
#if defined(HAVE_QT) && !defined(FG_TESTLIB)
flightgear::initApp(argc, argv);
root = SetupRootDialog::restoreUserSelectedRoot();
#endif
@ -2785,7 +2792,7 @@ void Options::setupRoot(int argc, char **argv)
string base_version = fgBasePackageVersion(root);
#if defined(HAVE_QT)
#if defined(HAVE_QT) && !defined(FG_TESTLIB)
// only compare major and minor version, not the patch level.
const int versionComp = simgear::strutils::compare_versions(FLIGHTGEAR_VERSION, base_version, 2);

View file

@ -1069,8 +1069,8 @@ WayptRef FlightPlan::waypointFromString(const string& tgt )
SGGeod basePosition;
if (_legs.empty()) {
// route is empty, use current position
basePosition = globals->get_aircraft_position();
// route is empty, use departure position / aircraft position
basePosition = _departure ? _departure->geod() : globals->get_aircraft_position();
} else {
basePosition = _legs.back()->waypoint()->position();
}

View file

@ -990,10 +990,13 @@ static naRef f_geodinfo(naContext c, naRef me, int argc, naRef* args)
SGGeod geod = SGGeod::fromDegM(lon, lat, elev);
if(!globals->get_scenery()->get_elevation_m(geod, elev, &material))
return naNil();
const SGMaterial *mat = dynamic_cast<const SGMaterial *>(material);
naRef vec = naNewVector(c);
naVec_append(vec, naNum(elev));
naRef matdata = naNil();
#ifndef FG_TESTLIB
const SGMaterial *mat = dynamic_cast<const SGMaterial *>(material);
if(mat) {
matdata = naNewHash(c);
naRef names = naNewVector(c);
@ -1009,6 +1012,7 @@ static naRef f_geodinfo(naContext c, naRef me, int argc, naRef* args)
HASHSET("light_coverage", 14, naNum(mat->get_light_coverage()));
}
naVec_append(vec, matdata);
#endif
return vec;
#undef HASHSET
}

View file

@ -895,8 +895,10 @@ void FGNasalSys::init()
initNasalPositioned(_globals, _context);
initNasalPositioned_cppbind(_globals, _context);
initNasalAircraft(_globals, _context);
#ifndef FG_TESTLIB
NasalClipboard::init(this);
initNasalCanvas(_globals, _context);
#endif
initNasalCondition(_globals, _context);
initNasalHTTP(_globals, _context);
initNasalSGPath(_globals, _context);
@ -998,15 +1000,17 @@ naRef FGNasalSys::wrappedPropsNode(SGPropertyNode* aProps)
void FGNasalSys::update(double)
{
#ifndef FG_TESTLIB
if( NasalClipboard::getInstance() )
NasalClipboard::getInstance()->update();
#endif
if(!_dead_listener.empty()) {
vector<FGNasalListener *>::iterator it, end = _dead_listener.end();
for(it = _dead_listener.begin(); it != end; ++it) delete *it;
_dead_listener.clear();
}
#ifndef FG_TESTLIB
if (!_loadList.empty())
{
if( _delay_load )
@ -1022,7 +1026,7 @@ void FGNasalSys::update(double)
// (only unload one per update loop to avoid excessive lags)
_unloadList.pop()->unload();
}
#endif
// Destroy all queued ghosts
nasal::ghostProcessDestroyList();
@ -1443,14 +1447,18 @@ naRef FGNasalSys::removeListener(naContext c, int argc, naRef* args)
void FGNasalSys::registerToLoad(FGNasalModelData *data)
{
#ifndef FG_TESTLIB
if( _loadList.empty() )
_delay_load = true;
_loadList.push(data);
#endif
}
void FGNasalSys::registerToUnload(FGNasalModelData *data)
{
#ifndef FG_TESTLIB
_unloadList.push(data);
#endif
}
void FGNasalSys::addCommand(naRef func, const std::string& name)
@ -1626,5 +1634,3 @@ naRef NasalXMLVisitor::make_string(const char* s, int n)
return naStr_fromdata(naNewString(_c), const_cast<char *>(s),
n < 0 ? strlen(s) : n);
}

View file

@ -155,10 +155,10 @@ private:
//friend class FGNasalScript;
friend class FGNasalListener;
friend class FGNasalModuleListener;
#ifndef FG_TESTLIB
SGLockedQueue<SGSharedPtr<FGNasalModelData> > _loadList;
SGLockedQueue<SGSharedPtr<FGNasalModelData> > _unloadList;
#endif
// Delay removing items of the _loadList to ensure the are already attached
// to the scene graph (eg. enables to retrieve world position in load
// callback).

View file

@ -1078,7 +1078,11 @@ double View::getOrientation_z() const{
double View::get_aspect_ratio() const
{
#ifdef FG_TESTLIB
return 4.0 / 3.0;
#else
return flightgear::CameraGroup::getDefault()->getMasterAspectRatio();
#endif
}
double View::getLon_deg() const

View file

@ -137,6 +137,7 @@ FGViewMgr::update (double dt)
// Update the current view
currentView->update(dt);
#ifndef FG_TESTLIB
// update the camera now
osg::ref_ptr<flightgear::CameraGroup> cameraGroup = flightgear::CameraGroup::getDefault();
@ -144,6 +145,7 @@ FGViewMgr::update (double dt)
toOsg(currentView->getViewOrientation()));
cameraGroup->setCameraParameters(currentView->get_v_fov(),
cameraGroup->getMasterAspectRatio());
#endif
}
void FGViewMgr::clear()

105
tests/CMakeLists.txt Normal file
View file

@ -0,0 +1,105 @@
set(sources
Main/options.cxx
Main/fg_commands.cxx
Main/fg_props.cxx
Main/globals.cxx
Main/locale.cxx
Main/util.cxx
Aircraft/controls.cxx
Aircraft/FlightHistory.cxx
Aircraft/flightrecorder.cxx
Aircraft/replay.cxx
Autopilot/route_mgr.cxx
Airports/airport.cxx
Airports/airport.hxx
Airports/apt_loader.cxx
Airports/airportdynamicsmanager.cxx
Airports/airportdynamicsmanager.hxx
Airports/dynamicloader.cxx
Airports/dynamics.cxx
Airports/xmlloader.cxx
Airports/runwaybase.cxx
Airports/pavement.cxx
Airports/parking.cxx
Airports/groundnetwork.cxx
Airports/gnnode.cxx
Airports/runways.cxx
Airports/runwayprefs.cxx
Airports/runwayprefloader.cxx
ATC/CommStation.cxx
# ATC/GroundController.cxx
# ATC/atc_mgr.cxx
Environment/atmosphere.cxx
Environment/environment.cxx
Environment/environment_mgr.cxx
Environment/environment_ctrl.cxx
Environment/presets.cxx
Environment/gravity.cxx
Environment/ridge_lift.cxx
Environment/magvarmanager.cxx
Navaids/airways.cxx
Navaids/fixlist.cxx
Navaids/markerbeacon.cxx
Navaids/NavDataCache.cxx
Navaids/navdb.cxx
Navaids/navlist.cxx
Navaids/navrecord.cxx
Navaids/poidb.cxx
Navaids/procedure.cxx
Navaids/positioned.cxx
Navaids/PositionedOctree.cxx
Navaids/routePath.cxx
Navaids/route.cxx
Navaids/waypoint.cxx
Navaids/FlightPlan.cxx
Navaids/LevelDXML.cxx
Network/HTTPClient.cxx
Time/TimeManager.cxx
Time/bodysolver.cxx
Scripting/NasalSys.cxx
Scripting/NasalCondition.cxx
Scripting/NasalAircraft.cxx
Scripting/NasalString.cxx
Scripting/NasalPositioned.cxx
Scripting/NasalPositioned_cppbind.cxx
Scripting/nasal-props.cxx
Scripting/NasalSGPath.cxx
Scripting/NasalHTTP.cxx
Viewer/view.cxx
Viewer/viewmgr.cxx
)
foreach(s ${sources})
set_property(DIRECTORY APPEND PROPERTY fgtestlib_sources "${CMAKE_SOURCE_DIR}/src/${s}")
endforeach()
set_property(DIRECTORY APPEND PROPERTY fgtestlib_sources "${CMAKE_SOURCE_DIR}/3rdparty/cjson/cJSON.c")
get_property(fgtestlib_sources DIRECTORY PROPERTY fgtestlib_sources)
add_library(fgtestlib SHARED ${fgtestlib_sources}
unitTestHelpers.cxx
testStubs.cxx
fake_sgSky.cxx
fake_sgPrecipitation.cxx
fake_sound.cxx)
set_target_properties (fgtestlib
PROPERTIES
COMPILE_DEFINITIONS "FG_TESTLIB"
)
target_link_libraries(fgtestlib SimGearCore fgsqlite3 ${PLATFORM_LIBS})
add_executable(fgtest fgTestDriver.cxx)
target_link_libraries(fgtest fgtestlib)
# repeat this section for each unit-test executable
add_executable(testnavs test_navaids2.cxx)
target_link_libraries(testnavs fgtestlib)
add_test(testnavs ${EXECUTABLE_OUTPUT_PATH}/testnavs)
add_executable(testflightplan test_flightplan.cxx)
target_link_libraries(testflightplan fgtestlib)
add_test(testflightplan ${EXECUTABLE_OUTPUT_PATH}/testflightplan)

View file

@ -0,0 +1,17 @@
#include <Environment/precipitation_mgr.hxx>
FGPrecipitationMgr::FGPrecipitationMgr()
{
}
FGPrecipitationMgr::~FGPrecipitationMgr()
{
}
void FGPrecipitationMgr::bind () {}
void FGPrecipitationMgr::unbind () {}
void FGPrecipitationMgr::init () {}
void FGPrecipitationMgr::update (double dt) {}

41
tests/fake_sgSky.cxx Normal file
View file

@ -0,0 +1,41 @@
#include "fake_sgSky.hxx"
void SGSky::add_cloud_layer(SGCloudLayer *layer)
{
_cloudLayers.push_back(layer);
}
SGCloudLayer *SGSky::get_cloud_layer(int i)
{
return _cloudLayers.at(i);
}
int SGSky::get_cloud_layer_count() const
{
return _cloudLayers.size();
}
void SGSky::set_clouds_enabled(bool enabled)
{
_3dcloudsEnabled = enabled;
}
const std::string &SGCloudLayer::getCoverageString() const
{
return std::string();
}
const std::string &SGCloudLayer::getCoverageString(SGCloudLayer::Coverage coverage)
{
return std::string();
}
void SGCloudLayer::setCoverageString(const std::string &coverage)
{
}
void SGCloudLayer::set_enable3dClouds(bool enable)
{
}

338
tests/fake_sgSky.hxx Normal file
View file

@ -0,0 +1,338 @@
#ifndef FG_TEST_FAKE_SGSKY_HXX
#define FG_TEST_FAKE_SGSKY_HXX
#include <simgear/structure/SGReferenced.hxx>
#include <string>
#include <vector>
class SGCloudLayer : public SGReferenced {
public:
/**
* This is the list of available cloud coverages/textures
*/
enum Coverage {
SG_CLOUD_OVERCAST = 0,
SG_CLOUD_BROKEN,
SG_CLOUD_SCATTERED,
SG_CLOUD_FEW,
SG_CLOUD_CIRRUS,
SG_CLOUD_CLEAR,
SG_MAX_CLOUD_COVERAGES
};
static const std::string SG_CLOUD_OVERCAST_STRING; // "overcast"
static const std::string SG_CLOUD_BROKEN_STRING; // "broken"
static const std::string SG_CLOUD_SCATTERED_STRING; // "scattered"
static const std::string SG_CLOUD_FEW_STRING; // "few"
static const std::string SG_CLOUD_CIRRUS_STRING; // "cirrus"
static const std::string SG_CLOUD_CLEAR_STRING; // "clear"
/**
* Constructor
* @param tex_path the path to the set of cloud textures
*/
SGCloudLayer( const std::string &tex_path ) { }
/**
* Destructor
*/
~SGCloudLayer( void ) { }
/** get the cloud span (in meters) */
float getSpan_m () const
{ return _spanM; }
/**
* set the cloud span
* @param span_m the cloud span in meters
*/
void setSpan_m (float span_m)
{ _spanM = span_m; }
/** get the layer elevation (in meters) */
float getElevation_m () const
{
return _elevationM;
}
/**
* set the layer elevation. Note that this specifies the bottom
* of the cloud layer. The elevation of the top of the layer is
* elevation_m + thickness_m.
* @param elevation_m the layer elevation in meters
* @param set_span defines whether it is allowed to adjust the span
*/
void setElevation_m (float elevation_m, bool set_span = true)
{
_elevationM = elevation_m;
}
/** get the layer thickness */
float getThickness_m () const
{
return _thicknessM;
}
/**
* set the layer thickness.
* @param thickness_m the layer thickness in meters.
*/
void setThickness_m (float thickness_m)
{
_thicknessM = thickness_m;
}
/** get the layer visibility */
float getVisibility_m() const
{
return _visibilityM;
}
/**
* set the layer visibility
* @param visibility_m the layer minimum visibility in meters.
*/
void setVisibility_m(float visibility_m)
{
_visibilityM = visibility_m;
}
/**
* get the transition/boundary layer depth in meters. This
* allows gradual entry/exit from the cloud layer via adjusting
* visibility.
*/
float getTransition_m () const
{
return _transitionM;
}
/**
* set the transition layer size in meters
* @param transition_m the transition layer size in meters
*/
void setTransition_m (float transition_m)
{
_transitionM = transition_m;
}
/** get coverage type */
Coverage getCoverage () const
{
return _coverage;
}
/**
* set coverage type
* @param coverage the coverage type
*/
void setCoverage (Coverage coverage)
{
_coverage = coverage;
}
/** get coverage as string */
const std::string & getCoverageString() const;
/** get coverage as string */
static const std::string & getCoverageString( Coverage coverage );
/** get coverage type from string */
static Coverage getCoverageType( const std::string & coverage );
/** set coverage as string */
void setCoverageString( const std::string & coverage );
/**
* set the cloud movement direction
* @param dir the cloud movement direction
*/
inline void setDirection(float dir) {
// cout << "cloud dir = " << dir << endl;
direction = dir;
}
/** get the cloud movement direction */
inline float getDirection() { return direction; }
/**
* set the cloud movement speed
* @param sp the cloud movement speed
*/
inline void setSpeed(float sp) {
// cout << "cloud speed = " << sp << endl;
speed = sp;
}
/** get the cloud movement speed */
float getSpeed() { return speed; }
void setAlpha( float alpha );
void setMaxAlpha( float alpha )
{
_maxAlpha = alpha;
}
float getMaxAlpha() const
{
return _maxAlpha;
}
/** Enable/disable 3D clouds in this layer */
void set_enable3dClouds(bool enable);
private:
float _spanM = 0.0f;
float _elevationM = 0.0f;
float _thicknessM = 0.0f;
float _transitionM = 0.0f;
float _visibilityM = 0.0f;
Coverage _coverage;
float scale = 0.0f;
float speed = 0.0f;
float direction = 0.0f;
float _maxAlpha = 0.0f;
};
class SGSky
{
public:
void add_cloud_layer (SGCloudLayer * layer);
const SGCloudLayer * get_cloud_layer (int i) const
{
return _cloudLayers.at(i);
}
SGCloudLayer * get_cloud_layer (int i);
int get_cloud_layer_count () const;
/** @return current effective visibility */
float get_visibility() const
{ return _visibility; }
/** Set desired clear air visibility.
* @param v visibility in meters
*/
void set_visibility( float v )
{ _visibility = v; }
/** Get 3D cloud density */
double get_3dCloudDensity() const
{
return _3dcloudDensity;
}
/** Set 3D cloud density
* @param density 3D cloud density
*/
void set_3dCloudDensity(double density)
{
_3dcloudDensity = density;
}
/** Get 3D cloud visibility range*/
float get_3dCloudVisRange() const
{
return _3dcloudVisRange;
}
/** Set 3D cloud visibility range
*
* @param vis 3D cloud visibility range
*/
void set_3dCloudVisRange(float vis)
{
_3dcloudVisRange = vis;
}
/** Get 3D cloud impostor distance*/
float get_3dCloudImpostorDistance() const
{
return _3dcloudImpostorDistance;
}
/** Set 3D cloud impostor distance
*
* @param vis 3D cloud impostor distance
*/
void set_3dCloudImpostorDistance(float vis)
{
_3dcloudImpostorDistance = vis;
}
/** Get 3D cloud LoD1 Range*/
float get_3dCloudLoD1Range() const
{
return _3dcloudLoDRange1;
}
/** Set 3D cloud LoD1 Range
* @param vis LoD1 Range
*/
void set_3dCloudLoD1Range(float vis)
{
_3dcloudLoDRange1 = vis;
}
/** Get 3D cloud LoD2 Range*/
float get_3dCloudLoD2Range() const
{
return _3dcloudLoDRange2;
}
/** Set 3D cloud LoD2 Range
* @param vis LoD2 Range
*/
void set_3dCloudLoD2Range(float vis)
{
_3dcloudLoDRange2 = vis;
}
/** Get 3D cloud impostor usage */
bool get_3dCloudUseImpostors() const
{
return _3dcloudUSeImpostors;
}
/** Set 3D cloud impostor usage
*
* @param imp whether use impostors for 3D clouds
*/
void set_3dCloudUseImpostors(bool imp)
{
_3dcloudUSeImpostors = imp;
}
/** Get 3D cloud wrapping */
bool get_3dCloudWrap() const
{ return _3dcloudWrap; }
/** Set 3D cloud wrapping
* @param wrap whether to wrap 3D clouds
*/
void set_3dCloudWrap(bool wrap)
{ _3dcloudWrap = wrap; }
void set_clouds_enabled(bool enabled);
private:
float _visibility = 0.0;
bool _3dcloudsEnabled = false;
bool _3dcloudWrap = false;
bool _3dcloudUSeImpostors = false;
float _3dcloudImpostorDistance = 0.0;
float _3dcloudLoDRange1 = 0.0;
float _3dcloudLoDRange2 = 0.0;
float _3dcloudVisRange = 0.0;
float _3dcloudDensity = 0.0;
std::vector<SGCloudLayer*> _cloudLayers;
};
#endif

57
tests/fake_sound.cxx Normal file
View file

@ -0,0 +1,57 @@
#include <simgear/sound/soundmgr.hxx>
class SGSoundMgr::SoundManagerPrivate
{
public:
};
SGSoundMgr::SGSoundMgr()
{
}
SGSoundMgr::~SGSoundMgr()
{
}
void SGSoundMgr::init()
{
}
void SGSoundMgr::stop()
{
}
void SGSoundMgr::suspend()
{
}
void SGSoundMgr::resume()
{
}
void SGSoundMgr::update(double dt)
{
}
void SGSoundMgr::reinit()
{
}
bool SGSoundMgr::load(const std::string &samplepath, void **data, int *format, size_t *size, int *freq, int *block)
{
return false;
}
std::vector<const char*> SGSoundMgr::get_available_devices()
{
std::vector<const char*> result;
return result;
}

77
tests/fgTestDriver.cxx Normal file
View file

@ -0,0 +1,77 @@
#include <vector>
#include <simgear/props/condition.hxx>
#include <simgear/props/props_io.hxx>
#include <simgear/math/SGMath.hxx>
class TestStep
{
public:
virtual void run() = 0;
// name for logging purposes
};
typedef std::vector<TestStep*> TestStepSequence;
class SimulateStep : public TestStep
{
public:
void run() override
{
}
private:
double m_count;
double m_dt;
SGGeod m_endPosition;
double m_endHeadingTrueDeg;
// other fake FDM data
};
class CommandStep : public TestStep
{
public:
void run() override
{
// build the command and run it
}
private:
SGPropertyNode_ptr m_cmd;
};
class CheckStep : public TestStep
{
public:
void run() override
{
for (auto cond : m_conditions) {
// eval
// if failed, boom
}
}
private:
std::vector<SGConditionRef> m_conditions;
};
int main(int argc, char* argv[])
{
// parse XML
// find test name
// wipe working dir
// create working dir
// build test stages
// read and create subsystems
// execute in turn
return EXIT_SUCCESS;
}

382
tests/testStubs.cxx Normal file
View file

@ -0,0 +1,382 @@
#include <string>
#include <simgear/misc/sg_path.hxx>
#include <simgear/structure/exception.hxx>
#include <Main/locale.hxx>
#include <Main/options.hxx>
#include <Scripting/NasalSys.hxx>
#include <GUI/MessageBox.hxx>
#include <ATC/trafficcontrol.hxx>
#include <ATC/GroundController.hxx>
#include <Scenery/scenery.hxx>
// declared extern in main.hxx
std::string hostname;
string fgBasePackageVersion(const SGPath& base_path)
{
return "";
}
void fgHiResDump()
{
}
void fgDumpSnapShot()
{
}
void fgCancelSnapShot()
{
}
void fgDumpSceneGraph()
{
}
void fgOSFullScreen()
{
}
void guiErrorMessage(const char *txt)
{
}
void guiErrorMessage(const char *txt, const sg_throwable &throwable)
{
}
void fgPrintVisibleSceneInfoCommand()
{
}
void openBrowser(const std::string& s)
{
}
void fgDumpTerrainBranch()
{
}
void fgOSExit(int code)
{
}
void postinitNasalGUI(naRef globals, naContext c)
{
}
void syncPausePopupState()
{
}
void
SGSetTextureFilter( int max)
{
}
int
SGGetTextureFilter()
{
return 0;
}
bool FGScenery::get_elevation_m(const SGGeod& geod, double& alt,
const simgear::BVHMaterial** material,
const osg::Node* butNotFrom)
{
return false;
}
namespace flightgear
{
MessageBoxResult modalMessageBox(const std::string& caption,
const std::string& msg,
const std::string& moreText)
{
return MSG_BOX_OK;
}
MessageBoxResult fatalMessageBox(const std::string& caption,
const std::string& msg,
const std::string& moreText)
{
return MSG_BOX_OK;
}
}
#ifdef __APPLE__
string_list
FGLocale::getUserLanguage()
{
string_list result;
const char* langEnv = ::getenv("LANG");
if (langEnv) {
result.push_back(langEnv);
}
return result;
}
namespace flightgear
{
SGPath Options::platformDefaultRoot() const
{
SGPath dataDir;
dataDir.append("data");
return dataDir;
}
} // of namespace flightgear
#endif
FGATCController::FGATCController()
{
}
FGATCController::~FGATCController()
{
}
FGATCInstruction::FGATCInstruction()
{
}
////////////////////////////////////////////////
FGTowerController::FGTowerController(FGAirportDynamics*)
{
}
FGTowerController::~FGTowerController()
{
}
void FGTowerController::render(bool)
{
}
void FGTowerController::signOff(int id)
{
}
std::string FGTowerController::getName()
{
return "tower";
}
void FGTowerController::update(double dt)
{
}
void FGTowerController::announcePosition(int id, FGAIFlightPlan *intendedRoute, int currentRoute, double lat, double lon, double hdg, double spd, double alt, double radius, int leg, FGAIAircraft *aircraft)
{
}
void FGTowerController::updateAircraftInformation(int id, double lat, double lon, double heading, double speed, double alt, double dt)
{
}
bool FGTowerController::hasInstruction(int id)
{
return false;
}
FGATCInstruction FGTowerController::getInstruction(int id)
{
return FGATCInstruction();
}
//////////////////////////////////////////////////////////////
/// \brief FGApproachController::FGApproachController
///
FGApproachController::FGApproachController(FGAirportDynamics*)
{
}
FGApproachController::~FGApproachController()
{
}
void FGApproachController::render(bool)
{
}
void FGApproachController::signOff(int id)
{
}
std::string FGApproachController::getName()
{
return "approach";
}
void FGApproachController::update(double dt)
{
}
void FGApproachController::announcePosition(int id, FGAIFlightPlan *intendedRoute, int currentRoute, double lat, double lon, double hdg, double spd, double alt, double radius, int leg, FGAIAircraft *aircraft)
{
}
void FGApproachController::updateAircraftInformation(int id, double lat, double lon, double heading, double speed, double alt, double dt)
{
}
bool FGApproachController::hasInstruction(int id)
{
return false;
}
FGATCInstruction FGApproachController::getInstruction(int id)
{
return FGATCInstruction();
}
//////////////////////////////////////////////////////
FGStartupController::FGStartupController(FGAirportDynamics*)
{
}
FGStartupController::~FGStartupController()
{
}
void FGStartupController::render(bool)
{
}
void FGStartupController::signOff(int id)
{
}
std::string FGStartupController::getName()
{
return "startup";
}
void FGStartupController::update(double dt)
{
}
void FGStartupController::announcePosition(int id, FGAIFlightPlan *intendedRoute, int currentRoute, double lat, double lon, double hdg, double spd, double alt, double radius, int leg, FGAIAircraft *aircraft)
{
}
void FGStartupController::updateAircraftInformation(int id, double lat, double lon, double heading, double speed, double alt, double dt)
{
}
bool FGStartupController::hasInstruction(int id)
{
return false;
}
FGATCInstruction FGStartupController::getInstruction(int id)
{
return FGATCInstruction();
}
//////////////////////////////////////////////////////
FGGroundController::FGGroundController()
{
}
FGGroundController::~FGGroundController()
{
}
void FGGroundController::init(FGAirportDynamics* pr)
{
}
void FGGroundController::render(bool)
{
}
void FGGroundController::signOff(int id)
{
}
std::string FGGroundController::getName()
{
return "ground";
}
void FGGroundController::update(double dt)
{
}
void FGGroundController::announcePosition(int id, FGAIFlightPlan *intendedRoute, int currentRoute, double lat, double lon, double hdg, double spd, double alt, double radius, int leg, FGAIAircraft *aircraft)
{
}
void FGGroundController::updateAircraftInformation(int id, double lat, double lon, double heading, double speed, double alt, double dt)
{
}
bool FGGroundController::hasInstruction(int id)
{
return false;
}
FGATCInstruction FGGroundController::getInstruction(int id)
{
return FGATCInstruction();
}
#if defined(SG_WINDOWS)
#include <plib/sg.h>
// this stub is needed on Windows because sg.h decleares this function as extern
void sgdMakeCoordMat4(sgdMat4 m, const SGDfloat x, const SGDfloat y, const SGDfloat z, const SGDfloat h, const SGDfloat p, const SGDfloat r)
{
}
#endif

147
tests/test_flightplan.cxx Normal file
View file

@ -0,0 +1,147 @@
#include "config.h"
#include "unitTestHelpers.hxx"
#include <simgear/misc/test_macros.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 <Airports/airport.hxx>
using namespace flightgear;
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;
FGAirportRef depApt = FGAirport::getByIdent(depICAO);
f->setDeparture(depApt->getRunwayByIdent(depRunway));
FGAirportRef destApt = FGAirport::getByIdent(destICAO);
f->setDestination(destApt->getRunwayByIdent(destRunway));
for (auto ws : simgear::strutils::split(waypoints)) {
WayptRef wpt = f->waypointFromString(ws);
f->insertWayptAtIndex(wpt, -1);
}
return f;
}
void testBasic()
{
FlightPlanRef fp1 = makeTestFP("EGCC", "23L", "EHAM", "24",
"TNT CLN");
fp1->setIdent("testplan");
SG_CHECK_EQUAL(fp1->ident(), "testplan");
SG_CHECK_EQUAL(fp1->departureAirport()->ident(), "EGCC");
SG_CHECK_EQUAL(fp1->departureRunway()->ident(), "23L");
SG_CHECK_EQUAL(fp1->destinationAirport()->ident(), "EHAM");
SG_CHECK_EQUAL(fp1->destinationRunway()->ident(), "24");
SG_CHECK_EQUAL(fp1->numLegs(), 2);
SG_CHECK_EQUAL(fp1->legAtIndex(0)->waypoint()->source()->ident(), "TNT");
SG_CHECK_EQUAL(fp1->legAtIndex(0)->waypoint()->source()->name(), "TRENT VOR-DME");
SG_CHECK_EQUAL(fp1->legAtIndex(1)->waypoint()->source()->ident(), "CLN");
SG_CHECK_EQUAL(fp1->legAtIndex(1)->waypoint()->source()->name(), "CLACTON VOR-DME");
}
void testRoutePathBasic()
{
FlightPlanRef fp1 = makeTestFP("EGHI", "20", "EDDM", "08L",
"SFD LYD BNE CIV ELLX LUX SAA KRH WLD");
RoutePath rtepath(fp1);
const unsigned int legCount = fp1->numLegs();
for (int leg = 0; leg < legCount; ++leg) {
rtepath.trackForIndex(leg);
rtepath.pathForIndex(leg);
rtepath.distanceForIndex(leg);
}
rtepath.distanceBetweenIndices(2, 5);
// check some leg parameters
// BOLOUGNE SUR MER, near LFAY (AMIENS)
FGNavRecordRef bne = FGNavList::findByFreq(113.8, FGAirport::getByIdent("LFAY")->geod());
// CHIEVRES
FGNavRecordRef civ = FGNavList::findByFreq(113.2, FGAirport::getByIdent("EBCI")->geod());
double distM = SGGeodesy::distanceM(bne->geod(), civ->geod());
double trackDeg = SGGeodesy::courseDeg(bne->geod(), civ->geod());
SG_CHECK_EQUAL_EP2(trackDeg, rtepath.trackForIndex(3), 0.5);
SG_CHECK_EQUAL_EP2(distM, rtepath.distanceForIndex(3), 2000); // 2km precision, allow for turns
}
// https://sourceforge.net/p/flightgear/codetickets/1703/
// https://sourceforge.net/p/flightgear/codetickets/1939/
void testRoutePathSkipped()
{
FlightPlanRef fp1 = makeTestFP("EHAM", "24", "EDDM", "08L",
"EHEH KBO TAU FFM FFM/100/0.01 FFM/120/0.02 WUR WLD");
RoutePath rtepath(fp1);
// skipped point uses inbound track
SG_CHECK_EQUAL_EP(rtepath.trackForIndex(3), rtepath.trackForIndex(4));
SG_CHECK_EQUAL_EP(0.0, rtepath.distanceForIndex(4));
SG_CHECK_EQUAL_EP(0.0, rtepath.distanceForIndex(5));
SG_CHECK_EQUAL_EP2(101000, rtepath.distanceForIndex(6), 1000);
// this tests skipping two preceeding points works as it should
SGGeodVec vec = rtepath.pathForIndex(6);
SG_CHECK_EQUAL(vec.size(), 9);
}
void testRoutePathTrivialFlightPlan()
{
FlightPlanRef fp1 = makeTestFP("EGPH", "24", "EGPH", "06",
"");
RoutePath rtepath(fp1);
const unsigned int legCount = fp1->numLegs();
for (int leg = 0; leg < legCount; ++leg) {
rtepath.trackForIndex(leg);
rtepath.pathForIndex(leg);
rtepath.distanceForIndex(leg);
}
SG_CHECK_EQUAL_EP(0.0, fp1->totalDistanceNm());
}
int main(int argc, char* argv[])
{
fgtest::initTestGlobals("flightplan");
testBasic();
testRoutePathBasic();
testRoutePathSkipped();
testRoutePathTrivialFlightPlan();
fgtest::shutdownTestGlobals();
}

29
tests/test_navaids2.cxx Normal file
View file

@ -0,0 +1,29 @@
#include "unitTestHelpers.hxx"
#include <simgear/misc/test_macros.hxx>
#include <Navaids/NavDataCache.hxx>
#include <Navaids/navrecord.hxx>
#include <Navaids/navlist.hxx>
void testBasic()
{
SGGeod egccPos = SGGeod::fromDeg(-2.27, 53.35);
FGNavRecordRef tla = FGNavList::findByFreq(115.7, egccPos);
SG_CHECK_EQUAL(strcmp(tla->get_ident(), "TNT"), 0);
SG_CHECK_EQUAL(tla->ident(), "TNT");
SG_CHECK_EQUAL(tla->name(), "TRENT VOR-DME");
SG_CHECK_EQUAL(tla->get_freq(), 11570);
SG_CHECK_EQUAL(tla->get_range(), 130);
}
int main(int argc, char* argv[])
{
fgtest::initTestGlobals("navaids2");
testBasic();
fgtest::shutdownTestGlobals();
}

88
tests/unitTestHelpers.cxx Normal file
View file

@ -0,0 +1,88 @@
#include "config.h"
#include "unitTestHelpers.hxx"
#include <Main/globals.hxx>
#include <Navaids/NavDataCache.hxx>
#include <Time/TimeManager.hxx>
#include <simgear/debug/logstream.hxx>
#include <simgear/misc/sg_dir.hxx>
#include <simgear/timing/timestamp.hxx>
#include <iostream>
namespace fgtest
{
bool looksLikeFGData(const SGPath& path)
{
return (path / "defaults.xml").exists();
}
void initTestGlobals(const std::string& testName)
{
sglog().setLogLevels( SG_ALL, SG_WARN );
sglog().setDeveloperMode(true);
globals = new FGGlobals;
bool foundRoot = false;
if (std::getenv("FG_ROOT")) {
SGPath fg_root = SGPath::fromEnv("FG_ROOT");
if (looksLikeFGData(fg_root)) {
globals->set_fg_root(fg_root);
foundRoot = true;
}
}
if (!foundRoot) {
SGPath pkgLibDir = SGPath::fromUtf8(PKGLIBDIR);
if (looksLikeFGData(pkgLibDir)) {
globals->set_fg_root(pkgLibDir);
foundRoot = true;
}
}
if (!foundRoot) {
SGPath dataDir = SGPath::fromUtf8(FGSRCDIR) / ".." / "fgdata";
if (looksLikeFGData(dataDir)) {
globals->set_fg_root(dataDir);
foundRoot = true;
}
}
if (!foundRoot) {
std::cerr << "FGData not found" << std::endl;
exit(EXIT_FAILURE);
}
// current dir
SGPath homePath = simgear::Dir::current().path() / "test_home";
if (!homePath.exists()) {
(homePath / "dummyFile").create_dir(0755);
}
globals->set_fg_home(homePath);
flightgear::NavDataCache* cache = flightgear::NavDataCache::createInstance();
if (cache->isRebuildRequired()) {
std::cerr << "Navcache rebuild for testing" << std::flush;
while (cache->rebuild() != flightgear::NavDataCache::REBUILD_DONE) {
SGTimeStamp::sleepForMSec(1000);
std::cerr << "." << std::flush;
}
}
TimeManager* t = new TimeManager;
t->init(); // establish mag-var data
}
void shutdownTestGlobals()
{
delete globals;
}
} // of namespace fgtest

15
tests/unitTestHelpers.hxx Normal file
View file

@ -0,0 +1,15 @@
#ifndef FG_TEST_HELPERS_HXX
#define FG_TEST_HELPERS_HXX
#include <string>
#include <simgear/misc/sg_path.hxx>
namespace fgtest
{
void initTestGlobals(const std::string& testName);
void shutdownTestGlobals();
}
#endif // of FG_TEST_HELPERS_HXX