abstractTests.ceylon
import ceylon.ast.core {
Node,
Identifier
}
import com.redhat.ceylon.compiler.typechecker.tree {
JNode=Node
}
import ceylon.ast.redhat {
RedHatTransformer,
SimpleTokenFactory
}
import ceylon.test {
assertEquals,
test
}
void assertNodesEquals(Node actual, Node expected, String? message = null) {
assertEquals {
actual = actual;
expected = expected;
message = message;
};
if (is Identifier actual) {
assert (is Identifier expected);
assertEquals {
actual = actual.usePrefix;
expected = expected.usePrefix;
message = message;
};
}
}
void doTest<CeylonAstType,RedHatType>(
CeylonAstType? compile(String code),
RedHatType fromCeylon(RedHatTransformer transformer)(CeylonAstType node), CeylonAstType toCeylon(RedHatType node),
<String->CeylonAstType>+ codes)
given CeylonAstType satisfies Node
given RedHatType satisfies JNode {
testCompilation(compile, *codes);
testConversion(fromCeylon, toCeylon, *codes.collect(Entry<String,CeylonAstType>.item));
}
void testConversion<CeylonAstType,RedHatType>(RedHatType fromCeylon(RedHatTransformer transformer)(CeylonAstType node), CeylonAstType toCeylon(RedHatType node), CeylonAstType+ nodes)
given CeylonAstType satisfies Node
given RedHatType satisfies JNode {
for (node in nodes) {
assertNodesEquals {
actual = toCeylon(fromCeylon(RedHatTransformer(SimpleTokenFactory()))(node));
expected = node;
message = "Double conversion";
};
}
}
void testCompilation<CeylonAstType>(CeylonAstType? compile(String code), <String->CeylonAstType>+ codes)
given CeylonAstType satisfies Node {
for (code->node in codes) {
assert (exists compiled = compile(code));
assertNodesEquals {
actual = compiled;
expected = node;
message = "Compile ‘``code``’";
};
}
}
// needed for variance – ConcreteTest’s type params
// must be invariant, but we need them 'out' for
// use in AbstractTest
shared interface CodesProvider<out CeylonAstType>
given CeylonAstType satisfies Node {
shared formal [<String->CeylonAstType>+] codes;
}
shared interface NodesProvider<out CeylonAstType>
given CeylonAstType satisfies Node {
shared formal [CeylonAstType+] nodes;
}
shared interface CompilationTest<out CeylonAstType>
satisfies CodesProvider<CeylonAstType>
given CeylonAstType satisfies Node {
shared formal CeylonAstType? compile(String code);
test
shared void compilation() => testCompilation(compile, *codes);
}
shared interface ConversionTest<CeylonAstType,RedHatType>
satisfies NodesProvider<CeylonAstType>
given CeylonAstType satisfies Node
given RedHatType satisfies JNode {
shared formal RedHatType fromCeylon(RedHatTransformer transformer)(CeylonAstType node);
shared formal CeylonAstType toCeylon(RedHatType node);
test
shared void conversion() => testConversion(fromCeylon, toCeylon, *nodes);
}
shared interface ConcreteTest<CeylonAstType,RedHatType>
satisfies CompilationTest<CeylonAstType> & ConversionTest<CeylonAstType,RedHatType>
given CeylonAstType satisfies Node
given RedHatType satisfies JNode {
shared actual [CeylonAstType+] nodes => codes*.item;
}
shared interface AbstractTest<CeylonAstType,RedHatType>
satisfies CompilationTest<CeylonAstType> & ConversionTest<CeylonAstType,RedHatType>
given CeylonAstType satisfies Node
given RedHatType satisfies JNode {
shared formal [CodesProvider<CeylonAstType>+] tests;
shared actual [<String->CeylonAstType>+] codes => [for (test in tests) for (code in test.codes) code];
shared actual [CeylonAstType+] nodes => codes*.item;
}
shared interface AbstractCompilationTest<out CeylonAstType>
satisfies CompilationTest<CeylonAstType>
given CeylonAstType satisfies Node {
shared formal [CodesProvider<CeylonAstType>+] tests;
shared actual [<String->CeylonAstType>+] codes => [for (test in tests) for (code in test.codes) code];
}
shared interface AbstractConversionTest<CeylonAstType,RedHatType>
satisfies ConversionTest<CeylonAstType,RedHatType>
given CeylonAstType satisfies Node
given RedHatType satisfies JNode {
shared formal [NodesProvider<CeylonAstType>+] tests;
shared actual [CeylonAstType+] nodes => [for (test in tests) for (node in test.nodes) node];
}