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

Apply Runtime constants

parent 55e2182a
Loading
Loading
Loading
Loading
+72 −72
Original line number Diff line number Diff line
@@ -116,8 +116,8 @@ public class JUnitTestGenerator extends Renderer {

	public static final String PACKAGE_PREFIX = "org.etsi.mts.tdl.execution.java",
			CORE_PACKAGE = PACKAGE_PREFIX + ".rt.core", TRI_PACKAGE = PACKAGE_PREFIX + ".tri",
			TESTER_CLASS = "TestControl", COMPONENT_FIELD = "tc", FUNCTIONS_FIELD = COMPONENT_FIELD + ".functions", SYSTEM_ADAPTER_FIELD = COMPONENT_FIELD + ".systemAdapter",
			VALIDATOR_FIELD = COMPONENT_FIELD + ".validator", REPORTER_FIELD = COMPONENT_FIELD + ".reporter", HELPER_FIELD = "runtimeHelper",
			TESTER_CLASS = "TestControl", COMPONENT_FIELD = "tc", FUNCTIONS_FIELD = COMPONENT_FIELD + "." + RuntimeApi.FUNCTIONS, SYSTEM_ADAPTER_FIELD = COMPONENT_FIELD + "." + RuntimeApi.SYSTEM_ADAPTER,
			VALIDATOR_FIELD = COMPONENT_FIELD + "." + RuntimeApi.VALIDATOR, REPORTER_FIELD = COMPONENT_FIELD + "." + RuntimeApi.REPORTER, HELPER_FIELD = "runtimeHelper",
			DECLARED_TYPES_FIELD = "declared_types";

	public static final String COMPONENT_CLASS_SUFFIX = "_Component", BEHAVIOR_METHOD_PREFIX = "td_",
@@ -159,7 +159,7 @@ public class JUnitTestGenerator extends Renderer {
			keyValues.add(PROPERTY_KEYS + "." + key);
			keyValues.add(value);
		});
		return PROPERTIES_CLASS + ".of(" + String.join(", ", keyValues) + ")";
		return PROPERTIES_CLASS + "." + RuntimeApi.OF + "(" + String.join(", ", keyValues) + ")";
	}

	protected Map<MappableDataElement, Set<DataElementMapping>> elementMappings = new Hashtable<MappableDataElement, Set<DataElementMapping>>();
