/** * Copyright 2011-2017 Asakusa Framework Team. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.asakusafw.operator.flowpart; import static org.hamcrest.Matchers.*; import static org.junit.Assert.*; import java.util.ArrayList; import java.util.Collections; import java.util.List; import javax.annotation.processing.ProcessingEnvironment; import javax.lang.model.element.AnnotationMirror; import javax.lang.model.element.ExecutableElement; import javax.lang.model.element.TypeElement; import javax.lang.model.type.TypeVariable; import javax.lang.model.util.ElementFilter; import org.junit.Test; import com.asakusafw.operator.Callback; import com.asakusafw.operator.CompileEnvironment; import com.asakusafw.operator.Constants; import com.asakusafw.operator.MockSource; import com.asakusafw.operator.OperatorCompilerTestRoot; import com.asakusafw.operator.description.ClassDescription; import com.asakusafw.operator.model.OperatorClass; import com.asakusafw.operator.model.OperatorDescription; import com.asakusafw.operator.model.OperatorDescription.Document; import com.asakusafw.operator.model.OperatorDescription.MethodReference; import com.asakusafw.operator.model.OperatorDescription.Node; import com.asakusafw.operator.model.OperatorDescription.Node.Kind; import com.asakusafw.operator.model.OperatorDescription.ParameterReference; import com.asakusafw.operator.model.OperatorDescription.ReferenceDocument; import com.asakusafw.operator.model.OperatorDescription.TextDocument; import com.asakusafw.operator.model.OperatorElement; import com.asakusafw.operator.util.AnnotationHelper; /** * Test for {@link FlowPartFactoryEmitter}. */ public class FlowPartFactoryEmitterTest extends OperatorCompilerTestRoot { /** * simple case. */ @Test public void simple() { Object factory = compile(new Action("com.example.Simple") { @Override protected OperatorDescription analyze(ExecutableElement element) { Document document = new TextDocument("Hello, world!"); List<Node> parameters = new ArrayList<>(); List<Node> outputs = new ArrayList<>(); return new OperatorDescription(document, parameters, outputs); } }); Object node = invoke(factory, "create"); assertThat(node.getClass().getName().replace('$', '.'), is("com.example.SimpleFactory.Simple")); } /** * w/ input. */ @Test public void input() { Object factory = compile(new Action("com.example.WithIn") { @Override protected OperatorDescription analyze(ExecutableElement element) { List<Node> parameters = new ArrayList<>(); parameters.add(new Node( Kind.INPUT, "in", new ReferenceDocument(new ParameterReference(0)), getType(String.class), new ParameterReference(0))); List<Node> outputs = new ArrayList<>(); return new OperatorDescription(new ReferenceDocument(new MethodReference()), parameters, outputs); } }); invoke(factory, "create", MockSource.of(String.class)); } /** * w/ output. */ @Test public void output() { Object factory = compile(new Action("com.example.WithOut") { @Override protected OperatorDescription analyze(ExecutableElement element) { List<Node> parameters = new ArrayList<>(); List<Node> outputs = new ArrayList<>(); outputs.add(new Node( Kind.OUTPUT, "output", new ReferenceDocument(new ParameterReference(0)), getType(String.class), new ParameterReference(0))); return new OperatorDescription(new ReferenceDocument(new MethodReference()), parameters, outputs); } }); Object object = invoke(factory, "create"); assertThat(field(object.getClass(), "output"), is(notNullValue())); } /** * w/ argument. */ @Test public void argument() { Object factory = compile(new Action("com.example.WithArgument") { @Override protected OperatorDescription analyze(ExecutableElement element) { List<Node> parameters = new ArrayList<>(); parameters.add(new Node( Kind.DATA, "argument", new ReferenceDocument(new ParameterReference(0)), getType(String.class), new ParameterReference(0))); List<Node> outputs = new ArrayList<>(); return new OperatorDescription(new ReferenceDocument(new MethodReference()), parameters, outputs); } }); invoke(factory, "create", "Hello, world!"); } /** * w/ type parameter. */ @Test public void projective() { Object factory = compile(new Action("com.example.WithTypeParameter") { @Override protected OperatorDescription analyze(ExecutableElement element) { TypeElement type = (TypeElement) element.getEnclosingElement(); List<Node> parameters = new ArrayList<>(); parameters.add(new Node( Kind.INPUT, "input", new ReferenceDocument(new ParameterReference(0)), type.getTypeParameters().get(0).asType(), new ParameterReference(0))); parameters.add(new Node( Kind.DATA, "argument", new ReferenceDocument(new ParameterReference(2)), getType(String.class), new ParameterReference(2))); List<Node> outputs = new ArrayList<>(); outputs.add(new Node( Kind.OUTPUT, "output", new ReferenceDocument(new ParameterReference(1)), type.getTypeParameters().get(0).asType(), new ParameterReference(1))); return new OperatorDescription(new ReferenceDocument(new MethodReference()), parameters, outputs); } }); Object node = invoke(factory, "create", MockSource.of(String.class), "Hello, world!"); assertThat(field(node.getClass(), "output"), is(notNullValue())); } /** * w/ type parameter. */ @Test public void output_infer_by_class() { Object factory = compile(new Action("com.example.WithClass") { @Override protected OperatorDescription analyze(ExecutableElement element) { TypeElement type = (TypeElement) element.getEnclosingElement(); TypeVariable va = getTypeVariable(type, "A"); TypeVariable vb = getTypeVariable(type, "B"); List<Node> parameters = new ArrayList<>(); parameters.add(new Node( Kind.INPUT, "input", new ReferenceDocument(new ParameterReference(0)), va, new ParameterReference(0))); parameters.add(new Node( Kind.DATA, "argument", new ReferenceDocument(new ParameterReference(2)), getType(Class.class, vb), new ParameterReference(2))); List<Node> outputs = new ArrayList<>(); outputs.add(new Node( Kind.OUTPUT, "output", new ReferenceDocument(new ParameterReference(1)), vb, new ParameterReference(1))); return new OperatorDescription(new ReferenceDocument(new MethodReference()), parameters, outputs); } }); Object node = invoke(factory, "create", MockSource.of(String.class), String.class); assertThat(field(node.getClass(), "output"), is(notNullValue())); } private Object compile(Action action) { add(action.className); ClassLoader classLoader = start(action); assertThat(action.performed, is(true)); ClassDescription implClass = Constants.getFactoryClass(action.className); return create(classLoader, implClass); } private abstract static class Action extends Callback { final String className; boolean performed; Action(String className) { this.className = className; } @Override protected CompileEnvironment createCompileEnvironment(ProcessingEnvironment processingEnv) { return new CompileEnvironment( processingEnv, Collections.emptyList(), Collections.emptyList()); } @Override protected void test() { TypeElement element = env.findTypeElement(new ClassDescription(className)); if (round.getRootElements().contains(element)) { TypeElement annotationType = env.findTypeElement(Constants.TYPE_FLOW_PART); AnnotationMirror annotation = AnnotationHelper.findAnnotation(env, annotationType, element); this.performed = true; List<OperatorElement> elems = new ArrayList<>(); for (ExecutableElement e : ElementFilter.constructorsIn(element.getEnclosedElements())) { OperatorDescription desc = analyze(e); elems.add(new OperatorElement(annotation, e, desc)); } OperatorClass analyzed = new OperatorClass(element, elems); FlowPartFactoryEmitter emitter = new FlowPartFactoryEmitter(env); emitter.emit(analyzed); } } protected abstract OperatorDescription analyze(ExecutableElement element); } }