// Revision: 16 1.12.1.4 source/core/testfw/itestmul.hpp, testfw, ioc.v400, 980918 
#ifndef _ITESTMUL_
#define _ITESTMUL_
/**
 * Class TestMultiplexer: Supports the model of multiple decision functions applied to
 * a single test target.
 *
 * Derive ITestMultiplexer when you want to test many functions on a single
 * target object without creating an ITest derived class for each test.
 *
 * To use this framework class, derive it and override the loadDecisions
 * function.  Derived classes should not override any other function (not even
 * the test function).  Derived classes should declare a new decision function
 * for each test, define a key for each decision function, and register each
 * key-decision function pair in loadDecisions.  loadDecisions should call
 * addDecision for each key-decision pair. This key is used to select the
 * decision function at run-time.
 *
 * The key may be changed by being directly set or by being passed in as
 * part of an argument.
 *
 * @package Test Framework
 * @category Testing
 *
 * @author Alan Liu
 * @task Initial Test Framework
 * @author Esther Tong
 * @task TestFrameworkLite
 * @author David McCusker, Christoper Miller, Carol Widra, and Kwansook Nam
 * @task Many of the other Contributors to TestFramework
 *
 * @copyright
 *      IBM Open Class Library
 *      (C) Copyright International Business Machines Corporation 1997
 *      Licensed Material - Program-Property of IBM - All Rights Reserved.
 *
 */

#include <ism2.h>
#include <itest.hpp>

#if __IBMCPP__ >= 400
#pragma namemangling(compat)
#endif

class IDecisionFnWrapper;

typedef bool (ITest::*ITestDecisionFn)();

#pragma enum(4)
#pragma pack(push,4)

/**
 * ITestMultiplexer is a subclass of ITest which tests a number of decision functions.
 *
 * Its purpose is to allow multiple related tests to be implemented in one
 * class.  Tests are implemented as member functions.  Clients derive
 * new subclasses of ITestMultiplexer containing member functions called
 * deision functions which return boolean success values.
 *
 * ITestMultiplexer selects one or more decision functions to execute
 * in order to perform the test.  The selection of the decision function
 * can be set either programmatically or by parsing the test input arguments.
 * To subclass ITestMultiplexer, clients write the decision functions and
 * override loadDecisions(..).
 *
 * These decision functions are methods which are analogous to the
 * ITest::test method.  They are different in that they return a Boolean
 * result rather than calling ITest::setSuccess; a TRUE return value
 * indicates success.  Each decision function has an associated text key.
 * This key is used to select the decision function at run-time.
 *
 * The key may be changed in a number of ways.  There are methods which
 * directly set the key.  Alternatively, a client may specify that one or
 * more of the initial input arguments are to be interpreted as a key.  These
 * two methods are mutually exclusive; only one or the other is in effect
 * at any time.
 *
 * One key comes predefined.  This is the key "kAllDecisions", which has the
 * effect of running all decision functions and doing a logical AND of the
 * results.  If any decision function fails, then the entire test is considered
 * to fail.  Subclasses initialize the key-decision table dynamically.  The
 * method loadDecision is a framework method which subclasses MUST override
 * to add each key-decision pair to a dictionary.
 *
 */
