3 import static org.junit.Assert.assertFalse;
4 import static org.junit.Assert.assertNotNull;
5 import static org.junit.Assert.assertNotSame;
6 import static org.junit.Assert.assertNull;
7 import static org.junit.Assert.assertSame;
8 import static org.junit.Assert.assertTrue;
9 import static org.junit.Assert.fail;
13 import org.junit.Before;
14 import org.junit.Test;
15 import org.springframework.util.ReflectionUtils;
17 import dst.ass2.di.type.ComplexComponent;
18 import dst.ass2.di.type.Container;
19 import dst.ass2.di.type.SimpleSingleton;
20 import dst.ass2.di.type.SubType;
21 import dst.ass2.di.type.SuperType;
23 public class SpecialInjectionTest {
24 private IInjectionController ic;
27 public void before() {
28 ic = InjectionControllerFactory.getNewStandaloneInstance();
32 * Attempts to create and initialize two singletons of the same time.
35 public void testInitializeSingletonTwice() {
36 // Initializing a singleton component also registers it for further use
37 ic.initialize(new SimpleSingleton());
39 // Initializing a singleton of the same type results in an InjectionException
40 ic.initialize(new SimpleSingleton());
41 fail(InjectionException.class.getSimpleName() + " expected.");
42 } catch (InjectionException e) {
48 * Attempts to initialize a singleton manually twice and retrieves it from the {@link IInjectionController}.
51 public void testInitializeSingletonManually() {
52 SimpleSingleton singleton = new SimpleSingleton();
53 ic.initialize(singleton);
55 // Initializing a singleton instance twice results in an InjectionException
56 ic.initialize(singleton);
57 fail(InjectionException.class.getSimpleName() + " expected.");
58 } catch (InjectionException e) {
62 // Retrieving a singleton of a certain type always returns the same object instance.
63 assertSame("Singletons must be the same object instance.", singleton, ic.getSingletonInstance(SimpleSingleton.class));
67 * Initializes a prototype twice.
69 * Every time a prototype component is initialized, all fields annotated with
70 * {@link dst.ass2.di.annotation.Inject Inject} become injected again. In other words, for every prototype the
71 * {@link IInjectionController} creates a new instance and replaces the reference to the the previous one.<br/>
72 * Finally, if nothing went wrong, the component gets a new component ID indicating that all fields have been
73 * re-injected successfully.
76 public void testInitializePrototypeTwice() {
77 // Create an initialize the container
78 Container container = new Container();
79 ic.initialize(container);
81 // Create a copy of the container by copying the object references for later comparison.
82 Container copy = new Container();
83 ReflectionUtils.shallowCopyFieldState(container, copy);
85 // Re-initialize the same object
86 ic.initialize(container);
88 // Verify that the object still references the same singleton.
89 assertSame("Both singleton references must be the same object instance.", copy.first, container.first);
90 assertSame("Both singleton references must be the same object instance.", copy.second, container.second);
92 // Verify that the prototype references have been changed.
93 assertNotSame("Prototype components must be different.", copy.component, container.component);
94 assertNotSame("Prototype components must be different.", copy.anotherComponent, container.anotherComponent);
96 // Verify that the IDs are different
97 assertTrue("The ID after the first initialization must be lower or equal to 3.", copy.id <= 3);
98 assertTrue("The ID after the second initialization must be between 4 and 6 inclusive.", 4 <= container.id && container.id <= 6);
100 // Verify that the IDs of the prototype components are correct
101 String afterFirst = "The ID of '%s' after the first initialization must be lower or equal to 3.";
102 String afterSecond = "The ID of '%s' after the second initialization must be between 4 and 6 inclusive.";
104 // Due to the fact that Container consists of two prototypes and one singleton, which is referenced twice,
105 // initializing the first Container requires 4 IDs and every additional instance 3 IDs
106 assertTrue(String.format(afterFirst, "component"), copy.component.id <= 3);
107 assertTrue(String.format(afterSecond, "component"), 4 <= container.component.id && container.component.id <= 6);
108 assertTrue(String.format(afterFirst, "anotherComponent"), copy.anotherComponent.id <= 3);
109 assertTrue(String.format(afterSecond, "anotherComponent"), 4 <= container.anotherComponent.id && container.anotherComponent.id <= 6);
113 * Tests the type qualifier of the {@link dst.ass2.di.annotation.Inject} annotation.
116 public void testQualifier() {
117 ComplexComponent component = new ComplexComponent();
118 ic.initialize(component);
120 // Required components
122 assertNotNull("'id' must not be null.", component.id);
123 // singleton is a required field
124 assertNotNull("'singleton' must not be null.", component.singleton);
125 // unknownSingleton is of type Object but requires the specific type SimpleSingleton
126 assertNotNull("'unknownSingleton' must not be null.", component.unknownSingleton);
127 assertSame("Both singleton references must be the same object instance.", component.singleton, component.unknownSingleton);
129 // Optional components
131 // theVoid is of type Void
132 assertNull("'theVoid must be null.'", component.theVoid);
133 // type Invalid, which is not a valid component
134 assertNull("'invalid' must be null.'", component.invalid);
135 // type SimpleComponent but requires SimpleSingleton which results in a ClassCastException
136 assertNull("'singletonPrototype' must be null.", component.singletonPrototype);
140 * Tests whether private hidden fields of super types are injected.
143 public void testInheritance() {
144 // When initializing an object, all fields are initialized (even those, which are not visible).
145 SubType subType = new SubType();
146 ic.initialize(subType);
148 // Retrieving all declared fields of the SubType and SuperType
149 Map<String, Object> subFields = InjectionUtils.getFields(subType, SubType.class);
150 Map<String, Object> superFields = InjectionUtils.getFields(subType, SuperType.class);
152 // Verify that the component IDs are set
153 assertNotNull("'id' of SubType must not be null.", subFields.get("id"));
154 assertNotNull("'id' of SuperType must not be null.", superFields.get("id"));
155 // The component IDs must be equal
156 assertTrue("The 'id's of SuperType and SubType must be equal.", subFields.get("id").equals(superFields.get("id")));
158 // Verify that all fields are initialized properly
159 assertNotNull("'component' of SubType must not be null.", subFields.get("component"));
160 assertNotNull("'component' of SuperType must not be null.", superFields.get("component"));
161 // The injected objects must be different
162 assertFalse("The 'component's of SuperType and SubType must not be the same object instance.", subFields.get("component") == superFields.get("component"));