/**
 * Class ITest: Abstract base class that defines the protocol for test running behavior.
 *
 * Clients use the ITest class to derive subclasses for testing features of their test targets.
 * ITest provides an output stream in which clients can record any tesxt output.
 * ITest provides input text arguments that can be used by clients to parameterize
 * the kind of test to be performed.  MetaInformation on teh test may also be
 * defined and obtained using the copyInfo and lookupInfo methods.
 *
 * @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.
 */
// Revision: 12 1.19.1.4 source/core/testfw/itest.hpp, testfw, ioc.v400, 980918 

#ifndef _ITEST_
#define _ITEST_

#include <istring.hpp>
#include <iseq2.h>

#include "ittxtbuf.hpp"
#include "iprimtyp.hpp"

#include <itfwpl.hpp>         // pragma library definitions

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

class ITieredTextBuffer;
class ITieredText;
class ITest;
class IStringWrapper;

template <class T, class U> class ISortedMap;

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

//-----------------------------------------------------------------------------
// ITest interface
//-----------------------------------------------------------------------------

/**
 * Class ITest
 *
 * General purpose class for writing Test Framework tests.
 *
 * Clients use ITest to derive subclasses for testing features of their test targets.
 * ITest provides an output stream in which clients can record any tesxt output.
 * ITest provides input text arguments that can be used by clients to parameterize
 * the kind of test to be performed.  MetaInformation on teh test may also be
 * defined and obtained using the copyInfo and lookupInfo methods.
 *
 */
