Search in sources :

Example 6 with RoleHandler

use of spoon.reflect.meta.RoleHandler in project spoon by INRIA.

the class ReplaceParametrizedTest method testContract.

@Test
public void testContract() throws Throwable {
    List<String> problems = new ArrayList<>();
    // contract: all elements are replaceable wherever they are in the model
    // this test puts them at all possible locations
    CtType<?> toTest = typeToTest.getModelInterface();
    CtElement o = factory.Core().create((Class<? extends CtElement>) toTest.getActualClass());
    for (MetamodelProperty mmField : typeToTest.getRoleToProperty().values()) {
        Class<?> argType = mmField.getItemValueType().getActualClass();
        if (!CtElement.class.isAssignableFrom(argType)) {
            continue;
        }
        CtTypeReference<?> itemType = mmField.getItemValueType();
        // special cases...
        if (itemType.getQualifiedName().equals(CtStatement.class.getName())) {
            // the children of CtLoop wraps CtStatement into an implicit CtBlock. So make a block directly to test plain get/set and not wrapping.
            itemType = factory.createCtTypeReference(CtBlock.class);
        }
        if (o.getClass().getSimpleName().equals("CtAnnotationFieldAccessImpl") && mmField.getRole() == CtRole.VARIABLE) {
            itemType = factory.createCtTypeReference(CtFieldReference.class);
        } else if (CtFieldAccess.class.isAssignableFrom(o.getClass()) && mmField.getRole() == CtRole.VARIABLE) {
            itemType = factory.createCtTypeReference(CtFieldReference.class);
        }
        CtElement argument = (CtElement) createCompatibleObject(itemType);
        assertNotNull(argument);
        // we create a fresh object
        CtElement receiver = ((CtElement) o).clone();
        RoleHandler rh = RoleHandlerHelper.getRoleHandler(o.getClass(), mmField.getRole());
        if (mmField.isUnsettable()) {
            try {
                // we invoke the setter
                invokeSetter(rh, receiver, argument);
            } catch (SpoonException e) {
                // ok this unsettable property has no setter at all
                return;
            }
            // this unsettable property has setter, but it should do nothing
            CtRole argumentsRoleInParent = argument.getRoleInParent();
            if (argumentsRoleInParent == null) {
                // OK - unsettable property set no value
                continue;
            }
            if (argumentsRoleInParent == mmField.getRole()) {
                problems.add("UnsettableProperty " + mmField + " sets the value");
            } else {
                if (mmField.isDerived()) {
                // it is OK, that setting of value into derived unsettable field influences other field
                // Example 1: CtCatchVariable.setType(x) influences result of getMultitype()
                // Example 2: CtEnumValue.setAssignment(x) influences result of getDefaultExpression()
                } else {
                    problems.add("UnsettableProperty " + mmField + " sets the value into different role " + argumentsRoleInParent);
                }
            }
            continue;
        }
        // we invoke the setter
        invokeSetter(rh, receiver, argument);
        // contract: a property setter sets properties that are visitable by a scanner
        CtElement finalArgument = argument;
        class Scanner extends CtScanner {

            boolean found = false;

            @Override
            public void scan(CtRole role, CtElement e) {
                super.scan(role, e);
                if (e == finalArgument) {
                    if (rh.getRole() == role || rh.getRole().getSuperRole() == role) {
                        found = true;
                        return;
                    }
                    // if (rh.getRole()==CtRole.TYPE && role==CtRole.MULTI_TYPE) {
                    // //CtCatchVaraible#type sets CtCatchVaraible#multiType - OK
                    // found = true;
                    // return;
                    // }
                    problems.add("Argument was set into " + rh.getRole() + " but was found in " + role);
                }
            }
        }
        ;
        Scanner s = new Scanner();
        receiver.accept(s);
        assertTrue("Settable field " + mmField.toString() + " should set value.\n" + getReport(problems), s.found);
        // contract: a property getter on the same role can be used to get the value back
        assertSame(argument, invokeGetter(rh, receiver));
        final CtElement argument2 = argument.clone();
        assertNotSame(argument, argument2);
        // we do the replace
        argument.replace(argument2);
        // the new element is indeed now in this AST
        assertTrue(receiver.getClass().getSimpleName() + " failed for " + mmField, receiver.getElements(new Filter<CtElement>() {

            @Override
            public boolean matches(CtElement element) {
                return element == argument2;
            }
        }).size() == 1);
    }
    if (problems.size() > 0) {
        fail(getReport(problems));
    }
}
Also used : CtScanner(spoon.reflect.visitor.CtScanner) SpoonException(spoon.SpoonException) CtElement(spoon.reflect.declaration.CtElement) RoleHandler(spoon.reflect.meta.RoleHandler) ArrayList(java.util.ArrayList) CtFieldReference(spoon.reflect.reference.CtFieldReference) CtBlock(spoon.reflect.code.CtBlock) CtStatement(spoon.reflect.code.CtStatement) Filter(spoon.reflect.visitor.Filter) MetamodelProperty(spoon.test.metamodel.MetamodelProperty) CtRole(spoon.reflect.path.CtRole) CtScanner(spoon.reflect.visitor.CtScanner) Test(org.junit.Test)

