package helpers;
import static org.junit.Assert.fail;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Iterator;
import java.util.ListIterator;
import javax.print.DocFlavor.STRING;
import org.junit.Assert;
import org.antlr.v4.runtime.misc.ParseCancellationException;
import reduction.Executor;
import sugarVisitors.Desugar;
import sugarVisitors.InjectionOnCore;
import sugarVisitors.ToFormattedText;
import ast.Ast.Path;
import ast.Ast;
import ast.ErrorMessage;
import ast.ExpCore;
import ast.ExpCore.ClassB;
import ast.ExpCore.ClassB.Member;
import ast.ExpCore.ClassB.NestedClass;
import ast.Expression;
import auxiliaryGrammar.Functions;
import programReduction.Program;
import facade.Configuration;
import facade.L42;
import facade.Parser;
import facade.L42.ExecutionStage;
import platformSpecific.javaTranslation.Resources;
import profiling.Timer;
public class TestHelper {
private static class LimitString {
private final String parent;
final int start;
final int end;
private LimitString(String _parent, int _start, int _end) {
parent = _parent;
start = _start;
end = _end; // index of character past _end, on the C model
}
public static LimitString search(String parent, int fromIndex, int startChar, int endChar) {
int startIndex = parent.indexOf(startChar, fromIndex);
int endIndex = parent.indexOf(endChar, startIndex+1);
if (-1 == startIndex | -1 == endIndex)
return null;
++endIndex;
try {
if ('\n' == parent.charAt(endIndex))
++endIndex;
}catch (IndexOutOfBoundsException i) {};
return new LimitString(parent, startIndex, endIndex);
}
public static LimitString search(String parent, int fromIndex, String target) {
int index = parent.indexOf(target, fromIndex);
if (-1 == index)
return null;
return new LimitString(parent, index, index + target.length());
}
public String contents() {
return parent.substring(start, end);
}
}
public static void check42Fails(String s){
if(s.isEmpty()){fail("String is empty, may have not even started!"); throw new Error();}
if(s.contains("Error kind:")){fail("Error of some kind"); throw new Error();}
//if(s.contains("Error kind: MalformedFinalResult")){fail("Error kind: MalformedFinalResult"); throw new Error();}
final String failString = "[FAIL] ";
final String definedOutputString = "[Defined output between]";
int fails = 0;
int index = s.indexOf(definedOutputString);
if (-1 != index) {
LimitString endOfDefinedMarker = LimitString.search(s, index + definedOutputString.length(), '[', ']');
LimitString endOfOutputMarker = null == endOfDefinedMarker
? null: LimitString.search(s, endOfDefinedMarker.end, '[', ']');
if (null == endOfOutputMarker) {
fail("Marker text(s), delimited by [] missing after "+definedOutputString); throw new Error();
}
LimitString endOfDefined = LimitString.search(s, endOfOutputMarker.end, endOfDefinedMarker.contents());
if (null == endOfDefined) {
fail("End of defined output marker, "+endOfDefinedMarker.contents()+" not found."); throw new Error();
}
LimitString endOfOutput = LimitString.search(s, endOfDefined.end, endOfOutputMarker.contents());
if (null == endOfOutput) {
fail("End of output marker, "+endOfOutput.contents()+" not found. Tests failed early?"); throw new Error();
}
if (s.length() != endOfOutput.end) {
fail("Junk after end of output: "+s.substring(endOfOutput.end)); throw new Error();
}
Assert.assertEquals(s.substring(endOfOutputMarker.end, endOfDefined.start),
s.substring(endOfDefined.end, endOfOutput.start));
// And configure so that the next loop leaves us be
index = -1;
}else{
index = s.indexOf(failString);
}
while( index != -1 ){
fails++;
index = s.indexOf(failString, index+1);
}
if(fails > 0){fail(fails+ " error(s) have occured in the test cases!\n"+s); throw new Error();}
}
public static void assertEqualExp(ExpCore e1,ExpCore e2){
assert e1!=null;
assert e2!=null;
String s1=ToFormattedText.of(e1);
String s2=ToFormattedText.of(e2);
if(e1.equals(e2) && s1.equals(s2)){return;}
if(s1.equals(s2)){
String s1A="ToTextEqual,AstIs:"+e1;
String s2A="ToTextEqual,AstIs:"+e2;
if(s1A.equals(s2A)){
Assert.assertEquals("EqualText and ast, as:"+s1+" : "+e1,"");
}
Assert.assertEquals(s1+" : "+s1A,s2+" : "+s2A);
}
Assert.assertEquals(s1,s2);
}
public static void assertEqualExp(Expression e1,Expression e2){
assert e1!=null;
assert e2!=null;
String s1=ToFormattedText.of(e1);
String s2=ToFormattedText.of(e2);
if(e1.equals(e2) && s1.equals(s2)){return;}
if(s1.equals(s2)){
String s1A="ToTextEqual,AstIs:"+e1;
String s2A="ToTextEqual,AstIs:"+e2;
if(s1A.equals(s2A)){
Assert.assertEquals("EqualText and ast, as:"+s1+" : "+e1,"");
}
Assert.assertEquals(s1+" : "+s1A,s2+" : "+s2A);
}
Assert.assertEquals(s1,s2);
}
public static void isETop(String s){
//Parser.getParser(s).nudeE();
Parser.parse(null,s);
}
public static void notETop(String s){
try{
Parser.parse(null,s);
/* ETopContext e2=(ETopContext)(Parser.getParser(s).nudeE()).children.get(0);
String rep="";
for( ParseTree e:e2.children){rep+=e.getClass().getSimpleName()+" "+e.toString();}
*/
throw new Error(s+" should be parse error but is accepted");
}
catch(ParseCancellationException e){}
catch(ErrorMessage e){}
catch(IllegalArgumentException e){}
}
/* public static Expression _testParseString(String s){
LoggedPrintStream lpsErr = LoggedPrintStream.create(System.err);
System.setErr(lpsErr);
try{
NudeEContext r = Parser.getParser(s).nudeE();
return r.accept(new ToAst());
}
catch(ParseCancellationException e){
throw new ParseCancellationException(e.getMessage()+"\n"+lpsErr.buf.toString());
// throw new RuntimeException(
// lpsErr.buf.toString()
// );
}finally{System.setErr(lpsErr.underlying);}
}*/
public static Program getProgramCD(){
return getProgram(new String[]{
"{C:{"
+ "class method This new() class method This1.C foo(class This1.C bar) (bar.foo(bar:this))}, D:{"
+ "class method This new(fwd This1.C x)"
+ "read method This1.C x()"
+ "mut method This1.C #x()"
+ "mut method Void x(This1.C that)"
+ "}}"
});
}
public static ExpCore getExpCore(String source, String _e1) {
Expression code1=Parser.parse("GeneratedByTestHelper_",_e1);
Expression code2=Desugar.of(code1);
ExpCore e1=code2.accept(new InjectionOnCore());
return e1;
}
public static ClassB getClassB(String source, String e1) {
Expression code1=Parser.parse("GeneratedByTestHelper_"+source,e1);
auxiliaryGrammar.WellFormedness.checkAll(code1);
Expression code2=Desugar.of(code1);
assert auxiliaryGrammar.WellFormedness.checkAll(code2);
ExpCore.ClassB code3=(ExpCore.ClassB)code2.accept(new InjectionOnCore());
assert coreVisitors.CheckNoVarDeclaredTwice.of(code3);
return code3;
}
public static ClassB getClassB(String e1) {
return getClassB(null, e1);
}
public static Program getProgram(/*List<Path> paths,*/String[] code){
Program p0=Program.emptyLibraryProgram();
Integer outerCount = code.length;
for(String s:code){
Expression e=Parser.parse("This"+outerCount,s);
--outerCount;
ClassB ec=(ClassB)Desugar.of(e).accept(new InjectionOnCore());
p0=p0.evilPush(ec);
}
return p0;
}
public static String multiLine(String ...ss){
StringBuffer res=new StringBuffer();
for(String s:ss){res.append(s);res.append("\n");}
return res.toString();
}/*
static class LoggedPrintStream extends PrintStream {
final StringBuilder buf;
final PrintStream underlying;
LoggedPrintStream(StringBuilder sb, OutputStream os, PrintStream ul) {
super(os);
this.buf = sb;
this.underlying = ul;
}
public static LoggedPrintStream create(PrintStream toLog) {//from http://stackoverflow.com/questions/4334808/how-could-i-read-java-console-output-into-a-string-buffer
try {
final StringBuilder sb = new StringBuilder();
Field f = FilterOutputStream.class.getDeclaredField("out");
f.setAccessible(true);
OutputStream psout = (OutputStream) f.get(toLog);
return new LoggedPrintStream(sb, new FilterOutputStream(psout) {
public void write(int b) throws IOException {
super.write(b);
sb.append((char) b);
}
}, toLog);
}
catch (NoSuchFieldException|IllegalArgumentException |IllegalAccessException e) {
throw Assertions.codeNotReachable();
}}}*/
public static void _dbgCompact(ExpCore e){
assert e instanceof ClassB;
ClassB cb=(ClassB)e;
ArrayList<Member> ms = new ArrayList<>();
for(Member m:cb.getMs()){
if(!(m instanceof NestedClass)) {continue;}
NestedClass nc=(NestedClass)m;
if((nc.getInner() instanceof ClassB)){continue;}
ms.add(nc);break;
}
cb=cb.withMs(ms);
System.out.println(ToFormattedText.of(cb));
}
public static List<Ast.C> cs(String pathS){
Path path=Path.sugarParse(pathS);
return path.isCore()?path.getCBar():path.sugarNames();
}
public static void configureForTest() {
Configuration.reduction=new reduction.Facade();
L42.record=new StringBuilder();
L42.usedNames.clear();
Resources.clearRes();
Timer.restart();
Timer.activate("TOP");
}
public static void reportError(ErrorMessage e){
if(Executor.last1==null||Executor.last2==null){throw e;}
ClassB c1=(ClassB)Executor.last1;
ClassB c2=(ClassB)Executor.last2;
ArrayList<Member> ms1 = new ArrayList<>();
ArrayList<Member> ms2 = new ArrayList<>();
{int i=-1;for(Member e1:c1.getMs()){i+=1;
Member e2=c2.getMs().get(i);
if(e1.equals(e2)){continue;}
ms1.add(e1);
ms2.add(e2);
}}
c1=c1.withMs(ms1);
c2=c2.withMs(ms2);
//TestHelper.assertEqualExp(c1, c2);
}
public static class ErrorCarry {
/* When testing for errors,
* when the errors have many parameters,
* and adjacent errors share most of them,
* this class carries those parameters
* from test to test,
* and gives each test a formatted error string.
*
* Because the presenting problem is the verbosity
* of typing all of the error parameters repeatedly,
* function names in this class put a premium on brevity.
*/
ArrayList<String> _parameters = null;
// invariant: even number of entries; category first then details
static String valueFormat(String value) {
/* If value is null, then no string should go into the error representation.
* If the string is already formatted as an annotation,
* (begins with '@ or '[@ or '[] )
* output it as formatted,
* otherwise annotate it as a unicode string
*/
if (null == value)
return "";
if (value.startsWith("//@") || value.startsWith("//[@") || value.startsWith("//[]"))
return value;
else
return "//@stringU\n//" + value;
}
public String str() {
return this.str(null);
}
public String str(java.io.PrintStream debugTo) {
StringBuffer result = new StringBuffer();
Iterator<String> itr = this._parameters.iterator();
result.append("{");
while (itr.hasNext()) {
result.append(itr.next());
result.append(":{");
result.append(valueFormat(itr.next()));
result.append("\n}");
}
result.append("}");
if (null != debugTo)
debugTo.println(result.toString());
return result.toString();
}
public ErrorCarry load(String kind, String ... parameters) {
assert(parameters.length %2 == 0);
_parameters = new ArrayList<String>();
_parameters.add("Kind");
_parameters.add(kind);
_parameters.addAll(Arrays.asList(parameters));
return this;
}
public ErrorCarry set(String ... parameters) {
/* set the values of some loaded parameters,
* which must be supplied in the same order as in the load().
*/
assert(parameters.length %2 == 0);
Iterator<String> setItr = Arrays.asList(parameters).iterator();
ListIterator<String> parmItr = _parameters.listIterator();
while (setItr.hasNext() && parmItr.hasNext()) {
String nextSet = setItr.next();
//System.out.println("looking for '"+nextSet+"'");
while (parmItr.hasNext()) {
Boolean match = (nextSet.equals(parmItr.next()));
parmItr.next();
if (match) {
//System.out.println("Putting '"+nextVal+"' in '"+nextSet+"'");
String nextVal = setItr.next();
parmItr.set(nextVal);
break;
}
}
}
assert(!setItr.hasNext()); // some element was out of order or didn't match at all
return this;
}
public ErrorCarry rename(String oldLabel, String newLabel) {
/* this function is an allowance for errors in the spelling
* of kinds or parameter labels.
* It changes one label to the new spelling,
* enabling a test of the old spelling to fail
* without breaking all subsequent tests.
*
* Could be abused to update parameter values;
* not intended for this purpose.
*/
ListIterator<String> parmItr = _parameters.listIterator();
while (parmItr.hasNext()) {
Boolean match = (oldLabel.equals(parmItr.next()));
if (match) {
parmItr.set(newLabel);
return this;
}
}
assert(false); // the rename didn't match, so something is broken
return this;
}
}
public static int lineNumber() {
return Thread.currentThread().getStackTrace()[2].getLineNumber();
}
public static List<Object[]> skipUntilLine(List<Object[]> tests, int startLine) {
// Element 0 of each test must be an int,
// being the line number in the test file at which the test starts.
// These will be assumed to be in ascending order.
// Find the first one >= startLine, and return the remainder of the list.
// Attempting to return no tests is an error.
ListIterator<Object[]> t = tests.listIterator();
while (t.hasNext()) {
if (startLine <= (int)(t.next()[0])) {
return tests.subList(t.previousIndex() ,tests.size());
}
}
assert(false); // no tests left, so something is broken
return null;
}
static String shortName(java.nio.file.Path p){
// Remove the uninteresting bits from a path, in order to make a short name for a test
final String preamble = "/Tests/bin/";
final String middle1 = "libTests";
// final String middle2 = "libProject";
String ret = p.toString();
int preStart = ret.indexOf(preamble);
ret = ret.substring(preStart + preamble.length());
ret = ret.replace(middle1, "");
// ret = ret.replace(middle2, "");
return ret;
}
}