class ITest {
public:

//-------------------------------------------------------------------------
/** @group Canonical methods */


/**
 * Destructor
 *
 * ITest destructor. Does NOT delete the target.
 * Subclasses must handle the target themselves.
 */
virtual ~ITest();



/**
 * Member Function operator=
 *
 * Standard assignment operator for ITest.
 *
 * @param test  ITest object to copy
 */
ITest& operator=(const ITest& test);



//-------------------------------------------------------------------------
/** @group Input Configuration */

/**
 * Member Function setInputs
 *
 * Copies UNIX-style input text to internal storage.
 *
 * @param argc UNIX-style argc parameter
 * @param argv UNIX-style argument vector
 *
 */
void setInputs(const int argc, const char *const *argv);


/**
 * Member Function copyInputs
 *
 * Copies parameters that take UNIX-style parameters to argv.
 *
 * Subclasses should NOT override copyInput.
 *
 * Clients may call copyInputs after running a test to correlate inputs with the
 * test results.  The caller owns the string array and should delete the storage.
 *
 * @param argc UNIX-style argc parameter
 * @param argv UNIX-style argument vector
 *
 */
void copyInputs(int& argc, char **&argv) const;


//-------------------------------------------------------------------------
/** @group Execution and success result */

/**
 * Member Function run
 *
 * This method is the public means of telling the test to execute itself.
 *
 * You may call run to execute a test instance.
 *
 * Subclasses should NOT override run.  run calls the method test to actually
 * perform the test.  run calls the framework methods:
 * <PRE>
 *             reset (if run has been called before)
 *             setup,
 *             test, and
 *             cleanup.
 * </PRE>
 *
 * Each time run is called it increments the value returned by runCount
 *
 * @see runCount
 *
 */
virtual void run();


/**
 * Member Function success
 *
 * Returns the success state of the last run.
 *
 * You may call success after a test has been run to see if the test succeeded.
 * This value is not meaningful if data member isReset is true.
 *
 * @return bool the success of the last run (not set, pass, or fail)
 *
 * @see isReset
 * @see setSuccess
 *
 */
bool success() const; // Did it succeed?


//-------------------------------------------------------------------------
/** @group Test Output Methods  */

/**
 * Member Function outputTextStream
 *
 * Returns a reference to a ITieredTextBuffer object.
 *
 * Subclasses may use the returned reference transparently to produce
 * textual output.
 *
 * @return An ITieredTextBuffer object
 *
 * @see ITieredTextBuffer
 * @see ITest::print
 *
 */
ITieredTextBuffer& outputTextStream(); // Output text


//-------------------------------------------------------------------------
/** @group Exceptions */

/**
 * Possible exception value settings.
 */
enum EStage {
        kNone,          // exception did not occur
        kRun,           // exception in Run() but not in any of the following:
        kReset,         // exception in Reset()
        kSetup,         // exception in Setup()
        kTest,          // exception in Test()
        kCleanup        // exception in Cleanup()
};


/**
 * Member Function exceptionStage
 *
 * Public exception method to determine when an exception occurred in run.
 *
 * <PRE>
 * EStage Values:
 * --------------
 *      kNone      # exception did not occur
 *      kRun       # exception in run() but not in any of the following:
 *      kReset     # exception in reset()
 *      kSetup     # exception in setup()
 *      kTest      # exception in test()
 *      kCleanup   # exception in cleanup()
 * </PRE>
 *
 * @return Current setting of fExceptionStage data member; one of the EStage values
 *
 */
virtual EStage exceptionStage() const; // When did an exception occur in Run?


//-------------------------------------------------------------------------
/** @group Bookkeeping methods */

/**
 * Member Function runCount
 *
 * Returns the number of times run has been called.
 *
 * @return The number of times run has been called
 *
 */
virtual unsigned long runCount() const;


//-------------------------------------------------------------------------
/** @group Meta-information Methods      */

/**
 * Member Function copyInfo
 *
 * Used to store meta-information about the client test. Subclasses should override.
 *
 * Clients can specify various types of meta-information, including the purpose of a test
 * and the name of the class being tested.  You can retrieve and display this
 * information by using the -info option when you start RunTest.
 *
 * When you assign information to a test, associate each test class with key/value
 * pairs in a dictionary.  This supports categorization of different kinds of tests and
 * analysis of large numbers of test results.
 *
 * The text values for the keys can be used with the -info option of RunTest to query
 * a specific key/value pair in the dictionary.  The following shows the predefined keys
 * and values:
 *
 * <PRE>
 *         KEY             KEYWORD(VALUE)        DESCRIPTION
 *     ---------------     --------------        -------------------------------------
 *     kDescriptionKey     Description           Description of this test subclass
 *     kInputSyntaxKey     Input Syntax          Input syntax for text arguments
 *     kTargetClassKey     Target Class          Name of target class
 *     kTestNameKey        Test Name             Name of test
 *     kTestVersionKey     Test Version          Version number of test
 *     kTestTypeKey        Test Type             Type of test (eg. unit, regression, etc.)
 *     kComponentKey       Component             Name of component to which this test applies
 *
 * </PRE>
 *
 * Inside of copyInfo, subclasses should call the inherited implementation
 * (IDerived::copyInfo should call IBase::copyInfo).  Then copyInfo should add
 * key/value pairs to infoMap by calling the addInfo() method.
 *
 * @override always
 * @callup yes
 * @see addInfo
 *
 */
virtual void copyInfo(); // Subclasses should override!


/**
 * Member Function lookupInfo
 *
 * Looks for the information corresponding to the key.
 *
 * If found, it copies the information into info and returns true.  Otherwise,
 * lookupInfo leaves info untouched and returns false.  Subclasses should NOT
 * override lookupInfo
 *
 * @param key      IString for the key
 * @param info     IString for returned value
 *
 * @return bool true if key found, otherwise false
 *
 */
virtual bool lookupInfo(const IString& key, IString& info);


#ifdef _AIX
        const static IString&  kDescriptionKey; // Description of this test subclass
        const static IString&  kInputSyntaxKey; // Input syntax for text arguments
        const static IString&  kTargetClassKey; // Name of target class
        const static IString&  kTestNameKey;    // Name of test
        const static IString&  kTestVersionKey; // Version number of test
        const static IString&  kTestTypeKey;    // Type of test (eg. unit, regression, etc.)
        const static IString&  kComponentKey;   // Name of component that this test applies to.
#else
        const static IString& _Import kDescriptionKey;  // Description of this test subclass
        const static IString& _Import kInputSyntaxKey;  // Input syntax for text arguments
        const static IString& _Import kTargetClassKey;  // Name of target class
        const static IString& _Import kTestNameKey;         // Name of test
        const static IString& _Import kTestVersionKey;  // Version number of test
        const static IString& _Import kTestTypeKey;         // Type of test (eg. unit, regression, etc.)
        const static IString& _Import kComponentKey;    // Name of component that this test applies to.
#endif

//_____________________________________________________________________________
protected:

//-------------------------------------------------------------------------
/** @group Constructors */

//-------------------------------------------------------------------------
//Canonical methods for abstract base class
//-------------------------------------------------------------------------

/**
 * Member Function ITest
 *
 * Default Constructor
 */
ITest();


/**
 * Member Function ITest Copy Constructor
 *
 * Copy Constructor
 *
 * @param test
 *
 */
ITest(const ITest& test);


//-------------------------------------------------------------------------
// Framework methods called by run; override these!

/** @group Main Testing Functions */

/**
 * Member Function reset
 *
 * Resets the internal state of ITest back to the initial state.
 *
 * Overriding methods should call the inherited method first.  This method
 * is used to perform necessary re-initialization operations for tests that
 * can be run more than once.  ITest::run calls this method before running
 * a test a second or later time.  ITest::run does not call reset before
 * running a test for the first time.  Subclasses that should not be run
 * more than once can use this method to ensure that multiple calls to
 * run do no harm.
 *
 * @override sometimes
 * @callup yes
 *
 */
virtual void reset();


/**
 * Member Function setup
 *
 * A framework method that subclasses override to do whatever setup work the test will need.
 *
 * Subclasses may override setup to perform any appropriate  initialization before test
 * is called.  For example, a test might instantiate a target object to be tested if
 * there is not one already.
 *
 * Note:  Anything that is done in setup should be undone, if necessary, in cleanup.
 *
 * @override sometimes
 * @see cleanup
 *
 */
virtual void setup();


/**
 * Member Function test
 *
 * A framework method that subclasses override to actually perform the test.
 *
 * The only ITest method that subclasses are required to call inside a test
 * is setSuccess.
 *
 * Note:  Subclasses MUST override this method, even if they do not override
 * any of the other methods in this section.
 *
 * @override always
 * @see setSuccess
 *
 */
virtual void test() = 0;


/**
 * Member Function cleanup
 *
 * A framework method that subclasses override to restore the system to its previous state.
 *
 * Any actions within setup (e.g., storage allocation) which need to be undone,
 * should be undone here.
 *
 * ITest::run always calls cleanup, even if an exception occurs.
 *
 * @override sometimes
 * @see setup
 *
 */
virtual void cleanup();


/**
 * Member Function print
 *
 * A framework method that subclasses may override to customize the way a test prints via operator<<(ITieredTextBuffer).
 * In subclass implementation, be sure to call the print method in the
 * immediate base class before doing anything else.  Then you output your own
 * information, with a final carriage return.  If a subclass overrides print, this
 * additional information is included in the test result.
 *
 * Note: The content of the print method is printed out only when you set (through
 * the command line) the echotier level equal to or below ITieredTextBuff::kDetail.
 *
 * @param ITieredTextBuffer
 *
 * @override sometimes
 * @callup yes
 *
 */
virtual void print(ITieredTextBuffer&);  // Subclasses can override


/**
 * Member Function addInfo
 *
 * Adds a key/value pair.
 * Most often used when overriding the copyInfo member function.
 *
 * @see copyInfo
 */
virtual void addInfo(const IString&, const IString&);


//-------------------------------------------------------------------------
/** @group Test Control */


/**
 * Member Function setSuccess
 *
 * Sets the success state of a test.
 *
 * Subclasses call setSuccess at anytime but especially during test, to
 * indicate the test's success.  A client can call setSuccess more than once.
 * For example, a subclass might call setSuccess(true) in setup, but then
 * call setSuccess(false) in test.
 *
 * @param success Success value to set (true/false)
 *
 * @see setStickySuccess
 *
 */
virtual void setSuccess(bool success);


/**
 * Member Function setStickySuccess
 *
 * Used to preserve the failure state of a test until teh next run of the test.
 *
 * The difference between setStickySuccess and setSuccess is that setStickySuccess
 * is called to preserve the failure of a test until the next run of the test.
 * Once setStickySuccess is called with false, the success value will remain false
 * from that point on.  It can no longer be changed to true even if setSuccess or
 * setStickySuccess is called with true.  If a test is run more than once, the
 * "sticky" flag will be reset in ITest:reset() so that success can be set to any
 * value in the next run of the test.
 *
 * Subclasses call setStickySuccess at anytime, be especially during test, to
 * indicate the test's success.
 *
 * @param success Success value to set (true/false)
 *
 * @see setSuccess
 *
 */
virtual void setStickySuccess(bool success);


/**
 * Member Function isSuccessUndecided
 *
 * True if setSuccess has not been called, or if reset has been called, otherwise returns false.
 *
 * @return bool true/false
 *
 */
virtual bool isSuccessUndecided() const; // Has setSuccess not been called?


/**
 * Member Function isReset
 *
 * True if the test has been reset without running.
 *
 * @return bool true/false
 *
 */
virtual bool isReset() const;



//_________________________________________________________________________
//_________________________________________________________________________
private:
//-------------------------------------------------------------------------
// Input / Output data members
//-------------------------------------------------------------------------
ISequence<IString> fInputTexts;
ITieredTextBuffer  fOutputTextBuffer;

//-------------------------------------------------------------------------
// Execution data members
//-------------------------------------------------------------------------
bool fIsSuccessful;
bool fIsSuccessDecided;
bool fIsReset;
bool fIsStickySuccess;

//-------------------------------------------------------------------------
// Exception data members
//-------------------------------------------------------------------------
EStage fExceptionStage;


//-------------------------------------------------------------------------
// Bookkeeping data members
//-------------------------------------------------------------------------
unsigned long fRunCount;
ISortedMap<IStringWrapper,IString>*  fInfoMap;

//-------------------------------------------------------------------------
// Exception methods
//-------------------------------------------------------------------------
static const char*     stageName(EStage);
static void            printException(ITieredTextBuffer&, const IException&, EStage);
void                   setStage(EStage);


//-------------------------------------------------------------------------
//  Methods
//-------------------------------------------------------------------------
// These two methods are made private because we don't want to expose OpenClass
// collection classes in our APIs. Users should use the public setInputs and
// copyInputs method which take argc and argv as arguments.
void    setInputs(const ISequence<IString>& TextFromWhere);
void    copyInputs(ISequence<IString>& textsToWhere) const;

void    importFrom(const ITest& source);

// Calls ITest::print
friend ITieredTextBuffer& operator<<(ITieredTextBuffer&, ITest&);

friend class ITestCollection;
friend class ITestMultiplexer;
friend class IArgumentDictionary;
friend class IMultiplexerTest;
friend class IAlbertTest;
friend class IGrafMatrixTest;
};

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

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

#endif  // _ITEST_