Example 7 with RoleHandler

use of spoon.reflect.meta.RoleHandler in project spoon by INRIA.

the class MetaModelTest method singleValueRoleAddSetRemove.

@Test
public void singleValueRoleAddSetRemove() {
    // contract: single value roles supports multivalue interface too
    Launcher launcher = new Launcher();
    Factory factory = launcher.getFactory();
    CtTypeReference<?> typeRef = factory.Type().createReference("some.test.package.TestType");
    RoleHandler rh = RoleHandlerHelper.getRoleHandler(typeRef.getClass(), CtRole.PACKAGE_REF);
    // contract: single value role provides a List
    List<CtPackageReference> packages = rh.asList(typeRef);
    assertListContracts(packages, typeRef, 1, "some.test.package");
    // contract: adding of existing value fails and changes nothing
    try {
        packages.add(typeRef.getPackage());
        fail();
    } catch (Exception e) {
    // OK
    }
    assertListContracts(packages, typeRef, 1, "some.test.package");
    // contract: adding of null fails and changes nothing
    try {
        assertFalse(packages.add(null));
        fail();
    } catch (Exception e) {
    // OK
    }
    assertListContracts(packages, typeRef, 1, "some.test.package");
    // contract: adding of different value fails, and changes nothing
    try {
        packages.add(factory.Package().createReference("some.test.another_package"));
        fail();
    } catch (SpoonException e) {
    // OK
    }
    assertListContracts(packages, typeRef, 1, "some.test.package");
    // contract remove of different value changes nothing
    assertFalse(packages.remove(factory.Package().createReference("some.test.another_package")));
    assertListContracts(packages, typeRef, 1, "some.test.package");
    // contract remove of null value changes nothing
    assertFalse(packages.remove(null));
    assertListContracts(packages, typeRef, 1, "some.test.package");
    // contract remove of existing value sets value to null and size to 0
    assertTrue(packages.remove(factory.Package().createReference("some.test.package")));
    assertListContracts(packages, typeRef, 0, null);
    // contract add of null into empty collection changes size to 1, but value is still null
    assertTrue(packages.add(null));
    assertListContracts(packages, typeRef, 1, null);
    // contract: adding of new value into collection with single null value fails and changes nothing
    try {
        packages.add(factory.Package().createReference("some.test.another_package"));
        fail();
    } catch (SpoonException e) {
    // OK
    }
    assertListContracts(packages, typeRef, 1, null);
    // contract: set of new value replaces existing value
    assertEquals(null, packages.set(0, factory.Package().createReference("some.test.package")));
    assertListContracts(packages, typeRef, 1, "some.test.package");
    // contract: set of null value keeps size==1 even if value is replaced by null
    assertEquals("some.test.package", packages.set(0, null).getQualifiedName());
    assertListContracts(packages, typeRef, 1, null);
    // contract: remove of null value by index sets size==0 the value is still null
    assertNull(packages.remove(0));
    assertListContracts(packages, typeRef, 0, null);
    // contract: add of null value sets size==1 the value is still null
    assertTrue(packages.add(null));
    assertListContracts(packages, typeRef, 1, null);
    // contract: remove of null value by value sets size==0 the value is still null
    assertTrue(packages.remove(null));
    assertListContracts(packages, typeRef, 0, null);
    // contract: set of new value on empty collection fails with IndexOutOfBounds and changes nothing
    try {
        packages.set(0, factory.Package().createReference("some.test.another_package"));
        fail();
    } catch (IndexOutOfBoundsException e) {
    // OK
    }
    assertListContracts(packages, typeRef, 0, null);
    // contract: adding of value into empty collection adds value
    assertTrue(packages.add(factory.Package().createReference("some.test.another_package")));
    assertListContracts(packages, typeRef, 1, "some.test.another_package");
    // contract: remove of value by index from collection removes that value
    assertEquals("some.test.another_package", packages.remove(0).getQualifiedName());
    assertListContracts(packages, typeRef, 0, null);
}
Also used : CtPackageReference(spoon.reflect.reference.CtPackageReference) SpoonException(spoon.SpoonException) RoleHandler(spoon.reflect.meta.RoleHandler) Launcher(spoon.Launcher) Factory(spoon.reflect.factory.Factory) SpoonException(spoon.SpoonException) Test(org.junit.Test)

