Search in sources :

Example 1 with SpoonMetaModel

use of spoon.test.metamodel.SpoonMetaModel in project spoon by INRIA.

the class SpoonArchitectureEnforcerTest method testInterfacesAreCtScannable.

@Test
public void testInterfacesAreCtScannable() {
    // contract: all non-leaf interfaces of the metamodel should be visited by CtInheritanceScanner
    Launcher interfaces = new Launcher();
    interfaces.addInputResource("src/main/java/spoon/support");
    interfaces.addInputResource("src/main/java/spoon/reflect/declaration");
    interfaces.addInputResource("src/main/java/spoon/reflect/code");
    interfaces.addInputResource("src/main/java/spoon/reflect/reference");
    interfaces.addInputResource("src/main/java/spoon/support/reflect/declaration");
    interfaces.addInputResource("src/main/java/spoon/support/reflect/code");
    interfaces.addInputResource("src/main/java/spoon/support/reflect/reference");
    interfaces.addInputResource("src/main/java/spoon/reflect/visitor/CtScanner.java");
    interfaces.buildModel();
    CtClass<?> ctScanner = interfaces.getFactory().Class().get(CtInheritanceScanner.class);
    List<String> missingMethods = new ArrayList<>();
    new SpoonMetaModel(interfaces.getFactory()).getConcepts().forEach(mmConcept -> {
        if (mmConcept.getKind() == ABSTRACT && mmConcept.getModelInterface() != null) {
            CtInterface abstractIface = mmConcept.getModelInterface();
            String methodName = "scan" + abstractIface.getSimpleName();
            if (ctScanner.getMethodsByName(methodName).isEmpty()) {
                missingMethods.add(methodName);
            }
        }
    });
    assertTrue("The following methods are missing in CtScanner: \n" + StringUtils.join(missingMethods, "\n"), missingMethods.isEmpty());
}
Also used : CtInterface(spoon.reflect.declaration.CtInterface) SpoonMetaModel(spoon.test.metamodel.SpoonMetaModel) ArrayList(java.util.ArrayList) Launcher(spoon.Launcher) Test(org.junit.Test)

Example 2 with SpoonMetaModel

use of spoon.test.metamodel.SpoonMetaModel in project spoon by INRIA.

the class ReplaceParametrizedTest method data.

@Parameterized.Parameters(name = "{0}")
public static Collection<Object[]> data() throws Exception {
    metaModel = new SpoonMetaModel(new File("src/main/java"));
    factory = metaModel.getFactory();
    List<Object[]> values = new ArrayList<>();
    for (MetamodelConcept t : metaModel.getConcepts()) {
        if (t.getKind() == MMTypeKind.LEAF) {
            values.add(new Object[] { t });
        }
    }
    return values;
}
Also used : SpoonMetaModel(spoon.test.metamodel.SpoonMetaModel) ArrayList(java.util.ArrayList) File(java.io.File) MetamodelConcept(spoon.test.metamodel.MetamodelConcept)

Example 3 with SpoonMetaModel

use of spoon.test.metamodel.SpoonMetaModel in project spoon by INRIA.

the class MetaModelTest method spoonMetaModelTest.

/*
	 * this test reports all spoon model elements which are not yet handled by meta model
	 * actually this is the result
	 */
