mavlink/qgroundcontrol — pull request #1108 by DonLakeFlyer (2014-12-11 00:02:39+00:00)
Title: New Singleton Manager

Here are the current problems/needs:
- The set of global Singletons we have must run on the main thread
- The global Singletons depend on each other so that creation order is important
- The Singletons are referenced from threads other than the main thread
- Using foo::instance() to create the singleton on first call leads to some amount of non-deterministic creation order
- Using foo::instance to create singletons can lead to them being created on the wrong thread
- Unit Tests need to be able to replace singletons with mock implementations for testing

The unit tests have been exposing all of the above problems by failing randomly depending on how you write your unit test. The app itself exhibits these issue as well depending on how you shut it down and what is running when you do that.

Welcome to the new singleton manager from hell, QGCSingleton:
- Only QGCApplication is allowed to create and destroy singletons
- Singletons are created and destroyed in a specific order
- The Unit Test harness is allow to create and destroy the set of singletons before/after each test case
- Except for Unit Tests no code is allowed to use a singleton's constructor/destructor
- Singletons may be derived from a base interface which is then derived from QGCSingleton. This allows you to create mock implementations of a singleton for testing.
- QGCSingleton has a setMock method which you use to install and remove the mock implementaion
- Client code still uses foo::instance() to access a singleton. If it asserts that the singleton is not created it means you have found a startup/shutdown sequence bug.

Here is the doc from the code for QGCSingleton:
/// This is the base class for all app global singletons
///
/// All global singletons are created/destroyed at boot time by QGCApplication::_createSingletons and destroyed by QGC::Application::_destroySingletons.
/// This is done in order to make sure they are all created on the main thread. As such no other code other than Unit Test
/// code has access to the constructor/destructor. QGCSingleton supports replacing singletons with a mock implementation.
/// In this case your object must derive from an interface which in turn derives from QGCSingleton. Youu can then use
/// the setMock method to add and remove you mock implementation. See UASManager example usage. In order to provide the
/// appropriate methods to make all this work you need to use the DECLARE_QGC_SINGLETON and IMPLEMENT_QGC_SINGLETON
/// macros as follows:
/// @code{.unparsed}
/// // Header file
///
/// class MySingleton : public QGCSingleton {
/// Q_OBJECT
///
/// DECLARE_QGC_SINGLETON(MySingleton, MySingleton)
///
/// ...
///
/// private:
/// // Constructor/Desctructor private since all access is through the singleton methods
/// MySingleton(QObject* parent == NULL);
/// ~MySingleton();
///
/// ...
/// }
///
/// // Code file
///
/// IMPLEMENT_QGC_SINGLETON(MySingleton, MySingleton)
///
/// MySingleton::MySingleton(QObject* parent) :
/// QGCSigleton(parent)
/// {
/// }
///
/// // Other class methods...
///
/// @endcode
/// The example above does not use an inteface so the second parameter to the macro is the class name as well.