Search in sources :

Example 1 with MetamodelConcept

use of spoon.test.metamodel.MetamodelConcept 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 2 with MetamodelConcept

use of spoon.test.metamodel.MetamodelConcept 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)

Aggregations

File (java.io.File)2 ArrayList (java.util.ArrayList)2 MetamodelConcept (spoon.test.metamodel.MetamodelConcept)2 SpoonMetaModel (spoon.test.metamodel.SpoonMetaModel)2 HashMap (java.util.HashMap)1 HashSet (java.util.HashSet)1 Test (org.junit.Test)1 Launcher (spoon.Launcher)1 CtInvocation (spoon.reflect.code.CtInvocation)1 CtClass (spoon.reflect.declaration.CtClass)1 CtMethod (spoon.reflect.declaration.CtMethod)1 CtRole (spoon.reflect.path.CtRole)1 TypeFilter (spoon.reflect.visitor.filter.TypeFilter)1 MMMethod (spoon.test.metamodel.MMMethod)1