/*
 * $Id: TestSuite.java,v 1.1.1.1 1998/05/11 18:43:03 metlov Exp $
 *
 * This file is part of the Java Expressions Library (JEL).
 *   For more information about JEL visit :
 *    http://galaxy.fzu.cz/JEL/
 *
 * (c) 1998 by Konstantin Metlov(metlov@fzu.cz);
 *
 * JEL is Distributed under the terms of GNU General Public License.
 *    This code comes with ABSOLUTELY NO WARRANTY.
 *  For license details see COPYING file in this directory.
 */



import gnu.jel.*;
import gnu.jel.generated.EC;
import gnu.jel.generated.ParseException;
import java.io.PrintStream;

public class TestSuite {
  
  static int successes=0;
  static int failures=0;
  
  public static void main(String[] args) {

    // Set UP Library
    Class[] staticLib=new Class[1];
    try {
      staticLib[0]=Class.forName("java.lang.Math");
    } catch(ClassNotFoundException e) {
      // Can't be ;)) ...... in java ... ;)
    };
    Library lib=new Library(staticLib,null);
    try {
    lib.markStateDependent("random",null);
    } catch (NoSuchMethodException e) {
      // Can't be also
    };

    PrintStream o=System.out;
    
    o.println(); o.println("----- TESTING ERROR REPORTING ------");
    o.println();
    
    testError("1.0-+1.0",lib,5,o);
    testError("1.0&1.0",lib,4,o);
    testError("-",lib,1,o);
    testError("0x56+0xXX",lib,7,o);
    testError("Sin(x)",lib,5,o);
    testError("Sin(6)",lib,1,o);
    testError("sin(' ')",lib,1,o);
    testError("'a'+'b'",lib,4,o);
    testError("1+sin(1,6)",lib,3,o);
    testError("2147483649L+2147483649",lib,13,o);
    testError("01234567+08+5",lib,11,o);
    
    o.println(); o.println("----- TESTING STATIC OPTIMIZATIONS ------");
    o.println();
    
    testExpression("2*2",new Long(4),null,lib,o);
    testExpression("2L*2L",new Long(4),null,lib,o);
    testExpression("2.0*2.0",new Double(4.0),null,lib,o);
    testExpression("2.0F*2.0F",new Double(4.0),null,lib,o);
    testExpression("sin(1)",new Double(Math.sin(1.0)),null,lib,o);
    testExpression("pow(sin(1),2)+pow(cos(1),2)",new Double(1.0),null,lib,o);
    testExpression("min(1+2*2,(1+2)*2)",new Long(5),null,lib,o);

    o.println(); o.println("----- TESTING DYNAMIC OPTIMIZATIONS (x=5)------");
    o.println();

    // Construct a new library
    Class[] dynamicLib=new Class[1];
    Object[] rtp=new Object[1];
    VariableProvider vp=new VariableProvider();
    Class oldmath=staticLib[0];
    staticLib=new Class[2];
    staticLib[0]=oldmath;
    // next line makes also static functions from VariablePrivider available
    staticLib[1]=vp.getClass();  
    
    vp.x=5.0;
    rtp[0]=vp;
    dynamicLib[0]=vp.getClass();
    lib=new Library(staticLib,dynamicLib);
    
    testExpression("sin(x/5)",new Double(Math.sin(1.0)),rtp,lib,o);
    testExpression("255+5+7+9-x",new Double(255+7+9),rtp,lib,o);
    testExpression("-x+255+5+7+9",new Double(255+7+9),rtp,lib,o);
    testExpression("-x+(255+5+7+9)",new Double(255+7+9),rtp,lib,o);
    
    o.println(); o.println("----- TESTING COMPILED-in EXCEPTIONS (x=5)------");
    o.println();
    
    testExpression("(1+6)/(2+2-4)",null,rtp,lib,o);
    testExpression("throw_arg_eq_4(6-2)",null,rtp,lib,o);
    
    o.println(); o.println("^^^^^^^^^^^^ SCORE success/failure = "+
			   successes+"/"+failures+
			   " ^^^^^^^^^^^^" );
    o.println();
    o.println("NOTE: Error detection test \"sin(' ')\" currently "+
	      "always fails.");

  };

