java -cp ../../zbnfjax/zbnf.jar org.vishia.zcmd.JZcmd testAll.jz.bat -t:testAll.jz.output.txt
exit /B

==JZcmd==

Class FileSystem = org.vishia.util.FileSystem; ##contains some nice static methods.

String const scriptStringEmpty;

##Example for a script level Java instance which is able to found in the given classpath of the JRE:
Obj scriptObj = new org.vishia.zcmd.JZcmdUserExample(text);

String scriptString = "scriptStringFirst";
String const scriptStringConst = "scriptStringConst";

String scriptStringSet2 = "string2";

set TEST="Env-TEST";

main(){
  call TestScriptVarAccess.test();
  call testBatch();              <+out>TEST 2<.+n>
  call testErrorlevel();          <+out>TEST 3<.+n>
  call testOutputTextIndent();   <+out>TEST 4<.+n>
  call testDebugErrorMsg();       <+out>TEST 5<.+n>
  call testErrorToOutput();       <+out>TEST 6<.+n>
  call TestErrorSub.test();        <+out>TEST 7<.+n>
  call TestExceptionInException.method(); <+out>TEST 8<.+n>
  call testDataAccess();
  call testMethodInvoke();         <+out>TEST 9<.+n>
  call testCalctime();           <+out>testCalctime<.+n>
  call testVariableDatapath();   <+out>testVariableDatapath<.+n>
  call testText();               <+out>testText<.+n>
  
  //call testDebug();
  //call TestResult.exec();
  //call TestCmdWindows.test();
  //call testFile();
  //call testStringBuffer();
  //call testNumeric();
  //call testIf();
  //call testJavaNew();
  //call testContainer();
  //call testEnv();
  //call TestChangeDir.exec();
  //call TestThread.exec();
  //call testIpset();
}



class TestScriptVarAccess
{

  sub test() {
    <+>
      ==testScriptVarAccess()==
      A scriptvariable is copied locally, changes are effective only locally. 
      But if jzcmd.scriptVariables().scriptString is set, it is effective in the script:
    <.+>
    <+:n>Text in a script variable: scriptString = <&scriptString><.+>
    scriptString = "new text";  ##this has only an effect inside this subroutine:
    <+:n>Changed: scriptString = <&scriptString><.+>
    if(scriptString != "new text"){ <+:n>!!!ERROR TestScriptVarAccess 1 !!! <.+> }
    call otherMethod(cmp = "scriptStringFirst");  ##to check the scriptvariable
    jzcmd.scriptVariables().scriptString = "changed on script level";
    call otherMethod(cmp = "changed on script level");  ##to check the scriptvariable
    <+><.+n>    
  }
  
  sub otherMethod(String cmp) { 
    <+:n>In other method: scriptString = <&scriptString><.+>
    if(scriptString != cmp){ <+:n>!!!ERROR TestScriptVarAccess <&cmp>!!!<.+n> }
  }
  
}


sub testBatch(){

  <+>
    ==testBatch()==
    This example creates an batchfile and executes it then. It works for MS-Windows. 
    The batch 'myBatch.bat' contains a 'dir' cmd which's output is redirected in a newly created text file 'out.txt'.
    After execution this JZcmd subroutine evaluates the 'out.txt'. 
    It searches in the line containing 'myBatch' in the and shows it.
  <.+>
 currdir = <:><&scriptdir>/..<.>;
 <+>
   ===Variantes of currdir: ===
   jzcmd.scriptLevel.currdir = <&jzcmd.scriptLevel.currdir>
   jzcmd.currdir() = <&jzcmd.currdir()>
   jzcmdsub.currdir = <&jzcmdsub.currdir>
   jzcmdsub.currdir = <&jzcmdsub.currdir()>
 <.+>
   
 Openfile bat = "myBatch.bat";  ##opens in current directory
 <+bat>
   echo off
   dir >out.txt
   call otherbatch.bat
 <.+close>
 <+:n>executes myBatch.bat, creates out.txt in the current directory ...<.+>
 cmd cmd.exe /C myBatch.bat;
 <+:n>evaluates 'out.txt': <.+>
 Stringjar sdir = FileSystem.readFile(File:out.txt);  ##reads the file.
 if(sdir.seek("myBatch").line().found()){
   String line = sdir.getCurrentPart();
   <+><&line><.+n>
 }
}




sub testErrorlevel()
{
  <+>
    ==testErrorlevel()==
  <.+>
  List testErrorlevels;
  testErrorlevels += "1";
  testErrorlevels += "2";
  testErrorlevels += "3";
  testErrorlevels += "5";

  for(level: testErrorlevels){
    ##to procude an errorlevel from a cmd invocation create a batch routine:
    Openfile bat = "error.bat";
    <+bat>exit <&level><.+close>
    cmd cmd.exe /C error.bat;
    throw on errorlevel 5;
    <+>testErrorlevel(): <&jzcmdsub.cmdErrorlevel> < 5 <.+n> 
    if errorlevel 2 { 
      <+>testErrorlevel(): <&jzcmdsub.cmdErrorlevel> >= 2 <.+n> 
    }
    ##
    onerror cmd {
      <+>testErrorlevel(): exeception handling <.+n>
    }
  }
}



