java/ch/wlkl/wsh/Tester.java
package ch.wlkl.wsh;
import static ch.wlkl.wsh.Env.env;
import static ch.wlkl.wsh.Strings.fill;
import static ch.wlkl.wsh.Strings.quote;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.io.Reader;
import java.io.StringReader;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* @author Keller
* test Infrasturcture and all tests for package shBuf
*
*/
public class Tester extends Top implements Read<String>, Write<String> {
final BufferedReader reader;
char type = ' ';
int nextStart = 0;
String val = null;
String token = null;
String line = null;
String scriptLine = null;
int scriptErase = -1;
int lineNo = 0;
HashMap<String, String> vars = new HashMap<String, String>();
List<String> compare = null;
final java.util.ArrayList<String> input = new java.util.ArrayList<String>();
ArrayList<String> output = new ArrayList<String> ();
ArrayList<String> script = new ArrayList<String> ();
int compareIx = -1;
int errors = 0;
String errorTests = "";
public final static String tempDir = "\\tmpelieli\\zwei/drei";
int readIx = -1;
Env<?, ?> envTop = null;
public static final Pattern space = Pattern.compile("\\s+");
public static final Pattern comment = Pattern.compile("\\*\\*");
public static final Pattern special = Pattern.compile("[+,:;()=]");
public static final Pattern name = Pattern.compile("\\w+");
public static final Pattern string = Pattern.compile("'([^']|'')*'");
final Matcher match = space.matcher("");
public Tester(Reader r) {
vars.put("nl", "\n");
reader = new BufferedReader(r);
parseNL();
parse();
}
boolean parseNL () {
if (scriptLine != null && scriptErase >= -1) {
if (scriptErase >= 0) {
scriptLine = scriptLine.substring(0, scriptErase);
scriptErase = -9;
}
script.add(scriptLine);
}
try {
if (null == (scriptLine = line = reader.readLine()))
return false;
} catch (IOException e) {
fail("exception in readLine " + e);
}
lineNo++;
match.reset(line);
nextStart = 0;
return true;
}
boolean parse(Pattern p) {
if (! match.region(nextStart, line.length()).usePattern(p).lookingAt())
return false;
nextStart = match.end();
return true;
}
boolean parse() {
if (line == null)
return false;
while (true) {
parse(space);
if (nextStart < line.length() && ! parse(comment))
break;
if (! parseNL()) {
type ='e';
token = val = null;
return false;
}
}
if (parse(special)) {
type = (token = val = match.group()).charAt(0);
} else if (parse(name)) {
type = 'n';
token = val = match.group();
} else if (parse(string)) {
type = 's';
val = Strings.unquote(token = val = match.group());
} else {
parseErr("cannot parse");
}
return true;
}
boolean parseName(String name) {
if (type != 'n' || ! val.equals(name))
return false;
parse();
return true;
}
boolean parseSp(char sp) {
if (type != sp)
return false;
parse();
return true;
}
void parseErr(String msg) {
fail("parse error: " + msg
+ "\n last token: " + token + " next: " + (line == null ? "endOfFile" :line.substring(nextStart, line.length() < nextStart+30 ? line.length() : nextStart+30))
+ "\n nextPos: " + nextStart + " in line " + lineNo + ": " + line);
}
static void parseTest() {
String src = "und wie gehts +; \n\n 'string mit ''.' "
+ "\n und so weiter ** kommentar ?"
+ "\n\n ** kommentar \n \n nachher .";
Tester t = new Tester(new StringReader(src));
do
sSay("type " + t.type + ", val " + t.val + ", token " + t.token);
while (t.parse());
}
String string() {
StringBuffer b = new StringBuffer();
boolean afterPlus = false;
while (true) {
if (type == 's') {
b.append(val);
parse();
} else if (type == 'n') {
String name = val;
if (parse() && type == '(') {
parse();
b.append(function(name, stream()));
if (type != ')')
parseErr("closing ) of function missing");
parse();
} else {
b.append(variable(name));
}
} else if (afterPlus) {
parseErr("no operand after +");
} else {
return null;
}
if (type != '+')
return b.toString();
parse();
afterPlus = true;
}
}
String variable(String name) {
if (! vars.containsKey(name))
parseErr("undefined variable " + name);
return vars.get(name);
}
String function(String name, List<String> args) {
if ("writeTestFiles".equals(name)) {
return writeTestFiles(args);
} else if ("removeTestFiles".equals(name)) {
removeTestFiles();
return null;
} else if ("timestamp".equals(name)) {
return timestamp(args.isEmpty() ? null : args.get(0));
} else if ("java".equals(name) && args.size() == 2) {
return args.get(1);
} else {
parseErr("unsupported function " + name);
return null;
}
}
static void stringTest() {
String r, src = "und wie gehts + 'aha '' und so' + weiter() \n\n 'string mit ''.' "
+ "\n und(so() + weiter('sd') +qu( )) ** kommentar ?"
+ "\n\n ** kommentar \n \n nachher ";
Tester t = new Tester(new StringReader(src));
t.vars.put("und", "<value of var und>");
t.vars.put("wie", "<value of var wie>");
t.vars.put("gehts", "<value of var gehts>");
while (null != (r = t.string()))
sSay("string() ==> " + r);
}
void scriptOn(int sx) {
if (scriptErase == -1)
parseErr("scriptOn but already true");
int ex = scriptErase >= 0 ? scriptErase : 0;
if (scriptLine != null)
scriptLine = scriptLine.substring(0, ex) + Strings.fill(" ", sx-ex) + scriptLine.substring(sx);
scriptErase = -1;
}
void scriptOff(int ex) {
if (scriptErase != -1)
parseErr("scriptOff but already false");
scriptErase = ex;
}
List<String> stream() {
List<String> b = new ArrayList<String>();
String one;
while (true) {
if (null == (one = string())) {
if (b.isEmpty())
return b;
parseErr("string expeceted after ,");
}
b.add(one);
if (type != ',')
return b;
parse();
}
}
public void run() {
String name = null;
String category = null;
String opt = null;
List<String> stream = null;
int cnt = 0;
while (true ? errors <= 0 : true) {
if (parseName("test")) {
if ( type != 'n')
parseErr("test name expected");
name = val;
if (! parse() || type != 'n')
parseErr("test category expected");
category = val;
if (parse() && (type == 's' || type == 'n')) {
opt = val;
parse();
}
if (! parseSp(':'))
parseErr(": expected after test " + name + "...");
stream = stream();
} else if (parseName("compare")) {
if (name == null)
parseErr("compare not following test");
if (type != ':')
parseErr(": after compare expected");
scriptOff(nextStart);
parse();
compare = stream();
runOne(name, category, opt, stream);
cnt = cnt + 1;
name = category = opt = null;
script.add(";");
scriptOn(nextStart);
} else if (parseName("remove")) {
while (type == 'n') {
vars.remove(val);
parse();
}
} else if (type == 'n') {
String nm = val;
parse();
if (! parseSp('='))
parseErr("= for assignment expected");
String vl = string();
if (vl == null)
parseErr("assignment string expected after " + nm + " =");
vars.put(nm, vl);
}
if (type == 'e')
break;
if (! parseSp(';'))
parseErr("; expected");
}
msg("--- --- --- " + cnt + " tests with " + errors + " errors in" + errorTests);
// sayScript();
}
public void sayScript() {
msg("new script " + script.size() + " lines");
for (String l: script)
msg(l);
}
void runOne (String name, String category, String opt, List<String> stream) {
output.clear();
input.clear();
readIx = -1;
final int oldErrors = errors;
out("--- --- test begin " + name + ' ' + category + ' ' + opt + " >>> " + stream.size() + " lines");
Env.push(Env.make((Env<String, String>) null, "<-?", this, ">-?", this));
envTop = env();
if (! category(category, opt, stream))
parseErr("unsupported category " + category);
if (envTop != env())
err("env has changed");
else if (env().in() != this)
err("env in changed");
else if (env().out() != this)
err("env out changed");
else
Env.pop();
if (output.size() < compare.size()) {
err("more compare lines (" + compare.size() + ") than output (" + output.size() +")");
for (int ix = compare.size(); ix < (compare.size() < output.size() + 5 ? compare.size(): output.size() + 5); ix++)
msg(" " + ix +": " + compare.get(ix));
}
msg("--- --- test end " + name + ' ' + category + (oldErrors == errors ? " ok" : " *****" + (errors - oldErrors) + " errors *****"));
if (oldErrors != errors)
errorTests += ' ' + name;
}
public boolean category(String category, String opt, List<String> stream) {
if (category.equals("prefix")) {
for (String s : stream)
out(opt + s);
} else if (category.equals("comp")) {
out("--- compile " + (opt.charAt(0) == 's' ? "coSh: " : "data: ") + stream.size() + " lines: " + stream.get(0));
Run r = new Compiler(Env.loader(), new Buf<String>(stream)).compileInstance(opt.charAt(0));
say("compiled: >>>>>>>>>>> " + r + " <<<<<<<<<<<<");
testRun(r);
} else {
return false;
}
return true;
}
public void testRun(Run r) {
out("--- run without input");
input();
r.run();
out("--- run with 3 inputs");
input("eins zwei drei", "zehn elf zw?lf?", "zwanzig 21 22 23 24 ... 29 und Schluss !");
r.run();
}
static void runTest() {
String src =
"v1 = 'value eins';" +
"v2 = 'werteZwei';" +
"test prefinxOne prefix 'the Prefix: ' :" +
"\n'line one v1 = ' + v1 + ', v2 = ' + v2 + ' = ' + v2 + ' v1 = ' + v1 + ' super lang'" +
"\n , 'line two long to here'" +
"\n;" +
"\ncompare : " +
"\n'>>>>> begin test prefinxOne prefix the prefix: >>> 2 lines'" +
"\n,'the prefix: line one super lanG'" +
"\n,'the prefix: line one'" +
"\n,'the prefix: line one'" ;
Tester t = new Tester(new StringReader(src));
t.run();
}
public void msg(String msg) {
System.out.println(msg);
}
// public void compare(String... c) {
// for (int i=0; i < c.length; i++)
// comp.add(c[i]);
// }
//
// public void end(String txt) {
// String r = "", c, o;
// StringBuffer t = new StringBuffer("");
// int min, d;
// for (String s: out)
// r = r + ", " + xQuote(s);
// say("output = (" + (r.equals("") ? "" : r.substring(2)) + ')');
// r = "";
// for (String s: comp)
// r = r + ", " + xQuote(s);
// say("compare = (" + (r.equals("") ? "" : r.substring(2)) + ')');
// if (comp.size() != out.size())
// err("size mismatch out " + out.size() + " != " + comp.size() + " compare");
// min = out.size() < comp.size() ? out.size() : comp.size();
// for (int i=0; i < min; i++) {
// if (! (o =out.get(i)).equals((c = comp.get(i)))) {
// for (d=0;d < o.length() && d < c.length() && o.charAt(d) == c.charAt(d) ;d++);
// t.delete(0, t.length());
// t.append("*** difference at line " + i + ",char " + d);
// if (t.length() < d+9)
// t = t.append(fill(" ", d+9-t.length()));
// t.insert(d+9, '*');
// say(new String(t));
// say ("compare: " + c);
// say ("out : " + o);
// errors++;
// }
// }
// }
//
public void out(String msg) {
int d, ix = output.size();
output.add(msg);
if (output.size() > compare.size()) {
if (output.size() == compare.size() + 1)
err("more new outputlines than " + compare.size() + " compare lines");
} else if (! msg.equals(compare.get(ix))) {
String cl = compare.get(ix);
for (d=0;d < msg.length() && d < cl.length() && msg.charAt(d) == cl.charAt(d) ;d++);
String e = "*** compare line " + ix + "(next) differs from output (overnext) at pos " + d;
if (d >= e.length()+2)
e += fill(" ", d-e.length() - 2) + " >*< ";
else if (d > 4)
e = e.substring(0, d-2) + " >*< " + e.substring(d-2);
msg(e);
msg(cl);
errors++;
}
msg(msg);
scriptString(output.size() == 1 ? " " : " , ", msg);
}
/**
* write a stream to the script expanding variables.
* @param pr
* @param msgs
*/
void scriptStream(String pr, String[] msgs) {
for (String m : msgs) {
scriptString(pr, m);
pr = " , ";
}
}
/**
* write a stream to the script expanding variables.
* @param pr
* @param msgs
*/
void scriptStream(String pr, List<String> msgs) {
scriptStream(pr, msgs.toArray(new String[msgs.size()]));
}
/**
* write a string to the script, expanding variables
* @param pr
* @param msg
*/
void scriptString(String pr, String msg) {
scriptString(pr, msg, vars.keySet().toArray(new String[vars.size()]), 0);
}
/**
* write a string to the script, expanding variables with keys keys[kx ... keys.length]
* @param pr
* @param msg
* @param keys
* @param kx
*/
void scriptString(String pr, String msg, String[] keys, int kx) {
int sx = -1;
String v = "";
for ( ; kx < keys.length && 0 > (sx = msg.indexOf(v = vars.get(keys[kx]))); kx++) ;
if (sx < 0 ){
script.add(pr + quote(msg, "'"));
return;
}
int ex = 0;
do {
if (sx > ex) {
scriptString(pr, msg.substring(ex, sx), keys, kx+1);
pr = " +";
}
script.add(pr + keys[kx]);
pr = " +";
} while (0 <= (sx = msg.indexOf(v, ex = sx + v.length())));
if (ex < msg.length())
scriptString(pr, msg.substring(ex), keys, kx+1);
}
public void err(String msg) {
msg("*** error: " + msg);
errors++;
}
public String writeTestFiles(List<String> names) {
FileRW wf = new FileRW();
for (int ix=0; ix < names.size(); ix++) {
wf.reset(tempDir + '\\' + names.get(ix));
wf.open("w");
Ut.write(wf, "test file " + ix + " of " + names.size(), "name = " + names.get(ix), "]end of test file " + ix + ": " + names.get(ix));
wf.close();
}
return tempDir;
}
public void removeTestFiles() {
removeRecursive(new File(tempDir));
}
public void removeRecursive(File f) {
if (f.isDirectory()) {
File [] li = f.listFiles();
for (int ix=0; ix < li.length; ix++)
removeRecursive(li[ix]);
}
if (! f.delete())
say("could not delete " + f);
}
public String timestamp(String arg) {
String r = new java.util.Date().toString();
if (arg == null)
r += " und verl?ngert !";
else if (arg.equals("fix"))
r = Strings.cut(r.replace(' ', '+'), 40, "+");
return r;
}
public static void runFile(String fn) {
Reader r = null;
Tester t = null;
try {
r = new FileReader(fn);
} catch (FileNotFoundException e) {
sFail("create FileReader " + fn + " caught " + e);
}
t = new Tester(r);
t.run();
try {
r.close();
} catch (IOException e) {
sFail("close FileReader " + fn + " caught " + e);
}
}
/**
* test the test machine of class Test itself
*/
@SuppressWarnings("unused")
public static void main(String[] args) {
String src = "und wie gehts +; \n\n 'string mit ''.' "
+ "\n und so weiter ** kommentar ?"
+ "\n\n ** kommentar \n \n nachher .";
Tester t = new Tester(new StringReader(src));
// parseTest();
// stringTest();
runFile("testScript");
/* String [] def1 = {"test", "testEnv", "envVars", "unQu", "bar", "barLazy", "wc", "words", "writeCat", "dir", "parser", "cmpLoad",
"sSyntax", "sJavaSyntax", "dConst", "dComment", "dString", "dJava", "dVars", "dInp", "dData",
"sJava", "sString", "sJava", "sString", "sVars", "sBlock", "sShString",
"sBar", "sRedirB", "sRedirF", "sHereData" , "sRedirCat", "sRedirRW",
"sCatAss", "sCatWr", "sRunD", "sRunS", "sReadInto", "sTypeVar", "typeRW", "sTypeRW", "sInDo", "sData", "dFor", "sForColl", "war"};
// still toDo war, sInDo mit Schachtelung
String [] def2 = {"sRedirB"}; // {"sTypeRW"};
String [] def = def1;
if ( args == null || args.length == 0)
args = def;
if (false) {
String [] a2 = new String [args.length * 2];
for (int i=0; i<args.length;i++) {
a2[2*i] = args[i];
a2[2*i + 1] = args[i];
}
args = a2;
}
int [] ers = new int [args.length];
String aa = ":";
int fE = -1;
for (int i=0; i<args.length;i++) {
// ers[i] = t.test(args[i]);
aa += ' ' + args[i] + "=" + ers[i];
if (fE < 0 && ers[i] != 0)
fE = i;
// if (t.errors > 0)
// break;
}
String to = "test main end " + t.errors + " errors" + (t.errors <= 0 ? "" : ", first " + fE + " " + args[fE]);
if (fE >= 0 && fE < args.length - 2) {
sSay("replay first error " + fE + ' ' + args[fE]);
// t.test(args[fE]);
sSay(to);
}
sSay(aa);
sSay(to);
*/ }
public void input(String... ins) {
readIx = -1;
input.clear();
Ut.addAll(input, ins);
}
public String read() {
readIx++;
if (readIx < input.size()) {
out("--- read " + readIx + ": " + input.get(readIx));
return input.get(readIx);
} else {
out("--- read " + readIx + "<<endOfInput>>");
return null;
}
}
public void close() {
// fail("Tester close");
}
public void open(String opt) {
// fail("Tester open");
}
public void reset(Object... args) {
fail("Tester reset");
}
public void write(String arg) {
out(arg);
}
public void writeAll(String opt, Read<String> r) {
Cat.writeAll(this, opt, r);
}
}