Search in sources :

Example 1 with SubTemplate

use of spoon.test.template.testclasses.inheritance.SubTemplate in project spoon by INRIA.

the class TemplateTest method testTemplateInheritance.

@Test
public void testTemplateInheritance() throws Exception {
    Launcher spoon = new Launcher();
    Factory factory = spoon.getFactory();
    spoon.getEnvironment().setCommentEnabled(true);
    spoon.createCompiler(factory, SpoonResourceHelper.resources("./src/test/java/spoon/test/template/testclasses/inheritance/SubClass.java", "./src/test/java/spoon/test/template/testclasses/inheritance/SuperClass.java"), SpoonResourceHelper.resources("./src/test/java/spoon/test/template/testclasses/inheritance/SubTemplate.java", "./src/test/java/spoon/test/template/testclasses/inheritance/SuperTemplate.java")).build();
    // Collects type members which should contain generated by comment
    final Map<CtElement, String> elementToGeneratedByMember = new IdentityHashMap<>();
    CtClass<?> superc = factory.Class().get(SuperClass.class);
    new SuperTemplate().addGeneratedBy(true).apply(superc);
    CtMethod<?> addedMethod = superc.getElements(new NamedElementFilter<>(CtMethod.class, "toBeOverriden")).get(0);
    assertEquals("toBeOverriden", addedMethod.getSimpleName());
    elementToGeneratedByMember.put(addedMethod, "#toBeOverriden");
    CtClass<?> subc = factory.Class().get(SubClass.class);
    SubTemplate template = new SubTemplate();
    template.addGeneratedBy(true);
    template.params = new ArrayList<>();
    CtParameter<Integer> parameter = factory.Core().createParameter();
    parameter.setSimpleName("x");
    parameter.setType(factory.Type().createReference(int.class));
    template.params.add(parameter);
    // templating the invocation
    template.invocation = factory.Code().createInvocation(null, addedMethod.getReference());
    // templating the foreach
    template.intValues = new CtExpression[2];
    template.intValues[0] = factory.Code().createLiteral(0);
    template.intValues[1] = factory.Code().createLiteral(1);
    // we apply the extension template to subc
    template.apply(subc);
    CtMethod<?> addedMethod2 = subc.getElements(new NamedElementFilter<>(CtMethod.class, "toBeOverriden")).get(0);
    assertEquals("toBeOverriden", addedMethod2.getSimpleName());
    assertEquals("super.toBeOverriden()", addedMethod2.getBody().getStatements().get(0).toString());
    elementToGeneratedByMember.put(addedMethod2, "#toBeOverriden");
    // contract; method parameter templates are handled
    CtMethod<?> methodWithTemplatedParameters = subc.getElements(new NamedElementFilter<>(CtMethod.class, "methodWithTemplatedParameters")).get(0);
    assertEquals("methodWithTemplatedParameters", methodWithTemplatedParameters.getSimpleName());
    assertEquals("x", methodWithTemplatedParameters.getParameters().get(0).getSimpleName());
    assertEquals("int x", methodWithTemplatedParameters.getParameters().get(0).toString());
    elementToGeneratedByMember.put(methodWithTemplatedParameters, "#methodWithTemplatedParameters");
    // contract: nested types of the templates are copied
    assertEquals(1, subc.getNestedTypes().size());
    elementToGeneratedByMember.put(subc.getNestedTypes().iterator().next(), "$InnerClass");
    // contract: methods are renamed
    assertEquals(1, subc.getMethodsByName("newVarName").size());
    CtMethod<?> varMethod = subc.getMethodsByName("newVarName").get(0);
    elementToGeneratedByMember.put(varMethod, "#var");
    // contract: parameters are replaced in comments too. The Class parameter value is converted to String
    assertEquals("newVarName", varMethod.getComments().get(0).getContent().split("[\\n\\r]+")[0]);
    assertEquals("{@link LinkedList}", varMethod.getComments().get(1).getContent());
    assertEquals("{@link SuperClass#toBeOverriden()}", varMethod.getComments().get(2).getContent());
    // contract: variable are renamed
    assertEquals("java.util.List newVarName = null", methodWithTemplatedParameters.getBody().getStatement(0).toString());
    // contract: types are replaced by other types
    assertEquals("java.util.LinkedList l = null", methodWithTemplatedParameters.getBody().getStatement(1).toString());
    // contract: casts are replaced by substitution types
    assertEquals("java.util.List o = ((java.util.LinkedList) (new java.util.LinkedList()))", methodWithTemplatedParameters.getBody().getStatement(2).toString());
    // contract: invocations are replaced by actual invocations
    assertEquals("toBeOverriden()", methodWithTemplatedParameters.getBody().getStatement(3).toString());
    // contract: foreach in block is inlined into that wrapping block
    CtBlock templatedForEach = methodWithTemplatedParameters.getBody().getStatement(4);
    assertEquals("java.lang.System.out.println(0)", templatedForEach.getStatement(0).toString());
    assertEquals("java.lang.System.out.println(1)", templatedForEach.getStatement(1).toString());
    // contract: foreach with single body block are inlined without extra block
    assertEquals("java.lang.System.out.println(0)", methodWithTemplatedParameters.getBody().getStatement(5).toString());
    assertEquals("java.lang.System.out.println(1)", methodWithTemplatedParameters.getBody().getStatement(6).toString());
    // contract: foreach with double body block are inlined with one extra block for each inlined statement
    assertEquals("java.lang.System.out.println(0)", ((CtBlock) methodWithTemplatedParameters.getBody().getStatement(7)).getStatement(0).toString());
    assertEquals("java.lang.System.out.println(1)", ((CtBlock) methodWithTemplatedParameters.getBody().getStatement(8)).getStatement(0).toString());
    // contract: foreach with statement are inlined without extra (implicit) block
    assertFalse(methodWithTemplatedParameters.getBody().getStatement(9) instanceof CtBlock);
    assertEquals("java.lang.System.out.println(0)", methodWithTemplatedParameters.getBody().getStatement(9).toString());
    assertFalse(methodWithTemplatedParameters.getBody().getStatement(10) instanceof CtBlock);
    assertEquals("java.lang.System.out.println(1)", methodWithTemplatedParameters.getBody().getStatement(10).toString());
    // contract: for each whose expression is not a template parameter is not inlined
    assertTrue(methodWithTemplatedParameters.getBody().getStatement(11) instanceof CtForEach);
    // contract: local variable write are replaced by local variable write with modified local variable name
    assertEquals("newVarName = o", methodWithTemplatedParameters.getBody().getStatement(12).toString());
    // contract: local variable read are replaced by local variable read with modified local variable name
    assertEquals("l = ((java.util.LinkedList) (newVarName))", methodWithTemplatedParameters.getBody().getStatement(13).toString());
    // contract; field access is handled same like local variable access
    CtMethod<?> methodWithFieldAccess = subc.getElements(new NamedElementFilter<>(CtMethod.class, "methodWithFieldAccess")).get(0);
    elementToGeneratedByMember.put(methodWithFieldAccess, "#methodWithFieldAccess");
    elementToGeneratedByMember.put(subc.getField("newVarName"), "#var");
    // contract: field write are replaced by field write with modified field name
    assertEquals("newVarName = o", methodWithFieldAccess.getBody().getStatement(2).toString());
    // contract: field read are replaced by field read with modified field name
    assertEquals("l = ((java.util.LinkedList) (newVarName))", methodWithFieldAccess.getBody().getStatement(3).toString());
    class Context {

        int nrTypeMembers = 0;

        int nrOthers = 0;
    }
    final Context ctx = new Context();
    // contract: each CtTypeMember has `Generated by ` with appropriate template class name, member name and line number
    superc.filterChildren(null).forEach((CtElement e) -> {
        if (e instanceof CtTypeMember) {
            ctx.nrTypeMembers++;
            assertCommentHasGeneratedBy(e, SuperTemplate.class.getName(), elementToGeneratedByMember);
        } else {
            ctx.nrOthers++;
            assertTrue(e.getDocComment() == null || e.getDocComment().indexOf("Generated by") == -1);
        }
    });
    assertTrue(ctx.nrTypeMembers > 0);
    assertTrue(ctx.nrOthers > 0);
    ctx.nrTypeMembers = 0;
    ctx.nrOthers = 0;
    subc.filterChildren(null).forEach((CtElement e) -> {
        if (e instanceof CtTypeMember) {
            ctx.nrTypeMembers++;
            assertCommentHasGeneratedBy(e, SubTemplate.class.getName(), elementToGeneratedByMember);
        } else {
            ctx.nrOthers++;
            assertTrue(e.getDocComment() == null || e.getDocComment().indexOf("Generated by") == -1);
        }
    });
    assertTrue(ctx.nrTypeMembers > 0);
    assertTrue(ctx.nrOthers > 0);
}
Also used : SubTemplate(spoon.test.template.testclasses.inheritance.SubTemplate) CtElement(spoon.reflect.declaration.CtElement) IdentityHashMap(java.util.IdentityHashMap) Factory(spoon.reflect.factory.Factory) CtForEach(spoon.reflect.code.CtForEach) CtBlock(spoon.reflect.code.CtBlock) CtTypeMember(spoon.reflect.declaration.CtTypeMember) SuperTemplate(spoon.test.template.testclasses.inheritance.SuperTemplate) NamedElementFilter(spoon.reflect.visitor.filter.NamedElementFilter) Launcher(spoon.Launcher) Test(org.junit.Test)

Aggregations

IdentityHashMap (java.util.IdentityHashMap)1 Test (org.junit.Test)1 Launcher (spoon.Launcher)1 CtBlock (spoon.reflect.code.CtBlock)1 CtForEach (spoon.reflect.code.CtForEach)1 CtElement (spoon.reflect.declaration.CtElement)1 CtTypeMember (spoon.reflect.declaration.CtTypeMember)1 Factory (spoon.reflect.factory.Factory)1 NamedElementFilter (spoon.reflect.visitor.filter.NamedElementFilter)1 SubTemplate (spoon.test.template.testclasses.inheritance.SubTemplate)1 SuperTemplate (spoon.test.template.testclasses.inheritance.SuperTemplate)1