diff --git a/src/test/java/info/ebenoit/ebul/cmp/TestNewComponentInfo.java b/src/test/java/info/ebenoit/ebul/cmp/TestNewComponentInfo.java new file mode 100644 index 0000000..3abcc0a --- /dev/null +++ b/src/test/java/info/ebenoit/ebul/cmp/TestNewComponentInfo.java @@ -0,0 +1,812 @@ +package info.ebenoit.ebul.cmp; + + +import org.junit.Test; + +import info.ebenoit.ebul.func.ThrowingBiConsumer; +import info.ebenoit.ebul.func.ThrowingConsumer; + +import static org.junit.Assert.*; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; + + + +/** + * Tests for the {@link NewComponentInfo} class + *

+ * Note: since most methods in this class are just accessors, they are not tested. + */ +public class TestNewComponentInfo +{ + /** Class that has no default constructor */ + private static class TestFail1 + { + private TestFail1( int arg ) + { + // EMPTY + } + } + + /** Test component with no information */ + private static class TestCmp1 + { + // EMPTY + } + + /** Test component with a name, autostart and dependency information */ + @Component( "Test component" ) + @Autostart + @Dependencies( { + "TestCmp1" , "TestCmp3" + } ) + private static class TestCmp2 + { + // EMPTY + } + + /** Test component acting as a driver for another */ + @DriverFor( "TestCmp1" ) + private static class TestCmp3 + { + // EMPTY + } + + /** Test component that should inherit dependencies */ + @Dependencies( "TestCmp5" ) + private static class TestCmp4 + extends TestCmp2 + { + // EMPTY + } + + /** Test component with a parametric name */ + private static class TestCmpPN + implements ParametricComponent + { + + @Override + public String getComponentName( ) + { + return "TestCmpPN"; + } + + } + + /** Test component with a parametric name and an annotation-specified name */ + @Component( "Fail" ) + private static class TestCmpPNFail + implements ParametricComponent + { + + @Override + public String getComponentName( ) + { + return "TestCmpPNFail"; + } + + } + + /** Test component that has lifecycle methods */ + private static class TestCmp5 + { + protected final boolean hadLifecycleAction[] = new boolean[ 4 ]; + + + @LifecycleMethod( LifecycleStage.INITIALISE ) + private void init( ) + { + hadLifecycleAction[ LifecycleStage.INITIALISE.ordinal( ) ] = true; + } + + + @LifecycleMethod( LifecycleStage.START ) + private void start( ) + { + hadLifecycleAction[ LifecycleStage.START.ordinal( ) ] = true; + } + + + @LifecycleMethod( LifecycleStage.STOP ) + private void stop( ) + { + hadLifecycleAction[ LifecycleStage.STOP.ordinal( ) ] = true; + } + + + @LifecycleMethod( LifecycleStage.DESTROY ) + private void destroy( ) + { + hadLifecycleAction[ LifecycleStage.DESTROY.ordinal( ) ] = true; + } + + } + + /** Test component that has inherited and overridden lifecycle methods */ + private static class TestCmp6 + extends TestCmp5 + { + private boolean hadLocalInitialise; + + + @LifecycleMethod( LifecycleStage.INITIALISE ) + private void init( ) + { + hadLocalInitialise = true; + } + + } + + /** Test interface that defines a lifecycle method */ + private static interface ITest7 + { + @LifecycleMethod( LifecycleStage.INITIALISE ) + public void init( ); + } + + /** Test component that has an interface-defined lifecycle method */ + private static class TestCmp7 + implements ITest7 + { + private boolean initialised; + + + @Override + public void init( ) + { + this.initialised = true; + } + + } + + /** Test component with duplicate lifecycle methods */ + private static class TestFail2 + { + + @LifecycleMethod( LifecycleStage.INITIALISE ) + private void init1( ) + { + // EMPTY + } + + + @LifecycleMethod( LifecycleStage.INITIALISE ) + private void init2( ) + { + // EMPTY + } + + } + + /** Test component with a dependency injection field using a name */ + private static class TestCmp8 + { + @UseComponent( "TestCmp1" ) + protected TestCmp1 dependency; + } + + /** Test component with a dependency injection field using the field's type */ + private static class TestCmp9 + { + @UseComponent + private TestCmp1 dependency; + } + + /** Test component with a static dependency injection field */ + private static class TestFail3 + { + @UseComponent + private static TestCmp1 dependency; + } + + /** Test component with a final dependency injection field */ + private static class TestFail4 + { + @UseComponent + private final TestCmp1 dependency; + + + private TestFail4( ) + { + super( ); + this.dependency = null; + } + + } + + /** Test component with a primitive dependency injection field */ + private static class TestFail5 + { + @UseComponent( "x" ) + private int dependency; + + } + + /** Test component with an array dependency injection field */ + private static class TestFail6 + { + @UseComponent( "x" ) + private Object[] dependency; + + } + + /** Test component with a dependency injection method using a name */ + private static class TestCmp10 + { + protected TestCmp1 dependency; + + + @UseComponent( "TestCmp1" ) + private void inject( TestCmp1 dependency ) + { + this.dependency = dependency; + } + } + + /** Test component with a dependency injection method with no name */ + private static class TestCmp11 + { + private TestCmp1 dependency; + + + @UseComponent + private void inject( TestCmp1 dependency ) + { + this.dependency = dependency; + } + } + + /** Test component with a static dependency injection method */ + private static class TestFail7 + { + @UseComponent + private static void inject( TestCmp1 dependency ) + { + // EMPTY + } + } + + /** Test component with a dependency injection method that has no parameters */ + private static class TestFail8 + { + @UseComponent( "x" ) + private void inject( ) + { + // EMPTY + } + + } + + /** Test component with a dependency injection method that has two parameters */ + private static class TestFail9 + { + @UseComponent + private void inject( TestCmp1 dependency , int x ) + { + // EMPTY + } + + } + + /** Test component with a primitive dependency injection method */ + private static class TestFail10 + { + @UseComponent( "x" ) + private void inject( int x ) + { + // EMPTY + } + + } + + /** Test component with an array dependency injection field */ + private static class TestFail11 + { + @UseComponent( "x" ) + private void inject( Object[] x ) + { + // EMPTY + } + + } + + /** Test component that inherits a dependency injection method */ + private static class TestCmp12 + extends TestCmp10 + { + // EMPTY + } + + /** Test component that inherits a dependency injection */ + private static class TestCmp13 + extends TestCmp8 + { + // EMPTY + } + + /** Interface that defines a dependency injection method */ + private static interface ITest14 + { + @UseComponent( "TestCmp1" ) + public void inject( TestCmp1 dependency ); + } + + /** Test component with a dependency injection method defined in an interface */ + private static class TestCmp14 + implements ITest14 + { + private TestCmp1 dependency; + + + @Override + public void inject( TestCmp1 dependency ) + { + this.dependency = dependency; + } + } + + + /** Test: {@link NewComponentInfo#addDependencyInjector(DependencyInfo, ThrowingBiConsumer)} adds a dependency */ + @Test + public void testAddDependencyInjector( ) + { + NewComponentInfo< Object > nci = new NewComponentInfo< Object >( new Object( ) ); + nci.addDependencyInjector( new DependencyInfo( "test" ) , ( cmp , dep ) -> { + } ); + assertTrue( nci.getDependencies( ).contains( new DependencyInfo( "test" ) ) ); + } + + + /** Test: {@link NewComponentInfo#fromClass(Class)} on a component class with no default constructor */ + @Test( expected = ComponentDefinitionException.class ) + public void testFromClassFail1( ) + { + NewComponentInfo.fromClass( TestFail1.class ); + } + + + /** Test: {@link NewComponentInfo#fromClass(Class)} on a component class with no information */ + @Test + public void testFromClass1( ) + { + NewComponentInfo< ? > nci = NewComponentInfo.fromClass( TestCmp1.class ); + assertEquals( "TestCmp1" , nci.getName( ) ); + assertFalse( nci.getAutostart( ) ); + assertTrue( nci.getDependencies( ).isEmpty( ) ); + assertNull( nci.getDriverFor( ) ); + assertTrue( nci.getInjectors( ).isEmpty( ) ); + assertTrue( nci.getSupplier( ).get( ) instanceof TestCmp1 ); + } + + + /** Test: {@link NewComponentInfo#fromClass(Class)} on a component class with a name, dependencies and autostart */ + @Test + public void testFromClass2( ) + { + NewComponentInfo< ? > nci = NewComponentInfo.fromClass( TestCmp2.class ); + assertEquals( "Test component" , nci.getName( ) ); + assertTrue( nci.getAutostart( ) ); + HashSet< DependencyInfo > deps = nci.getDependencies( ); + assertEquals( 2 , deps.size( ) ); + assertTrue( deps.contains( new DependencyInfo( "TestCmp1" ) ) ); + assertTrue( deps.contains( new DependencyInfo( "TestCmp3" ) ) ); + } + + + /** Test: {@link NewComponentInfo#fromClass(Class)} on a component class set to be a driver for another component */ + @Test + public void testFromClass3( ) + { + NewComponentInfo< ? > nci = NewComponentInfo.fromClass( TestCmp3.class ); + HashSet< DependencyInfo > deps = nci.getDependencies( ); + assertEquals( 1 , deps.size( ) ); + assertTrue( deps.contains( new DependencyInfo( "TestCmp1" ) ) ); + assertEquals( "TestCmp1" , nci.getDriverFor( ) ); + } + + + /** Test: {@link NewComponentInfo#fromClass(Class)} on a component class with inherited + local dependencies */ + @Test + public void testFromClass4( ) + { + NewComponentInfo< ? > nci = NewComponentInfo.fromClass( TestCmp4.class ); + assertEquals( "component name was inherited!" , "TestCmp4" , nci.getName( ) ); + assertFalse( "autostart state was inherited!" , nci.getAutostart( ) ); + HashSet< DependencyInfo > deps = nci.getDependencies( ); + assertEquals( 3 , deps.size( ) ); + assertTrue( deps.contains( new DependencyInfo( "TestCmp1" ) ) ); + assertTrue( deps.contains( new DependencyInfo( "TestCmp3" ) ) ); + assertTrue( deps.contains( new DependencyInfo( "TestCmp5" ) ) ); + } + + + /** + * Test: {@link NewComponentInfo#fromClass(Class)} on a component class that implements {@link ParametricComponent} + */ + @Test + public void testFromClassPN1( ) + { + NewComponentInfo< ? > nci = NewComponentInfo.fromClass( TestCmpPN.class ); + assertNull( nci.getName( ) ); + } + + + /** + * Test: {@link NewComponentInfo#fromClass(Class)} on a component class that implements {@link ParametricComponent} + * but also has an annotation-specified name + */ + @Test( expected = ComponentDefinitionException.class ) + public void testFromClassPNFail1( ) + { + NewComponentInfo.fromClass( TestCmpPNFail.class ); + } + + + /** Test: {@link NewComponentInfo#fromClass(Class)} on a component class with lifecycle methods */ + @Test + public void testFromClass5( ) + { + NewComponentInfo< TestCmp5 > nci = NewComponentInfo.fromClass( TestCmp5.class ); + TestCmp5 cmp = nci.getSupplier( ).get( ); + + for ( LifecycleStage stage : LifecycleStage.values( ) ) { + ThrowingConsumer< ? super TestCmp5 > f = nci.getLifecycleAction( stage ); + assertNotNull( f ); + assertFalse( cmp.hadLifecycleAction[ stage.ordinal( ) ] ); + f.accept( cmp ); + assertTrue( cmp.hadLifecycleAction[ stage.ordinal( ) ] ); + } + } + + + /** + * Test: {@link NewComponentInfo#fromClass(Class)} on a component class with inherited and overridden lifecycle + * methods + */ + @Test + public void testFromClass6( ) + { + NewComponentInfo< TestCmp6 > nci = NewComponentInfo.fromClass( TestCmp6.class ); + TestCmp6 cmp = nci.getSupplier( ).get( ); + + for ( LifecycleStage stage : LifecycleStage.values( ) ) { + ThrowingConsumer< ? super TestCmp6 > f = nci.getLifecycleAction( stage ); + assertNotNull( f ); + assertFalse( cmp.hadLifecycleAction[ stage.ordinal( ) ] ); + f.accept( cmp ); + if ( stage == LifecycleStage.INITIALISE ) { + assertFalse( cmp.hadLifecycleAction[ stage.ordinal( ) ] ); + assertTrue( cmp.hadLocalInitialise ); + } else { + assertTrue( cmp.hadLifecycleAction[ stage.ordinal( ) ] ); + } + } + } + + + /** + * Test: {@link NewComponentInfo#fromClass(Class)} on a component class with interface-defined lifecycle methods + */ + @Test + public void testFromClass7( ) + { + NewComponentInfo< TestCmp7 > nci = NewComponentInfo.fromClass( TestCmp7.class ); + TestCmp7 cmp = nci.getSupplier( ).get( ); + + ThrowingConsumer< ? super TestCmp7 > f = nci.getLifecycleAction( LifecycleStage.INITIALISE ); + assertNotNull( f ); + f.accept( cmp ); + assertTrue( cmp.initialised ); + } + + + /** + * Test: {@link NewComponentInfo#fromClass(Class)} on a component class that defines more than one method for a + * single lifecycle stage + */ + @Test( expected = ComponentDefinitionException.class ) + public void testFromClassFail2( ) + { + NewComponentInfo.fromClass( TestFail2.class ); + } + + + /** + * Test: {@link NewComponentInfo#fromClass(Class)} on a component class with a dependency injection field that names + * its target + */ + @Test + public void testFromClass8( ) + { + NewComponentInfo< TestCmp8 > nci = NewComponentInfo.fromClass( TestCmp8.class ); + DependencyInfo expectedDep = new DependencyInfo( "TestCmp1" ); + + HashSet< DependencyInfo > deps = nci.getDependencies( ); + assertEquals( 1 , deps.size( ) ); + assertTrue( deps.contains( expectedDep ) ); + + HashMap< DependencyInfo , ArrayList< ThrowingBiConsumer< ? super TestCmp8 , Object > > > injectors = nci + .getInjectors( ); + assertEquals( 1 , injectors.size( ) ); + ArrayList< ThrowingBiConsumer< ? super TestCmp8 , Object > > diList = injectors.get( expectedDep ); + assertEquals( 1 , diList.size( ) ); + ThrowingBiConsumer< ? super TestCmp8 , Object > injector = diList.get( 0 ); + assertNotNull( injector ); + + TestCmp8 cmp = nci.getSupplier( ).get( ); + TestCmp1 inject = new TestCmp1( ); + injector.accept( cmp , inject ); + assertSame( inject , cmp.dependency ); + } + + + /** + * Test: {@link NewComponentInfo#fromClass(Class)} on a component class with a dependency injection field that + * doesn't name its target + */ + @Test + public void testFromClass9( ) + { + NewComponentInfo< TestCmp9 > nci = NewComponentInfo.fromClass( TestCmp9.class ); + DependencyInfo expectedDep = new DependencyInfo( TestCmp1.class ); + + HashSet< DependencyInfo > deps = nci.getDependencies( ); + assertEquals( 1 , deps.size( ) ); + assertTrue( deps.contains( expectedDep ) ); + + HashMap< DependencyInfo , ArrayList< ThrowingBiConsumer< ? super TestCmp9 , Object > > > injectors = nci + .getInjectors( ); + assertEquals( 1 , injectors.size( ) ); + ArrayList< ThrowingBiConsumer< ? super TestCmp9 , Object > > diList = injectors.get( expectedDep ); + assertEquals( 1 , diList.size( ) ); + ThrowingBiConsumer< ? super TestCmp9 , Object > injector = diList.get( 0 ); + assertNotNull( injector ); + + TestCmp9 cmp = nci.getSupplier( ).get( ); + TestCmp1 inject = new TestCmp1( ); + injector.accept( cmp , inject ); + assertSame( inject , cmp.dependency ); + } + + + /** + * Test: {@link NewComponentInfo#fromClass(Class)} on a component class that has a static dependency injection field + */ + @Test( expected = ComponentDefinitionException.class ) + public void testFromClassFail3( ) + { + NewComponentInfo.fromClass( TestFail3.class ); + } + + + /** + * Test: {@link NewComponentInfo#fromClass(Class)} on a component class that has a final dependency injection field + */ + @Test( expected = ComponentDefinitionException.class ) + public void testFromClassFail4( ) + { + NewComponentInfo.fromClass( TestFail4.class ); + } + + + /** + * Test: {@link NewComponentInfo#fromClass(Class)} on a component class that has a primitive dependency injection + * field + */ + @Test( expected = ComponentDefinitionException.class ) + public void testFromClassFail5( ) + { + NewComponentInfo.fromClass( TestFail5.class ); + } + + + /** + * Test: {@link NewComponentInfo#fromClass(Class)} on a component class that has an array dependency injection field + */ + @Test( expected = ComponentDefinitionException.class ) + public void testFromClassFail6( ) + { + NewComponentInfo.fromClass( TestFail6.class ); + } + + + /** + * Test: {@link NewComponentInfo#fromClass(Class)} on a component class with a dependency injection method that + * names its target + */ + @Test + public void testFromClass10( ) + { + NewComponentInfo< TestCmp10 > nci = NewComponentInfo.fromClass( TestCmp10.class ); + DependencyInfo expectedDep = new DependencyInfo( "TestCmp1" ); + + HashSet< DependencyInfo > deps = nci.getDependencies( ); + assertEquals( 1 , deps.size( ) ); + assertTrue( deps.contains( expectedDep ) ); + + HashMap< DependencyInfo , ArrayList< ThrowingBiConsumer< ? super TestCmp10 , Object > > > injectors = nci + .getInjectors( ); + assertEquals( 1 , injectors.size( ) ); + ArrayList< ThrowingBiConsumer< ? super TestCmp10 , Object > > diList = injectors.get( expectedDep ); + assertEquals( 1 , diList.size( ) ); + ThrowingBiConsumer< ? super TestCmp10 , Object > injector = diList.get( 0 ); + assertNotNull( injector ); + + TestCmp10 cmp = nci.getSupplier( ).get( ); + TestCmp1 inject = new TestCmp1( ); + injector.accept( cmp , inject ); + assertSame( inject , cmp.dependency ); + } + + + /** + * Test: {@link NewComponentInfo#fromClass(Class)} on a component class with a dependency injection method that + * doesn't name its target + */ + @Test + public void testFromClass11( ) + { + NewComponentInfo< TestCmp11 > nci = NewComponentInfo.fromClass( TestCmp11.class ); + DependencyInfo expectedDep = new DependencyInfo( TestCmp1.class ); + + HashSet< DependencyInfo > deps = nci.getDependencies( ); + assertEquals( 1 , deps.size( ) ); + assertTrue( deps.contains( expectedDep ) ); + + HashMap< DependencyInfo , ArrayList< ThrowingBiConsumer< ? super TestCmp11 , Object > > > injectors = nci + .getInjectors( ); + assertEquals( 1 , injectors.size( ) ); + ArrayList< ThrowingBiConsumer< ? super TestCmp11 , Object > > diList = injectors.get( expectedDep ); + assertEquals( 1 , diList.size( ) ); + ThrowingBiConsumer< ? super TestCmp11 , Object > injector = diList.get( 0 ); + assertNotNull( injector ); + + TestCmp11 cmp = nci.getSupplier( ).get( ); + TestCmp1 inject = new TestCmp1( ); + injector.accept( cmp , inject ); + assertSame( inject , cmp.dependency ); + } + + + /** + * Test: {@link NewComponentInfo#fromClass(Class)} on a component class that has a static dependency injection + * method + */ + @Test( expected = ComponentDefinitionException.class ) + public void testFromClassFail7( ) + { + NewComponentInfo.fromClass( TestFail7.class ); + } + + + /** + * Test: {@link NewComponentInfo#fromClass(Class)} on a component class that has a dependency injection method with + * no arguments + */ + @Test( expected = ComponentDefinitionException.class ) + public void testFromClassFail8( ) + { + NewComponentInfo.fromClass( TestFail8.class ); + } + + + /** + * Test: {@link NewComponentInfo#fromClass(Class)} on a component class that has a dependency injection method with + * more than one argument field + */ + @Test( expected = ComponentDefinitionException.class ) + public void testFromClassFail9( ) + { + NewComponentInfo.fromClass( TestFail9.class ); + } + + + /** + * Test: {@link NewComponentInfo#fromClass(Class)} on a component class that has a dependency injection method with + * a primitive argument + */ + @Test( expected = ComponentDefinitionException.class ) + public void testFromClassFail10( ) + { + NewComponentInfo.fromClass( TestFail10.class ); + } + + + /** + * Test: {@link NewComponentInfo#fromClass(Class)} on a component class that has a dependency injection method with + * an array argument + */ + @Test( expected = ComponentDefinitionException.class ) + public void testFromClassFail11( ) + { + NewComponentInfo.fromClass( TestFail11.class ); + } + + + /** + * Test: {@link NewComponentInfo#fromClass(Class)} on a component class with an inherited dependency injection + * method + */ + @Test + public void testFromClass12( ) + { + NewComponentInfo< TestCmp12 > nci = NewComponentInfo.fromClass( TestCmp12.class ); + DependencyInfo expectedDep = new DependencyInfo( "TestCmp1" ); + + HashSet< DependencyInfo > deps = nci.getDependencies( ); + assertEquals( 1 , deps.size( ) ); + assertTrue( deps.contains( expectedDep ) ); + + HashMap< DependencyInfo , ArrayList< ThrowingBiConsumer< ? super TestCmp12 , Object > > > injectors = nci + .getInjectors( ); + assertEquals( 1 , injectors.size( ) ); + ArrayList< ThrowingBiConsumer< ? super TestCmp12 , Object > > diList = injectors.get( expectedDep ); + assertEquals( 1 , diList.size( ) ); + ThrowingBiConsumer< ? super TestCmp12 , Object > injector = diList.get( 0 ); + assertNotNull( injector ); + + TestCmp12 cmp = nci.getSupplier( ).get( ); + TestCmp1 inject = new TestCmp1( ); + injector.accept( cmp , inject ); + assertSame( inject , cmp.dependency ); + } + + + /** + * Test: {@link NewComponentInfo#fromClass(Class)} on a component class with an inherited dependency injection field + */ + @Test + public void testFromClass13( ) + { + NewComponentInfo< TestCmp13 > nci = NewComponentInfo.fromClass( TestCmp13.class ); + DependencyInfo expectedDep = new DependencyInfo( "TestCmp1" ); + + HashSet< DependencyInfo > deps = nci.getDependencies( ); + assertEquals( 1 , deps.size( ) ); + assertTrue( deps.contains( expectedDep ) ); + + HashMap< DependencyInfo , ArrayList< ThrowingBiConsumer< ? super TestCmp13 , Object > > > injectors = nci + .getInjectors( ); + assertEquals( 1 , injectors.size( ) ); + ArrayList< ThrowingBiConsumer< ? super TestCmp13 , Object > > diList = injectors.get( expectedDep ); + assertEquals( 1 , diList.size( ) ); + ThrowingBiConsumer< ? super TestCmp13 , Object > injector = diList.get( 0 ); + assertNotNull( injector ); + + TestCmp13 cmp = nci.getSupplier( ).get( ); + TestCmp1 inject = new TestCmp1( ); + injector.accept( cmp , inject ); + assertSame( inject , cmp.dependency ); + } + + + /** + * Test: {@link NewComponentInfo#fromClass(Class)} on a component class with an interface-defined dependency + * injection method + */ + @Test + public void testFromClass14( ) + { + NewComponentInfo< TestCmp14 > nci = NewComponentInfo.fromClass( TestCmp14.class ); + DependencyInfo expectedDep = new DependencyInfo( "TestCmp1" ); + + HashSet< DependencyInfo > deps = nci.getDependencies( ); + assertEquals( 1 , deps.size( ) ); + assertTrue( deps.contains( expectedDep ) ); + + HashMap< DependencyInfo , ArrayList< ThrowingBiConsumer< ? super TestCmp14 , Object > > > injectors = nci + .getInjectors( ); + assertEquals( 1 , injectors.size( ) ); + ArrayList< ThrowingBiConsumer< ? super TestCmp14 , Object > > diList = injectors.get( expectedDep ); + assertEquals( 1 , diList.size( ) ); + ThrowingBiConsumer< ? super TestCmp14 , Object > injector = diList.get( 0 ); + assertNotNull( injector ); + + TestCmp14 cmp = nci.getSupplier( ).get( ); + TestCmp1 inject = new TestCmp1( ); + injector.accept( cmp , inject ); + assertSame( inject , cmp.dependency ); + } +}