package bluej.stride.framedjava.convert;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.ThreadLocalRandom;
import java.util.function.Supplier;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import bluej.stride.framedjava.ast.AccessPermission;
import bluej.stride.framedjava.ast.AccessPermissionFragment;
import bluej.stride.framedjava.ast.CallExpressionSlotFragment;
import bluej.stride.framedjava.ast.ExpressionSlotFragment;
import bluej.stride.framedjava.ast.FilledExpressionSlotFragment;
import bluej.stride.framedjava.ast.JavadocUnit;
import bluej.stride.framedjava.ast.NameDefSlotFragment;
import bluej.stride.framedjava.ast.OptionalExpressionSlotFragment;
import bluej.stride.framedjava.ast.ParamFragment;
import bluej.stride.framedjava.ast.Parser;
import bluej.stride.framedjava.ast.Parser.JavaContext;
import bluej.stride.framedjava.ast.SuperThis;
import bluej.stride.framedjava.ast.SuperThisFragment;
import bluej.stride.framedjava.ast.SuperThisParamsExpressionFragment;
import bluej.stride.framedjava.ast.ThrowsTypeFragment;
import bluej.stride.framedjava.ast.TypeSlotFragment;
import bluej.stride.framedjava.convert.ConversionWarning.UnsupportedFeature;
import bluej.stride.framedjava.convert.ConversionWarning.UnsupportedModifier;
import bluej.stride.framedjava.elements.AssignElement;
import bluej.stride.framedjava.elements.BreakElement;
import bluej.stride.framedjava.elements.CallElement;
import bluej.stride.framedjava.elements.CaseElement;
import bluej.stride.framedjava.elements.ClassElement;
import bluej.stride.framedjava.elements.CodeElement;
import bluej.stride.framedjava.elements.CommentElement;
import bluej.stride.framedjava.elements.ConstructorElement;
import bluej.stride.framedjava.elements.ForeachElement;
import bluej.stride.framedjava.elements.IfElement;
import bluej.stride.framedjava.elements.ImportElement;
import bluej.stride.framedjava.elements.InterfaceElement;
import bluej.stride.framedjava.elements.LocatableElement;
import bluej.stride.framedjava.elements.MethodProtoElement;
import bluej.stride.framedjava.elements.NormalMethodElement;
import bluej.stride.framedjava.elements.ReturnElement;
import bluej.stride.framedjava.elements.SwitchElement;
import bluej.stride.framedjava.elements.ThrowElement;
import bluej.stride.framedjava.elements.TryElement;
import bluej.stride.framedjava.elements.VarElement;
import bluej.stride.framedjava.elements.WhileElement;
import bluej.utility.Utility;
import nu.xom.Element;
import org.junit.Assert;
import org.junit.Test;
import static bluej.stride.framedjava.convert.Expression.uniformSpacing;
| Note: some of the test cases are not semantically valid, but as long as they are syntactically valid
| (in Java and Stride) that is fine for parser tests.
|
public class JavaToStrideTest
{
@Test
public void testStatements()
{
assertEquals("while (true);", _while("true"));
assertEquals("while (true) while (false);", _while("true", _while("false")));
assertEquals("while (true) {}", _while("true"));
assertEquals("while (true) {while (false); while (0);}", _while("true", _while("false"), _while("0")));
assertEquals("while (0) {while (1) { while (2) {} } while (3) while (4); while(5); }",
_while("0", _while("1", _while("2")), _while("3", _while("4")), _while("5")));
assertEquals("while (true /* false */);", _while("true", _comment("false")));
assertEquals("return 0;", _return("0"));
assertEquals("return 0+1;", _return("0 + 1"));
assertEquals("return 0+(1+2);", _return("0 + ( 1 + 2 )"));
assertEquals("return;", _return());
assertEquals("break;", new BreakElement(null, true));
assertEquals("throw e;", new ThrowElement(null, filled("e"), true));
assertEquals("throw new IOException();", new ThrowElement(null, filled("new IOException ( )"), true));
assertEquals("try { return 0; } catch (Exception e) { return 1; }", _try(l(_return("0")), l(type("Exception")), l(name("e")), l(l(_return("1"))), null));
assertEquals("try { return 0; } finally { return 1;}", _try(l(_return("0")), l(), l(), l(), l(_return("1"))));
assertEquals("try { return 0; } catch (E1 e1) { return 1; } catch (E2 e2) { return 2; } finally { return -1;}", _try(l(_return("0")), l(type("E1"), type("E2")), l(name("e1"), name("e2")), l(l(_return("1")), l(_return("2"))), l(_return("- 1"))));
assertEquals("try { return 0; } catch (E1A|E1B e1) { return 1; } catch (E2A|E2B|E2C e2) { return 2; } finally { return -1;}",
_try(l(_return("0")),
l(type("E1A"), type("E1B"), type("E2A"), type("E2B"), type("E2C")),
l(name("e1"), name("e1"), name("e2"), name("e2"), name("e2")),
l(l(_return("1")), l(_return("1")), l(_return("2")), l(_return("2")), l(_return("2"))), l(_return("- 1"))));
assertEquals("try { } catch (java.lang.String x) { while (0) { } } catch (int x) { }",
_try(l(), l(type("java.lang.String"), type("int")), l(name("x"), name("x")), l(l(_while("0")), l()), null));
assertEquals("switch (0) { case 1: break; }", _switch("0", l(_case("1", new BreakElement(null, true))), null));
assertEquals("switch (0) { default: break; }", _switch("0", l(), l(new BreakElement(null, true))));
assertEquals("for (int x : xs) return;", _forEach("int", "x", filled("xs"), _return()));
assertEquals("for (int x : (int[])xs) return;", _forEach("int", "x", filled("( int [ ] ) xs"), _return()));
assertEquals("for (int i = 0; i < 10; i = i + 2) return;",
_var(null, false, false, "int", "i", filled("0")),
_while("i < 10", _return(), _assign("i", "i + 2"))
);
assertEquals("for (int i = 0; i < 10; i++) return;",
_forEach("int", "i", _range("0", "9"), _return())
);
assertEquals("for (int i = 0; i < 10; ++i) return;",
_forEach("int", "i", _range("0", "9"), _return())
);
assertEquals("for (int i = 0; i <= 10; i++) return;",
_forEach("int", "i", _range("0", "10"), _return())
);
assertEquals("for (int i = 0; i < 10; i = i + 1) return;",
_forEach("int", "i", _range("0", "9"), _return())
);
assertEquals("for (int i = 0; i < 10; i += 1) return;",
_forEach("int", "i", _range("0", "9"), _return())
);
assertEquals("for (int i = 0; i < 10+1; i++) return;",
_var(null, false, false, "int", "i", filled("0")),
_while("i < 10 + 1", _return(), _assign("i", "i + 1"))
);
assertEquals("for (int i = 0; i < size; i++) return;",
_var(null, false, false, "int", "i", filled("0")),
_while("i < size", _return(), _assign("i", "i + 1"))
);
assertEquals("for (byte i = 0; i < 10; i += 1) return;",
_var(null, false, false, "byte", "i", filled("0")),
_while("i < 10", _return(), _assign("i", "i + 1"))
);
assertEquals("for (int i = 0; i < 10; i--) return;",
_var(null, false, false, "int", "i", filled("0")),
_while("i < 10", _return(), _assign("i", "i - 1"))
);
assertEquals("for (int i = 0, j, k = (double)7, l; i < 10; i = i + 1) {return 0; return 1;}",
_var(null, false, false, "int", "i", filled("0")),
_var(null, false, false, "int", "j", null),
_var(null, false, false, "int", "k", filled("( double ) 7")),
_var(null, false, false, "int", "l", null),
_while("i < 10", _return("0"), _return("1"), _assign("i", "i + 1"))
);
assertEquals("for (;;) return;", _while("true", _return()));
assertEquals("for (;false;) return;", _while("false", _return()));
assertEquals("return 0; {return 1;}", _return("0"), _return("1"));
assertEquals("{return 0;} {return 1;}", _return("0"), _return("1"));
assertEquals("if (true) {return 0;} {return 1;}", _if("true", _return("0")), _return("1"));
assertWarning("assert true;", UnsupportedFeature.class, _commentWarn(UnsupportedFeature.class));
assertWarning("synchronized (this) { };", UnsupportedFeature.class, _commentWarn(UnsupportedFeature.class));
assertWarning("synchronized (this) { return; };", UnsupportedFeature.class, _commentWarn(UnsupportedFeature.class), _return());
}
@Test
public void testIncDec()
{
assertEquals("++i;", _assign("i", "i + 1"));
assertEquals("i++;", _assign("i", "i + 1"));
assertEquals("++i[j.k];", _assign("i [ j . k ]", "i [ j . k ] + 1"));
assertEquals("i[j.k]++;", _assign("i [ j . k ]", "i [ j . k ] + 1"));
assertEquals("--i;", _assign("i", "i - 1"));
assertEquals("i--;", _assign("i", "i - 1"));
assertEquals("--i[j.k];", _assign("i [ j . k ]", "i [ j . k ] - 1"));
assertEquals("i[j.k]--;", _assign("i [ j . k ]", "i [ j . k ] - 1"));
assertWarning("foo(--i);", UnsupportedFeature.class, _commentWarn(UnsupportedFeature.class), _call("foo ( -- i )"));
assertWarning("x = 0 + i++;", UnsupportedFeature.class, _commentWarn(UnsupportedFeature.class), _assign("x", "0 + i ++"));
assertWarning("while (++i <= 10) ;", UnsupportedFeature.class, _commentWarn(UnsupportedFeature.class), _while("++ i <= 10"));
}
@Test
public void testAssign()
{
assertEquals("i += 1;", _assign("i", "i + 1"));
assertEquals("a . x <<= 4;", _assign("a . x", "a . x << 4"));
assertWarning("while ((i += 1) < 7) ;", UnsupportedFeature.class, _commentWarn(UnsupportedFeature.class), _while("( i += 1 ) < 7"));
assertWarning("while ((i = next()) != null) ;", UnsupportedFeature.class, _commentWarn(UnsupportedFeature.class), _while("( i = next ( ) ) != null"));
assertWarning("while (b = cond()) ;", UnsupportedFeature.class, _commentWarn(UnsupportedFeature.class), _while("b = cond ( )"));
assertEquals("x = new Foo();", _assign("x", "new Foo ( )"));
assertWarning("x = new Foo() { };", UnsupportedFeature.class, _commentWarn(UnsupportedFeature.class), _assign("x", "new Foo ( )"));
assertWarning("x = new Foo() { int y; };", UnsupportedFeature.class, _commentWarn(UnsupportedFeature.class), _assign("x", "new Foo ( )"));
assertEquals("x = c -> 3;", _assign("x", "c -> 3"));
assertWarning("x = c -> {return 3;};", UnsupportedFeature.class, _commentWarn(UnsupportedFeature.class), _assign("x", "c ->"));
assertWarning("x = (final c) -> 3;", UnsupportedModifier.class, _commentWarn(UnsupportedModifier.class), _assign("x", "( c ) -> 3"));
assertWarning("x = (int c) -> 3;", UnsupportedFeature.class, _commentWarn(UnsupportedFeature.class), _assign("x", "( c ) -> 3"));
assertWarning("x = a ? b : c;", UnsupportedFeature.class, _commentWarn(UnsupportedFeature.class), _assign("x", "a b c"));
assertEquals("ref = a::b;", _assign("ref", "a :: b"));
}
private CodeElement _assign(String lhs, String rhs)
{
return new AssignElement(null, filled(lhs), filled(rhs), true);
}
private CodeElement _forEach(String type, String var, FilledExpressionSlotFragment of, CodeElement... body)
{
return new ForeachElement(null, type(type), name(var), of, l(body), true);
}
private static TypeSlotFragment type(String t)
{
return new TypeSlotFragment(t, t);
}
private static NameDefSlotFragment name(String n)
{
return new NameDefSlotFragment(n);
}
private SwitchElement _switch(String exp, List<CaseElement> cases, List<CodeElement> defaultBody)
{
return new SwitchElement(null, filled(exp), cases, defaultBody, true);
}
private CaseElement _case(String exp, CodeElement... body)
{
return new CaseElement(null, filled(exp), l(body), true);
}
private TryElement _try(List<CodeElement> tryContents, List<TypeSlotFragment> catchTypes, List<NameDefSlotFragment> catchNames, List<List<CodeElement>> catchContents, List<CodeElement> finallyContents)
{
return new TryElement(null, tryContents, catchTypes, catchNames, catchContents, finallyContents, true);
}
@Test
public void testIf()
{
assertEquals("if (0);", _if("0"));
assertEquals("if (0) return 1;", _if("0", _return("1")));
assertEquals("if (0) return 1; else return 2;", _ifElse("0", Arrays.asList(_return("1")), Arrays.asList(_return("2"))));
assertEquals("if (0) return 1; else if (2) return 3; else if (4) return 5; else return 6;",
_ifElseIf("0", Arrays.asList(_return("1")),
Arrays.asList("2", "4"), Arrays.asList(Arrays.asList(_return("3")), Arrays.asList(_return("5"))),
Arrays.asList(_return("6"))));
assertEquals("if (0) return 1; else if (2) return 3; else if (4) return 5;",
_ifElseIf("0", Arrays.asList(_return("1")),
Arrays.asList("2", "4"), Arrays.asList(Arrays.asList(_return("3")), Arrays.asList(_return("5"))),
null));
}
@Test
public void testCall()
{
assertEquals("go();", _call("go ( )"));
assertEquals("move(6 + 7);", _call("move ( 6 + 7 )"));
assertEquals("getFoo().move(6 + 7);", _call("getFoo ( ) . move ( 6 + 7 )"));
assertEquals("x = getX();", _assign("x", "getX ( )"));
}
@Test
public void testExpression()
{
assertExpression("0", "0");
assertExpression("0 + 1", "0+1");
assertExpression("0 + 1", "0 + 1");
assertExpression("0 + 1", "0 + 1");
assertExpression("0 >= 1", "0 >= 1");
assertExpression("0 > = 1", "0 > = 1");
assertExpression("new Foo ( )", "new Foo()");
assertExpression("newFoo ( )", "newFoo()");
assertExpression("<:", "instanceof");
assertExpression("a <: b", "a instanceof b");
assertExpression("a instanceofb", "a instanceofb");
assertExpression("a < : b", "a <: b");
assertExpression("0 << 1", "0 << 1");
assertExpression("0 | 1", "0|1");
assertExpression("0 & 1", "0&1");
assertExpression("0 || 1", "0 ||1");
assertExpression("0 && 1", "0&& 1");
assertExpression("a :: b", "a::b");
assertEquals("if (c == '\\\\' || c == '\"' || c == '\\'') buf.append('\\\\');",
_if("c == '\\\\' || c == '\"' || c == '\\''", _call("buf . append ( '\\\\' )")));
}
@Test
public void testInstanceof()
{
assertEquals("while (a instanceof b) {}", _while(new FilledExpressionSlotFragment("a <: b", "a instanceof b")));
assertEquals("if (a instanceof b) {} else if (c instanceof d) {}", _ifElseIf(new FilledExpressionSlotFragment("a <: b", "a instanceof b"), l(), l(new FilledExpressionSlotFragment("c <: d", "c instanceof d")), l(l()), null));
assertEquals("foo(a instanceof b);", _call(new CallExpressionSlotFragment("foo ( a <: b )", "foo ( a instanceof b )")));
assertEquals("return (a instanceof b);", _return(new OptionalExpressionSlotFragment("( a <: b )", "( a instanceof b )")));
assertEqualsMember("C() {super(a instanceof b);}", _constructorDelegate(null, AccessPermission.PROTECTED, l(), l(), SuperThis.SUPER, new SuperThisParamsExpressionFragment("a <: b", "a instanceof b"), l()));
}
@Test
public void testMethod()
{
assertEqualsMember("public void foo() { return; }", _method(null, AccessPermission.PUBLIC, false, false, "void", "foo", Collections.emptyList(), Collections.emptyList(), Arrays.asList(_return())));
assertEqualsMember("public final void foo(int x) { return; }", _method(null, AccessPermission.PUBLIC, false, true, "void", "foo", Arrays.asList(_param("int", "x")), Collections.emptyList(), Arrays.asList(_return())));
assertEqualsMember("@Override public final void foo(int[] x, double y[][], String[] s[]) { return; }",
_method(null, AccessPermission.PUBLIC, false, true, "void", "foo",
Arrays.asList(_param("int[]", "x"), _param("double[][]", "y"), _param("String[][]", "s")),
Collections.emptyList(), Arrays.asList(_return())));
assertEqualsMember("Foo(int x, String y) throws IOException { }",
_constructor(null, AccessPermission.PROTECTED, Arrays.asList(_param("int", "x"), _param("String", "y")),
Arrays.asList("IOException"), Arrays.asList()));
assertEqualsMember("/** Comment */ private void foo() {}", _method("Comment", AccessPermission.PRIVATE, false, false, "void", "foo", Collections.emptyList(), Collections.emptyList(), Collections.emptyList()));
assertEqualsMember("// Comment\nprivate void foo() {}", _comment("Comment"), _method(null, AccessPermission.PRIVATE, false, false, "void", "foo", Collections.emptyList(), Collections.emptyList(), Collections.emptyList()));
assertEqualsMember("/** Multi\n * line \n * comment.\n*/ private static final java.lang.String foo() throws IOException, NullPointerException {}",
_method("Multi line comment.", AccessPermission.PRIVATE, true, true, "java.lang.String", "foo",
Collections.emptyList(), Arrays.asList("IOException", "NullPointerException"), Collections.emptyList()));
assertEqualsMember("/** First\nPara.\n\nSecond\nPara.\n\n\nThird Para.*/\nprotected Foo(){}",
_constructor("First Para.\nSecond Para.\n\nThird Para.",
AccessPermission.PROTECTED, Collections.emptyList(), Collections.emptyList(), Collections.emptyList()));
assertEqualsMember("/** X*/\npublic Bar() { this(0); }", _constructorDelegate("X", AccessPermission.PUBLIC, Collections.emptyList(), Collections.emptyList(), SuperThis.THIS, "0", Collections.emptyList()));
assertEqualsMember("C() {this2(0);}", _constructor(null, AccessPermission.PROTECTED, l(), l(), l(_call("this2 ( 0 )"))));
assertEqualsMember("C() {super(2, 3);}", _constructorDelegate(null, AccessPermission.PROTECTED, l(), l(), SuperThis.SUPER, "2 , 3", l()));
assertEqualsMember("//Normal\n/** Javadoc */ private void foo() {}", _comment("Normal"), _method("Javadoc", AccessPermission.PRIVATE, false, false, "void", "foo", Collections.emptyList(), Collections.emptyList(), Collections.emptyList()));
assertWarningMember("private <T extends A> List<T> foo(T t) {}", UnsupportedFeature.class,
_commentWarn(UnsupportedFeature.class),
_method(null, AccessPermission.PRIVATE, false, false, "List<T>", "foo", l(_param("T", "t")), l(), l()));
assertWarningMember("@Override Foo() {}", UnsupportedModifier.class, _commentWarn(UnsupportedModifier.class),
_constructor(null, AccessPermission.PROTECTED, l(), l(), l()));
assertWarningMember("/**Javadoc*/@Override Foo() {}", UnsupportedModifier.class, _commentWarn(UnsupportedModifier.class),
_constructor("Javadoc", AccessPermission.PROTECTED, l(), l(), l()));
}
@Test
public void testFieldAndVar()
{
assertEqualsMember("int x;", _var(AccessPermission.PROTECTED, false, false, "int", "x", null));
assertEqualsMember("public static final int CONST=7;", _var(AccessPermission.PUBLIC, true, true, "int", "CONST", filled("7")));
assertEqualsMember("private final bool b = 7, c=false;",
_var(AccessPermission.PRIVATE, false, true, "bool", "b", filled("7")),
_var(AccessPermission.PRIVATE, false, true, "bool", "c", filled("false")));
assertEqualsMember("public static String a = null, b, c=(String)false, d;",
_var(AccessPermission.PUBLIC, true, false, "String", "a", filled("null")),
_var(AccessPermission.PUBLIC, true, false, "String", "b", null),
_var(AccessPermission.PUBLIC, true, false, "String", "c", filled("( String ) false")),
_var(AccessPermission.PUBLIC, true, false, "String", "d", null));
assertEquals("int x;", _var(null, false, false, "int", "x", null));
assertEquals("final int CONST=7;", _var(null, false, true, "int", "CONST", filled("7")));
assertEquals("bool b = 7, c=false;",
_var(null, false, false, "bool", "b", filled("7")),
_var(null, false, false, "bool", "c", filled("false")));
assertEquals("final String a = null, b, c=(String)false, d;",
_var(null, false, true, "String", "a", filled("null")),
_var(null, false, true, "String", "b", null),
_var(null, false, true, "String", "c", filled("( String ) false")),
_var(null, false, true, "String", "d", null));
assertEquals("int[] x;", _var(null, false, false, "int[]", "x", null));
assertEquals("int x[];", _var(null, false, false, "int[]", "x", null));
assertEquals("int[] x[];", _var(null, false, false, "int[][]", "x", null));
assertEquals("int x = /*6*/7;", _comment("6"), _var(null, false, false, "int", "x", filled("7")));
assertEquals("int x = 7/*8*/;", _var(null, false, false, "int", "x", filled("7")), _comment("8"));
}
@Test
public void testComments()
{
assertEquals("//ABC", _comment("ABC"));
assertEquals("//Declares x\nint x;", _comment("Declares x"), _var(null, false, false, "int", "x", null));
assertEquals("//Declares x\nint x /* empty */;", _comment("Declares x empty"), _var(null, false, false, "int", "x", null));
assertEquals("//Declares x\nint x /* empty */;int y;", _comment("Declares x empty"), _var(null, false, false, "int", "x", null), _var(null, false, false, "int", "y", null));
assertEquals("//Declares x\nint x;int y/* empty */;", _comment("Declares x"), _var(null, false, false, "int", "x", null), _comment("empty"), _var(null, false, false, "int", "y", null));
assertEquals("break; // Post-comment", new BreakElement(null, true), _comment("Post-comment"));
assertEquals("while(true) {/*Just-comment*/}", _while("true", _comment("Just-comment")));
assertEquals("while(true) {/*Pre-comment*/ break;}", _while("true", _comment("Pre-comment"), new BreakElement(null, true)));
assertEquals("while(true) /*Pre-comment*/ break;", _while("true", _comment("Pre-comment"), new BreakElement(null, true)));
assertEquals("while(true) {break; /*End-comment*/}", _while("true", new BreakElement(null, true), _comment("End-comment")));
assertEquals("while(true) {break; }/*After-comment*/", _while("true", new BreakElement(null, true)), _comment("After-comment"));
assertEquals("while(true) break;/*After-comment*/", _while("true", new BreakElement(null, true)), _comment("After-comment"));
assertEquals("return 0; /*XXX*/ while(true) {}", _return("0"), _comment("XXX"), _while("true"));
}
@Test
public void testWhole()
{
assertEqualsFile("class Foo {}", _class(null, l(), null, false, "Foo", null, l(), l(), l(), l()));
assertEqualsFile("abstract class A extends B { int x; }",
_class(null, l(), null, true, "A", "B", l(), l(_var(AccessPermission.PROTECTED, false, false, "int", "x", null)), l(), l()));
assertEqualsFile("package p; import java.util.*; /**Mixed order*/class Jumble implements A,B,C { public double method() {return 0.0;}; private int member; protected Jumble() {return;} }",
_class("p", l("java.util.*"), "Mixed order", false, "Jumble", null, l("A", "B", "C"),
l(_var(AccessPermission.PRIVATE, false, false, "int", "member", null)),
l(_constructor(null, AccessPermission.PROTECTED, l(), l(), l(_return()))),
l(_method(null, AccessPermission.PUBLIC, false, false, "double", "method", l(), l(), l(_return("0.0"))))));
assertWarningFile("public enum Foo { F }", UnsupportedFeature.class, _commentWarn(UnsupportedFeature.class));
assertWarningFile("class Foo { { int x; } }", UnsupportedFeature.class, _class(null, l(), null, false, "Foo", null, l(), l(_commentWarn(UnsupportedFeature.class)), l(), l()));
assertWarningFile("class Foo { { return; } }", UnsupportedFeature.class, _class(null, l(), null, false, "Foo", null, l(), l(_commentWarn(UnsupportedFeature.class)), l(), l()));
assertWarningFile("interface Foo { static { int x; } }", UnsupportedFeature.class, _interface("", "Foo", l(), l(_commentWarn(UnsupportedFeature.class)), l()));
assertWarningMember("{ int x; }", UnsupportedFeature.class, _commentWarn(UnsupportedFeature.class));
assertWarningMember("static { int x; }", UnsupportedFeature.class, _commentWarn(UnsupportedFeature.class));
assertWarningMember("class Inner { }", UnsupportedFeature.class, _commentWarn(UnsupportedFeature.class));
assertWarningMember("class Inner extends A implements B { int x; public Inner() {return;} private void foo() { break; } }", UnsupportedFeature.class, _commentWarn(UnsupportedFeature.class));
assertWarningFile("class Outer { class Inner extends A implements B { int x; public Inner() {return;} private void foo() { break; } } }", UnsupportedFeature.class, _class(null, l(), null, false, "Outer", null, l(), l(_commentWarn(UnsupportedFeature.class)), l(), l()));
assertWarningMember("private interface Inner { }", UnsupportedFeature.class, _commentWarn(UnsupportedFeature.class));
assertWarningMember("public enum Inner { I }", UnsupportedFeature.class, _comment("WARNING:" + UnsupportedFeature.class.getName() + " WARNING:" + UnsupportedFeature.class.getName()));
assertWarningFile("/**Hi*/interface Foo extends A, B { default public void foo() {} }", UnsupportedFeature.class,
_interface("Hi", "Foo", l("A", "B"), l(_commentWarn(UnsupportedModifier.class), _commentWarn(UnsupportedFeature.class)), l()));
}
private InterfaceElement _interface(String javadoc, String name, List<String> extendsTypes, List<CodeElement> fields, List<CodeElement> methods)
{
return new InterfaceElement(null, null, name(name), extendsTypes.stream().map(JavaToStrideTest::type).collect(Collectors.toList()),
fields, methods, new JavadocUnit(javadoc), null, Collections.emptyList(), true);
}
private CommentElement _commentWarn(Class<? extends ConversionWarning> cls)
{
return _comment("WARNING:" + cls.getName());
}
@Test
public void testRandomStatement()
{
for (int i = 0; i < 1000; i++)
{
roundTrip(many(() -> genStatement(4)), Parser.JavaContext.STATEMENT);
}
}
@Test
public void testRandomTopLevel()
{
for (int i = 0; i < 1000; i++)
{
roundTrip(l(genTopLevel()), Parser.JavaContext.TOP_LEVEL);
}
}
private static CodeElement genTopLevel()
{
return genOneOf(
() -> new ClassElement(null, null, rand(), genName(), rand() ? genType() : null, some(() -> genType()),
somePrecede(() -> genComment(), () -> new VarElement(null, genAccess(), rand(), rand(), genType(), genName(), rand() ? genExpression() : null, true)),
somePrecede(() -> genComment(), () -> {
boolean hasSuperThis = rand();
boolean isSuper = rand();
return new ConstructorElement(null, genAccess(), some(() -> genParam()), some(() -> genThrowsType()), hasSuperThis ? new SuperThisFragment(isSuper ? SuperThis.SUPER : SuperThis.THIS) : null, hasSuperThis ? genSuperThisParams() : null, some(() -> genStatement(3)), rand() ? null : genJavadoc(), true);
}),
somePrecede(() -> genComment(), () -> genOneOf(
() -> new NormalMethodElement(null, genAccess(), rand(), rand(), genType(), genName(), some(() -> genParam()), some(() -> genThrowsType()), some(() -> genStatement(3)), rand() ? null : genJavadoc(), true),
() -> new MethodProtoElement(null, genType(), genName(), some(() -> genParam()), some(() -> genThrowsType()), rand() ? null : genJavadoc(), true)
)),
genJavadoc(), rand() ? null : genPackage(), some(() -> genImport()), true),
() -> new InterfaceElement(null, null, genName(), some(() -> genType()),
somePrecede(() -> genComment(), () -> new VarElement(null, genAccess(), rand(), rand(), genType(), genName(), rand() ? genExpression() : null, true)),
somePrecede(() -> genComment(),
() -> new MethodProtoElement(null, genType(), genName(), some(() -> genParam()), some(() -> genThrowsType()), rand() ? null : genJavadoc(), true)
),
genJavadoc(), rand() ? null : genPackage(), some(() -> genImport()), true)
);
}
private static CommentElement genComment()
{
return new CommentElement(oneOf("Hello", "Bye", "Whatever", "///"));
}
private static ImportElement genImport()
{
return new ImportElement(oneOf("p.*", "hi.xx", "java.lang.String", "java.util.*"), null, true);
}
private static String genPackage()
{
return oneOf("p", "hi.xx", "a0.b1.c2");
}
private static SuperThisParamsExpressionFragment genSuperThisParams()
{
return some(() -> (ExpressionSlotFragment)genExpression()).stream().map(e -> new SuperThisParamsExpressionFragment(e.getContent(), e.getJavaCode())).reduce((a, b) -> new SuperThisParamsExpressionFragment(a.getContent() + " , " + b.getContent(), a.getJavaCode() + " , " + b.getJavaCode())).orElse(new SuperThisParamsExpressionFragment("", ""));
}
private static ThrowsTypeFragment genThrowsType()
{
return new ThrowsTypeFragment(genType());
}
private static ParamFragment genParam()
{
return new ParamFragment(genType(), genName());
}
private static AccessPermissionFragment genAccess()
{
return new AccessPermissionFragment(oneOf(AccessPermission.PRIVATE, AccessPermission.PROTECTED, AccessPermission.PUBLIC));
}
private static JavadocUnit genJavadoc()
{
return new JavadocUnit(oneOf("Hi", "One Two", "A B C."));
}
private static CodeElement genStatement(int maxDepth)
{
List<Supplier<CodeElement>> terminals = Arrays.asList(
() -> new CommentElement("c" + rand(0, 9)),
() -> new BreakElement(null, true),
() -> new ReturnElement(null, genOptExpression(), true),
() -> new ThrowElement(null, genExpression(), true),
() -> new VarElement(null, null, false, rand(), genType(), genName(), rand() ? genExpression() : null, true),
() -> genCallOrAssign()
);
List<Supplier<CodeElement>> all = new ArrayList<>(Arrays.asList(
() -> new WhileElement(null, genExpression(), some(() -> genStatement(maxDepth - 1)), true),
() -> {
int else{ Ifs = rand(0, 2);
}
boolean _else = rand(0, 1) == 1;
return new IfElement(null, genExpression(), some(() -> genStatement(maxDepth - 1)),
replicate(elseIfs, () -> genExpression()),
replicate(elseIfs, () -> some(() -> genStatement(maxDepth - 1))),
_else ? null : some(() -> genStatement(maxDepth - 1)), true);
},
() -> {
int catches = rand(0, 2);
boolean _finally = rand(0, 1) == 1;
return new TryElement(null, some(() -> genStatement(maxDepth - 1)),
replicate(catches, () -> genType()),
replicate(catches, () -> genName()),
replicate(catches, () -> some(() -> genStatement(maxDepth - 1))),
_finally ? null : some(() -> genStatement(maxDepth - 1)), true);
},
() -> new ForeachElement(null, genType(), genName(), genExpression(), some(() -> genStatement(maxDepth - 1)), true),
() -> new SwitchElement(null, genExpression(), some(() -> genCase()), rand() ? null : some(() -> genStatement(maxDepth - 1)), true)
));
all.addAll(terminals);
if (maxDepth <= 1)
{
return JavaToStrideTest.<CodeElement>genOneOf(terminals.toArray(new Supplier[0]));
}
else
{
return JavaToStrideTest.<CodeElement>genOneOf(all.toArray(new Supplier[0]));
}
}
private static CaseElement genCase()
{
return new CaseElement(null, genExpression(), some(() -> genStatement(2)), true);
}
private static boolean rand()
{
return rand(0, 1) == 0;
}
private static CodeElement genCallOrAssign()
{
return genOneOf(
() -> {
return new AssignElement(null, filled(genName().getContent()), genExpression(), true);
},
() -> {
FilledExpressionSlotFragment call = genCall();
return new CallElement(null, new CallExpressionSlotFragment(call.getContent(), call.getJavaCode()), true);
}
);
}
private static List replicate(int count, Supplier<T> supplier)
{
ArrayList<T> r = new ArrayList<>();
for (int i = 0; i < count; i++)
r.add(supplier.get());
return r;
}
private static OptionalExpressionSlotFragment genOptExpression()
{
return genOneOf(() -> null, () -> new OptionalExpressionSlotFragment(genExpression()));
}
private static FilledExpressionSlotFragment genExpression()
{
return genExpression(2);
}
private static FilledExpressionSlotFragment concat(FilledExpressionSlotFragment a, FilledExpressionSlotFragment b)
{
return new FilledExpressionSlotFragment(a.getContent() + " " + b.getContent(), a.getJavaCode() + " " + b.getJavaCode());
}
private static FilledExpressionSlotFragment genExpression(int maxDepth)
{
List<Supplier<FilledExpressionSlotFragment>> all = Arrays.asList(
() -> filled("0"),
() -> filled("\"hello\\n\""),
() -> filled("\"c\" + 0"),
() -> filled("\"\" . length ( )"),
() -> filled("new Foo ( )"),
() -> new FilledExpressionSlotFragment("a <: b", "a instanceof b"),
() -> genCall()
);
if (maxDepth > 1)
{
return genOneOf(
() -> concat(filled(oneOf("!")), genExpression(maxDepth - 1)),
() -> {
TypeSlotFragment t = genType();
return concat(new FilledExpressionSlotFragment("( " + uniformSpacing(t.getContent(), false) + " )", "( " + uniformSpacing(t.getJavaCode(), false) + " )"), genExpression(maxDepth - 1));
},
() -> concat(genExpression(maxDepth - 1), genOneOf(
() -> concat(filled("+"), genExpression(maxDepth - 1)),
() -> concat(filled("-"), genExpression(maxDepth - 1)),
() -> concat(filled("<<"), genExpression(maxDepth - 1)),
() -> {
TypeSlotFragment t = genType();
return new FilledExpressionSlotFragment("<: " + uniformSpacing(t.getContent(), false), "instanceof " + uniformSpacing(t.getJavaCode(), false));
})
)
);
}
return JavaToStrideTest.<FilledExpressionSlotFragment>genOneOf(all.toArray(new Supplier[0]));
}
private static FilledExpressionSlotFragment genCall()
{
return filled(oneOf("foo . getX ( )", "x ( )", "foo ( ) [ getN ( 6 + 7 ) ]", "x ( )", "y ( )", "a ( ) . b ( )"));
}
private static TypeSlotFragment genType()
{
return type(oneOf("T", "int", "char", "double", "float", "int_", "double", "Double", "java.lang.String", "a.b", "a.b.c.d", "List<String>", "A.B<C.D>[]", "int[]", "double[][]", "List<String>[][]"));
}
private static NameDefSlotFragment genName()
{
return name(oneOf("x","y","i","z081","foo","bar","name_thing", "Class", "_package", "ABCD"));
}
private static T oneOf(T... items)
{
return items[rand(0, items.length - 1)];
}
private static T genOneOf(Supplier<T>... items)
{
return items[rand(0, items.length - 1)].get();
}
private static List collapseComments(List<T> items)
{
ArrayList<T> r = new ArrayList<>(items);
int i = 1;
while (i < r.size())
{
if (r.get(i - 1) instanceof CommentElement && r.get(i) instanceof CommentElement)
r.remove(i);
else{ i += 1;
}
}
return r;
}
private static List some(Supplier<T> item)
{
return collapseComments(Stream.generate(item).limit(rand(0, 4)).collect(Collectors.toList()));
}
private static List somePrecede(Supplier<T> before, Supplier<T> item)
{
return collapseComments(Stream.generate(item).limit(rand(0, 4)).flatMap(x -> rand() ? Stream.of(x) : Stream.of(before.get(), x)).collect(Collectors.toList()));
}
private static List many(Supplier<T> item)
{
return collapseComments(Stream.generate(item).limit(rand(1, 5)).collect(Collectors.toList()));
}
private static int rand(int min, int max)
{
return ThreadLocalRandom.current().nextInt(min, max + 1);
}
private static void roundTrip(List<CodeElement> original, Parser.JavaContext context)
{
String java = collapseComments(original).stream().map(el -> el.toJavaSource().toTemporaryJavaCodeString()).collect(Collectors.joining("\n"));
try
{
test(java, original.toArray(new CodeElement[0]), context, true);
}
catch (Exception e)
{
System.err.println("Error while round-tripping: " + original.stream().map(CodeElement::toXML).map(LocatableElement::toXML).collect(Collectors.joining()) + "\n\n" + java);
throw e;
}
}
private ClassElement _class(String pkg, List<String> imports, String javadoc, boolean _abstract, String name, String _extends, List<String> _implements, List<CodeElement> fields, List<ConstructorElement> constructors, List<NormalMethodElement> methods)
{
return new ClassElement(null, null, _abstract, name(name), _extends == null ? null : type(_extends),
_implements.stream().map(t -> type(t)).collect(Collectors.toList()),
fields, constructors, methods, new JavadocUnit(javadoc), pkg == null ? null : pkg, imports.stream().map(i -> new ImportElement(i, null, true)).collect(Collectors.toList()), true);
}
private CommentElement _comment(String s)
{
return new CommentElement(s);
}
private VarElement _var(AccessPermission access, boolean _static, boolean _final, String type, String name, FilledExpressionSlotFragment init)
{
return new VarElement(null, access == null ? null : new AccessPermissionFragment(access), _static, _final, type(type), name(name), init, true);
}
private ParamFragment _param(String type, String name)
{
return new ParamFragment(type(type), name(name));
}
private NormalMethodElement _method(String comment, AccessPermission accessPermission, boolean _static, boolean _final, String returnType, String name, List<ParamFragment> params, List<String> _throws, List<CodeElement> body)
{
return new NormalMethodElement(null, new AccessPermissionFragment(accessPermission), _static, _final, type(returnType), name(name), params, _throws.stream().map(t -> new ThrowsTypeFragment(type(t))).collect(Collectors.toList()), body, new JavadocUnit(comment), true);
}
private ConstructorElement _constructor(String comment, AccessPermission accessPermission, List<ParamFragment> params, List<String> _throws, List<CodeElement> body)
{
return new ConstructorElement(null, new AccessPermissionFragment(accessPermission), params, _throws.stream().map(t -> new ThrowsTypeFragment(type(t))).collect(Collectors.toList()), null, null, body, new JavadocUnit(comment), true);
}
private CodeElement _constructorDelegate(String comment, AccessPermission accessPermission, List<ParamFragment> params, List<String> _throws, SuperThis superThis, String superThisArgs, List<CodeElement> body)
{
return new ConstructorElement(null, new AccessPermissionFragment(accessPermission), params, _throws.stream().map(t -> new ThrowsTypeFragment(type(t))).collect(Collectors.toList()), new SuperThisFragment(superThis), new SuperThisParamsExpressionFragment(superThisArgs, superThisArgs), body, new JavadocUnit(comment), true);
}
private CodeElement _constructorDelegate(String comment, AccessPermission accessPermission, List<ParamFragment> params, List<String> _throws, SuperThis superThis, SuperThisParamsExpressionFragment superThisArgs, List<CodeElement> body)
{
return new ConstructorElement(null, new AccessPermissionFragment(accessPermission), params, _throws.stream().map(t -> new ThrowsTypeFragment(type(t))).collect(Collectors.toList()), new SuperThisFragment(superThis), superThisArgs, body, new JavadocUnit(comment), true);
}
private static void assertExpression(String expectedStride, String original)
{
Assert.assertEquals(expectedStride, new Expression(original, Collections.emptyList(), w -> {
}).toFilled().getContent());
}
private CallElement _call(String call)
{
return _call(new CallExpressionSlotFragment(call, call));
}
private CallElement _call(CallExpressionSlotFragment call)
{
return new CallElement(null, call, true);
}
private ReturnElement _return()
{
return new ReturnElement(null, null, true);
}
private ReturnElement _return(String s)
{
return _return(new OptionalExpressionSlotFragment(s, s));
}
private ReturnElement _return(OptionalExpressionSlotFragment s)
{
return new ReturnElement(null, s, true);
}
private WhileElement _while(String expression, CodeElement... body)
{
return _while(filled(expression), body);
}
private WhileElement _while(FilledExpressionSlotFragment expression, CodeElement... body)
{
return new WhileElement(null, expression, Arrays.asList(body), true);
}
private IfElement _if(String expression, CodeElement... body)
{
return _ifElse(expression, Arrays.asList(body), null);
}
private IfElement _ifElse(String expression, List<CodeElement> body, List<CodeElement> else{ Body){
return _ifElseIf(expression, body, Collections.emptyList(), Collections.emptyList(), elseBody);
}
}
private IfElement _ifElseIf(String expression, List<CodeElement> body, List<String> expressions, List<List<CodeElement>> else{ IfBodies, List<CodeElement> elseBody){
return new IfElement(null, filled(expression), body, expressions.stream().map(JavaToStrideTest::filled).collect(Collectors.toList()), elseIfBodies, elseBody, true);
}
}
private IfElement _ifElseIf(FilledExpressionSlotFragment expression, List<CodeElement> body, List<FilledExpressionSlotFragment> expressions, List<List<CodeElement>> else{ IfBodies, List<CodeElement> elseBody){
return new IfElement(null, expression, body, expressions, elseIfBodies, elseBody, true);
}
}
private static FilledExpressionSlotFragment filled(String e)
{
return new FilledExpressionSlotFragment(e, e);
}
private FilledExpressionSlotFragment _range(String lower, String upper)
{
return new FilledExpressionSlotFragment(lower + ".." + upper, "lang.stride.Utility.makeRange(" + lower + ", " + upper + ")");
}
private static List l(T... items)
{
return Arrays.asList(items);
}
private static void assertEquals(String javaSource, CodeElement... expectedStride)
{
test(javaSource, expectedStride, Parser.JavaContext.STATEMENT, true);
roundTrip(Arrays.asList(expectedStride), Parser.JavaContext.STATEMENT);
}
private static void assertEqualsMember(String javaSource, CodeElement... expectedStride)
{
test(javaSource, expectedStride, Parser.JavaContext.CLASS_MEMBER, true);
}
private static void assertEqualsFile(String javaSource, CodeElement... expectedStride)
{
test(javaSource, expectedStride, Parser.JavaContext.TOP_LEVEL, true);
}
private static String serialise(Element el)
{
try
{
return Utility.serialiseCodeToString(el);
}
catch (IOException e)
{
return null;
}
}
private static void test(String javaSource, CodeElement[] expectedStride, Parser.JavaContext classMember, boolean checkNoWarnings)
{
Parser.ConversionResult result = Parser.javaToStride(javaSource, classMember, true);
List<String> resultXML = result.getElements().stream().map(CodeElement::toXML).map(JavaToStrideTest::serialise).collect(Collectors.toList());
List<String> expectedXML = Arrays.stream(expectedStride).map(CodeElement::toXML).map(JavaToStrideTest::serialise).collect(Collectors.toList());
if (expectedXML.size() == 1 && resultXML.size() == 1)
Assert.assertEquals("Checking XML", expectedXML.get(0), resultXML.get(0));
else{ Assert.assertEquals("Checking XML", expectedXML, resultXML);
}
if (checkNoWarnings)
Assert.assertEquals("No warnings\n" + javaSource, Collections.emptyList(), result.getWarnings());
}
private static void assertWarningMember(String javaSource, Class<? extends ConversionWarning> cls, CodeElement... items)
{
testWarning(javaSource, cls, Parser.JavaContext.CLASS_MEMBER);
test(javaSource, items, Parser.JavaContext.CLASS_MEMBER, false);
}
private static void assertWarning(String javaSource, Class<? extends ConversionWarning> cls, CodeElement... items)
{
testWarning(javaSource, cls, JavaContext.STATEMENT);
test(javaSource, items, JavaContext.STATEMENT, false);
}
private static void assertWarningFile(String javaSource, Class<? extends ConversionWarning> cls, CodeElement... items)
{
testWarning(javaSource, cls, JavaContext.TOP_LEVEL);
test(javaSource, items, JavaContext.TOP_LEVEL, false);
}
private static void testWarning(String javaSource, Class<? extends ConversionWarning> cls, JavaContext context)
{
List<ConversionWarning> warnings = Parser.javaToStride(javaSource, context, true).getWarnings();
Assert.assertTrue("Expected warning", !warnings.isEmpty());
Assert.assertTrue("Expected specific warning type", warnings.stream().anyMatch(cls::isInstance));
}
}
top,
use,
map,
class JavaToStrideTest
. testStatements
. testIncDec
. testAssign
. _assign
. _forEach
. type
. name
. _switch
. _case
. _try
. testIf
. testCall
. testExpression
. testInstanceof
. testMethod
. testFieldAndVar
. testComments
. testWhole
. _interface
. _commentWarn
. testRandomStatement
. testRandomTopLevel
. genTopLevel
. genComment
. genImport
. genPackage
. genSuperThisParams
. genThrowsType
. genParam
. genAccess
. genJavadoc
. genStatement
. genCase
. rand
. genCallOrAssign
. replicate
. genOptExpression
. genExpression
. concat
. genExpression
. genCall
. genType
. genName
. oneOf
. genOneOf
. collapseComments
. some
. somePrecede
. many
. rand
. roundTrip
. _class
. _comment
. _var
. _param
. _method
. _constructor
. _constructorDelegate
. _constructorDelegate
. assertExpression
. _call
. _call
. _return
. _return
. _return
. _while
. _while
. _if
. _ifElse
. _ifElseIf
. _ifElseIf
. filled
. _range
. l
. assertEquals
. assertEqualsMember
. assertEqualsFile
. serialise
. test
. assertWarningMember
. assertWarning
. assertWarningFile
. testWarning
1184 neLoCode
+ 2 LoComm