import java.util.StringTokenizer;
import java.beans.Introspector;
import java.beans.IntrospectionException;
import java.beans.MethodDescriptor;
import java.beans.PropertyDescriptor;
import java.beans.BeanInfo;
import java.beans.Beans;
import java.lang.reflect.Method;
import java.lang.reflect.InvocationTargetException;
import java.lang.IllegalAccessException;
import java.lang.IllegalArgumentException;
import java.io.IOException;
import java.util.Properties;

//F>=========================================================================
// UnitTest.java
// RCS: $Revision: 1.00 $ $Date: 2001/03/22 01:23:17 $ $Author: steffen $
//========================================DISCLAIMER=========================
// This file has been developed by and/or for the U.S. government within the
// Forecast Systems Laboratory by government and/or contract personnel.
// As required by government regulations, this file is in the public
// domain, and is furnished "as is", without technical support, and with
// no warranty, express or implied, as to its usefulness for any purpose.
//F>>=====================================description (optional)=============
//F>>>=======================================================================
/**
 * <p>The UnitTest class makes adding additional tests simple since the only
 * requirements are to:</p>
 * <p>1) Create an inner class of the class you wish to test:</p>
 * <PRE>
 * <FONT COLOR=#000000>
 * <p>
 * 
 * BEGIN:EXAMPLE
 *
 * // Suppose we need a method which will rotate a string so 
 * // that the first character becomes the last.
 * // All other characters keep their original relative position.
 * import UnitTest;
 * class Rotate
 *     {
 *     public String rotate(String str)
 *         {
 *         if (str.length() > 0)
 *             return str.substring(1, str.length()) + str.substring(0, 1);
 *         return str;
 *         }
 * 
 *     public static class Test extends UnitTest
 *         {
 *         // java -nojit 'Hello$Test' -v test
 *         //Boiler plate "main" to give copy of Test to superclass UnitTest.
 *         public static void main(String args[])
 *             {
 *             System.exit(new Test().runTest(args));
 *             }
 *         // Add one test for every method/function  
 *         public void testRotate() throws Exception
 *             {
 *             Rotate r = new Rotate();
 *             assert(r.rotate("Hello World").equals("ello WorldH"));
 *             assert(r.rotate("ello WorldH").equals("llo WorldHe"));
 *             assert(r.rotate("").equals(""));
 *             assert(r.rotate("a").equals("a"));
 *             }
 *         }
 *     }
 * 
 * OUTPUT:
 * > java -nojit 'Rotate$Test' -v test
 * PASS: Rotate$Test.testRotate: RunTime = 4 mSecs
 * ALL PASS: Rotate$Test Module
 * 
 * END: EXAMPLE
 *
 * </p>
 * </FONT>
 * </PRE>
 * <p>Write new test methods following the prototype.</p>
 * <p>Run the tests from a script containing the commands:
 * <PRE>
 * <FONT COLOR=#000000>
 * "java -nojit -mx65536000 -ms55000000  ClassToTest$Test [-option] [suite prefix] [min Time]"
 * There will only be output if a test fails.
 * Other command line options include:
 *     " " print fails only.
 *     "-m"  print module pass or fail.
 *     "-v"  verbose print of test pass or fail.
 *     "-h"  Print this message.
 * suite prefix default = "test"  Prefix of tests to run.
 * min Time default = "0"  Minimum test execution time to report. </p>
 * In order to maintain the first option, it is necessary to restrict testing 
 * to nonprinting parts of methods.
 * </FONT>
 * </PRE>
 * <p>As an example, the UnitTest.java class has a set of tests.
 * The only difference is that the inner class is named "SelfTest" rather
 * than "Test".  This is to avoid naming conflicts.  You may run the self
 * test using the command 
 * "java -nojit -mx65536000 -ms55000000  UnitTest$SelfTest -v test 0"</p>
 * <p>Test code is in the same file as the code to be tested so the tests 
 * won't be lost.  However, the test class is an inner class so the test
 * class has access to private member variables and private functions of the 
 * class to be tested.  In addition, the test object code compiles into a 
 * different file than the code to be tested.  Separating the compiled 
 * deliverable object code from the test code ensures that the compiled 
 * test code does not have to be downloaded with an applet.  Tests inherit 
 * from a single class called UnitTest.java which uses introspection and 
 * reflection to determine the test names based on a prefix for the test 
 * methods.  The tests can be run from a makefile or script. 
 * 
 * A few more interesting details.
 * A new test class is instantiated before every test is run.
 * setup() is run before every test.
 * teardown() is run after every test.
 * </p>
 * 
 * Acknowledgements: This code is modeled after PyUnit.  
 * 
 * Send questions to Christopher E. Steffen  Email: drcesteffen@yahoo.com
 *
 */
 // <p>The <a href="UnitTest.java">Source</a>
 // @author    Christopher E. Steffen, Ph.D.
 // @author    $Author: steffen $
 // @version   $Revision: 1.00 $
 // @since     $Date: 2001/03/22 01:23:17 $
 //
 // </p>
