package nl.ipo.cds.attributemapping.operations.discover.annotation; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.fail; import java.util.Collection; import java.util.List; import javax.inject.Inject; import nl.ipo.cds.attributemapping.operations.OperationInputType; import nl.ipo.cds.attributemapping.operations.OperationType; import nl.ipo.cds.attributemapping.operations.annotation.Execute; import nl.ipo.cds.attributemapping.operations.annotation.Input; import nl.ipo.cds.attributemapping.operations.discover.OperationDiscovererException; import nl.ipo.cds.attributemapping.operations.discover.annotation.AnnotationInputOperationType; import nl.ipo.cds.attributemapping.operations.discover.annotation.AnnotationOperationDiscoverer; import nl.ipo.cds.attributemapping.operations.discover.annotation.AnnotationOperationType; import nl.ipo.cds.attributemapping.operations.discover.annotation.AnnotationOutputOperationType; import nl.ipo.cds.attributemapping.operations.discover.annotation.AnnotationTransformOperationType; import nl.ipo.cds.attributemapping.operations.discover.annotation.TestAnnotationOperationDiscoverer.TestAnnotationOperationDiscovererConfig; import nl.ipo.cds.attributemapping.operations.discover.annotation.operations.Package; import nl.ipo.cds.attributemapping.operations.discover.annotation.operations.TestOperation; import nl.ipo.cds.attributemapping.operations.discover.annotation.operations.TestOperationBeforeAfter; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(classes = TestAnnotationOperationDiscovererConfig.class) public class TestAnnotationOperationDiscoverer { @Inject private AnnotationOperationDiscoverer operationDiscoverer; @Inject private ApplicationContext applicationContext; @Configuration @ComponentScan(basePackageClasses = Package.class) public static class TestAnnotationOperationDiscovererConfig { @Bean public AnnotationOperationDiscoverer annotationOperationDiscoverer () { return new AnnotationOperationDiscoverer (); } } @Test public void testDiscover () { final Collection<OperationType> types = operationDiscoverer.getOperationTypes (); assertNotNull (types); assertHasOperation (types, "testOperation", AnnotationTransformOperationType.class, String.class, TestOperation.Settings.class); assertHasOperation (types, "testOperationWithMultipleMethods", AnnotationTransformOperationType.class, String.class, null); assertHasOperation (types, "testInput", AnnotationInputOperationType.class, String.class, null); assertHasOperation (types, "testOutput", AnnotationOutputOperationType.class, Void.TYPE, null); assertHasOperation (types, "testOperationVarargs", AnnotationTransformOperationType.class, String.class, null); assertHasOperation (types, "testOperationBeforeAfter", AnnotationTransformOperationType.class, String.class, TestOperationBeforeAfter.Settings.class); assertHasInputs (types, "testOperation", new In ("a", String.class, false), new In ("b", String.class, false) ); assertHasInputs (types, "testOperationWithMultipleMethods", new In ("a", String.class, false), new In ("b", String.class, false) ); assertHasInputs (types, "testInput"); assertHasInputs (types, "testOutput", new In ("in", String.class, false) ); assertHasInputs (types, "testOperationVarargs", new In ("a", Integer.TYPE, false), new In ("b", String.class, true) ); } static void assertHasOperation (final Collection<OperationType> operations, final String name, final Class<?> iface, final Class<?> returnType, final Class<?> beanClass) { for (final OperationType ot: operations) { if ( name.equals (ot.getName ()) && iface.isAssignableFrom (ot.getClass ()) && returnType.equals (ot.getReturnType ()) && ((beanClass == null && ot.getPropertyBeanClass () == null) || (beanClass != null && beanClass.equals (ot.getPropertyBeanClass())))) { return; } } fail (String.format ("Missing operation: %s", name)); } static void assertHasInputs (final Collection<OperationType> operations, final String name, final In ... inputs) { OperationType operationType = null; for (final OperationType ot: operations) { if (name.equals (ot.getName ())) { operationType = ot; break; } } if (operationType == null) { fail ("Operation type not found"); } final List<OperationInputType> operationInputs = operationType.getInputs (); if (operationInputs.size () != inputs.length) { fail (String.format ("Operation %s, expected %d inputs, found %d", name, operationInputs.size (), inputs.length)); } for (int i = 0; i < inputs.length; ++ i) { final OperationInputType it = operationInputs.get (i); if (!it.getName ().equals (inputs[i].name)) { fail (String.format ("Operation %s, expected input %s, found %s at %d", name, inputs[i].name, it.getName (), i)); } if (!it.getInputType ().equals (inputs[i].type)) { fail (String.format ("Input %s.%s, expected type %s, found %s", name, inputs[i].name, inputs[i].type, it.getInputType ())); } if (it.isVariableInputCount () != inputs[i].variableInputs) { fail (String.format ("Input %s.%s has wrong varinputs setting", name, inputs[i].name)); } } } @Test(expected = OperationDiscovererException.class) public void testDiscoverNoExecuteMethod () { AnnotationOperationType.getOperationMethod (new Object () { }); } @Test(expected = OperationDiscovererException.class) public void testDiscoverMultipleExecuteMethods () { AnnotationOperationType.getOperationMethod (new Object () { @SuppressWarnings("unused") public int a () { return 0; } @SuppressWarnings("unused") public void b (int a) { } }); } @Test(expected = OperationDiscovererException.class) public void testDiscoverInvalidExecuteMethod () { AnnotationOperationType.getOperationMethod (new Object () { @SuppressWarnings("unused") public void a () { } }); } @Test(expected = OperationDiscovererException.class) public void testDiscoverMultiplAnnotatedMethods () { AnnotationOperationType.getOperationMethod (new Object () { @Execute public void a (int a) { } @Execute public void b (int b) { } }); } @Test(expected = OperationDiscovererException.class) public void testDiscoverNoInputAnnotation () { AnnotationOperationType.getOperationMethod (new Object () { @Execute public void a (int a) { } }); } @Test public void testDiscoverAnnotatedInput () { AnnotationOperationType.getOperationMethod (new Object () { @Execute public void a (@Input int a) { } }); } @Test(expected = OperationDiscovererException.class) public void testDiscoverDuplicateInput () { final Object obj = new Object () { @Execute public int a (@Input("a") int a, @Input("a") int b) { return 0; } }; new AnnotationTransformOperationType (obj, "obj", applicationContext); } private static class In { public final String name; public final Class<?> type; public final boolean variableInputs; public In (final String name, final Class<?> type, final boolean variableInputs) { this.name = name; this.type = type; this.variableInputs = variableInputs; } } }