#define CATCH_CONFIG_RUNNER
#include "catch.hpp"
#include <string>
#include <deque>

class CoverageScannerListener : public Catch::TestEventListenerBase
{
public:
    using TestEventListenerBase::TestEventListenerBase;

    virtual void sectionStarting( Catch::SectionInfo const& sectionInfo ) override
    {
        m_testNameHierarchy.push_back( sectionInfo.name );
#ifdef __COVERAGESCANNER__
        // Adjusting the name of the test for the CoverageBrowser
        std::string testname = implodeTestNameHierarchy();
        // Reset the code coverage data to get only the code coverage
        // of the actual unit test.
        __coveragescanner_clear();
        __coveragescanner_testname( testname.c_str() );
#endif
    }

    virtual void sectionEnded( Catch::SectionStats const& sectionStats ) override
    {
        m_testNameHierarchy.pop_back();
#ifdef __COVERAGESCANNER__
        // Recording the execution state in the coverage report
        if ( sectionStats.assertions.allPassed() )
            __coveragescanner_teststate( "PASSED" );
        else
            __coveragescanner_teststate( "FAILED" );
        // Saving the code coverage report of the unit test
        __coveragescanner_save();
        __coveragescanner_testname( "" );
#endif
    }

private:
    std::deque<std::string> m_testNameHierarchy;

    /* Helper method which generates a hierarchical name string usable by the coveragebrowser. */
    std::string implodeTestNameHierarchy() {
        std::string fullTestName ( "Catch2" );
        std::deque<std::string>::const_iterator it = m_testNameHierarchy.cbegin();
        while ( it != m_testNameHierarchy.cend() ) {
            fullTestName += "/" + *it;
            it++;
        }
        return fullTestName;
    }
};

// Register the coveragescanner listener with Catch2
CATCH_REGISTER_LISTENER( CoverageScannerListener )

int main( int argc, char* argv[] )
{
#ifdef __COVERAGESCANNER__
    __coveragescanner_install( argv[0] );
#endif
    return Catch::Session().run( argc, argv );
}