sub testOutputTextIndent()
{
  <+>
    ==testOutputTextIndent()==
  <.+>
  <+><: >  ## without emtpy line
    First line left aligned
   Second line left aligned
    Third line left aligned
      forth line 2 spaces, <: >
         continue of forth line, one space
    fifth line left aligned.
  <.+>      
}


sub testCausesError(){
  <+>Variable not exists: <&faultyVariable><.+n>
}


sub testDebugErrorMsg(){
  <+>
    ==testDebugErrorMsg()==
  <.+>
  call testCausesError();
  <+>This statment is skipped on error<.+n>
  onerror{ <+>Any error in 'testDebugErrorMsg': <&error><.+n> }
  
}




##It shows how to handle errors while generating text
sub testErrorToOutput(){
  <+>
    ==testErrorToOutput()==
  <.+>
  errortoOutput;       ##with this statement an error text will be written into the output text with 
  <+>unknown variable: <&unknown><.+n>
  errortoOutput off;   ##with this statement an exception is thrown on the unknown variable, executes the onerror-block
    then.
  <+>unknown variable: <&unknown><.+n>
  onerror{
    <+>there is an error: <&error>
      The error with stacktrace: <&jzcmdsub.excStacktraceinfo()>
    <.+n>
  }  
  <+>test throw...<.+n>
  throw "text";
  <+>further statement skipped!<.+n>
  onerror{ <+>error throw: <&error><.+n> }  
}



class TestErrorSub 
{
  sub causeError(){
    String xx = nonexistVariable;  //causes error, not caught here.
  }
  
  
  sub test(){
    <+>
      ==TestErrorSub.test()==
    <.+>
    call TestErrorSub.causeError();
    onerror{
      <+>TestErrorSub - onerror reached: <&error> <.+n>
    }
  }

}



class TestExceptionInException
{

  sub methodinner(){
    String xx = nonexistVariable;  //causes error, not caught here.
    onerror{
      <+>TestExceptionInException with errorneous: <&unknownVariable><.+n>
      onerror{
        <+>An inner onerror catches the error in an error handling: <&error><.+n>
      }
    }

    String x2 = nonexistVariable;  //causes error, not caught here.
    onerror{
      <+>Second error is not catched: <&unknownVariable><.+n>
    }
    
  }
  
  
  sub method()
  { <+>==TestExceptionInException==<.+n>
    call methodinner();
    onerror{
      <+>An onerror block in an outer routine should be correct: <&error><.+n>
    }
  }  

}





##checks the access to a String in a Java user class:
sub testDataAccess(){
  <+:n>==testDataAccess()==<.+>
  <+:n>Text in a user Java instance: scriptObj.simpleTestString = <&scriptObj.simpeTestString><.+>
  scriptObj.simpeTestString = "new text";  ##sets a String in the users class.
  <+:n>Changed scriptObj.simpeTestString = "new text"; result = <&scriptObj.simpeTestString><.+>
  if(scriptObj.simpeTestString != "new text"){ <+:n>!!!ERROR testDataAccess !!! <.+> }
  //create a new variable inside a container in a Java user class.
  String scriptObj.testVariables.inUserData = "test in users data";   
  onerror {
    <+>Access ERROR in script: <&error><.+>
  }
  <+><.+n>
}



##searches the correct method by arguments.
sub testMethodInvoke(){
  <+>
    ==testMethodInvoke()==
  <.+>
  Obj obj = new org.vishia.zcmd.JZcmdUserExample(text);
  //obj.methodTest(5,8);
  //obj.methodTest(5*Math.PI,8+5);

  ##Converts to an absolute file with currdir
  obj.methodTest(File: "myFile");  
  obj.methodTest(File: path/myFile.ext);  

  
  ## invokes methodTest(char)
  obj.methodTest("x", "text");
  obj.methodTest('a');
  obj.methodTest('b'-1);
  obj.methodTest(65+32);
  obj.methodTest(0x61);
  obj.methodTest("a");
  
  ## invokes methodTest(String)
  obj.methodTest(<:>content of <&obj><.>);

}



sub testCalctime(){

  <+>
    ==testCalctime()==
  <.+>
  Class Tester = org.vishia.test.TestCalctime_sin;
  Obj tester = java new org.vishia.test.TestCalctime_sin();
  //Obj y = new org.vishia.test.TestCalctime_sin.Double_ab();
  <+>Start...<.+n>
  Num starttime = System.currentTimeMillis();
  Num i = 1;
  do{
    tester.fourier(i); 
    i = i + 1;
  } while(i < 1000);
  Num endtime = System.currentTimeMillis();
  Num timediff = endtime - starttime;
  <+>Time = <&timediff> ms. <.+n>
}






sub testVariableDatapath()
{
  <+>
    ==testVariableDatapath()==
  <.+>
  Map map;
  String map.varA = "valA";  ## example for data tree
  String map.varB = "valB";
  String map.varC = "valC";

  String select = "B";       ## any selection input
  
  String path = <:>map.var<&select><.>;  ##build the path with text expression
  String result1 = &(path);              ##access with variable datapath 
  <+><&result1><.+n>

  String datafieldname = <:>var<&select><.>;  ##build a field name for selection
  String result2 = &map.&(datafieldname);     ##access with variable field name.
  <+><&result2><.+n>
  

}



sub testText()
{
  <+>
    ==testText()==
  <.+>
  String text1 = <:>text1 scriptdir = <:scriptdir><.>;
  
  String text2 = "constant text";


}