Example 8 with RoleHandler

use of spoon.reflect.meta.RoleHandler in project spoon by INRIA.

the class MetaModelTest method listValueRoleSetOn.

@Test
public void listValueRoleSetOn() {
    // contract: multi-value role supports set(int, Object)
    Launcher launcher = new Launcher();
    Factory factory = launcher.getFactory();
    CtClass<?> ctClass = factory.Class().create("some.test.TestClass");
    RoleHandler rh = RoleHandlerHelper.getRoleHandler(ctClass.getClass(), CtRole.TYPE_MEMBER);
    List<CtTypeMember> typeMembers = rh.asList(ctClass);
    assertEquals(0, typeMembers.size());
    CtField<?> field1 = createField(factory, "field1");
    CtField<?> field2 = createField(factory, "field2");
    CtField<?> field3 = createField(factory, "field3");
    // check that field was not added in type yet
    assertEquals(0, typeMembers.size());
    // contract: call of add on RoleHandler collection adds the item into real collection too
    typeMembers.add(field1);
    assertEquals(1, typeMembers.size());
    assertEquals(1, ctClass.getTypeMembers().size());
    assertSame(ctClass, field1.getDeclaringType());
    assertThat(asList("field1"), is(ctClass.filterChildren(new TypeFilter(CtField.class)).map((CtField e) -> e.getSimpleName()).list()));
    // contract: call of add on RoleHandler collection adds the item into real collection too
    typeMembers.add(field2);
    assertSame(ctClass, field2.getDeclaringType());
    assertThat(asList("field1", "field2"), is(ctClass.filterChildren(new TypeFilter(CtField.class)).map((CtField e) -> e.getSimpleName()).list()));
    // contract: call of set on RoleHandler collection replaces the item in real collection
    typeMembers.set(0, field3);
    assertSame(ctClass, field3.getDeclaringType());
    assertThat(asList("field3", "field2"), is(ctClass.filterChildren(new TypeFilter(CtField.class)).map((CtField e) -> e.getSimpleName()).list()));
    typeMembers.set(1, field1);
    assertThat(asList("field3", "field1"), is(ctClass.filterChildren(new TypeFilter(CtField.class)).map((CtField e) -> e.getSimpleName()).list()));
    // contract: call of remove(int) on RoleHandler collection removes the item in real collection
    assertSame(field3, typeMembers.remove(0));
    assertThat(asList("field1"), is(ctClass.filterChildren(new TypeFilter(CtField.class)).map((CtField e) -> e.getSimpleName()).list()));
    // contract: call of remove(Object) which does not exist does nothing
    assertFalse(typeMembers.remove(field2));
    assertThat(asList("field1"), is(ctClass.filterChildren(new TypeFilter(CtField.class)).map((CtField e) -> e.getSimpleName()).list()));
    // contract: call of remove(Object) on RoleHandler collection removes the item in real collection
    assertTrue(typeMembers.remove(field1));
    assertThat(asList(), is(ctClass.filterChildren(new TypeFilter(CtField.class)).map((CtField e) -> e.getSimpleName()).list()));
}
Also used : CtTypeMember(spoon.reflect.declaration.CtTypeMember) RoleHandler(spoon.reflect.meta.RoleHandler) CtField(spoon.reflect.declaration.CtField) Launcher(spoon.Launcher) Factory(spoon.reflect.factory.Factory) TypeFilter(spoon.reflect.visitor.filter.TypeFilter) Test(org.junit.Test)

Example 9 with RoleHandler

use of spoon.reflect.meta.RoleHandler in project spoon by INRIA.

the class CtScannerTest method testScan.