  private static void testExpression(String expr, Object tobe, 
				     Object[] runtimeParameters,
				     Library lib,   PrintStream o ) {
    o.print("*** : \""); o.print(expr); 
    if (tobe != null) {
      o.print("\" = "); o.println(tobe);
    } else {
      o.println("\"   Should throw an exception at run time.");
    };
    OpenOptimizer op=null;
    try {
      op=fillOptimizer(expr,lib);
    } catch (CompilationException ce) {
      o.print("--- COMPILATION ERROR :");
      o.println(ce.getMessage());
      o.print("                       ");
      o.println(expr);
      int column=ce.getColumn(); // Column, where error was found
      for(int i=0;i<column+23-1;i++) System.err.print(' ');
      o.println('^');
      o.println("Unexpected syntax error on supposingly correct expression.");
      FAIL(o);
      return;
    };
    
    boolean testok=true;
    
    boolean optimized=true;
    int iteration=0;
    while(optimized) {
      String message=""+iteration+" |"+op.toString();
      o.print(message);
      for (int k=message.length();k<59;k++) o.print(' ');

      Object result=null;
      try {
	CompiledExpression expr_c=op.compile();
	result=(Number)expr_c.evaluate(runtimeParameters);
      } catch (Throwable e) {
	if (tobe==null)	 
	  o.println("EXPECTED EXCEPTION.");
	else
	  o.println("Exception emerged during compilation/evaluation.");
	o.print("      ");o.println(e.getMessage());
	testok=(tobe==null);
      };
      
      if (tobe!=null) {
	if (result!=null) {
	  o.print(" ="); o.println(result);
	  testok=testok && (result.equals(tobe));
	} else {
	  o.println("NO RESULT");
	  testok=false;
	};
      } else {
	testok=(result==null);
	if (result!=null) o.println(" ="+result.toString());
      };
      
      optimized=op.optimizeIteration();
      iteration++;
    };
    
    if (testok) OK(o); else FAIL(o);
    
  };
  
  private static void testError(String expr, Library lib, int errcol,
				PrintStream o) {
    o.print("*** : \""); o.print(expr); o.println('"');

    CompilationException ce=null;
    try {
      OpenOptimizer op=fillOptimizer(expr,lib);
    } catch (CompilationException e) {
      ce=e;
    };
    if (ce==null) {
      o.println("No error detected."); 
      FAIL(o);
    } else {
      o.print("       ");
      int column=ce.getColumn(); // Column, where error was found
      for(int i=0;i<column-1;i++) o.print(' ');
      o.println('^');
      
      o.print("MESSAGE: "); o.println(ce.getMessage());
      
      if (ce.getColumn()!=errcol) {
	o.print("Error detected at column "); o.print(ce.getColumn());
	o.print(" while it should be at "); o.print(errcol); o.println(" .");
	FAIL(o);
      } else OK(o);

    };

  };

  private static void FAIL(PrintStream o) {
    failures++;
    o.println(" TEST FAILED !!!"); //o.println(); 
  };

  private static void OK(PrintStream o) {
    successes++;
    o.println(" TEST PASSED."); //o.println();
  };
  


  // Mostly copied from jel.Evaluator
  static OpenOptimizer fillOptimizer(String expression, Library lib) 
       throws CompilationException {
    EC ec=new EC(new java.io.StringReader(expression));
    OpenOptimizer o=new OpenOptimizer(lib);
    try {
      ec.expression(o);
    } catch (ParseException pe) {
      throw new CompilationException(pe);
    };
    return o;
  };

};

class OpenOptimizer extends Optimizer {
  
  OpenOptimizer(Library lib) {super(lib);};
  
  public boolean optimizeIteration() {
    return super.optimizeIteration();
  };
  
};