@@ -495,18 +495,18 @@ public class JUnitTestGenerator extends Renderer {
		newLine();
		line("ComponentExecutor executor = new ComponentExecutor();");
		for (String tClass : testerClasses)
			line("executor.addTest(a" + tClass + ".getTestControl(), () -> a" + tClass + ".test_" + tdName + "());");
			line("executor." + RuntimeApi.ADD_TEST + "(a" + tClass + ".getTestControl(), () -> a" + tClass + ".test_" + tdName + "());");

		newLine();
		append("try");
		blockOpen();
		line("executor.execute();");
		line("executor." + RuntimeApi.EXECUTE + "();");
		blockClose();
		append("finally");
		blockOpen();
		lineComment("End the test scope for every component.");
		for (String tClass : testerClasses)
			line("a" + tClass + ".getTestControl().shutdown();");
			line("a" + tClass + ".getTestControl()." + RuntimeApi.SHUTDOWN + "();");
		blockClose();

		blockClose();
@@ -656,7 +656,7 @@ public class JUnitTestGenerator extends Renderer {
			callClose();

		});
		append(COMPONENT_FIELD + ".configure(new Connection[] {");
		append(COMPONENT_FIELD + "." + RuntimeApi.CONFIGURE + "(new Connection[] {");
		boolean first = true;
		for (String cn : connectionNames) {
			if (!first)
@@ -681,7 +681,7 @@ public class JUnitTestGenerator extends Renderer {
		blockOpen();
		lineComment("End the test scope: release ports/clients and stop processing");
		lineComment("any messages arriving after the test behaviour has completed.");
		line(COMPONENT_FIELD + ".shutdown();");
		line(COMPONENT_FIELD + "." + RuntimeApi.SHUTDOWN + "();");
		blockClose();
		newLine();
	}
@@ -703,12 +703,12 @@ public class JUnitTestGenerator extends Renderer {
	}

	private void writeGetConnection(GateReference tester, GateReference remote) {
		append(COMPONENT_FIELD + ".getConnection(\"" + tester.getComponent().getName() + "\", \"" + tester.getGate().getName() + "\", \""
		append(COMPONENT_FIELD + "." + RuntimeApi.GET_CONNECTION + "(\"" + tester.getComponent().getName() + "\", \"" + tester.getGate().getName() + "\", \""
				+ remote.getComponent().getName() + "\", \"" + remote.getGate().getName() + "\")");
	}

	private void writeGetGateReference(GateReference tester) {
		append(COMPONENT_FIELD + ".getGateReference(\"" + tester.getComponent().getName() + "\", \"" + tester.getGate().getName() + "\")");
		append(COMPONENT_FIELD + "." + RuntimeApi.GET_GATE_REFERENCE + "(\"" + tester.getComponent().getName() + "\", \"" + tester.getGate().getName() + "\")");
	}

	private void declareUnmappedTypes(TestDescription tc) {
@@ -798,7 +798,7 @@ public class JUnitTestGenerator extends Renderer {
					DataElementMapping superMapping = getMapping(superType);
					if (superMapping != null) {
						String superMappingName = typeVariables.get(superType) + "_mapping";
						line(mappingName + ".setParent(" + superMappingName + ");");
						line(mappingName + "." + RuntimeApi.SET_PARENT + "(" + superMappingName + ");");
					}
				}
			}
@@ -808,17 +808,17 @@ public class JUnitTestGenerator extends Renderer {
		writeSetName(t);
		writeAddAnnotations(t);
		if (mapping != null) {
			line(".setMapping(" + mappingName + ")");
			line("." + RuntimeApi.SET_MAPPING + "(" + mappingName + ")");
		}
		if (t instanceof StructuredDataType) {
			line(".setIsStructure(true)");
			line("." + RuntimeApi.SET_IS_STRUCTURE + "(true)");
			for (Member m : ((StructuredDataType) t).allMembers()) {
				line(".setParameter(\"" + m.getName() + "\", " + typeVariables.get(m.getDataType()) + ")");
				line("." + RuntimeApi.SET_PARAMETER + "(\"" + m.getName() + "\", " + typeVariables.get(m.getDataType()) + ")");
			}

		} else if (t instanceof CollectionDataType) {
			line(".setIsCollection(true)");
			line(".setItemType(" + typeVariables.get(((CollectionDataType) t).getItemType()) + ")");
			line("." + RuntimeApi.SET_IS_COLLECTION + "(true)");
			line("." + RuntimeApi.SET_ITEM_TYPE + "(" + typeVariables.get(((CollectionDataType) t).getItemType()) + ")");
		}
		line(";");

@@ -852,7 +852,7 @@ public class JUnitTestGenerator extends Renderer {
		append(".setResource");
		blockOpenParen();
		line("new " + CORE_PACKAGE + ".MappingImpl(\"" + name + "\", \"" + rsMapping.getResourceURI() + "\")");
		line(".setIsResource(true)");
		line("." + RuntimeApi.SET_IS_RESOURCE + "(true)");
		writeAddAnnotations(rsMapping);
		blockCloseParen();
		
@@ -862,7 +862,7 @@ public class JUnitTestGenerator extends Renderer {
			blockOpenParen();
			line("\"" + pName + "\", ");
			line("new " + CORE_PACKAGE + ".MappingImpl(\"" + name + "\", \"" + pMapping.getParameterURI() + "\")");
			line(".setIsParameter(true)");
			line("." + RuntimeApi.SET_IS_PARAMETER + "(true)");
			writeAddAnnotations(pMapping);
			blockCloseParen();
		}
@@ -872,13 +872,13 @@ public class JUnitTestGenerator extends Renderer {
	}

	private void writeSetName(NamedElement e) {
		line(".setName(\"" + e.getName() + "\", \"" + e.getQualifiedName() + "\")");
		line("." + RuntimeApi.SET_NAME + "(\"" + e.getName() + "\", \"" + e.getQualifiedName() + "\")");
	}

	private void writeAddAnnotations(Element e) {
		for (Annotation a : e.getAnnotation()) {
			String value = a.getValue();
			line(".addAnnotation(\"" + a.getKey().getQualifiedName() + "\", "
			line("." + RuntimeApi.ADD_ANNOTATION + "(\"" + a.getKey().getQualifiedName() + "\", "
					+ (value != null ? "\"" + a.getValue() + "\"" : "null") + ")");
		}
	}
@@ -934,9 +934,9 @@ public class JUnitTestGenerator extends Renderer {
				append("catch (" + ex + " e)");
				blockOpen();
				if (ex.equals(STOP_EXCEPTION)) {
					append("if (e.getVerdict() != null)");
					append("if (e." + RuntimeApi.GET_VERDICT + "() != null)");
					blockOpen();
					line(VALIDATOR_FIELD + ".setVerdict(e.getVerdict());");
					line(VALIDATOR_FIELD + ".setVerdict(e." + RuntimeApi.GET_VERDICT + "());");
					blockClose();
				}
				line("throw new " + ASSERTION_EXCEPTION + "(e.getMessage());");
@@ -945,7 +945,7 @@ public class JUnitTestGenerator extends Renderer {
		}
		append("catch (RuntimeException e)");
		blockOpen();
		line(REPORTER_FIELD + ".runtimeError(" + COMPONENT_FIELD + ".getTesterComponent().getName(), " + "e);");
		line(REPORTER_FIELD + ".runtimeError(" + COMPONENT_FIELD + "." + RuntimeApi.GET_TESTER_COMPONENT + "().getName(), " + "e);");
		line("throw e;");
		blockClose();

@@ -1054,7 +1054,7 @@ public class JUnitTestGenerator extends Renderer {
				append("while (!Thread.interrupted()) ");
				blockOpen();
				line("long sleepTime = nextExecution - System.currentTimeMillis();");
				line("if (sleepTime > 0) Thread.sleep(sleepTime);");
				line("if (sleepTime > 0) Thread." + RuntimeApi.SLEEP + "(sleepTime);");

				write(pb.getBlock(), null, null, thrownExceptions);

@@ -1102,7 +1102,7 @@ public class JUnitTestGenerator extends Renderer {
				Set<String> innerExceptions = new HashSet<String>();
				write(eb.getBlock(), exceptionalBehaviourName, null, innerExceptions);

				line(COMPONENT_FIELD + ".addExceptionalBehaviour(" + exceptionalBehaviourName + ");");
				line(COMPONENT_FIELD + "." + RuntimeApi.ADD_EXCEPTIONAL_BEHAVIOUR + "(" + exceptionalBehaviourName + ");");
				newLine();
				exceptionalBehaviours.add(exceptionalBehaviourName);
			}
@@ -1221,7 +1221,7 @@ public class JUnitTestGenerator extends Renderer {
				if (verdict != null)
					write(((Assertion) b).getOtherwise(), dataUseVariables);
				else
					append("VerdictImpl.fail");
					append("VerdictImpl." + RuntimeApi.FAIL);
				line(");");

				writeAssertionFailure(b, condition, dataUseVariables);
@@ -1244,14 +1244,14 @@ public class JUnitTestGenerator extends Renderer {

				// Indirect throw via helper so the JLS reachability check accepts any
				// generated code that follows (e.g. cleanup or trailing siblings).
				line(COMPONENT_FIELD + ".breakBlock(\"" + getElementName(bl) + "\");");
				line(COMPONENT_FIELD + "." + RuntimeApi.BREAK_BLOCK + "(\"" + getElementName(bl) + "\");");
				thrownExceptions.add(BREAK_EXCEPTION);

			} else if (b instanceof Stop) {

				// Indirect throw via helper so the JLS reachability check accepts any
				// generated code that follows (e.g. cleanup or trailing siblings).
				line(COMPONENT_FIELD + ".terminate(\"Stop " + getQName(b) + "\");");
				line(COMPONENT_FIELD + "." + RuntimeApi.TERMINATE + "(\"Stop " + getQName(b) + "\");");
				thrownExceptions.add(STOP_EXCEPTION);

			}
@@ -1270,7 +1270,7 @@ public class JUnitTestGenerator extends Renderer {
				line(");");

			} else if (b instanceof TimerStop) {
				append(COMPONENT_FIELD + "." + getTimerName(((TimerOperation) b).getTimer()) + ".stop();");
				append(COMPONENT_FIELD + "." + getTimerName(((TimerOperation) b).getTimer()) + "." + RuntimeApi.TIMER_STOP + "();");

			} else if (b instanceof TimeOut) {
				FutureInfo futureInfo = writeTesterInput(b, dataUseVariables);
@@ -1280,7 +1280,7 @@ public class JUnitTestGenerator extends Renderer {
			// Gate operations
			else if (b instanceof Wait) {
				FutureInfo futureInfo = declareFuture(b, dataUseVariables);
				line(futureInfo.varName + ".execute().get();");
				line(futureInfo.varName + "." + RuntimeApi.EXECUTE + "().get();");

			} else if (b instanceof Quiescence) {
				FutureInfo futureInfo = writeTesterInput(b, dataUseVariables);
@@ -1530,13 +1530,13 @@ public class JUnitTestGenerator extends Renderer {
				// expectable has been added, so an exceptional cannot lose its message to
				// an alternative simply because of submission ordering.
				line("BatchedFutures " + batchName + " = " + COMPONENT_FIELD
						+ ".executeAlternativesAndExceptionals(" + callablesListName + ");");
				line("List<Future<ExecutionResult>> " + futuresName + " = " + batchName + ".alternatives;");
				line("List<Future<ExecutionResult>> " + excName + " = " + batchName + ".exceptionals;");
						+ "." + RuntimeApi.EXECUTE_ALTERNATIVES_AND_EXCEPTIONALS + "(" + callablesListName + ");");
				line("List<Future<ExecutionResult>> " + futuresName + " = " + batchName + "." + RuntimeApi.ALTERNATIVES + ";");
				line("List<Future<ExecutionResult>> " + excName + " = " + batchName + "." + RuntimeApi.EXCEPTIONALS + ";");
				newLine();

				// Wait for first completion
				line("Future<ExecutionResult> " + winnerName + " = " + COMPONENT_FIELD + ".next();");
				line("Future<ExecutionResult> " + winnerName + " = " + COMPONENT_FIELD + "." + RuntimeApi.NEXT + "();");
				line("boolean " + interruptedName + " = false;");
				newLine();

@@ -1568,7 +1568,7 @@ public class JUnitTestGenerator extends Renderer {
						// Single tester-input: value assignments + timeout handling
						writeResultHandling(f.b, dataUseVariables);
						if (f.kind.equals("TimeoutResult")) {
							line(COMPONENT_FIELD + ".terminate(\"Timeout\");");
							line(COMPONENT_FIELD + "." + RuntimeApi.TERMINATE + "(\"" + escape(f.terminationMessage) + "\");");
							thrownExceptions.add(STOP_EXCEPTION);
						}
					}
@@ -1580,11 +1580,11 @@ public class JUnitTestGenerator extends Renderer {
				append(" else ");
				blockOpen();
				line("ExceptionalBehaviour exceptionalBehaviour = " + COMPONENT_FIELD
						+ ".getExceptionalBehaviour(" + winnerName + ");");
						+ "." + RuntimeApi.GET_EXCEPTIONAL_BEHAVIOUR + "(" + winnerName + ");");
				append("if (exceptionalBehaviour != null) ");
				blockOpen();
				line("exceptionalBehaviour.behaviour.execute();");
				line(interruptedName + " = exceptionalBehaviour.isInterrupt;");
				line("exceptionalBehaviour.behaviour." + RuntimeApi.EXECUTE + "();");
				line(interruptedName + " = exceptionalBehaviour." + RuntimeApi.IS_INTERRUPT + ";");
				blockClose();
				blockClose();
				thrownExceptions.add(STOP_EXCEPTION);
@@ -1600,10 +1600,10 @@ public class JUnitTestGenerator extends Renderer {
				blockOpen();

				// Cleanup
				line(COMPONENT_FIELD + ".cleanupBatch(" + batchName + ");");
				line(futuresName + ".forEach(f -> " + COMPONENT_FIELD + ".stop(f));");
				line(excName + ".forEach(f -> " + COMPONENT_FIELD + ".stop(f));");
				line(COMPONENT_FIELD + ".resumeReceiving();");
				line(COMPONENT_FIELD + "." + RuntimeApi.CLEANUP_BATCH + "(" + batchName + ");");
				line(futuresName + ".forEach(f -> " + COMPONENT_FIELD + "." + RuntimeApi.STOP + "(f));");
				line(excName + ".forEach(f -> " + COMPONENT_FIELD + "." + RuntimeApi.STOP + "(f));");
				line(COMPONENT_FIELD + "." + RuntimeApi.RESUME_RECEIVING + "();");

				blockClose();

@@ -1647,7 +1647,7 @@ public class JUnitTestGenerator extends Renderer {

		newLine();
		exceptionalBehaviours.forEach(eb -> {
			line(COMPONENT_FIELD + ".removeExceptionalBehaviour(" + eb + ");");
			line(COMPONENT_FIELD + "." + RuntimeApi.REMOVE_EXCEPTIONAL_BEHAVIOUR + "(" + eb + ");");
		});

		blockClose();
@@ -1669,7 +1669,7 @@ public class JUnitTestGenerator extends Renderer {
					append(COMPONENT_FIELD + "." + getElementName(var));
					append(" = ");
					append("(" + getJavaType(var.getDataType()) + ")");
					line("result.data.getValue();");
					line("result." + RuntimeApi.DATA + ".getValue();");
				}
			}
		}
@@ -1738,10 +1738,10 @@ public class JUnitTestGenerator extends Renderer {
						// Initiating behaviour
						lineComment("This gets executed automatically with all interactions");
						FutureInfo callable = writeTesterInput(b, dataUseVariables);
						line(exceptionalBehaviourName + ".setCallable(" + callable.varName + ");");
						line(exceptionalBehaviourName + "." + RuntimeApi.SET_CALLABLE + "(" + callable.varName + ");");
						newLine();

						append(exceptionalBehaviourName + ".behaviour = () -> ");
						append(exceptionalBehaviourName + "." + RuntimeApi.BEHAVIOUR + " = () -> ");
						blockOpen();

						writeNotification((ExceptionalBehaviour) bl.eContainer(), true);
@@ -1749,7 +1749,7 @@ public class JUnitTestGenerator extends Renderer {
						lineComment("Protect the handler body: suspend all active exceptional behaviours");
						lineComment("(siblings, outer defaults/interrupts and this one) for its duration.");
						line("List<ExceptionalBehaviour> " + exceptionalBehaviourName
								+ "_suspended = " + COMPONENT_FIELD + ".disableActiveExceptionalBehaviours();");
								+ "_suspended = " + COMPONENT_FIELD + "." + RuntimeApi.DISABLE_ACTIVE_EXCEPTIONAL_BEHAVIOURS + "();");
						newLine();

						append("try");
@@ -1778,7 +1778,7 @@ public class JUnitTestGenerator extends Renderer {
			blockOpen();

			lineComment("Re-enable the suspended exceptional behaviours");
			line(COMPONENT_FIELD + ".enableExceptionalBehaviours(" + exceptionalBehaviourName + "_suspended);");
			line(COMPONENT_FIELD + "." + RuntimeApi.ENABLE_EXCEPTIONAL_BEHAVIOURS + "(" + exceptionalBehaviourName + "_suspended);");

			writeNotification((ExceptionalBehaviour) bl.eContainer(), false);
			blockClose();
@@ -1800,7 +1800,7 @@ public class JUnitTestGenerator extends Renderer {
		if (myThrownExceptions.contains(BREAK_EXCEPTION)) {
			append("catch (" + BREAK_EXCEPTION + " e)");
			blockOpen();
			line("if (\"" + getElementName(bl) + "\".equals(e.getBlockName()))");
			line("if (\"" + getElementName(bl) + "\".equals(e." + RuntimeApi.GET_BLOCK_NAME + "()))");
			lineInc(bl.container() instanceof CompoundBehaviour ? "return;" : "break;");
			line("else");
			lineInc("throw e;");
@@ -1842,7 +1842,7 @@ public class JUnitTestGenerator extends Renderer {
			String futureName = "timeout_" + getElementName(b);

			String timerName = getTimerName(((TimerOperation) b).getTimer());
			append("ExecutionCallable timeout_" + getElementName(b) + " = " + COMPONENT_FIELD + ".timeout(" + COMPONENT_FIELD + "." + timerName + ")");
			append("ExecutionCallable timeout_" + getElementName(b) + " = " + COMPONENT_FIELD + "." + RuntimeApi.TIMEOUT + "(" + COMPONENT_FIELD + "." + timerName + ")");
			line(";");

			return new FutureInfo(futureName, "TimeoutResult", b);
@@ -1853,7 +1853,7 @@ public class JUnitTestGenerator extends Renderer {
			DataUse period = ((TimeOperation) b).getPeriod();
			initializeDataUse(period, dataUseVariables);

			append("ExecutionCallable " + futureName + " = " + COMPONENT_FIELD + ".sleep(");
			append("ExecutionCallable " + futureName + " = " + COMPONENT_FIELD + "." + RuntimeApi.SLEEP + "(");
			write(period, dataUseVariables);
			append(")");
			line(";");
@@ -1866,7 +1866,7 @@ public class JUnitTestGenerator extends Renderer {
			DataUse period = ((TimeOperation) b).getPeriod();
			initializeDataUse(period, dataUseVariables);

			append("ExecutionCallable " + futureName + " = " + COMPONENT_FIELD + ".noInput(");
			append("ExecutionCallable " + futureName + " = " + COMPONENT_FIELD + "." + RuntimeApi.NO_INPUT + "(");
			write(period, dataUseVariables);
			append(", ");
			GateReference gr = ((Quiescence) b).getGateReference();
@@ -1886,7 +1886,7 @@ public class JUnitTestGenerator extends Renderer {
			DataUse arg = m.getArgument();
			initializeDataUse(arg, dataUseVariables);

			append("ExecutionCallable " + futureName + " = " + COMPONENT_FIELD + "." + (m.isIsTrigger() ? "trigger" : "receive") + "(");
			append("ExecutionCallable " + futureName + " = " + COMPONENT_FIELD + "." + (m.isIsTrigger() ? RuntimeApi.TRIGGER : RuntimeApi.RECEIVE) + "(");
			convertToData(arg, dataUseVariables);
			append(", ");
			writeGetConnection(localTarget.getTargetGate(), m.getSourceGate());
@@ -1920,7 +1920,7 @@ public class JUnitTestGenerator extends Renderer {
				arguments.forEach(arg -> initializeDataUse(arg.getDataUse(), dataUseVariables));
				replyArguments.forEach(arg -> initializeDataUse(arg.getDataUse(), dataUseVariables));

				append("ExecutionCallable " + futureName + " = " + COMPONENT_FIELD + ".call(");
				append("ExecutionCallable " + futureName + " = " + COMPONENT_FIELD + "." + RuntimeApi.CALL + "(");
				writeCallArguments(pc, reply[0], true, dataUseVariables);
				append(", ");
				writeGetConnection(localTarget.getTargetGate(), pc.getSourceGate());
@@ -2292,7 +2292,7 @@ public class JUnitTestGenerator extends Renderer {
					line(unmappedDataInitializer);
					// The TDL identity of the instance; the mapping is for the adapter
					writeSetName(dataInstance);
					append(".setMapping(");
					append("." + RuntimeApi.SET_MAPPING + "(");
					writeMapping(m, ref + "_mapping", true);
					line(")");

@@ -2316,9 +2316,9 @@ public class JUnitTestGenerator extends Renderer {
			if (isUnmapped()) {
				append(unmappedDataInitializer);
				if (isCollection)
					line(".setIsCollection(true)");
					line("." + RuntimeApi.SET_IS_COLLECTION + "(true)");
				else
					line(".setIsStructure(true)");
					line("." + RuntimeApi.SET_IS_STRUCTURE + "(true)");

			} else {
				DataElementMapping m = getMapping(dataType);
@@ -2355,7 +2355,7 @@ public class JUnitTestGenerator extends Renderer {

		} else if (d instanceof LiteralValueUse) {
			if (isUnmapped())
				append(unmappedDataInitializer + ".setValue(");
				append(unmappedDataInitializer + "." + RuntimeApi.SET_VALUE + "(");
			String str = ((LiteralValueUse) d).getValue();
			BigInteger i = ((LiteralValueUse) d).getIntValue();
			Boolean b = ((LiteralValueUse) d).getBoolValue();
@@ -2447,7 +2447,7 @@ public class JUnitTestGenerator extends Renderer {
			for (DataUse item : collectionItems) {
				String itemRef = dataUseVariables.get(item);
				if (isUnmapped())
					append(ref + ".addItem(" + itemRef + ".asData())");
					append(ref + "." + RuntimeApi.ADD_ITEM + "(" + itemRef + "." + RuntimeApi.AS_DATA + "())");
				else
					append(ref + ".add(" + itemRef + ")");
				line(";");
@@ -2482,7 +2482,7 @@ public class JUnitTestGenerator extends Renderer {

		UnassignedMemberTreatment treatment = getUnassignedMemberTreatment(d, dataInstance);
		if (treatment != null)
			append(".setUnassignedMemberTreatment(SpecialValue." + treatment.getName() + ")");
			append("." + RuntimeApi.SET_UNASSIGNED_MEMBER_TREATMENT + "(SpecialValue." + treatment.getName() + ")");

		if (memberAssignments != null)
			for (MemberAssignment ma : memberAssignments)
@@ -2495,19 +2495,19 @@ public class JUnitTestGenerator extends Renderer {
			// Items are positional, so every item gets an entry
			for (DataUse item : collectionItems) {
				String itemTemplate = getTemplateVariable(item, dataUseVariables);
				append(".item(" + (itemTemplate != null ? itemTemplate : "TemplateImpl.NONE") + ")");
				append("." + RuntimeApi.ITEM + "(" + (itemTemplate != null ? itemTemplate : "TemplateImpl." + RuntimeApi.NONE) + ")");
			}
		}
		line(";");

		if (isUnmapped())
			line(ref + ".setTemplate(" + templateRef + ");");
			line(ref + "." + RuntimeApi.SET_TEMPLATE + "(" + templateRef + ");");
	}

	private void writeTemplateMember(Parameter p, DataUse memberSpec, Map<DataUse, String> dataUseVariables) {
		String memberTemplate = getTemplateVariable(memberSpec, dataUseVariables);
		if (memberTemplate != null)
			append(".member(\"" + getTemplateMemberName(p) + "\", " + memberTemplate + ")");
			append("." + RuntimeApi.MEMBER + "(\"" + getTemplateMemberName(p) + "\", " + memberTemplate + ")");
	}

	/**
@@ -2870,7 +2870,7 @@ public class JUnitTestGenerator extends Renderer {
			append("/* ");
			line(c.getBody());
			line("*/ ");
			line(REPORTER_FIELD + ".comment(" + COMPONENT_FIELD + ".getTesterComponent().getName(), " + "\"" + c.getBody() + "\");");
			line(REPORTER_FIELD + ".comment(" + COMPONENT_FIELD + "." + RuntimeApi.GET_TESTER_COMPONENT + "().getName(), " + "\"" + c.getBody() + "\");");
		});
	}

@@ -2878,7 +2878,7 @@ public class JUnitTestGenerator extends Renderer {
		// TODO multiple URIs
		objectives.forEach(to -> {
			append(REPORTER_FIELD + ".testObjectiveReached(");
			append(COMPONENT_FIELD + ".getTesterComponent().getName(), ");
			append(COMPONENT_FIELD + "." + RuntimeApi.GET_TESTER_COMPONENT + "().getName(), ");
			writeTextBlock(String.join(" | ", to.getObjectiveURI()));
			append(", ");
			writeTextBlock(to.getDescription());
@@ -2897,7 +2897,7 @@ public class JUnitTestGenerator extends Renderer {
			append(REPORTER_FIELD + ".");
			append(started ? "behaviourStarted" : "behaviourCompleted");
			append("(");
			append(COMPONENT_FIELD + ".getTesterComponent().getName(), ");
			append(COMPONENT_FIELD + "." + RuntimeApi.GET_TESTER_COMPONENT + "().getName(), ");
			if (started)
				append("\"" + b.eClass().getName() + "\", ");
			append("\"" + getQName(b) + "\", ");
@@ -2918,11 +2918,11 @@ public class JUnitTestGenerator extends Renderer {
			ICompositeNode node = NodeModelUtils.getNode(b);
			if (node != null) {
				String path = b.eResource().getURI().toPlatformString(false);
				keyValues.add(PROPERTY_KEYS + ".SOURCE");
				keyValues.add(PROPERTY_KEYS + "." + RuntimeApi.PROPERTY_SOURCE);
				keyValues.add("\"" + escape(path + ":" + node.getStartLine()) + "\"");
			}
		}
		append(PROPERTIES_CLASS + ".of(" + String.join(", ", keyValues) + ")");
		append(PROPERTIES_CLASS + "." + RuntimeApi.OF + "(" + String.join(", ", keyValues) + ")");
	}

	private String getQName(Element b) {
@@ -2960,14 +2960,14 @@ public class JUnitTestGenerator extends Renderer {
	}

	private void addAssertionOutcomeProperties(Element assertion, DataUse condition) {
		addOutcomeProperty(assertion, "RESULT", getAssertionResultVariable(assertion));
		addOutcomeProperty(assertion, RuntimeApi.PROPERTY_RESULT, getAssertionResultVariable(assertion));
		if (!getAssertionOperands(condition).isEmpty()) {
			DataUse top = condition instanceof CastDataUse ? ((CastDataUse) condition).getDataUse() : condition;
			String fn = ((PredefinedFunctionCall) top).getFunction().getName();
			addOutcomeProperty(assertion, "OPERATOR", "\"" + escape(fn) + "\"");
			addOutcomeProperty(assertion, "OPERANDS", getAssertionOperandsVariable(assertion));
			addOutcomeProperty(assertion, RuntimeApi.PROPERTY_OPERATOR, "\"" + escape(fn) + "\"");
			addOutcomeProperty(assertion, RuntimeApi.PROPERTY_OPERANDS, getAssertionOperandsVariable(assertion));
		} else {
			addOutcomeProperty(assertion, "VALUE", getAssertionResultVariable(assertion));
			addOutcomeProperty(assertion, RuntimeApi.PROPERTY_VALUE, getAssertionResultVariable(assertion));
		}
	}