Loading plugins/org.etsi.mts.tdl.execution.java.codegen/src/org/etsi/mts/tdl/execution/java/codegen/JUnitTestGenerator.java +247 −17 Original line number Diff line number Diff line Loading @@ -15,6 +15,7 @@ import java.util.stream.Collectors; import org.eclipse.emf.common.util.TreeIterator; import org.eclipse.emf.ecore.EObject; import org.eclipse.emf.ecore.EStructuralFeature; import org.eclipse.xtext.nodemodel.ICompositeNode; import org.eclipse.xtext.nodemodel.util.NodeModelUtils; import org.eclipse.xtext.resource.XtextResource; Loading Loading @@ -95,6 +96,7 @@ import org.etsi.mts.tdl.Time; import org.etsi.mts.tdl.TimeConstraint; import org.etsi.mts.tdl.TimeLabel; import org.etsi.mts.tdl.TimeLabelUse; import org.etsi.mts.tdl.UnassignedMemberTreatment; import org.etsi.mts.tdl.TimeOperation; import org.etsi.mts.tdl.TimeOut; import org.etsi.mts.tdl.Timer; Loading @@ -107,6 +109,7 @@ import org.etsi.mts.tdl.Variable; import org.etsi.mts.tdl.VariableUse; import org.etsi.mts.tdl.VerdictAssignment; import org.etsi.mts.tdl.Wait; import org.etsi.mts.tdl.tdlPackage; public class JUnitTestGenerator extends Renderer { Loading Loading @@ -147,6 +150,12 @@ public class JUnitTestGenerator extends Renderer { private Map<DataType, String> declaredTypes = new Hashtable<DataType, String>(); /** * Suffix of the variable holding the {@code TemplateImpl} that accompanies a * data use variable (see {@link #getTemplateVariable(DataUse, Map)}). */ private static final String TEMPLATE_VARIABLE_SUFFIX = "_t"; public JUnitTestGenerator(Package model, Settings settings) { super(settings.outputFile, settings.outPackage); this.model = model; Loading Loading @@ -2047,6 +2056,9 @@ public class JUnitTestGenerator extends Renderer { } } if (needsTemplate(d)) line("TemplateImpl " + varName + TEMPLATE_VARIABLE_SUFFIX + ";"); dataUseVariables.put(d, varName); if (inst instanceof StructuredDataInstance || inst instanceof CollectionDataInstance) { Loading Loading @@ -2109,6 +2121,7 @@ public class JUnitTestGenerator extends Renderer { DataType castTo = null; String ref = dataUseVariables.get(d); String templateRef = getTemplateVariable(d, dataUseVariables); List<ParameterBinding> arguments = getDataUseArguments(d); if (d instanceof CastDataUse) { Loading Loading @@ -2234,21 +2247,17 @@ public class JUnitTestGenerator extends Renderer { } } else if (d instanceof SpecialValueUse) { String anyKind = "AnyValue"; anyKind = null; // Defaults to "AnyValue"; if (d instanceof AnyValueOrOmit) anyKind = "AnyValueOrOmit"; else if (d instanceof OmitValue) anyKind = "OmitValue"; // A special value has no value of its own, it is marked in the template // (see writeTemplate() below) if (isUnmapped()) { if (anyKind != null) append(ref + " = new " + CORE_PACKAGE + ".ValueImpl(" + CORE_PACKAGE + ".SpecialValue.AnyValue)"); if (typeName != null) append(unmappedDataInitializer); else append("null"); line(";"); append(" = new " + CORE_PACKAGE + ".ValueImpl()"); } else { // XXX append("null"); // The variable may be of a Java primitive type: assign its default, // the template marking makes the actual value irrelevant append(javaDefaultLiteral(d.resolveDataType())); } } else if (d instanceof LiteralValueUse) { Loading Loading @@ -2352,6 +2361,202 @@ public class JUnitTestGenerator extends Renderer { } } if (templateRef != null) { // Members of a referenced structured data instance are part of the // template even when the instance value is pre-built (mapped) List<MemberAssignment> templateMembers = memberAssignments; if (templateMembers == null && dataInstance instanceof StructuredDataInstance) templateMembers = ((StructuredDataInstance) dataInstance).getMemberAssignment(); writeTemplate(d, ref, templateRef, dataInstance, templateMembers, arguments, collectionItems, dataUseVariables); } } /** * Emits the initialization of the template variable of a data use: the special * value, the treatment of unassigned members and the templates of members and items that need one. In * unmapped mode the template is also attached to the value. */ private void writeTemplate(DataUse d, String ref, String templateRef, DataInstance dataInstance, List<MemberAssignment> memberAssignments, List<ParameterBinding> arguments, List<DataUse> collectionItems, Map<DataUse, String> dataUseVariables) { append(templateRef + " = new TemplateImpl("); if (d instanceof SpecialValueUse) append("SpecialValue." + getSpecialValueName((SpecialValueUse) d)); append(")"); UnassignedMemberTreatment treatment = getUnassignedMemberTreatment(d, dataInstance); if (treatment != null) append(".setUnassignedMemberTreatment(SpecialValue." + treatment.getName() + ")"); if (memberAssignments != null) for (MemberAssignment ma : memberAssignments) writeTemplateMember(ma.getMember(), ma.getMemberSpec(), dataUseVariables); if (arguments != null) for (ParameterBinding arg : arguments) writeTemplateMember(arg.getParameter(), arg.getDataUse(), dataUseVariables); if (collectionItems != null && collectionItems.stream().anyMatch(item -> needsTemplate(item))) { // 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") + ")"); } } line(";"); if (isUnmapped()) line(ref + ".setTemplate(" + 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 + ")"); } /** * The name under which a member is registered in a template: the same name a * consumer navigates the value with, i.e. the mapped Java field name * (parameter URI of the mapping) in mapped mode and the TDL member name in * unmapped mode. */ private String getTemplateMemberName(Parameter p) { if (!isUnmapped()) { String uri = getParameterMappingUri(p); if (uri != null) return uri; } return p.getName(); } /** * The Java default value literal for the mapped type of a data type: * <code>null</code> for reference types, the zero value for primitives. */ private String javaDefaultLiteral(DataType type) { if (type == null || isUnmapped()) return "null"; String javaType = getElementName(type); if (javaType == null) return "null"; switch (javaType) { case "int": case "long": case "short": case "byte": return "0"; case "char": return "'\\0'"; case "boolean": return "false"; case "float": return "0f"; case "double": return "0d"; default: return "null"; } } private String getSpecialValueName(SpecialValueUse d) { if (d instanceof AnyValueOrOmit) return "AnyValueOrOmit"; if (d instanceof OmitValue) return "OmitValue"; return "AnyValue"; } /** * The treatment of unassigned members defined for a data use: the * <i>unassignedMember</i> property of the closest element that defines one, * looking from the use outwards in: the use itself, the use wrapped by it * (for a cast), then the referenced data instance. The property is read * generically from whichever of these elements carries it in the meta-model. * * @param dataInstance The referenced data instance if already resolved by the * caller, otherwise <b>null</b> (resolved here). * @return The treatment, or <b>null</b> if undefined everywhere. */ private UnassignedMemberTreatment getUnassignedMemberTreatment(DataUse d, DataInstance dataInstance) { // Closest first: the use and, for a cast, the wrapped use(s) for (DataUse use = d; use != null; use = use instanceof CastDataUse ? ((CastDataUse) use).getDataUse() : null) { UnassignedMemberTreatment t = null; if (use instanceof DataInstanceUse) t = getUnassignedMember(use, tdlPackage.eINSTANCE.getDataInstanceUse_UnassignedMember()); if (use instanceof DataElementUse) t = getUnassignedMember(use, tdlPackage.eINSTANCE.getDataElementUse_UnassignedMember()); if (!isUndefined(t)) return t; if (dataInstance == null) dataInstance = getReferencedDataInstance(use); } // Then the definition of the referenced data instance if (dataInstance instanceof StructuredDataInstance) { UnassignedMemberTreatment t = getUnassignedMember(dataInstance, tdlPackage.eINSTANCE.getStructuredDataInstance_UnassignedMember()); return isUndefined(t) ? null : t; } return null; } /** * The <i>unassignedMember</i> property of a model element, or <b>null</b> if * the element's meta-class does not have it. */ private UnassignedMemberTreatment getUnassignedMember(EObject e, EStructuralFeature f) { if (e == null) return null; Object value = e.eGet(f); return value instanceof UnassignedMemberTreatment ? (UnassignedMemberTreatment) value : null; } private DataInstance getReferencedDataInstance(DataUse d) { if (d instanceof DataElementUse && ((DataElementUse) d).getDataElement() instanceof DataInstance) return (DataInstance) ((DataElementUse) d).getDataElement(); if (d instanceof DataInstanceUse) return ((DataInstanceUse) d).getDataInstance(); return null; } private boolean isUndefined(UnassignedMemberTreatment t) { return t == null || t == UnassignedMemberTreatment.UNDEFINED; } /** * Whether a data use needs a template: it is a special value, defines a * treatment of unassigned members, or contains (transitively) a member or item * that does. */ private boolean needsTemplate(DataUse d) { if (d == null || d instanceof VariableUse || d instanceof TimeLabelUse) return false; if (d instanceof CastDataUse) return needsTemplate(((CastDataUse) d).getDataUse()); if (d instanceof SpecialValueUse) return true; if (getUnassignedMemberTreatment(d, null) != null) return true; if (d instanceof DataElementUse) for (DataUse item : ((DataElementUse) d).getItem()) if (needsTemplate(item)) return true; for (DataUse arg : getDataUseArgumentValues(d)) if (needsTemplate(arg)) return true; return false; } /** * The name of the template variable accompanying the variable of a data use, * or <b>null</b> if the data use needs no template. */ private String getTemplateVariable(DataUse d, Map<DataUse, String> dataUseVariables) { if (!needsTemplate(d)) return null; String ref = dataUseVariables.get(d); return ref != null ? ref + TEMPLATE_VARIABLE_SUFFIX : null; } private void writeMemberAssignment(Parameter p, DataUse v, Map<DataUse, String> dataUseVariables) { Loading @@ -2365,8 +2570,12 @@ public class JUnitTestGenerator extends Renderer { } else { ParameterMapping mapping = getParameterMapping(p); if (mapping != null) { if (hasAnnotation(mapping, MAPPING_ANNOTATION_SETTER)) { append(mapping.getParameterURI()); Annotation setter = getAnnotation(mapping, MAPPING_ANNOTATION_SETTER); if (setter != null) { String setterName = setter.getValue(); if (setterName == null || setterName.isEmpty()) setterName = mapping.getParameterURI(); append(setterName); append("("); write(v, dataUseVariables); append(")"); Loading Loading @@ -2474,12 +2683,33 @@ public class JUnitTestGenerator extends Renderer { } private void convertToData(DataUse d, Map<DataUse, String> dataUseVariables) { String templateRef = getTemplateVariable(d, dataUseVariables); DataUse inner = d instanceof CastDataUse ? ((CastDataUse) d).getDataUse() : d; if (inner instanceof SpecialValueUse) { // A special value as the whole expected data has no value to derive the // type from, so the type must be given explicitly (used for decoding) DataType type = d.resolveDataType(); if (type == null) throw new RuntimeException("A special value used as expected data must have a data type (" + getSpecialValueName((SpecialValueUse) inner) + " in " + dataUseVariables.get(d) + ")"); if (!isUnmapped()) { String classLiteral = type instanceof CollectionDataType ? "java.util.List.class" : getElementName(type) + ".class"; append("new PojoData(" + classLiteral + ", " + templateRef + ")"); return; } } if (!isUnmapped()) append("new PojoData("); write(d, dataUseVariables); if (!isUnmapped()) if (!isUnmapped()) { if (templateRef != null) append(", " + templateRef); append(")"); } } private void convertToArgument(String parameterName, DataUse d, Map<DataUse, String> dataUseVariables) { if (!isUnmapped()) Loading Loading
plugins/org.etsi.mts.tdl.execution.java.codegen/src/org/etsi/mts/tdl/execution/java/codegen/JUnitTestGenerator.java +247 −17 Original line number Diff line number Diff line Loading @@ -15,6 +15,7 @@ import java.util.stream.Collectors; import org.eclipse.emf.common.util.TreeIterator; import org.eclipse.emf.ecore.EObject; import org.eclipse.emf.ecore.EStructuralFeature; import org.eclipse.xtext.nodemodel.ICompositeNode; import org.eclipse.xtext.nodemodel.util.NodeModelUtils; import org.eclipse.xtext.resource.XtextResource; Loading Loading @@ -95,6 +96,7 @@ import org.etsi.mts.tdl.Time; import org.etsi.mts.tdl.TimeConstraint; import org.etsi.mts.tdl.TimeLabel; import org.etsi.mts.tdl.TimeLabelUse; import org.etsi.mts.tdl.UnassignedMemberTreatment; import org.etsi.mts.tdl.TimeOperation; import org.etsi.mts.tdl.TimeOut; import org.etsi.mts.tdl.Timer; Loading @@ -107,6 +109,7 @@ import org.etsi.mts.tdl.Variable; import org.etsi.mts.tdl.VariableUse; import org.etsi.mts.tdl.VerdictAssignment; import org.etsi.mts.tdl.Wait; import org.etsi.mts.tdl.tdlPackage; public class JUnitTestGenerator extends Renderer { Loading Loading @@ -147,6 +150,12 @@ public class JUnitTestGenerator extends Renderer { private Map<DataType, String> declaredTypes = new Hashtable<DataType, String>(); /** * Suffix of the variable holding the {@code TemplateImpl} that accompanies a * data use variable (see {@link #getTemplateVariable(DataUse, Map)}). */ private static final String TEMPLATE_VARIABLE_SUFFIX = "_t"; public JUnitTestGenerator(Package model, Settings settings) { super(settings.outputFile, settings.outPackage); this.model = model; Loading Loading @@ -2047,6 +2056,9 @@ public class JUnitTestGenerator extends Renderer { } } if (needsTemplate(d)) line("TemplateImpl " + varName + TEMPLATE_VARIABLE_SUFFIX + ";"); dataUseVariables.put(d, varName); if (inst instanceof StructuredDataInstance || inst instanceof CollectionDataInstance) { Loading Loading @@ -2109,6 +2121,7 @@ public class JUnitTestGenerator extends Renderer { DataType castTo = null; String ref = dataUseVariables.get(d); String templateRef = getTemplateVariable(d, dataUseVariables); List<ParameterBinding> arguments = getDataUseArguments(d); if (d instanceof CastDataUse) { Loading Loading @@ -2234,21 +2247,17 @@ public class JUnitTestGenerator extends Renderer { } } else if (d instanceof SpecialValueUse) { String anyKind = "AnyValue"; anyKind = null; // Defaults to "AnyValue"; if (d instanceof AnyValueOrOmit) anyKind = "AnyValueOrOmit"; else if (d instanceof OmitValue) anyKind = "OmitValue"; // A special value has no value of its own, it is marked in the template // (see writeTemplate() below) if (isUnmapped()) { if (anyKind != null) append(ref + " = new " + CORE_PACKAGE + ".ValueImpl(" + CORE_PACKAGE + ".SpecialValue.AnyValue)"); if (typeName != null) append(unmappedDataInitializer); else append("null"); line(";"); append(" = new " + CORE_PACKAGE + ".ValueImpl()"); } else { // XXX append("null"); // The variable may be of a Java primitive type: assign its default, // the template marking makes the actual value irrelevant append(javaDefaultLiteral(d.resolveDataType())); } } else if (d instanceof LiteralValueUse) { Loading Loading @@ -2352,6 +2361,202 @@ public class JUnitTestGenerator extends Renderer { } } if (templateRef != null) { // Members of a referenced structured data instance are part of the // template even when the instance value is pre-built (mapped) List<MemberAssignment> templateMembers = memberAssignments; if (templateMembers == null && dataInstance instanceof StructuredDataInstance) templateMembers = ((StructuredDataInstance) dataInstance).getMemberAssignment(); writeTemplate(d, ref, templateRef, dataInstance, templateMembers, arguments, collectionItems, dataUseVariables); } } /** * Emits the initialization of the template variable of a data use: the special * value, the treatment of unassigned members and the templates of members and items that need one. In * unmapped mode the template is also attached to the value. */ private void writeTemplate(DataUse d, String ref, String templateRef, DataInstance dataInstance, List<MemberAssignment> memberAssignments, List<ParameterBinding> arguments, List<DataUse> collectionItems, Map<DataUse, String> dataUseVariables) { append(templateRef + " = new TemplateImpl("); if (d instanceof SpecialValueUse) append("SpecialValue." + getSpecialValueName((SpecialValueUse) d)); append(")"); UnassignedMemberTreatment treatment = getUnassignedMemberTreatment(d, dataInstance); if (treatment != null) append(".setUnassignedMemberTreatment(SpecialValue." + treatment.getName() + ")"); if (memberAssignments != null) for (MemberAssignment ma : memberAssignments) writeTemplateMember(ma.getMember(), ma.getMemberSpec(), dataUseVariables); if (arguments != null) for (ParameterBinding arg : arguments) writeTemplateMember(arg.getParameter(), arg.getDataUse(), dataUseVariables); if (collectionItems != null && collectionItems.stream().anyMatch(item -> needsTemplate(item))) { // 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") + ")"); } } line(";"); if (isUnmapped()) line(ref + ".setTemplate(" + 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 + ")"); } /** * The name under which a member is registered in a template: the same name a * consumer navigates the value with, i.e. the mapped Java field name * (parameter URI of the mapping) in mapped mode and the TDL member name in * unmapped mode. */ private String getTemplateMemberName(Parameter p) { if (!isUnmapped()) { String uri = getParameterMappingUri(p); if (uri != null) return uri; } return p.getName(); } /** * The Java default value literal for the mapped type of a data type: * <code>null</code> for reference types, the zero value for primitives. */ private String javaDefaultLiteral(DataType type) { if (type == null || isUnmapped()) return "null"; String javaType = getElementName(type); if (javaType == null) return "null"; switch (javaType) { case "int": case "long": case "short": case "byte": return "0"; case "char": return "'\\0'"; case "boolean": return "false"; case "float": return "0f"; case "double": return "0d"; default: return "null"; } } private String getSpecialValueName(SpecialValueUse d) { if (d instanceof AnyValueOrOmit) return "AnyValueOrOmit"; if (d instanceof OmitValue) return "OmitValue"; return "AnyValue"; } /** * The treatment of unassigned members defined for a data use: the * <i>unassignedMember</i> property of the closest element that defines one, * looking from the use outwards in: the use itself, the use wrapped by it * (for a cast), then the referenced data instance. The property is read * generically from whichever of these elements carries it in the meta-model. * * @param dataInstance The referenced data instance if already resolved by the * caller, otherwise <b>null</b> (resolved here). * @return The treatment, or <b>null</b> if undefined everywhere. */ private UnassignedMemberTreatment getUnassignedMemberTreatment(DataUse d, DataInstance dataInstance) { // Closest first: the use and, for a cast, the wrapped use(s) for (DataUse use = d; use != null; use = use instanceof CastDataUse ? ((CastDataUse) use).getDataUse() : null) { UnassignedMemberTreatment t = null; if (use instanceof DataInstanceUse) t = getUnassignedMember(use, tdlPackage.eINSTANCE.getDataInstanceUse_UnassignedMember()); if (use instanceof DataElementUse) t = getUnassignedMember(use, tdlPackage.eINSTANCE.getDataElementUse_UnassignedMember()); if (!isUndefined(t)) return t; if (dataInstance == null) dataInstance = getReferencedDataInstance(use); } // Then the definition of the referenced data instance if (dataInstance instanceof StructuredDataInstance) { UnassignedMemberTreatment t = getUnassignedMember(dataInstance, tdlPackage.eINSTANCE.getStructuredDataInstance_UnassignedMember()); return isUndefined(t) ? null : t; } return null; } /** * The <i>unassignedMember</i> property of a model element, or <b>null</b> if * the element's meta-class does not have it. */ private UnassignedMemberTreatment getUnassignedMember(EObject e, EStructuralFeature f) { if (e == null) return null; Object value = e.eGet(f); return value instanceof UnassignedMemberTreatment ? (UnassignedMemberTreatment) value : null; } private DataInstance getReferencedDataInstance(DataUse d) { if (d instanceof DataElementUse && ((DataElementUse) d).getDataElement() instanceof DataInstance) return (DataInstance) ((DataElementUse) d).getDataElement(); if (d instanceof DataInstanceUse) return ((DataInstanceUse) d).getDataInstance(); return null; } private boolean isUndefined(UnassignedMemberTreatment t) { return t == null || t == UnassignedMemberTreatment.UNDEFINED; } /** * Whether a data use needs a template: it is a special value, defines a * treatment of unassigned members, or contains (transitively) a member or item * that does. */ private boolean needsTemplate(DataUse d) { if (d == null || d instanceof VariableUse || d instanceof TimeLabelUse) return false; if (d instanceof CastDataUse) return needsTemplate(((CastDataUse) d).getDataUse()); if (d instanceof SpecialValueUse) return true; if (getUnassignedMemberTreatment(d, null) != null) return true; if (d instanceof DataElementUse) for (DataUse item : ((DataElementUse) d).getItem()) if (needsTemplate(item)) return true; for (DataUse arg : getDataUseArgumentValues(d)) if (needsTemplate(arg)) return true; return false; } /** * The name of the template variable accompanying the variable of a data use, * or <b>null</b> if the data use needs no template. */ private String getTemplateVariable(DataUse d, Map<DataUse, String> dataUseVariables) { if (!needsTemplate(d)) return null; String ref = dataUseVariables.get(d); return ref != null ? ref + TEMPLATE_VARIABLE_SUFFIX : null; } private void writeMemberAssignment(Parameter p, DataUse v, Map<DataUse, String> dataUseVariables) { Loading @@ -2365,8 +2570,12 @@ public class JUnitTestGenerator extends Renderer { } else { ParameterMapping mapping = getParameterMapping(p); if (mapping != null) { if (hasAnnotation(mapping, MAPPING_ANNOTATION_SETTER)) { append(mapping.getParameterURI()); Annotation setter = getAnnotation(mapping, MAPPING_ANNOTATION_SETTER); if (setter != null) { String setterName = setter.getValue(); if (setterName == null || setterName.isEmpty()) setterName = mapping.getParameterURI(); append(setterName); append("("); write(v, dataUseVariables); append(")"); Loading Loading @@ -2474,12 +2683,33 @@ public class JUnitTestGenerator extends Renderer { } private void convertToData(DataUse d, Map<DataUse, String> dataUseVariables) { String templateRef = getTemplateVariable(d, dataUseVariables); DataUse inner = d instanceof CastDataUse ? ((CastDataUse) d).getDataUse() : d; if (inner instanceof SpecialValueUse) { // A special value as the whole expected data has no value to derive the // type from, so the type must be given explicitly (used for decoding) DataType type = d.resolveDataType(); if (type == null) throw new RuntimeException("A special value used as expected data must have a data type (" + getSpecialValueName((SpecialValueUse) inner) + " in " + dataUseVariables.get(d) + ")"); if (!isUnmapped()) { String classLiteral = type instanceof CollectionDataType ? "java.util.List.class" : getElementName(type) + ".class"; append("new PojoData(" + classLiteral + ", " + templateRef + ")"); return; } } if (!isUnmapped()) append("new PojoData("); write(d, dataUseVariables); if (!isUnmapped()) if (!isUnmapped()) { if (templateRef != null) append(", " + templateRef); append(")"); } } private void convertToArgument(String parameterName, DataUse d, Map<DataUse, String> dataUseVariables) { if (!isUnmapped()) Loading