diff --git a/build.gradle b/build.gradle index b500675302032e9d073e9b004158bd60ef888ab8..a82d2d7079fcd0f5ccd4192d1665ce807b200fd0 100644 --- a/build.gradle +++ b/build.gradle @@ -153,6 +153,13 @@ test.dependsOn compileRelationTest compileRelationTest.dependsOn doublePreprocessRelationTest doublePreprocessRelationTest.dependsOn preprocessRelationTest +task compileConstructorTest(type: RelastTest) { + relastFiles 'src/test/jastadd/constructors/Constructors.relast' + grammarName = 'src/test/jastadd/constructors/Constructors' + packageName = 'constructors.ast' + moreInputFiles 'src/test/jastadd/constructors/Constructors.jrag' +} + task compileDefaultNamesTest(type: RelastTest) { relastFiles 'src/test/jastadd/relations/Relations.relast' grammarName = 'src/test/jastadd/relations/Relations3' @@ -247,7 +254,6 @@ task compileSerializerDefaultNamesTest(type: RelastTest) { } task compileSerializerPointerTest(type: RelastTest) { - verbose = true resolverHelper = true relastFiles 'src/test/jastadd/serializer-pointer/Serializer.relast' grammarName = 'src/test/jastadd/serializer-pointer/Serializer' @@ -257,7 +263,6 @@ task compileSerializerPointerTest(type: RelastTest) { } task compileSerializerManualTest(type: RelastTest) { - verbose = true resolverHelper = true relastFiles 'src/test/jastadd/serializer-manual/Serializer.relast' grammarName = 'src/test/jastadd/serializer-manual/Serializer' @@ -267,7 +272,6 @@ task compileSerializerManualTest(type: RelastTest) { } task compileSerializerManualRelativeTest(type: RelastTest) { - verbose = true resolverHelper = true relastFiles 'src/test/jastadd/serializer-manual-relative/Serializer.relast' grammarName = 'src/test/jastadd/serializer-manual-relative/Serializer' diff --git a/src/main/jastadd/Analysis.jrag b/src/main/jastadd/Analysis.jrag index 27f3a7d89731f351b8a21043e9b2a816cd3d3548..139bd082748e4407dbdcbf851f54a8147fba7949 100644 --- a/src/main/jastadd/Analysis.jrag +++ b/src/main/jastadd/Analysis.jrag @@ -105,6 +105,11 @@ aspect ComponentAnalysis { //--- isEqual --- syn boolean Component.isEqual(Component c) = this.getClass() == c.getClass() && getTypeUse().isEqual(c.getTypeUse()); + /** + * TokenComponents may be specialized by NTATokenComponents and vice versa + */ + eq TokenComponent.isEqual(Component c) = (c instanceof TokenComponent) && getTypeUse().isEqual(c.getTypeUse()); + syn boolean TypeUse.isEqual(TypeUse u); eq SimpleTypeUse.isEqual(TypeUse u) = u instanceof SimpleTypeUse && getID().equals(u.getID()); eq ParameterizedTypeUse.isEqual(TypeUse u) { @@ -228,17 +233,7 @@ aspect Constructors { } //--- needsConstructor --- - syn boolean TypeDecl.needsConstructor() { - if (componentsTransitive().isEmpty()) { - return false; - } - if (!relationComponents().isEmpty()) { - return true; - } - return hasSuper() - && getSuper().decl() != null - && getSuper().decl().needsConstructor(); - } + syn boolean TypeDecl.needsConstructor() = !componentsTransitive().isEmpty() && !relationComponentsTransitive().isEmpty(); //--- inConstructor --- /** @@ -248,6 +243,7 @@ aspect Constructors { eq NTAComponent.inConstructor() = false; eq NTAOptComponent.inConstructor() = false; eq NTAListComponent.inConstructor() = false; + eq NTATokenComponent.inConstructor() = false; } aspect Utils { diff --git a/src/main/jastadd/Backend.jadd b/src/main/jastadd/Backend.jadd index 26591c03e65af7dd169b1ec4e54bd0798e5d3dc1..cab17e15766bc3323d2cc8b6c1b8f5c3c754c396 100644 --- a/src/main/jastadd/Backend.jadd +++ b/src/main/jastadd/Backend.jadd @@ -111,6 +111,9 @@ aspect BackendAbstractGrammar { public String TokenComponent.generateAbstractGrammar() { return "<" + getID() + ":" + getTypeUse() + ">"; } + public String NTATokenComponent.generateAbstractGrammar() { + return "/<" + getID() + ":" + getTypeUse() + ">/"; + } public String RelationComponent.generateAbstractGrammar() { return "<" + getImplAttributeName() + ":" + ofTypeDecl() + ">"; diff --git a/src/main/jastadd/RelAst.ast b/src/main/jastadd/RelAst.ast index f0132fc4b3a4c32f1e2f49aad19382dc64379dcf..31083b99eda970809f5f61e6e44a8e4fb23d1a68 100644 --- a/src/main/jastadd/RelAst.ast +++ b/src/main/jastadd/RelAst.ast @@ -11,6 +11,7 @@ NTAComponent : SimpleTypeComponent; NTAOptComponent : SimpleTypeComponent; NTAListComponent : SimpleTypeComponent; TokenComponent : Component ::= TypeUse; +NTATokenComponent : TokenComponent ::= TypeUse; abstract TypeUse ::= <ID>; SimpleTypeUse : TypeUse; diff --git a/src/main/jastadd/RelAst.flex b/src/main/jastadd/RelAst.flex index 17049259871bf75b47bc9c5a2ef9d5a4fb4d9932..7c06485cec6e976d9297ac752ce4146c35c3ab4e 100644 --- a/src/main/jastadd/RelAst.flex +++ b/src/main/jastadd/RelAst.flex @@ -37,7 +37,7 @@ import org.jastadd.relast.parser.RelAstParser.Terminals; WhiteSpace = [ ] | \t | \f | \n | \r | \r\n TraditionalComment = [/][*][^*]*[*]+([^*/][^*]*[*]+)*[/] -EndOfLineComment = "//" [^\n|\r|\r\n]* +EndOfLineComment = "//" [^\n\r]* Comment = {TraditionalComment} | {EndOfLineComment} ID = [a-zA-Z$_][a-zA-Z0-9$_]* diff --git a/src/main/jastadd/RelAst.parser b/src/main/jastadd/RelAst.parser index 6b138b97d35b76583a3226b376613b8316a95a36..32236a483b646c518fd69c9fc383c9ec594bc09c 100644 --- a/src/main/jastadd/RelAst.parser +++ b/src/main/jastadd/RelAst.parser @@ -34,9 +34,16 @@ SimpleTypeUse s_type_use = ID {: return new SimpleTypeUse(ID); :} ; +ArrayList inner_type_use + = ID + | inner_type_use DOT ID + ; + TypeUse type_use = - s_type_use.u {: return u; :} - | parameterized_type_use.p {: return p; :} +// s_type_use.u {: return u; :} +// | + parameterized_type_use.p {: return p; :} + | inner_type_use.p {: return new SimpleTypeUse((String)p.stream().map( x -> ((Symbol)x).value.toString()).collect(java.util.stream.Collectors.joining("."))); :} ; ParameterizedTypeUse parameterized_type_use = ID LT type_use_list.l GT {: return new ParameterizedTypeUse(ID, l); :} @@ -63,11 +70,11 @@ Component component = | ID COL s_type_use.u STAR {: return new ListComponent(ID, u); :} | s_type_use.u STAR {: return new ListComponent(u.getID(), u); :} // Opt - | LBRACKET ID COL s_type_use.u RBRACKET {: return new OptComponent(ID, u); :} - | LBRACKET s_type_use.u RBRACKET {: return new OptComponent(u.getID(), u); :} + | LBRACKET ID COL s_type_use.u RBRACKET {: return new OptComponent(ID, u); :} + | LBRACKET s_type_use.u RBRACKET {: return new OptComponent(u.getID(), u); :} // NTA list - | SLASH ID COL s_type_use.u STAR SLASH {: return new NTAListComponent(ID, u); :} - | SLASH s_type_use.u STAR SLASH {: return new NTAListComponent(u.getID(), u); :} + | SLASH ID COL s_type_use.u STAR SLASH {: return new NTAListComponent(ID, u); :} + | SLASH s_type_use.u STAR SLASH {: return new NTAListComponent(u.getID(), u); :} // NTA opt | SLASH LBRACKET ID COL s_type_use.u RBRACKET SLASH {: return new NTAOptComponent(ID, u); :} | SLASH LBRACKET s_type_use.u RBRACKET SLASH {: return new NTAOptComponent(u.getID(), u); :} @@ -75,8 +82,8 @@ Component component = | SLASH ID COL s_type_use.u SLASH {: return new NTAComponent(ID, u); :} | SLASH s_type_use.u SLASH {: return new NTAComponent(u.getID(), u); :} // NTA Token (same as NTA) - | SLASH LT ID COL s_type_use.u GT SLASH {: return new NTAComponent(ID, u); :} - | SLASH LT s_type_use.u GT SLASH {: return new NTAComponent(u.getID(), u); :} + | SLASH LT ID COL s_type_use.u GT SLASH {: return new NTATokenComponent(ID, u); :} + | SLASH LT ID GT SLASH {: return new NTATokenComponent(ID, new SimpleTypeUse("String")); :} // Token | LT ID COL type_use.u GT {: return new TokenComponent(ID, u); :} | LT ID GT {: return new TokenComponent(ID, new SimpleTypeUse("String")); :} diff --git a/src/test/jastadd/constructors/Constructors.jrag b/src/test/jastadd/constructors/Constructors.jrag new file mode 100644 index 0000000000000000000000000000000000000000..fd86b7f2f08d915ae6cc20a90de2383e5ae5fb44 --- /dev/null +++ b/src/test/jastadd/constructors/Constructors.jrag @@ -0,0 +1,13 @@ +aspect NTAs { + syn A S.getS4() = new A(); + syn List<A> S.getS5List() = new List<>(); + syn Opt<A> S.getS6Opt() = new Opt<>(); + syn String S.getS7() = ""; + syn long S.getS8() = 1L; + + syn A B.getB4() = new A(); + syn List<A> B.getB5List() = new List<>(); + syn Opt<A> B.getB6Opt() = new Opt<>(); + syn String B.getB7() = ""; + syn long B.getB8() = 1L; +} diff --git a/src/test/jastadd/constructors/Constructors.relast b/src/test/jastadd/constructors/Constructors.relast new file mode 100644 index 0000000000000000000000000000000000000000..5b3d5a9eda5af27ecaef5382c3d83fb65ee3a7cf --- /dev/null +++ b/src/test/jastadd/constructors/Constructors.relast @@ -0,0 +1,9 @@ +A; +S ::= S1:A S2:A* [S3:A] /S4:A/ /S5:A*/ /[S6:A]/ /<S7>/ /<S8:long>/; +B : S ::= B1:A B2:A* [B3:A] /B4:A/ /B5:A*/ /[B6:A]/ /<B7>/ /<B8:long>/; +X; +Y; + +rel A.r1 -> X; +rel S.r2* <-> Y.r2; +rel B.r3? -> X; diff --git a/src/test/jastadd/errors/Inheritance.expected b/src/test/jastadd/errors/Inheritance.expected index b3382e004ae6e15ca9bbd1ed6695ece0e3110fbe..29ee61a9bffb84a9cbd5f05b874b5cdc88819446 100644 --- a/src/test/jastadd/errors/Inheritance.expected +++ b/src/test/jastadd/errors/Inheritance.expected @@ -1,3 +1,64 @@ Errors: $FILENAME Line 4, column 12: Token 'X' is an invalid redefinition for type 'B3', conflicts with supertype 'A' -$FILENAME Line 7, column 5: Role 'X' is an invalid redefinition for type 'B2', conflicts with supertype 'A' +$FILENAME Line 4, column 23: Token 'MyName' is an invalid redefinition for type 'B3', conflicts with supertype 'A' + +$FILENAME Line 11, column 5: Role 'X' is an invalid redefinition for type 'B2', conflicts with supertype 'A' +$FILENAME Line 12, column 5: Role 'X' is an invalid redefinition for type 'B2', conflicts with supertype 'A' +$FILENAME Line 13, column 5: Role 'X' is an invalid redefinition for type 'B2', conflicts with supertype 'A' +$FILENAME Line 14, column 5: Role 'X' is an invalid redefinition for type 'B2', conflicts with supertype 'A' +$FILENAME Line 15, column 5: Role 'X' is an invalid redefinition for type 'B2', conflicts with supertype 'A' +$FILENAME Line 16, column 5: Role 'X' is an invalid redefinition for type 'B2', conflicts with supertype 'A' +$FILENAME Line 12, column 5: Role 'X' is already declared for type 'B2' +$FILENAME Line 13, column 5: Role 'X' is already declared for type 'B2' +$FILENAME Line 14, column 5: Role 'X' is already declared for type 'B2' +$FILENAME Line 15, column 5: Role 'X' is already declared for type 'B2' +$FILENAME Line 16, column 5: Role 'X' is already declared for type 'B2' + +$FILENAME Line 18, column 5: Role 'MyName' is an invalid redefinition for type 'B2', conflicts with supertype 'A' +$FILENAME Line 19, column 5: Role 'MyName' is an invalid redefinition for type 'B2', conflicts with supertype 'A' +$FILENAME Line 20, column 5: Role 'MyName' is an invalid redefinition for type 'B2', conflicts with supertype 'A' +$FILENAME Line 21, column 5: Role 'MyName' is an invalid redefinition for type 'B2', conflicts with supertype 'A' +$FILENAME Line 22, column 5: Role 'MyName' is an invalid redefinition for type 'B2', conflicts with supertype 'A' +$FILENAME Line 23, column 5: Role 'MyName' is an invalid redefinition for type 'B2', conflicts with supertype 'A' +$FILENAME Line 19, column 5: Role 'MyName' is already declared for type 'B2' +$FILENAME Line 20, column 5: Role 'MyName' is already declared for type 'B2' +$FILENAME Line 21, column 5: Role 'MyName' is already declared for type 'B2' +$FILENAME Line 22, column 5: Role 'MyName' is already declared for type 'B2' +$FILENAME Line 23, column 5: Role 'MyName' is already declared for type 'B2' + +$FILENAME Line 28, column 12: Token 'X' is an invalid redefinition for type 'D3', conflicts with supertype 'C' +$FILENAME Line 30, column 5: Role 'X' is an invalid redefinition for type 'D2', conflicts with supertype 'C' +$FILENAME Line 31, column 5: Role 'X' is an invalid redefinition for type 'D2', conflicts with supertype 'C' +$FILENAME Line 32, column 5: Role 'X' is an invalid redefinition for type 'D2', conflicts with supertype 'C' +$FILENAME Line 33, column 5: Role 'X' is an invalid redefinition for type 'D2', conflicts with supertype 'C' +$FILENAME Line 34, column 5: Role 'X' is an invalid redefinition for type 'D2', conflicts with supertype 'C' +$FILENAME Line 35, column 5: Role 'X' is an invalid redefinition for type 'D2', conflicts with supertype 'C' +$FILENAME Line 31, column 5: Role 'X' is already declared for type 'D2' +$FILENAME Line 32, column 5: Role 'X' is already declared for type 'D2' +$FILENAME Line 33, column 5: Role 'X' is already declared for type 'D2' +$FILENAME Line 34, column 5: Role 'X' is already declared for type 'D2' +$FILENAME Line 35, column 5: Role 'X' is already declared for type 'D2' + +$FILENAME Line 37, column 5: Role 'MyName' is an invalid redefinition for type 'D2', conflicts with supertype 'C' +$FILENAME Line 38, column 5: Role 'MyName' is an invalid redefinition for type 'D2', conflicts with supertype 'C' +$FILENAME Line 39, column 5: Role 'MyName' is an invalid redefinition for type 'D2', conflicts with supertype 'C' +$FILENAME Line 40, column 5: Role 'MyName' is an invalid redefinition for type 'D2', conflicts with supertype 'C' +$FILENAME Line 41, column 5: Role 'MyName' is an invalid redefinition for type 'D2', conflicts with supertype 'C' +$FILENAME Line 42, column 5: Role 'MyName' is an invalid redefinition for type 'D2', conflicts with supertype 'C' +$FILENAME Line 38, column 5: Role 'MyName' is already declared for type 'D2' +$FILENAME Line 39, column 5: Role 'MyName' is already declared for type 'D2' +$FILENAME Line 40, column 5: Role 'MyName' is already declared for type 'D2' +$FILENAME Line 41, column 5: Role 'MyName' is already declared for type 'D2' +$FILENAME Line 42, column 5: Role 'MyName' is already declared for type 'D2' + +$FILENAME Line 44, column 5: Role 'X2' is an invalid redefinition for type 'D2', conflicts with supertype 'C' +$FILENAME Line 45, column 5: Role 'X2' is an invalid redefinition for type 'D2', conflicts with supertype 'C' +$FILENAME Line 46, column 5: Role 'X2' is an invalid redefinition for type 'D2', conflicts with supertype 'C' +$FILENAME Line 47, column 5: Role 'X2' is an invalid redefinition for type 'D2', conflicts with supertype 'C' +$FILENAME Line 48, column 5: Role 'X2' is an invalid redefinition for type 'D2', conflicts with supertype 'C' +$FILENAME Line 49, column 5: Role 'X2' is an invalid redefinition for type 'D2', conflicts with supertype 'C' +$FILENAME Line 45, column 5: Role 'X2' is already declared for type 'D2' +$FILENAME Line 46, column 5: Role 'X2' is already declared for type 'D2' +$FILENAME Line 47, column 5: Role 'X2' is already declared for type 'D2' +$FILENAME Line 48, column 5: Role 'X2' is already declared for type 'D2' +$FILENAME Line 49, column 5: Role 'X2' is already declared for type 'D2' diff --git a/src/test/jastadd/errors/Inheritance.relast b/src/test/jastadd/errors/Inheritance.relast index db746eb173254ba6c28d7bb2d585b1c92f7e76f3..e8529a8be66598c2d56fddd38dd15c66d1f732e5 100644 --- a/src/test/jastadd/errors/Inheritance.relast +++ b/src/test/jastadd/errors/Inheritance.relast @@ -1,7 +1,49 @@ -A ::= X; -B1 : A ::= X; +A ::= X MyName:X; +B1 : A ::= X MyName:X MyName:Y; B2 : A; -B3 : A ::= <X:String>; +B3 : A ::= <X:String> <MyName:String>; +// B4 has a child named X of type SubX +B4 : A ::= X:SubX; X; +SubX : X; +Y; rel B2.X -> X; +rel B2.X -> Y; +rel B2.X? -> X; +rel B2.X? -> Y; +rel B2.X* -> X; +rel B2.X* -> Y; + +rel B2.MyName -> X; +rel B2.MyName -> Y; +rel B2.MyName? -> X; +rel B2.MyName? -> Y; +rel B2.MyName* -> X; +rel B2.MyName* -> Y; + +C ::= /X/ /MyName:X/ /<X2:long>/ ; +D1 : C ::= X; +D2 : C; +D3 : C ::= <X:String> ; + +rel D2.X -> X; +rel D2.X -> Y; +rel D2.X? -> X; +rel D2.X? -> Y; +rel D2.X* -> X; +rel D2.X* -> Y; + +rel D2.MyName -> X; +rel D2.MyName -> Y; +rel D2.MyName? -> X; +rel D2.MyName? -> Y; +rel D2.MyName* -> X; +rel D2.MyName* -> Y; + +rel D2.X2 -> X; +rel D2.X2 -> Y; +rel D2.X2? -> X; +rel D2.X2? -> Y; +rel D2.X2* -> X; +rel D2.X2* -> Y; diff --git a/src/test/jastadd/relations/Relations.relast b/src/test/jastadd/relations/Relations.relast index bdcc87885ae227cfd2d384659a8d1d535ee63aa0..498e4fcf2553c37020ae9b53e64b3cd0f5703fb7 100644 --- a/src/test/jastadd/relations/Relations.relast +++ b/src/test/jastadd/relations/Relations.relast @@ -41,3 +41,23 @@ rel A <- Root.AaLeft?; rel B <- A.Di1Left ; rel B <- A.Di2Left?; rel B <- A.Di3Left*; + +// empty productions +C ; + +// production with nonterminals of different kinds +D ::= SingleA:A ListOfA:A* [OptionalA:A] /NTAA:A/ ; + +// production with tokens, nonterminal-tokens, multi-line +E ::= <T1> <T2:String> <T3:boolean> <T4:int> <T5:float> <T6:double> <T7:long> + /<NT2:String>/ /<NT3:boolean>/ /<NT4:int>/ /<NT5:float>/ /<NT6:double>/ /<NT7:long>/ ; + +rel E.NT1 -> A ; +// inheritance and empty +F : A ; + +// inheritance and more on RHS +G : C ::= [D] ; + +// line comment with special symbols like |, *, ->, <-, <->, [A], B ::= C, :, \n, \r, ~, #, /A/ +/* block comment with special symbols like |, *, ->, <-, <->, [A], B ::= C, :, \n, \r, ~, #, /A/ */ diff --git a/src/test/java/org/jastadd/relast/tests/ConstructorsTest.java b/src/test/java/org/jastadd/relast/tests/ConstructorsTest.java new file mode 100644 index 0000000000000000000000000000000000000000..689e991ea44e38f6cd96c6211a797b34c9041905 --- /dev/null +++ b/src/test/java/org/jastadd/relast/tests/ConstructorsTest.java @@ -0,0 +1,58 @@ +package org.jastadd.relast.tests; + +import constructors.ast.*; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +import java.util.ArrayList; + +/** + * Testing generated constructors. + * + * @author rschoene - Initial contribution + */ +@SuppressWarnings("unused") +public class ConstructorsTest { + + @Test + public void testX() { + X x = new X(); + Assertions.assertEquals(1, numberOfConstructors(X.class)); + } + + @Test + public void testY() { + Y y0 = new Y(); + Y y1 = new Y(new S()); + Assertions.assertEquals(2, numberOfConstructors(Y.class)); + } + + @Test + public void testA() { + A a0 = new A(); + A a1 = new A(new X()); + Assertions.assertEquals(2, numberOfConstructors(A.class)); + } + + @Test + public void testS() { + A a = new A(); + S s0 = new S(); + S s1 = new S(a, new List<>(), new Opt<>()); + S s2 = new S(a, new List<>(), new Opt<>(), new ArrayList<>()); + Assertions.assertEquals(3, numberOfConstructors(S.class)); + } + + @Test + public void testB() { + A a = new A(); + B b0 = new B(); + B b1 = new B(a, new List<>(), new Opt<>(), a, new List<>(), new Opt<>()); + B b2 = new B(a, new List<>(), new Opt<>(), new ArrayList<>(), a, new List<>(), new Opt<>(), null); + Assertions.assertEquals(3, numberOfConstructors(B.class)); + } + + private int numberOfConstructors(Class<?> clazz) { + return clazz.getConstructors().length; + } +} diff --git a/src/test/java/org/jastadd/relast/tests/Errors.java b/src/test/java/org/jastadd/relast/tests/Errors.java index 718c049708281b26dea16e8792062be067c2938e..5134381a825854479ba6c7b5b179c4310e3a491b 100644 --- a/src/test/java/org/jastadd/relast/tests/Errors.java +++ b/src/test/java/org/jastadd/relast/tests/Errors.java @@ -10,6 +10,7 @@ import java.io.File; import java.io.IOException; import java.nio.charset.Charset; import java.util.Arrays; +import java.util.Collections; import java.util.List; import java.util.stream.Collectors; @@ -23,32 +24,32 @@ class Errors { private static final String FILENAME_PATTERN = "$FILENAME"; @Test - void test1() throws IOException { + void testStandardErrors() throws IOException { test("Errors"); } @Test - void test1Left() throws IOException { + void testStandardErrorsLeft() throws IOException { test("ErrorsLeft"); } @Test - void test2() throws IOException { + void testInheritance() throws IOException { test("Inheritance"); } @Test - void test2Left() throws IOException { + void testInheritanceLeft() throws IOException { test("InheritanceLeft"); } @Test - void test3() throws IOException { + void testMultipleFiles() throws IOException { test("Multiple", "Multiple_1", "Multiple_2"); } @Test - void test3Left() throws IOException { + void testMultipleFilesLeft() throws IOException { test("MultipleLeft", "MultipleLeft_1", "MultipleLeft_2"); } @@ -60,7 +61,7 @@ class Errors { String expectedFile = "./src/test/jastadd/errors/" + name + ".expected"; try { - System.out.println(System.getProperty("user.dir")); + logger.debug("user.dir: {}", System.getProperty("user.dir")); int returnValue = exec(Compiler.class, inFiles.toArray(new String[0]), new File(outFile)); Assertions.assertEquals(1, returnValue, "Relast did not return with value 1"); } catch (IOException | InterruptedException e) { @@ -76,7 +77,14 @@ class Errors { expected = expected.replace(FILENAME_PATTERN + (i + 1), inFiles.get(i)); } } - Assertions.assertEquals(expected, out); + List<String> outList = Arrays.asList(out.split("\n")); + Collections.sort(outList); + List<String> expectedList = Arrays.stream(expected.split("\n")) + .sorted() + .filter(s -> !s.isEmpty() && !s.startsWith("//")) + .collect(Collectors.toList()); + + Assertions.assertLinesMatch(expectedList, outList); logger.info("relast for " + name + " returned \n{}", out); }