Commit bccc0869 authored by Martti Käärik's avatar Martti Käärik
Browse files

Serialization tests should try clean from-model serialization + reparse after...

Serialization tests should try clean from-model serialization + reparse after serialization to check model conformance.
parent bada1fc6
Loading
Loading
Loading
Loading
+14 −2
Changes for plugins/org.etsi.mts.tdl.tx.tests/src/org/etsi/mts/tdl/tx/tests/TDLtxAbstractTest.java: 14 added lines, 2 removed lines.
Original line number Diff line number Diff line
@@ -69,14 +69,26 @@ public abstract class TDLtxAbstractTest {
		if (libraryDir != null && libraryDir.exists()) {
			File[] libs = libraryDir.listFiles((dir, name) -> name.endsWith(".tdltx"));
			if (libs != null) {
				// A library that does not parse is loaded as a truncated package. If it shares
				// its name with another library it silently shadows the complete one, and every
				// reference into it fails to link. Fail the suite, naming all broken libraries.
				List<String> broken = new ArrayList<>();
				for (File lib : libs) {
					String content = new String(java.nio.file.Files.readAllBytes(lib.toPath()));
					URI uri = URI.createFileURI(lib.getAbsolutePath());
					try {
						parseHelper.parse(content, uri, rs);
						Package library = parseHelper.parse(content, uri, rs);
						if (library == null) {
							broken.add(lib.getName() + ": no content");
						} else if (!library.eResource().getErrors().isEmpty()) {
							broken.add(lib.getName() + ": " + library.eResource().getErrors());
						}
					} catch (Exception e) {
						System.out.println("Warning: could not load library " + lib.getName() + ": " + e.getMessage());
						broken.add(lib.getName() + ": " + e);
					}
				}
				if (!broken.isEmpty()) {
					throw new AssertionError("Syntax errors in libraries:" + System.lineSeparator() + "  " + String.join(System.lineSeparator() + "  ", broken));
				}
			}
		}
+53 −10
Changes for plugins/org.etsi.mts.tdl.tx.tests/src/org/etsi/mts/tdl/tx/tests/TDLtxSerialisationTest.java: 53 added lines, 10 removed lines.
Original line number Diff line number Diff line
package org.etsi.mts.tdl.tx.tests;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.OutputStream;
import java.nio.file.Files;
import java.nio.charset.StandardCharsets;
import java.util.Collection;

import org.eclipse.emf.common.util.URI;
@@ -46,6 +46,11 @@ public class TDLtxSerialisationTest extends TDLtxAbstractTest {

	}

	/**
	 * Round trip: parse, link, serialise a detached copy (no node model, so the serializer
	 * has to work from the semantic model alone), parse the serialised text again and
	 * compare it with the original model.
	 */
	@Override
	public void verifySingleModel(File file) throws Exception {
		String extension = "tdltx";
@@ -62,26 +67,64 @@ public class TDLtxSerialisationTest extends TDLtxAbstractTest {
		Assertions.assertTrue(result.eResource().getErrors().isEmpty(),
			"Syntax errors in " + fileName + ": " + result.eResource().getErrors());

		// Resolve all cross-references before serialising: the serializer can only fall back
		// to the original text for an unresolved reference when a node model is present, so an
		// unresolved reference in the copy below surfaces as an opaque backtracking failure.
		// Report it as what it is.
		EcoreUtil.resolveAll(result);
		Assertions.assertTrue(result.eResource().getErrors().isEmpty(),
			"Linking errors in " + fileName + ": " + result.eResource().getErrors());

		//NOTE: this requires manual registration of validator when running in eclipse, completeOCL initialisation when running in maven
		//TODO: disabled — JUnit validation differs from editor (some constraints produce ERRORs in JUnit that are WARNINGs or absent in editor)
		//validationHelper.assertNoErrors(result);

		URI targetURI = URI.createURI(uri.toString()+"."+extension);
//		XtextResourceSet resourceSet = injector.getInstance(XtextResourceSet.class);
//		resourceSet = rs;
		URI roundTripURI = URI.createURI(uri.toString()+".roundtrip."+extension);
		Resource tr = rs.createResource(targetURI);
		
		Resource reparsed = null;
		try {
			tr.getContents().add(EcoreUtil.copy(result));
			String serialised;
			try {
			//NOTE: only resolve within the copied resource, not into library
			//      resources (TDL library has ^true/^false which can't be serialised)
			EcoreUtil.resolveAll(result);
			tr.save(OutputStream.nullOutputStream(), null);
				ByteArrayOutputStream out = new ByteArrayOutputStream();
				tr.save(out, null);
				serialised = out.toString(StandardCharsets.UTF_8);
			} catch (Exception e1) {
				System.err.println("  Serialisation: "+e1.getMessage());
			//e1.printStackTrace();
				Assertions.fail(e1.getMessage(), e1);
				//TODO: provide an error dialog, fall back to XF, indicate approximate location based on error message / details
				return;
			}

			// The serialised text has to parse, link and denote the same model. This is what
			// catches a serializer that picks a syntactically valid but semantically different
			// form, such as dropping the parentheses around a lower-precedence operand.
			Package roundTrip = parseHelper.parse(serialised, roundTripURI, rs);
			Assertions.assertNotNull(roundTrip, "Serialised text of " + fileName + " did not parse:\n" + serialised);
			reparsed = roundTrip.eResource();
			Assertions.assertTrue(reparsed.getErrors().isEmpty(),
				"Syntax errors in serialised text of " + fileName + ": " + reparsed.getErrors() + "\n" + serialised);
			EcoreUtil.resolveAll(roundTrip);
			Assertions.assertTrue(reparsed.getErrors().isEmpty(),
				"Linking errors in serialised text of " + fileName + ": " + reparsed.getErrors() + "\n" + serialised);

			StringBuilder expected = new StringBuilder();
			dumpStructure(result, expected, 0);
			StringBuilder actual = new StringBuilder();
			dumpStructure(roundTrip, actual, 0);
			Assertions.assertEquals(expected.toString(), actual.toString(),
				"Structure of " + fileName + " changed on round trip. Serialised text:\n" + serialised);
			Assertions.assertTrue(EcoreUtil.equals(result, roundTrip),
				"Model of " + fileName + " changed on round trip. Serialised text:\n" + serialised);
		} finally {
			// keep the shared resource set free of duplicate packages for the next model
			for (Resource r : new Resource[] { tr, reparsed }) {
				if (r != null) {
					r.unload();
					rs.getResources().remove(r);
				}
			}
		}
	}