/**
 * @file   chained_callback.h
 * @author Nat Goodspeed
 * @date   2020-01-03
 * @brief  Subclass of tut::callback used for chaining callbacks.
 * 
 * $LicenseInfo:firstyear=2020&license=viewerlgpl$
 * Copyright (c) 2020, Linden Research, Inc.
 * $/LicenseInfo$
 */

#if ! defined(LL_CHAINED_CALLBACK_H)
#define LL_CHAINED_CALLBACK_H

#include "lltut.h"

/**
 * Derive your TUT callback from chained_callback instead of tut::callback to
 * ensure that multiple such callbacks can coexist in a given test executable.
 * The relevant callback method will be called for each callback instance in
 * reverse order of the instance's link() methods being called: the most
 * recently link()ed callback will be called first, then the previous, and so
 * forth.
 *
 * Obviously, for this to work, all relevant callbacks must be derived from
 * chained_callback instead of tut::callback. Given that, control should reach
 * each of them regardless of their construction order. The chain is
 * guaranteed to stop because the first link() call will link to test_runner's
 * default_callback, which is simply an instance of the callback() base class.
 *
 * The rule for deriving from chained_callback is that you may override any of
 * its virtual methods, but your override must at some point call the
 * corresponding chained_callback method.
 */
class chained_callback: public tut::callback
{
public:
    /**
     * Instead of calling tut::test_runner::set_callback(&your_callback), call
     * your_callback.link();
     * This uses the canonical instance of tut::test_runner.
     */
    void link()
    {
        link(tut::runner.get());
    }

    /**
     * If for some reason you have a different instance of test_runner...
     */
    void link(tut::test_runner& runner)
    {
        // Since test_runner's constructor sets a default callback,
        // get_callback() will always return a reference to a valid callback
        // instance.
        mPrev = &runner.get_callback();
        runner.set_callback(this);
    }

    /**
     * Called when new test run started.
     */
    virtual void run_started()
    {
        mPrev->run_started();
    }

    /**
     * Called when a group started
     * @param name Name of the group
     */
    virtual void group_started(const std::string& name)
    {
        mPrev->group_started(name);
    }

    /**
     * Called when a test finished.
     * @param tr Test results.
     */
    virtual void test_completed(const tut::test_result& tr)
    {
        mPrev->test_completed(tr);
    }

    /**
     * Called when a group is completed
     * @param name Name of the group
     */
    virtual void group_completed(const std::string& name)
    {
        mPrev->group_completed(name);
    }

    /**
     * Called when all tests in run completed.
     */
    virtual void run_completed()
    {
        mPrev->run_completed();
    }

private:
    tut::callback* mPrev;
};

#endif /* ! defined(LL_CHAINED_CALLBACK_H) */