@Test
public void spoonMetaModelTest() {
    SpoonMetaModel mm = new SpoonMetaModel(new File("./src/main/java"));
    List<String> problems = new ArrayList<>();
    // detect unused CtRoles
    Set<CtRole> unhandledRoles = new HashSet<>(Arrays.asList(CtRole.values()));
    mm.getConcepts().forEach(mmConcept -> {
        mmConcept.getRoleToProperty().forEach((role, mmField) -> {
            if (mmField.isUnsettable()) {
                // contract: all unsettable fields are derived too
                assertTrue("Unsettable field " + mmField + " must be derived too", mmField.isDerived());
            }
            unhandledRoles.remove(role);
            if (mmField.getMethod(MMMethodKind.GET) == null) {
                problems.add("Missing getter for " + mmField.getOwnerConcept().getName() + " and CtRole." + mmField.getRole());
            }
            if (mmField.getMethod(MMMethodKind.SET) == null) {
                if (mmConcept.getTypeContext().isSubtypeOf(mm.getFactory().Type().createReference(CtReference.class)) == false && mmConcept.getName().equals("CtTypeInformation") == false) {
                    // only NON references needs a setter
                    problems.add("Missing setter for " + mmField.getOwnerConcept().getName() + " and CtRole." + mmField.getRole());
                }
            }
            // contract: type of field value is never implicit
            assertFalse("Value type of Field " + mmField.toString() + " is implicit", mmField.getValueType().isImplicit());
            assertFalse("Item value type of Field " + mmField.toString() + " is implicit", mmField.getItemValueType().isImplicit());
            mmField.forEachUnhandledMethod(ctMethod -> problems.add("Unhandled method signature: " + ctMethod.getDeclaringType().getSimpleName() + "#" + ctMethod.getSignature()));
        });
    });
    unhandledRoles.forEach(it -> problems.add("Unused CtRole." + it.name()));
/*
		 * This assertion prints all the methods which are not covered by current implementation of SpoonMetaModel.
		 * It is not a bug. It is useful to see how much is SpoonMetaModel covering real Spoon model.
		 */
// assertTrue(String.join("\n", problems), problems.isEmpty());
}
Also used : SpoonMetaModel(spoon.test.metamodel.SpoonMetaModel) CtReference(spoon.reflect.reference.CtReference) ArrayList(java.util.ArrayList) CtRole(spoon.reflect.path.CtRole) File(java.io.File) HashSet(java.util.HashSet) Test(org.junit.Test)

Example 4 with SpoonMetaModel

use of spoon.test.metamodel.SpoonMetaModel in project spoon by INRIA.

the class CtScannerTest method testScannerCallsAllProperties.

