Loading plugins/org.etsi.mts.tdl.tx.tests/src/fixtures/f1/Config.tdltx 0 → 100644 +21 −0 Changes for plugins/org.etsi.mts.tdl.tx.tests/src/fixtures/f1/Config.tdltx: 21 added lines, 0 removed lines. Original line number Diff line number Diff line // F1 multi-file fixture: gate/component/configuration definitions. Imports // F1Data (types used by the gate and the variables) and is imported by TD.tdltx. Package F1Config { Import all from TDL Import Shape, Point, Colour from F1Data // explicit import (TD.tdltx uses 'Import all') Message Gate shapeGate accepts Shape, Point, Colour, Integer Component Node { gate shapeGate g variable Integer count variable Shape lastShape timer t } Configuration Basic { Node tester as Tester, Node sut as SUT, connect tester::g to sut::g } } plugins/org.etsi.mts.tdl.tx.tests/src/fixtures/f1/Data.tdltx 0 → 100644 +39 −0 Changes for plugins/org.etsi.mts.tdl.tx.tests/src/fixtures/f1/Data.tdltx: 39 added lines, 0 removed lines. Original line number Diff line number Diff line // F1 multi-file fixture (docs/reliability/11-test-suite-design.md): data // definitions imported by Config.tdltx and TD.tdltx. Every kind of element // that the other files reference across the file boundary lives here. Package F1Data { Import all from TDL Enumerated Colour { Colour red, // explicit type green, // implicit: typed by the enclosing enumeration blue } Type Id Id id1 Id id2 Structure Point ( Integer x, Integer y ) Collection Points of Point Structure Shape ( Id id, Colour colour, Points outline ) Point origin ( x = 0, y = 0 ) Point unit ( x = 1, y = 1 ) Points square [ origin, unit ] Shape shape1 ( id = id1, colour = red, outline = square ) Shape shape2 ( id = id2, colour = green, outline = square ) second oneSecond second twoSeconds Function area ( Shape s ) returns Integer : "area of a shape" } plugins/org.etsi.mts.tdl.tx.tests/src/fixtures/f1/TD.tdltx 0 → 100644 +30 −0 Changes for plugins/org.etsi.mts.tdl.tx.tests/src/fixtures/f1/TD.tdltx: 30 added lines, 0 removed lines. Original line number Diff line number Diff line // F1 multi-file fixture: test descriptions. References data (F1Data) and the // configuration, component instances, gates and timers (F1Config) across two // file boundaries; also references an element (Basic) that itself references // a third file (Node -> shapeGate -> Shape). Package F1TD { Import all from TDL Import all from F1Data Import all from F1Config Test Description sendShape uses Basic { tester::g sends shape1 to sut::g sut::g sends shape2 ( colour = blue ) to tester::g tester::g receives shape1 ( colour = ?, outline = square ) from sut::g set verdict to pass } Test Description withTimers uses Basic { start tester::t for oneSecond tester::g sends origin to sut::g alternatively { tester::g receives unit from sut::g stop tester::t set verdict to pass } or { timeout on tester::t set verdict to fail } wait for twoSeconds on tester } } plugins/org.etsi.mts.tdl.tx.tests/src/org/etsi/mts/tdl/tx/tests/EnumTypingTest.java 0 → 100644 +97 −0 Changes for plugins/org.etsi.mts.tdl.tx.tests/src/org/etsi/mts/tdl/tx/tests/EnumTypingTest.java: 97 added lines, 0 removed lines. Original line number Diff line number Diff line package org.etsi.mts.tdl.tx.tests; import java.io.File; import java.util.List; import org.eclipse.emf.ecore.resource.Resource; import org.eclipse.xtext.resource.XtextResource; import org.eclipse.xtext.serializer.ISerializer; import org.eclipse.xtext.validation.Issue; import org.etsi.mts.tdl.EnumDataType; import org.etsi.mts.tdl.Package; import org.etsi.mts.tdl.SimpleDataInstance; import org.etsi.mts.tdl.tdlPackage; import org.etsi.mts.tdl.tx.tests.oracle.LinkOracle; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; import com.google.inject.Inject; /** * Task 2.2 / experiment X5: enumeration values are typed by their enclosing * enumeration without derived state — on read, for EMF multiplicity checks, * for cross-file references, and without leaking into the serialised text. */ public class EnumTypingTest extends TDLtxAbstractTest { @Inject ISerializer serializer; @Override public void verifySingleModel(File file) { } private EnumDataType colour() throws Exception { Fixtures.loadStandardLibrary(parseHelper, rs); XtextResource data = Fixtures.load(parseHelper, rs, "f1", Fixtures.F1).get(0); Package pkg = (Package) data.getContents().get(0); return (EnumDataType) pkg.getPackagedElement().stream().filter(e -> "Colour".equals(e.getName())).findFirst().orElseThrow(); } @Test public void implicitValuesAreTypedByTheEnumeration() throws Exception { EnumDataType colour = colour(); Assertions.assertEquals(3, colour.getValue().size()); for (SimpleDataInstance v : colour.getValue()) { Assertions.assertSame(colour, v.getDataType(), v.getName() + ".getDataType()"); Assertions.assertSame(colour, v.eGet(tdlPackage.Literals.DATA_INSTANCE__DATA_TYPE, false), v.getName() + " eGet(resolve=false)"); Assertions.assertTrue(v.eIsSet(tdlPackage.Literals.DATA_INSTANCE__DATA_TYPE), v.getName() + " eIsSet"); } } @Test public void noMultiplicityOrTypeIssuesOnEnumValues() throws Exception { EnumDataType colour = colour(); List<Issue> issues = validationHelper.validate(colour.eResource()); for (Issue i : issues) { boolean aboutValue = i.getUriToProblem() != null && i.getUriToProblem().fragment() != null && colour.getValue().stream() .anyMatch(v -> i.getUriToProblem().fragment().equals(v.eResource().getURIFragment(v))); Assertions.assertFalse(aboutValue, "issue on an enum value: " + i); } } @Test public void implicitTypeIsNotSerialised() throws Exception { EnumDataType colour = colour(); String text = serializer.serialize(colour); Assertions.assertTrue(text.contains("Colour red"), "explicit type kept: " + text); Assertions.assertFalse(text.contains("Colour green") || text.contains("Colour blue"), "implicit types must stay implicit: " + text); } @Test public void crossFileReferenceToAnImplicitValueResolves() throws Exception { Fixtures.loadStandardLibrary(parseHelper, rs); List<XtextResource> resources = Fixtures.load(parseHelper, rs, "f1", Fixtures.F1); XtextResource td = resources.get(2); assertFullyLinked(resources); boolean found = LinkOracle.links(td).stream().anyMatch(l -> "blue".equals(l.text) && l.isResolved() && l.target instanceof SimpleDataInstance && ((SimpleDataInstance) l.target).getDataType() instanceof EnumDataType); Assertions.assertTrue(found, "TD.tdltx must reference the implicitly typed value 'blue'"); for (Resource r : resources) { Assertions.assertTrue(r.getErrors().isEmpty(), r.getURI().lastSegment() + ": " + r.getErrors()); } } private static void assertFullyLinked(List<XtextResource> resources) { List<String> problems = new java.util.ArrayList<>(); for (XtextResource r : resources) { for (LinkOracle.Link l : LinkOracle.unresolved(r)) { problems.add(r.getURI().lastSegment() + ": " + l); } for (Resource.Diagnostic d : r.getErrors()) { problems.add(r.getURI().lastSegment() + ": error " + d.getMessage() + " (line " + d.getLine() + ")"); } } Assertions.assertTrue(problems.isEmpty(), "unresolved references / errors:\n " + String.join("\n ", problems)); } } plugins/org.etsi.mts.tdl.tx.tests/src/org/etsi/mts/tdl/tx/tests/Fixtures.java 0 → 100644 +95 −0 Changes for plugins/org.etsi.mts.tdl.tx.tests/src/org/etsi/mts/tdl/tx/tests/Fixtures.java: 95 added lines, 0 removed lines. Original line number Diff line number Diff line package org.etsi.mts.tdl.tx.tests; import java.io.File; import java.io.IOException; import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import org.eclipse.emf.common.util.URI; import org.eclipse.emf.ecore.resource.ResourceSet; import org.eclipse.xtext.resource.XtextResource; import org.eclipse.xtext.testing.util.ParseHelper; import org.etsi.mts.tdl.Package; /** * Locates the fixture modules of docs/reliability/11-test-suite-design.md * ({@code src/fixtures/<module>}) and loads them into a resource set in a * chosen order. F1 is the well-formed multi-file project; broken variants are * derived from it by the tests themselves. */ public final class Fixtures { /** The standard library file every project ships with (the project wizard copies it). */ public static final String STANDARD_LIBRARY = "TDL.tdltx"; /** F1 file names in dependency order (Data has no project imports, TD imports both others). */ public static final List<String> F1 = Arrays.asList("Data.tdltx", "Config.tdltx", "TD.tdltx"); private Fixtures() { } public static File libraryFolder() { String userDir = System.getProperty("user.dir"); File f = new File(userDir, "../org.etsi.mts.tdl.library/src/org/etsi/mts/tdl/library"); if (!f.exists()) { f = new File(userDir, "plugins/org.etsi.mts.tdl.library/src/org/etsi/mts/tdl/library"); } if (!f.exists()) { throw new IllegalStateException("TDL library folder not found (user.dir=" + userDir + ")"); } return f; } public static String standardLibrary() throws IOException { return new String(Files.readAllBytes(new File(libraryFolder(), STANDARD_LIBRARY).toPath()), StandardCharsets.UTF_8); } /** Parses the standard library into the resource set (without linking). */ public static XtextResource loadStandardLibrary(ParseHelper<Package> parseHelper, ResourceSet rs) throws Exception { URI uri = URI.createFileURI(new File(libraryFolder(), STANDARD_LIBRARY).getAbsolutePath()); Package pkg = parseHelper.parse(standardLibrary(), uri, rs); return (XtextResource) pkg.eResource(); } public static File folder(String module) { String userDir = System.getProperty("user.dir"); File f = new File(userDir, "src/fixtures/" + module); if (!f.exists()) { f = new File(userDir, "plugins/org.etsi.mts.tdl.tx.tests/src/fixtures/" + module); } if (!f.exists()) { // from a sibling test plugin (org.etsi.mts.tdl.tx.ui.tests) f = new File(userDir, "../org.etsi.mts.tdl.tx.tests/src/fixtures/" + module); } if (!f.exists()) { throw new IllegalStateException("fixture module not found: " + module + " (user.dir=" + userDir + ")"); } return f; } public static File file(String module, String name) { return new File(folder(module), name); } public static String content(String module, String name) throws IOException { return new String(Files.readAllBytes(file(module, name).toPath()), StandardCharsets.UTF_8); } /** Parses the given files of a module into the resource set, in the given order, without linking. */ public static List<XtextResource> load(ParseHelper<Package> parseHelper, ResourceSet rs, String module, List<String> names) throws Exception { List<XtextResource> result = new ArrayList<>(); for (String name : names) { result.add(load(parseHelper, rs, module, name, content(module, name))); } return result; } /** Parses {@code text} as if it were the given fixture file (used for broken/modified variants). */ public static XtextResource load(ParseHelper<Package> parseHelper, ResourceSet rs, String module, String name, String text) throws Exception { URI uri = URI.createFileURI(file(module, name).getAbsolutePath()); Package pkg = parseHelper.parse(text, uri, rs); return (XtextResource) pkg.eResource(); } } Loading
plugins/org.etsi.mts.tdl.tx.tests/src/fixtures/f1/Config.tdltx 0 → 100644 +21 −0 Changes for plugins/org.etsi.mts.tdl.tx.tests/src/fixtures/f1/Config.tdltx: 21 added lines, 0 removed lines. Original line number Diff line number Diff line // F1 multi-file fixture: gate/component/configuration definitions. Imports // F1Data (types used by the gate and the variables) and is imported by TD.tdltx. Package F1Config { Import all from TDL Import Shape, Point, Colour from F1Data // explicit import (TD.tdltx uses 'Import all') Message Gate shapeGate accepts Shape, Point, Colour, Integer Component Node { gate shapeGate g variable Integer count variable Shape lastShape timer t } Configuration Basic { Node tester as Tester, Node sut as SUT, connect tester::g to sut::g } }
plugins/org.etsi.mts.tdl.tx.tests/src/fixtures/f1/Data.tdltx 0 → 100644 +39 −0 Changes for plugins/org.etsi.mts.tdl.tx.tests/src/fixtures/f1/Data.tdltx: 39 added lines, 0 removed lines. Original line number Diff line number Diff line // F1 multi-file fixture (docs/reliability/11-test-suite-design.md): data // definitions imported by Config.tdltx and TD.tdltx. Every kind of element // that the other files reference across the file boundary lives here. Package F1Data { Import all from TDL Enumerated Colour { Colour red, // explicit type green, // implicit: typed by the enclosing enumeration blue } Type Id Id id1 Id id2 Structure Point ( Integer x, Integer y ) Collection Points of Point Structure Shape ( Id id, Colour colour, Points outline ) Point origin ( x = 0, y = 0 ) Point unit ( x = 1, y = 1 ) Points square [ origin, unit ] Shape shape1 ( id = id1, colour = red, outline = square ) Shape shape2 ( id = id2, colour = green, outline = square ) second oneSecond second twoSeconds Function area ( Shape s ) returns Integer : "area of a shape" }
plugins/org.etsi.mts.tdl.tx.tests/src/fixtures/f1/TD.tdltx 0 → 100644 +30 −0 Changes for plugins/org.etsi.mts.tdl.tx.tests/src/fixtures/f1/TD.tdltx: 30 added lines, 0 removed lines. Original line number Diff line number Diff line // F1 multi-file fixture: test descriptions. References data (F1Data) and the // configuration, component instances, gates and timers (F1Config) across two // file boundaries; also references an element (Basic) that itself references // a third file (Node -> shapeGate -> Shape). Package F1TD { Import all from TDL Import all from F1Data Import all from F1Config Test Description sendShape uses Basic { tester::g sends shape1 to sut::g sut::g sends shape2 ( colour = blue ) to tester::g tester::g receives shape1 ( colour = ?, outline = square ) from sut::g set verdict to pass } Test Description withTimers uses Basic { start tester::t for oneSecond tester::g sends origin to sut::g alternatively { tester::g receives unit from sut::g stop tester::t set verdict to pass } or { timeout on tester::t set verdict to fail } wait for twoSeconds on tester } }
plugins/org.etsi.mts.tdl.tx.tests/src/org/etsi/mts/tdl/tx/tests/EnumTypingTest.java 0 → 100644 +97 −0 Changes for plugins/org.etsi.mts.tdl.tx.tests/src/org/etsi/mts/tdl/tx/tests/EnumTypingTest.java: 97 added lines, 0 removed lines. Original line number Diff line number Diff line package org.etsi.mts.tdl.tx.tests; import java.io.File; import java.util.List; import org.eclipse.emf.ecore.resource.Resource; import org.eclipse.xtext.resource.XtextResource; import org.eclipse.xtext.serializer.ISerializer; import org.eclipse.xtext.validation.Issue; import org.etsi.mts.tdl.EnumDataType; import org.etsi.mts.tdl.Package; import org.etsi.mts.tdl.SimpleDataInstance; import org.etsi.mts.tdl.tdlPackage; import org.etsi.mts.tdl.tx.tests.oracle.LinkOracle; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; import com.google.inject.Inject; /** * Task 2.2 / experiment X5: enumeration values are typed by their enclosing * enumeration without derived state — on read, for EMF multiplicity checks, * for cross-file references, and without leaking into the serialised text. */ public class EnumTypingTest extends TDLtxAbstractTest { @Inject ISerializer serializer; @Override public void verifySingleModel(File file) { } private EnumDataType colour() throws Exception { Fixtures.loadStandardLibrary(parseHelper, rs); XtextResource data = Fixtures.load(parseHelper, rs, "f1", Fixtures.F1).get(0); Package pkg = (Package) data.getContents().get(0); return (EnumDataType) pkg.getPackagedElement().stream().filter(e -> "Colour".equals(e.getName())).findFirst().orElseThrow(); } @Test public void implicitValuesAreTypedByTheEnumeration() throws Exception { EnumDataType colour = colour(); Assertions.assertEquals(3, colour.getValue().size()); for (SimpleDataInstance v : colour.getValue()) { Assertions.assertSame(colour, v.getDataType(), v.getName() + ".getDataType()"); Assertions.assertSame(colour, v.eGet(tdlPackage.Literals.DATA_INSTANCE__DATA_TYPE, false), v.getName() + " eGet(resolve=false)"); Assertions.assertTrue(v.eIsSet(tdlPackage.Literals.DATA_INSTANCE__DATA_TYPE), v.getName() + " eIsSet"); } } @Test public void noMultiplicityOrTypeIssuesOnEnumValues() throws Exception { EnumDataType colour = colour(); List<Issue> issues = validationHelper.validate(colour.eResource()); for (Issue i : issues) { boolean aboutValue = i.getUriToProblem() != null && i.getUriToProblem().fragment() != null && colour.getValue().stream() .anyMatch(v -> i.getUriToProblem().fragment().equals(v.eResource().getURIFragment(v))); Assertions.assertFalse(aboutValue, "issue on an enum value: " + i); } } @Test public void implicitTypeIsNotSerialised() throws Exception { EnumDataType colour = colour(); String text = serializer.serialize(colour); Assertions.assertTrue(text.contains("Colour red"), "explicit type kept: " + text); Assertions.assertFalse(text.contains("Colour green") || text.contains("Colour blue"), "implicit types must stay implicit: " + text); } @Test public void crossFileReferenceToAnImplicitValueResolves() throws Exception { Fixtures.loadStandardLibrary(parseHelper, rs); List<XtextResource> resources = Fixtures.load(parseHelper, rs, "f1", Fixtures.F1); XtextResource td = resources.get(2); assertFullyLinked(resources); boolean found = LinkOracle.links(td).stream().anyMatch(l -> "blue".equals(l.text) && l.isResolved() && l.target instanceof SimpleDataInstance && ((SimpleDataInstance) l.target).getDataType() instanceof EnumDataType); Assertions.assertTrue(found, "TD.tdltx must reference the implicitly typed value 'blue'"); for (Resource r : resources) { Assertions.assertTrue(r.getErrors().isEmpty(), r.getURI().lastSegment() + ": " + r.getErrors()); } } private static void assertFullyLinked(List<XtextResource> resources) { List<String> problems = new java.util.ArrayList<>(); for (XtextResource r : resources) { for (LinkOracle.Link l : LinkOracle.unresolved(r)) { problems.add(r.getURI().lastSegment() + ": " + l); } for (Resource.Diagnostic d : r.getErrors()) { problems.add(r.getURI().lastSegment() + ": error " + d.getMessage() + " (line " + d.getLine() + ")"); } } Assertions.assertTrue(problems.isEmpty(), "unresolved references / errors:\n " + String.join("\n ", problems)); } }
plugins/org.etsi.mts.tdl.tx.tests/src/org/etsi/mts/tdl/tx/tests/Fixtures.java 0 → 100644 +95 −0 Changes for plugins/org.etsi.mts.tdl.tx.tests/src/org/etsi/mts/tdl/tx/tests/Fixtures.java: 95 added lines, 0 removed lines. Original line number Diff line number Diff line package org.etsi.mts.tdl.tx.tests; import java.io.File; import java.io.IOException; import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import org.eclipse.emf.common.util.URI; import org.eclipse.emf.ecore.resource.ResourceSet; import org.eclipse.xtext.resource.XtextResource; import org.eclipse.xtext.testing.util.ParseHelper; import org.etsi.mts.tdl.Package; /** * Locates the fixture modules of docs/reliability/11-test-suite-design.md * ({@code src/fixtures/<module>}) and loads them into a resource set in a * chosen order. F1 is the well-formed multi-file project; broken variants are * derived from it by the tests themselves. */ public final class Fixtures { /** The standard library file every project ships with (the project wizard copies it). */ public static final String STANDARD_LIBRARY = "TDL.tdltx"; /** F1 file names in dependency order (Data has no project imports, TD imports both others). */ public static final List<String> F1 = Arrays.asList("Data.tdltx", "Config.tdltx", "TD.tdltx"); private Fixtures() { } public static File libraryFolder() { String userDir = System.getProperty("user.dir"); File f = new File(userDir, "../org.etsi.mts.tdl.library/src/org/etsi/mts/tdl/library"); if (!f.exists()) { f = new File(userDir, "plugins/org.etsi.mts.tdl.library/src/org/etsi/mts/tdl/library"); } if (!f.exists()) { throw new IllegalStateException("TDL library folder not found (user.dir=" + userDir + ")"); } return f; } public static String standardLibrary() throws IOException { return new String(Files.readAllBytes(new File(libraryFolder(), STANDARD_LIBRARY).toPath()), StandardCharsets.UTF_8); } /** Parses the standard library into the resource set (without linking). */ public static XtextResource loadStandardLibrary(ParseHelper<Package> parseHelper, ResourceSet rs) throws Exception { URI uri = URI.createFileURI(new File(libraryFolder(), STANDARD_LIBRARY).getAbsolutePath()); Package pkg = parseHelper.parse(standardLibrary(), uri, rs); return (XtextResource) pkg.eResource(); } public static File folder(String module) { String userDir = System.getProperty("user.dir"); File f = new File(userDir, "src/fixtures/" + module); if (!f.exists()) { f = new File(userDir, "plugins/org.etsi.mts.tdl.tx.tests/src/fixtures/" + module); } if (!f.exists()) { // from a sibling test plugin (org.etsi.mts.tdl.tx.ui.tests) f = new File(userDir, "../org.etsi.mts.tdl.tx.tests/src/fixtures/" + module); } if (!f.exists()) { throw new IllegalStateException("fixture module not found: " + module + " (user.dir=" + userDir + ")"); } return f; } public static File file(String module, String name) { return new File(folder(module), name); } public static String content(String module, String name) throws IOException { return new String(Files.readAllBytes(file(module, name).toPath()), StandardCharsets.UTF_8); } /** Parses the given files of a module into the resource set, in the given order, without linking. */ public static List<XtextResource> load(ParseHelper<Package> parseHelper, ResourceSet rs, String module, List<String> names) throws Exception { List<XtextResource> result = new ArrayList<>(); for (String name : names) { result.add(load(parseHelper, rs, module, name, content(module, name))); } return result; } /** Parses {@code text} as if it were the given fixture file (used for broken/modified variants). */ public static XtextResource load(ParseHelper<Package> parseHelper, ResourceSet rs, String module, String name, String text) throws Exception { URI uri = URI.createFileURI(file(module, name).getAbsolutePath()); Package pkg = parseHelper.parse(text, uri, rs); return (XtextResource) pkg.eResource(); } }