class ITestMultiplexer:  public ITest {

public:

//------------------------------------------------------------------------
//  Canonical methods
//------------------------------------------------------------------------

/** @group Construction and  Destruction */


/**
 * Standard Assignment Operator
 */
ITestMultiplexer& operator=(const ITestMultiplexer&);


/**
 * Destructor
 */
virtual ~ITestMultiplexer();


//------------------------------------------------------------------------
//  Decision key methods
//------------------------------------------------------------------------

/** @group Decision key methods */


/**
 * Sets the key that will be used in subsequent calls to test.
 *
 * Callers should use the key ITestMultiplexer::kAllDecisions to specify that all
 * decision functions are to be run.  setDecisionKey calls
 * setInputAsKeys(0) so that no inputs will be interpreted as keys.
 *
 * @param key    The key to use
 *
 * @return bool  False and does nothing if the Key is not a valid key; otherwise returns true.
 *
 * @see setInputAsKeys
 * @see andAllDecisions
 *
 */
virtual bool setDecisionKey(const IString& key);


/**
 * Sets the argument "dest" to the current decision key.  If input AsKey is
 * set to zero returns a NULL string.
 *
 * @see setInputsAsKeys
 *
 */
virtual void decisionKey(IString& dest) const;


/**
 * Allows clients to specify how many of the ITest input arguments, starting
 * with the first one, will be interpreted as keys.
 *
 * Calling setInputsAsKeys with a nonzero value overrides any current key set via
 * setDecisionKey, and causes decisionKey to return an empty string.  Calling
 * setInputsAsKey(0) will reactivate any key previously set via setDecisionKey,
 * or the key kAllDecisions if setDecisionKey has not been called.
 *
 * @param howMany     How many of the leading input arguments are keys
 *
 */
virtual void setInputsAsKeys(unsigned int howMany);


/**
 * Returns the current value of fInputsAsKeys.
 *
 * @return the current value of fInputsAsKeys
 *
 */
virtual unsigned int inputsAsKeys() const;


#ifdef _AIX
 static const IString& kAllDecisions;
#else
 static const IString& _Import kAllDecisions;
#endif

protected:

//------------------------------------------------------------------------
//  Canonical methods
//------------------------------------------------------------------------

/** @group Constructors */

/**
 * Default constructor
 */
ITestMultiplexer();


/**
 * Constructor taking the key and the number of inputs as keys
 *
 * @param theKey                The decision key used for the current key
 * @param howManyInputsAsKeys   The number of inputs that are interpreted as keys
 *
 */
ITestMultiplexer(const IString& theKey, unsigned int howManyInputsAsKeys = 0);


/**
 * Copy Constructor
 *
 * @param ITestMultiplexer&     The object to copy
 */
ITestMultiplexer(const ITestMultiplexer&);



//------------------------------------------------------------------------
// Clients should override loadDecisions
//------------------------------------------------------------------------

/** @group Client Action Functions */

/**
 * A framework method for subclasses to override.
 *
 * Inside loadDecisions subclasses must first call the inherited
 * implementation (IDervied::loadDecisions must call IBase::loadDecisions).
 * Then loadDecisions should register each key-decision function pair by
 * calling addDecisions(theKey, theFunc), where theKey and theFunc are the
 * key and the address of the decision member function.  If a subclass has
 * overridden a decision member function in its base class, it must register
 * the keyword and the subclass's version of the function in loadDecisions.
 * Clients should not call loadDecisions; it is called by ITestMultiplexer.
 *
 */
virtual void loadDecisions();


/**
 * Adds the pair aKey-aFunc to the dictionary.
 *
 * Subclasses should call addDecision in their loadDecisions method to
 * register each decision function which they have defined or overridden.
 *
 * Subclasses should register overridden decision functions with the
 * same key that the base class uses.
 *
 * @param IString& key         The key to add
 * @param ITestDecisionFn fun  The decision function to add
 *
 */
virtual void addDecision(const IString&, ITestDecisionFn);


/**
 * This method executes the decision function and returns the result.
 *
 * Clients can override this function to customize the execution of the
 * decision function, for example, to write information to log or to
 * catch certain exceptions thrown by the function.  To override
 * handleDecision, add code before and/or after calling the decision
 * functions. If not overridden, handleDecision just calls the decision
 * function and returns the result boolean value.
 *
 * @param ITestDecisionFn     The decision function to run
 * @param IString&            The key of the decision function.  If not overridden, key is ignored.
 *
 * @return bool    The result of the decision function that was run
 *
 * @override sometimes
 *
 */
virtual bool handleDecision(ITestDecisionFn, const IString&);

//------------------------------------------------------------------------
//  Clients should not use any methods in this section directly
//------------------------------------------------------------------------

/**
 * Runs specified decision functions and returns logical AND of the results.
 *
 * Runs whatever decision functions have previously been specified by their
 * keys and calls setSuccess with the logical AND of the results.
 *
 * Note:  Contrary to usual ITest practice, subclasses should NOT override
 * this method.  Instead, subclasses should:
 *
 * <PRE>
 *     - declare a new decision function for each test
 *     - define a key for each decision function
 *     - register each key-decision function pair in an overridden
 *       version of the loadDecisions methods
 *</PRE>
 *
 * Clients should NOT call this method directly; it is called by ITest::run.
 *
 */
virtual void test();


/**
 *
 * Called by ITest if the key kAllDecisions is in effect.
 *
 * Calls all decision functions (including those in base classes which have not
 * been overridden), performs logical AND of their return values, and returns
 * the result.  Clients should NOT call this method directly.  Clients may override
 * AllDecisions if they wish to change its behavior.
 *
 * @return bool  True/False:  logical AND of test results
 *
 */
virtual bool andAllDecisions();


/**
 * Prints the keys used for running the test to the given ITieredTextBuffer.
 *
 * Note: This function is NOT to be called directly
 *
 * @param ITieredTextBuffer&   An ITieredTextBuffer buffer.
 *
 */
virtual void print(ITieredTextBuffer&);


//-----------------------------------------------------------------------------
private:

IString                       fKey;
unsigned long                 fInputsAsKeys;
ISortedMap<IDecisionFnWrapper, IString>* fDictionary;
bool                          fIsLoaded;

void                 loadDictionary();

ITestDecisionFn      findDecision(const IString&);

bool                 privateTrueDecision();

virtual bool         unknownDecision();

};

#pragma pack(pop)
#pragma enum(pop)

#if __IBMCPP__ >= 400
#pragma namemangling()
#endif

#endif // _ITESTMUL_