public class UnitTest
    {
    /** <PRE><FONT><p>
     * usage: java -nojit display.Beep\$Test [-options] [suite prefix] [minTime]
     * or on Windows java -nojit display.Beep$Test [-options] [suite prefix] [minTime]
     * where command line options include:
     *     " " print fails only.
     *     "-m"  print module pass or fail.
     *     "-v"  verbose print of test pass or fail.
     *     "-h"  Print this message.
     * suite prefix default = "test"  Prefix of tests to run.
     * min Time default = "0"  Minimum test execution time to report.
     * @return 0 for pass and nonzero for fail.
     * Example:
     * java -nojit -mx65536000 -ms55000000  display.Beep$Test -m
     * </p></FONT></PRE>
     */
    public static void main(String args[])
        {
        System.exit(new SelfTest().runTest(args));
        }
    /** <PRE><FONT><p>
     * usage: java -nojit display.Beep\$Test [-options] [suite prefix] [minTime]
     * or on Windows java -nojit display.Beep$Test [-options] [suite prefix] [minTime]
     * where command line options include:
     *     " " print fails only.
     *     "-m"  print module pass or fail.
     *     "-v"  verbose print of test pass or fail.
     *     "-h"  Print this message.
     * suite prefix default = "test"  Prefix of tests to run.
     * min Time default = "0"  Minimum test execution time to report.
     * @return 0 for pass and nonzero for fail.
     * @param ut = "new Test()" from test class extending UnitTest.
     * @return 0 for pass and nonzero for fail.
     * Example:
     * java -nojit -mx65536000 -ms55000000  display.Beep$Test -m
     * </p></FONT></PRE>
     */
    protected int runTest(String[] args)
        {
        return(this.all(args, this.getPkgClass(this), 
          this.getPkgClassTest(this)));
        }
    /** <PRE><FONT><p>
     * Usage in each test class do the following:
     * static {_utst = (UnitTest)(new Test());}
     * </p></FONT></PRE>
     */
    protected String getPkgClassTest(UnitTest ut)
        {
        return (ut.getClass().getName());
        }
    /** <PRE><FONT><p>
     * Usage in each test class do the following:
     * static {_utst = (UnitTest)(new Test());}
     * </p></FONT></PRE>
     */
    protected String getPkgClass(UnitTest ut)
        {
        StringTokenizer st = new StringTokenizer(
          ut.getClass().getName(),"$");
        return (st.nextToken());
        }
    /** <PRE><FONT><p>
     * Explains the command line parameters:
     * usage: java -nojit display.Beep\$UnitTest [-options] [suite prefix] [minTime]
     * or on Windows java -nojit display.BAlertScroller$UnitTest [-options] [suite prefix] [minTime]
     * where command line options include:
     *     " " print fails only.
     *     "-m"  print module pass or fail.
     *     "-v"  verbose print of test pass or fail.
     *     "-h"  Print this message.
     * suite prefix default = "test"  Prefix of tests to run.
     * min Time default = "0"  Minimum test execution time to report.
     * @param strPkgClassTest Example "display.Beep$Test"
     * </p></FONT></PRE>
     */
    protected void dieUsage(String strPkgClassTest)
        {
        StringTokenizer st = new StringTokenizer(strPkgClassTest,"$");
        String str[] = new String[st.countTokens()];
        int i = 0;
        while(st.hasMoreElements())
            str[i] = st.nextToken();
        System.out.println(" usage: \tjava -nojit "+str[0]
          +"\\$"+str[str.length-1]+" [-options] [suite prefix] [minTime] \n"
          +" or on Windows \tjava -nojit "+strPkgClassTest+" [-options] [suite prefix] [minTime]\n"
          +" where options include: \n"
          +" \" \" \t\tPrint fails only. \n"
          +" \"-m\"  \t\tPrint module pass or fail.\n"
          +" \"-v\"  \t\tVerbose print of test pass or fail. \n"
          +" \"-h\"  \t\tPrint this message. \n"
          +" suite prefix default = \"test\"  \tPrefix of tests to run.\n"
          +" min Time default = \"0\"  \t\tMinimum test execution time to report. \n");
        System.exit(1);
        }
    /** <PRE><FONT><p>
     * usage: call like a java bean.
     * @param args[] options include:
     *     " " print fails only.
     *     "-m"  print module pass or fail.
     *     "-v"  verbose print of test pass or fail.
     *     "-h"  Print this message.
     * suite prefix default = "test"  Prefix of tests to run.
     * min Time default = "0"  Minimum test execution time to report.
     * @param strPkgClass Package.Class of class to be tested.
     *      Example: "ldadapp.text.BAlertScroller"
     * @return 0 for pass and nonzero for fail.
     * </p></FONT></PRE>
     */
    protected int all(String args[], String strPkgClass, 
      String strPkgClassTest)
        {
        String strPattern = "test";
        long lnMinDeltaTm = Long.MAX_VALUE;
        String strVerbose = "-v";
        String strModule = "-m";
        boolean boPrintTstPass = false;
        boolean boPrintModulePass = false;
        int nCnt = 0;
        if(args == null) dieUsage(strPkgClassTest);
        for(int i=0;i<args.length;i++)
            { // Parse args[]
            if(args[i] != null)
                {
                nCnt++;
                if(args[i].equals("-h")) dieUsage(strPkgClassTest);
                if(strVerbose.equals(args[i]))
                    {
                    boPrintTstPass = true;
                    }
                else if(strModule.equals(args[i]))
                    {
                    boPrintModulePass = true;
                    }
                else if(!args[i].substring(0,1).equals("-"))
                    {
                    try {
                        lnMinDeltaTm = Long.parseLong(args[i]);
                        }
                    catch(NumberFormatException nfe)
                        {
                        strPattern = args[i];
                        }
                    }
                else
                    {
                    nCnt--;
                    }
                }
            else
                {
                dieUsage(strPkgClassTest);
                }
            }
        if(nCnt != args.length) dieUsage(strPkgClassTest);
        StringTokenizer st = new StringTokenizer(strPkgClassTest,".");
        String strTestMod = "ClassName";
        while(st.hasMoreElements())
            strTestMod = st.nextToken();
        return(results(new UnitTest(), strTestMod, strPkgClass, strPkgClassTest,
          boPrintTstPass, boPrintModulePass, strPattern, lnMinDeltaTm));
        }
    /** <PRE><FONT><p>
     * Get the test results.  Accessible via Beans self introspection.
     * @param tst Object with same classloader as test class.
     *      Example: "new UnitTest()"
     * @param strTestMod Class name of module under test.
     *      Example "BAlertScroller"
     * @param strPkgClass Package.Class name of module under test.
     *      Example "ldadapp.text.BAlertScroller"
     * @param strPkgClassTest Package.Class$Test name of Test module.
     *      Example "ldadapp.text.BAlertScroller$Test"
     * @param boPrintTstPass 
     *     "true" Print results if test passes or fails.
     *     "false" Print results if test fails.
     * @param boPrintModulePass 
     *     "true" Print results if module passes or fails.
     *     "false" Print results if some tests fail.
     * @param strPattern Prefix for test cases to run.
     *      Example: "test" runs all functions matching pattern "test*()"
     * @param lnMinDeltaTm Minimum Run Time to report in millisec.
     * @return 0 for pass and nonzero for fail.
     * </p></FONT></PRE>
     */
    protected int results(Object tst, String strTestMod,
      String strPkgClass, String strPkgClassTest, boolean boPrintTstPass,
      boolean boPrintModulePass, String strPattern,
      long lnMinDeltaTm)
        {
        String str = null;
        int nExit = 0;
        int nExitTest = 0;
        String strName = null;
        long lnDeltaTm = 0L;
        long lnStartTime = 0L;
        int nCnt = 0;
        Object obj = instantiate(tst.getClass(),strPkgClassTest);
        MethodDescriptor md[] = getMethodDesc(obj.getClass());        
        MethodDescriptor md2[] = null;
        Exception e = null;
        for(int i=0;i<md.length;i++)
            {
            nExitTest = 0;
            strName = md[i].getMethod().getName();
            if((strName.length() >= strPattern.length())
              && (strName.substring(0, strPattern.length())
              .equals(strPattern)))
                {
                obj = instantiate(tst.getClass(), strPkgClassTest);
                md2 = getMethodDesc(obj.getClass());        
                runMethod("setup", md2, obj);
            	lnStartTime = System.currentTimeMillis();
                e = runTestMethod(md2[i].getMethod(), obj);
                if(e != null)
                    {
                    System.out.println("\nFAIL: "+strTestMod+"."+strName );
                    nExitTest |= 1;
                    e.printStackTrace();
                    }
                nExit |= nExitTest;
                lnDeltaTm = System.currentTimeMillis() - lnStartTime;
                runMethod("teardown", md2, obj);
            	obj = null;
                nCnt++;
                str = getFailStatus(strTestMod, boPrintTstPass, 
                  strName, lnDeltaTm, lnMinDeltaTm, nExitTest);
                if(str != null) System.out.println(str);    
                }
            }
        str = getPassStatus(strTestMod, boPrintTstPass, 
          boPrintModulePass, nCnt, nExit);
        if(str != null) System.out.println(str);    
        return nExit;
        }


    /**    
     * runTestMethod
     * @param mthd Method to run.
     * @param obj Object to call the method on.
     * @return "null" if test passes.  Exception containing test 
     * results if test fails. 
     */
    protected Exception runTestMethod(Method mthd, Object obj) 
        {
        Exception e = null;
        try {
            mthd.invoke(obj, null);
            }
        catch(IllegalAccessException iae)
            {iae.printStackTrace();}
        catch(IllegalArgumentException iarge)
            {iarge.printStackTrace();}
        catch(InvocationTargetException ite)
            {
            if(ite.getTargetException() instanceof Exception)    
                e = (Exception)(ite.getTargetException());
            else
                ite.getTargetException().printStackTrace();
            }
        return e;    
        }


    /**    
     * runMethod for setup and teardown.
     * @param strMethodName Method to run.
     * @param md List of Method descriptor to choose from.
     * @param obj Object to call the method on.
     * @return "0" if successful. "0" if unsuccessful.
     */
    protected int runMethod(String strMethodName, MethodDescriptor[] md, 
      Object obj) 
        {
        try {
            getMethod(md, strMethodName).invoke(obj, null);
            }
        catch(IllegalAccessException iae)
            {
            iae.printStackTrace();
            return 1;
            }
        catch(IllegalArgumentException iarge)
            {
            iarge.printStackTrace();
            return 1;
            }
        catch(InvocationTargetException ite)
            {
            ite.getTargetException().printStackTrace();
            return 1;
            }
        return 0;
        }
    /**    
     * Fail Status interpreted.
     * @param strTestMod Class name of module under test.
     *      Example "BAlertScroller"
     * @param boPrintTstPass 
     *     "true" Print results if test passes or fails.
     *     "false" Print results if test fails.
     * @param strName Name of test method.
     * @param lnDeltaTm Run Time of test method.
     * @param lnMinDeltaTm Minimum Run Time to report in millisec.
     * @param nExitTest "0" if this test passed. "1" if this test failed.
     * @return FailStatusString
     */
    protected String getFailStatus(String strTestMod, boolean boPrintTstPass, 
      String strName, long lnDeltaTm, long lnMinDeltaTm, int nExitTest)
        {
        String str = null;    
        if(boPrintTstPass && (nExitTest == 0))
            str = new String("PASS: "+strTestMod+"."
              +strName+": RunTime = " + lnDeltaTm + " mSecs");
        else if((lnDeltaTm >= lnMinDeltaTm) && (nExitTest == 0))
            str = new String(strTestMod+".RunTime: "
              +strName+" RunTime = " + lnDeltaTm + " mSecs >= "
              +lnMinDeltaTm);
        return str;
        }        
        
        
        
    /**    
     * Pass Status interpreted.
     * @param strTestMod Class name of module under test.
     *      Example "BAlertScroller"
     * @param boPrintTstPass 
     *     "true" Print results if test passes or fails.
     *     "false" Print results if test fails.
     * @param boPrintModulePass 
     *     "true" Print results if module passes or fails.
     *     "false" Print results if some tests fail.
     * @param nCnt number of tests run.
     *      Example: "test" runs all functions matching pattern "test*()"
     * @param nExit "0" if all tests passed. "1" if some tests failed.
     * @return PassStatusString
     */
    protected String getPassStatus(String strTestMod, boolean boPrintTstPass, 
      boolean boPrintModulePass, int nCnt, int nExit)
        {
        String str = null;    
        if((boPrintTstPass || boPrintModulePass) && (nCnt > 0))
            {
            if(nExit == 0)
                str = new String("ALL PASS: "+strTestMod+" Module\n");
            else
                str = new String("SOME FAIL: "+strTestMod+" Module\n");
            }
        else if(nCnt == 0)
            str = new String("NO MATCHING TESTS: "+strTestMod+" Module\n");
        if(boPrintTstPass) 
            str = new String(str + "\n");
        return str;
        }        
        
        
    /**<PRE><FONT><p> Get the described method.
     * @param md[] array of method descriptors to get method from.
     * @param strMethod Method to get.
     * @return Method.
     *</p></FONT></PRE>
     */
    protected Method getMethod(MethodDescriptor[] md, String strMethod)
        {
        Method methd = null;     
        for(int i=0;i<md.length;i++)
            {
            if(md[i].getMethod().getName().equals(strMethod))
                {
                methd = md[i].getMethod();
                break;
                }
            }
        return methd;
        }    
    /** <PRE><FONT><p> Get the array of Method Descriptors.
     * @param cls class to get the classloader from.
     * @return MethodDescriptor[]
     * </p></FONT></PRE>
     */
    protected MethodDescriptor[] getMethodDesc(Class cls)
        {
        BeanInfo BnInfo = null;
        try {
            BnInfo = Introspector.getBeanInfo(cls,
              new Object().getClass());
            }
        catch(IntrospectionException ie)
            {
            ie.printStackTrace();
            }
        MethodDescriptor md[] = BnInfo.getMethodDescriptors();
        return(md);
        }    
    /** <PRE><FONT><p> Instantiate the class.
     * @param cls class to get the classloader from.
     * @param strPkgClass Class to instantiate.
     * @return Object instantiated.
     * </p></FONT></PRE>
     */
    protected Object instantiate(Class cls, String strPkgClass)
        {
        Object obj = null;
        try {
            ClassLoader cl = cls.getClassLoader();
            obj = ((Object)Beans.instantiate(cl, strPkgClass));
            }
        catch (ClassNotFoundException cnfe)
            {
            System.out.println(strPkgClass+" ClassNotFoundException");
            cnfe.printStackTrace();
            }
        catch (IOException ioe)
            {
            System.out.println(strPkgClass+" IOException");
            ioe.printStackTrace();
            }
        return obj;
        }
    /** <PRE><FONT><p> Throw exception if argument false.
     * @param bo boolean assertation.
     * @exception Exception Throws Exception if value is not true.
     * </p></FONT></PRE>
     */
    protected void assert(boolean bo) throws Exception
        {
        if(!bo) throw new Exception(new String("FAIL assert = "+bo));
        }
    /** <PRE><FONT><p> Throw exception if argument false.
     * @param bo boolean assertation.
     * @param strExpression boolean expression evaluated.
     * @exception Exception Throws Exception if value is not true.
     * </p></FONT></PRE>
     */
    protected void assert(boolean bo, String strExpression) throws Exception
        {
//        System.out.println(new String("assert => "+strExpression+" = "+bo));    
        if(!bo) throw new Exception(new String(
          "FAIL assert => "+strExpression+" = "+bo));
        }
    /** <PRE><FONT><p> Automatically called before each test.
     * </p></FONT></PRE>
     */
    public void setup()
        {
        }
    /** <PRE><FONT><p> Automatically called after each test.
     * </p></FONT></PRE>
     */
    public void teardown()
        {
        }
    /** <PRE><FONT><p> Force the failure of a test.
     * </p></FONT></PRE>
     */
    public void fail(String strMsg) throws Exception
        {
        throw new Exception(strMsg);    
        }
        
    public static class SelfTest extends UnitTest
        {
        public static void main(String args[]){System.exit(new SelfTest().runTest(args));}


        public void testAssert() throws Exception
            {
            UnitTest ut = new UnitTest();
            ut.assert(true);
            boolean boThrowWorks = false;
            try {
                ut.assert(false);
                }
            catch(Exception e)
                {
                boThrowWorks = true;    
                }
            if(!boThrowWorks)
                throw new Exception("assert() failed");
            }
            
        public void testInstantiate() throws Exception
            {
            UnitTest ut = new UnitTest();
            Object obj = ut.instantiate(new SelfTest().getClass(), 
              "UnitTest");
            ut.assert(obj != null);
            ut.assert(obj instanceof UnitTest);
            }
        public void testGetPkgClassTest() throws Exception
            {
            UnitTest ut = new UnitTest();
            ut.assert(ut.getPkgClassTest(new SelfTest()).equals(
              new SelfTest().getClass().getName()));
            }
        public void testGetPkgClass() throws Exception
            {
            UnitTest ut = new UnitTest();
            ut.assert(ut.getPkgClass(new SelfTest()).equals(
              new SelfTest().getClass().getName().substring(0,8)));
            }
        public void testSetup() throws Exception
            {
            UnitTest ut = new UnitTest();
            ut.setup();
            }
        public void testTeardown() throws Exception
            {
            UnitTest ut = new UnitTest();
            ut.teardown();
            }
            
        public void testGetMethodDesc() throws Exception
            {
            UnitTest ut = new UnitTest();
            MethodDescriptor md[] = ut.getMethodDesc(ut.getClass());
            ut.assert(md != null);            
            ut.assert(md.length > 0);            
            ut.assert(md[0] != null);            
            }
            
        public void testGetMethod() throws Exception
            {
            UnitTest ut = new UnitTest();
            MethodDescriptor md[] = ut.getMethodDesc(ut.getClass());
            Method mSetup = ut.getMethod(md, "setup");
            ut.assert(mSetup != null);
            ut.assert(mSetup.getName().equals("setup"));
            Method mTeardown = ut.getMethod(md, "teardown");
            ut.assert(mTeardown != null);
            ut.assert(mTeardown.getName().equals("teardown"));
            }

        public void testGetPassStatus() throws Exception
            {
            UnitTest ut = new UnitTest();
            String strTestMod = "Test String";
            String str = ut.getPassStatus(strTestMod, true, false, 1, 0);
            ut.assert(str.equals("ALL PASS: "+strTestMod+" Module\n\n"));
            str = ut.getPassStatus(strTestMod, true, false, 1, 1);
            ut.assert(str.equals("SOME FAIL: "+strTestMod+" Module\n\n"));
            str = ut.getPassStatus(strTestMod, true, false, 0, 0);
            ut.assert(str.equals("NO MATCHING TESTS: "+strTestMod+" Module\n\n"));
            str = ut.getPassStatus(strTestMod, true, false, 1, 0);
            ut.assert(str.equals("ALL PASS: "+strTestMod+" Module\n\n"));
            str = ut.getPassStatus(strTestMod, false, true, 1, 0);
            ut.assert(str.equals("ALL PASS: "+strTestMod+" Module\n"));
            str = ut.getPassStatus(strTestMod, false, true, 1, 1);
            ut.assert(str.equals("SOME FAIL: "+strTestMod+" Module\n"));
            str = ut.getPassStatus(strTestMod, false, true, 0, 0);
            ut.assert(str.equals("NO MATCHING TESTS: "+strTestMod+" Module\n"));
            str = ut.getPassStatus(strTestMod, false, true, 1, 0);
            ut.assert(str.equals("ALL PASS: "+strTestMod+" Module\n"));
            }            

        public void testGetFailStatus() throws Exception
            {
            UnitTest ut = new UnitTest();
            String strTestMod = "Test String";
            String strName = "CESteffen";
            long lnDeltaTm = 0L;
            long lnMinDeltaTm = Long.MAX_VALUE;
            String str = ut.getFailStatus(strTestMod, true, 
              strName, lnDeltaTm, lnMinDeltaTm, 0);
            ut.assert(str.equals("PASS: "+strTestMod+"."
              +strName+": RunTime = " + lnDeltaTm + " mSecs"));
            str = ut.getFailStatus(strTestMod, false, 
              strName, lnDeltaTm, lnMinDeltaTm, 0);
            ut.assert(str == null);
            str = ut.getFailStatus(strTestMod, true, 
              strName, lnDeltaTm, lnMinDeltaTm, 1);
            ut.assert(str == null);
            lnMinDeltaTm = 0;
            str = ut.getFailStatus(strTestMod, false, 
              strName, lnDeltaTm, lnMinDeltaTm, 0);
            ut.assert(str.equals(strTestMod+".RunTime: "
              +strName+" RunTime = " + lnDeltaTm + " mSecs >= "
              +lnMinDeltaTm));
            }

            
        public void testRunMethod() throws Exception
            {
            UnitTest ut = new UnitTest();
            Object obj = ut.instantiate(ut.getClass(), "UnitTest");
            MethodDescriptor md2[] = ut.getMethodDesc(obj.getClass());        
            int nExit = ut.runMethod("setup", md2, obj);
            ut.assert(nExit == 0);
            }            
            
        public void fail1() throws Exception
            {
            throw new Exception("Fail");    
            }
        public void pass1() throws Exception
            {
            }
            
        public void testRunTestMethod() throws Exception
            {
            UnitTest ut = new UnitTest();
            Object obj = ut.instantiate(ut.getClass(), "UnitTest$SelfTest");
            MethodDescriptor md2[] = ut.getMethodDesc(obj.getClass());        
            Method mthd = ut.getMethod(md2, "pass1");
            Exception e = ut.runTestMethod(mthd, obj);
            ut.assert(e == null);
            mthd = ut.getMethod(md2, "fail1");
            e = ut.runTestMethod(mthd, obj);
            ut.assert(e != null);
            }            
        }
    }