@Test
public void testScan() throws Exception {
    // contract: all AST nodes are visisted through method "scan"
    Launcher launcher;
    launcher = new Launcher();
    launcher.getEnvironment().setNoClasspath(true);
    launcher.addInputResource("src/test/resources/noclasspath/draw2d");
    launcher.buildModel();
    class Counter {

        int nEnter = 0;

        int nExit = 0;

        int nObject = 0;

        int nElement = 0;

        Deque<CollectionContext> contexts = new ArrayDeque<>();
    }
    ;
    Counter counter = new Counter();
    launcher.getModel().getRootPackage().accept(new CtScanner() {

        @Override
        public void scan(Object o) {
            counter.nObject++;
            super.scan(o);
        }

        @Override
        public void scan(CtElement o) {
            counter.nElement++;
            super.scan(o);
        }

        @Override
        public void enter(CtElement o) {
            counter.nEnter++;
            super.enter(o);
        }

        @Override
        public void exit(CtElement o) {
            counter.nExit++;
            super.exit(o);
        }
    });
    // interesting, this is never called because of covariance, only CtElement or Collection is called
    assertEquals(0, counter.nObject);
    // this is a coarse-grain check to see if the scanner changes
    // no more exec ref in paramref
    assertEquals(3616, counter.nElement);
    assertEquals(2396, counter.nEnter);
    assertEquals(2396, counter.nExit);
    // contract: all AST nodes which are part of Collection or Map are visited first by method "scan(Collection|Map)" and then by method "scan(CtElement)"
    Counter counter2 = new Counter();
    launcher.getModel().getRootPackage().accept(new CtScanner() {

        @Override
        public void scan(Object o) {
            counter2.nObject++;
            super.scan(o);
        }

        @Override
        public void scan(CtRole role, CtElement o) {
            if (o == null) {
                // there is no collection involved in scanning of this single value NULL attribute
                assertNull(counter2.contexts.peek().col);
            } else {
                RoleHandler rh = RoleHandlerHelper.getRoleHandler(o.getParent().getClass(), role);
                if (rh.getContainerKind() == ContainerKind.SINGLE) {
                    // there is no collection involved in scanning of this single value attribute
                    assertNull(counter2.contexts.peek().col);
                } else {
                    counter2.contexts.peek().assertRemoveSame(o);
                }
            }
            counter2.nElement++;
            super.scan(o);
        }

        @Override
        public void scan(CtRole role, Collection<? extends CtElement> elements) {
            // contract: before processed collection is finished before it starts with next collection
            counter2.contexts.peek().initCollection(elements);
            super.scan(role, elements);
            // contract: all elements of collection are processed in previous super.scan call
            counter2.contexts.peek().assertCollectionIsEmpty();
        }

        @Override
        public void scan(CtRole role, Map<String, ? extends CtElement> elements) {
            // contract: before processed collection is finished before it starts with next collection
            counter2.contexts.peek().initCollection(elements.values());
            super.scan(role, elements);
            // contract: all elements of collection are processed in previous super.scan call
            counter2.contexts.peek().assertCollectionIsEmpty();
        }

        @Override
        public void enter(CtElement o) {
            counter2.nEnter++;
            counter2.contexts.push(new CollectionContext());
        }

        @Override
        public void exit(CtElement o) {
            counter2.nExit++;
            counter2.contexts.peek().assertCollectionIsEmpty();
            counter2.contexts.pop();
        }
    });
    assertEquals(counter.nObject, counter2.nObject);
    assertEquals(counter.nElement, counter2.nElement);
    assertEquals(counter.nEnter, counter2.nEnter);
    assertEquals(counter.nExit, counter2.nExit);
}
Also used : CtElement(spoon.reflect.declaration.CtElement) RoleHandler(spoon.reflect.meta.RoleHandler) Deque(java.util.Deque) ArrayDeque(java.util.ArrayDeque) Launcher(spoon.Launcher) CtRole(spoon.reflect.path.CtRole) Test(org.junit.Test)

Example 10 with RoleHandler

use of spoon.reflect.meta.RoleHandler in project spoon by INRIA.

the class CtElementImpl method setValueByRole.

@Override
public <E extends CtElement, T> E setValueByRole(CtRole role, T value) {
    RoleHandler rh = RoleHandlerHelper.getRoleHandler(this.getClass(), role);
    rh.setValue(this, value);
    return (E) this;
}
Also used : RoleHandler(spoon.reflect.meta.RoleHandler)

Aggregations

RoleHandler (spoon.reflect.meta.RoleHandler)10 Test (org.junit.Test)5 Launcher (spoon.Launcher)4 CtElement (spoon.reflect.declaration.CtElement)4 CtRole (spoon.reflect.path.CtRole)4 ArrayList (java.util.ArrayList)3 SpoonException (spoon.SpoonException)3 Factory (spoon.reflect.factory.Factory)3 CtClass (spoon.reflect.declaration.CtClass)2 ArrayDeque (java.util.ArrayDeque)1 Deque (java.util.Deque)1 HashSet (java.util.HashSet)1 LinkedList (java.util.LinkedList)1 List (java.util.List)1 Map (java.util.Map)1 CtBlock (spoon.reflect.code.CtBlock)1 CtStatement (spoon.reflect.code.CtStatement)1 CtAnnotation (spoon.reflect.declaration.CtAnnotation)1 CtField (spoon.reflect.declaration.CtField)1 CtNamedElement (spoon.reflect.declaration.CtNamedElement)1