@Test
public void testScannerCallsAllProperties() throws Exception {
    // contract: CtScanner must visit all metamodel properties and use correct CtRole!
    final Launcher launcher = new Launcher();
    launcher.addInputResource("./src/main/java/spoon/reflect/");
    launcher.run();
    CtTypeReference<?> ctElementRef = launcher.getFactory().createCtTypeReference(CtElement.class);
    CtTypeReference<?> ctRefRef = launcher.getFactory().createCtTypeReference(CtReference.class);
    CtClass<?> scannerCtClass = (CtClass<?>) launcher.getFactory().Type().get(CtScanner.class);
    List<String> problems = new ArrayList<>();
    Set<String> ignoredInvocations = new HashSet(Arrays.asList("scan", "enter", "exit"));
    SpoonMetaModel metaModel = new SpoonMetaModel(new File("./src/main/java"));
    // collect all scanner visit methods, to check if all were checked
    Map<String, CtMethod<?>> scannerVisitMethodsByName = new HashMap<>();
    scannerCtClass.getAllMethods().forEach(m -> {
        if (m.getSimpleName().startsWith("visit")) {
            scannerVisitMethodsByName.put(m.getSimpleName(), m);
        }
    });
    class Counter {

        int nbChecks = 0;
    }
    Counter c = new Counter();
    for (MetamodelConcept leafConcept : metaModel.getConcepts()) {
        // we only consider leaf, actual classes of the metamodel (eg CtInvocation) and not abstract ones (eg CtModifiable)
        if (leafConcept.getKind() != MMTypeKind.LEAF) {
            continue;
        }
        CtMethod<?> visitMethod = scannerVisitMethodsByName.remove("visit" + leafConcept.getName());
        assertNotNull("CtScanner#" + "visit" + leafConcept.getName() + "(...) not found", visitMethod);
        Set<String> calledMethods = new HashSet<>();
        Set<String> checkedMethods = new HashSet<>();
        // go over the roles and the corresponding fields of this type
        leafConcept.getRoleToProperty().forEach((role, mmField) -> {
            if (mmField.isDerived()) {
                // return of the lambda
                return;
            }
            // ignore fields, which doesn't return CtElement
            if (mmField.getItemValueType().isSubtypeOf(ctElementRef) == false) {
                // return of the lambda
                return;
            }
            MMMethod getter = mmField.getMethod(MMMethodKind.GET);
            checkedMethods.add(getter.getSignature());
            // System.out.println("checking "+m.getSignature() +" in "+visitMethod.getSignature());
            // now, we collect at least one invocation to this getter in the visit method
            CtInvocation invocation = visitMethod.filterChildren(new TypeFilter<CtInvocation>(CtInvocation.class) {

                @Override
                public boolean matches(CtInvocation element) {
                    if (ignoredInvocations.contains(element.getExecutable().getSimpleName())) {
                        return false;
                    }
                    calledMethods.add(element.getExecutable().getSignature());
                    return super.matches(element) && element.getExecutable().getSimpleName().equals(getter.getName());
                }
            }).first();
            if (getter.getName().equals("getComments") && leafConcept.getModelInterface().isSubtypeOf(ctRefRef)) {
                // one cannot set comments on references see the @UnsettableProperty of CtReference#setComments
                return;
            }
            // contract: there ia at least one invocation to all non-derived, role-based getters in the visit method of the Scanner
            if (invocation == null) {
                problems.add("no " + getter.getSignature() + " in " + visitMethod);
            } else {
                c.nbChecks++;
                // System.out.println(invocation.toString());
                // contract: the scan method is called with the same role as the one set on field / property
                CtRole expectedRole = metaModel.getRoleOfMethod((CtMethod<?>) invocation.getExecutable().getDeclaration());
                CtInvocation<?> scanInvocation = invocation.getParent(CtInvocation.class);
                String realRoleName = ((CtFieldRead<?>) scanInvocation.getArguments().get(0)).getVariable().getSimpleName();
                if (expectedRole.name().equals(realRoleName) == false) {
                    problems.add("Wrong role " + realRoleName + " used in " + scanInvocation.getPosition());
                }
            }
        });
        calledMethods.removeAll(checkedMethods);
        // contract: CtScanner only calls methods that have a role and the associated getter
        if (calledMethods.size() > 0) {
            problems.add("CtScanner " + visitMethod.getPosition() + " calls unexpected methods: " + calledMethods);
        }
    }
    // contract: all visit* methods in CtScanner have been checked
    if (scannerVisitMethodsByName.isEmpty() == false) {
        problems.add("These CtScanner visit methods were not checked: " + scannerVisitMethodsByName.keySet());
    }
    if (problems.size() > 0) {
        fail(String.join("\n", problems));
    }
    assertTrue("not enough checks", c.nbChecks >= 200);
}
Also used : SpoonMetaModel(spoon.test.metamodel.SpoonMetaModel) MMMethod(spoon.test.metamodel.MMMethod) HashMap(java.util.HashMap) ArrayList(java.util.ArrayList) TypeFilter(spoon.reflect.visitor.filter.TypeFilter) CtClass(spoon.reflect.declaration.CtClass) CtInvocation(spoon.reflect.code.CtInvocation) Launcher(spoon.Launcher) CtRole(spoon.reflect.path.CtRole) File(java.io.File) MetamodelConcept(spoon.test.metamodel.MetamodelConcept) CtMethod(spoon.reflect.declaration.CtMethod) HashSet(java.util.HashSet) Test(org.junit.Test)

Example 5 with SpoonMetaModel

use of spoon.test.metamodel.SpoonMetaModel in project spoon by INRIA.

the class RoleHandlersGenerator method process.

@Override
public void process() {
    SpoonMetaModel metaModel = new SpoonMetaModel(getFactory());
    // all root super MMFields
    List<MetamodelProperty> superFields = new ArrayList<>();
    metaModel.getConcepts().forEach(mmConcept -> {
        mmConcept.getRoleToProperty().forEach((role, rim) -> {
            addUniqueObject(superFields, rim.getRootSuperField());
        });
    });
    superFields.sort((a, b) -> {
        int d = a.getRole().name().compareTo(b.getRole().name());
        if (d != 0) {
            return d;
        }
        return a.getOwnerConcept().getName().compareTo(b.getOwnerConcept().getName());
    });
    PrinterHelper concept = new PrinterHelper(getFactory().getEnvironment());
    superFields.forEach(mmField -> {
        concept.write(mmField.getOwnerConcept().getName() + " CtRole." + mmField.getRole().name()).writeln().incTab().write("ItemType: ").write(mmField.getValueType().toString()).writeln();
        for (MMMethodKind mk : MMMethodKind.values()) {
            MMMethod mmMethod = mmField.getMethod(mk);
            if (mmMethod != null) {
                concept.write(mk.name()).write(": ").write(mmMethod.getSignature()).write(" : ").write(mmMethod.getReturnType().toString()).writeln();
            }
        }
        concept.decTab();
        concept.write("----------------------------------------------------------").writeln();
    });
    try (Writer w = new OutputStreamWriter(new FileOutputStream(file("target/report/concept.txt")))) {
        w.write(concept.toString());
    } catch (IOException e) {
        throw new RuntimeException(e);
    }
    CtType<?> template = getTemplate("spoon.generating.meta.ModelRoleHandlerTemplate");
    CtClass<?> modelRoleHandlersClass = Substitution.createTypeFromTemplate(TARGET_PACKAGE + ".ModelRoleHandlers", template, new HashMap<>());
    CtNewArray<?> roleHandlersFieldExpr = (CtNewArray<?>) modelRoleHandlersClass.getField("roleHandlers").getDefaultExpression();
    superFields.forEach(rim -> {
        Map<String, Object> params = new HashMap<>();
        params.put("$getterName$", rim.getMethod(MMMethodKind.GET).getName());
        if (rim.getMethod(MMMethodKind.SET) != null) {
            params.put("$setterName$", rim.getMethod(MMMethodKind.SET).getName());
        }
        params.put("$Role$", getFactory().Type().createReference(CtRole.class));
        params.put("ROLE", rim.getRole().name());
        params.put("$TargetType$", rim.getOwnerConcept().getModelInterface().getReference());
        // params.put("AbstractHandler", getFactory().Type().createReference("spoon.reflect.meta.impl.AbstractRoleHandler"));
        params.put("AbstractHandler", getRoleHandlerSuperTypeQName(rim));
        params.put("Node", rim.getOwnerConcept().getModelInterface().getReference());
        params.put("ValueType", fixMainValueType(getRoleHandlerSuperTypeQName(rim).endsWith("SingleHandler") ? rim.getValueType() : rim.getItemValueType()));
        CtClass<?> modelRoleHandlerClass = Substitution.createTypeFromTemplate(getHandlerName(rim), getTemplate("spoon.generating.meta.RoleHandlerTemplate"), params);
        if (rim.getMethod(MMMethodKind.SET) == null) {
            modelRoleHandlerClass.getMethodsByName("setValue").forEach(m -> m.delete());
        }
        modelRoleHandlerClass.addModifier(ModifierKind.STATIC);
        modelRoleHandlersClass.addNestedType(modelRoleHandlerClass);
        roleHandlersFieldExpr.addElement(getFactory().createCodeSnippetExpression("new " + modelRoleHandlerClass.getSimpleName() + "()"));
    });
}
Also used : SpoonMetaModel(spoon.test.metamodel.SpoonMetaModel) MMMethod(spoon.test.metamodel.MMMethod) HashMap(java.util.HashMap) ArrayList(java.util.ArrayList) IOException(java.io.IOException) CtNewArray(spoon.reflect.code.CtNewArray) PrinterHelper(spoon.reflect.visitor.PrinterHelper) FileOutputStream(java.io.FileOutputStream) MetamodelProperty(spoon.test.metamodel.MetamodelProperty) CtRole(spoon.reflect.path.CtRole) OutputStreamWriter(java.io.OutputStreamWriter) MMMethodKind(spoon.test.metamodel.MMMethodKind) OutputStreamWriter(java.io.OutputStreamWriter) Writer(java.io.Writer)

Aggregations

ArrayList (java.util.ArrayList)5 SpoonMetaModel (spoon.test.metamodel.SpoonMetaModel)5 File (java.io.File)3 Test (org.junit.Test)3 CtRole (spoon.reflect.path.CtRole)3 HashMap (java.util.HashMap)2 HashSet (java.util.HashSet)2 Launcher (spoon.Launcher)2 MMMethod (spoon.test.metamodel.MMMethod)2 MetamodelConcept (spoon.test.metamodel.MetamodelConcept)2 FileOutputStream (java.io.FileOutputStream)1 IOException (java.io.IOException)1 OutputStreamWriter (java.io.OutputStreamWriter)1 Writer (java.io.Writer)1 CtInvocation (spoon.reflect.code.CtInvocation)1 CtNewArray (spoon.reflect.code.CtNewArray)1 CtClass (spoon.reflect.declaration.CtClass)1 CtInterface (spoon.reflect.declaration.CtInterface)1 CtMethod (spoon.reflect.declaration.CtMethod)1 CtReference (spoon.reflect.reference.CtReference)1