]> git.somenet.org - pub/jan/dst18.git/blob - ass2-di/src/test/java/dst/ass2/di/SpecialInjectionTest.java
[3.3] first part.
[pub/jan/dst18.git] / ass2-di / src / test / java / dst / ass2 / di / SpecialInjectionTest.java
1 package dst.ass2.di;
2
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;
10
11 import java.util.Map;
12
13 import org.junit.Before;
14 import org.junit.Test;
15 import org.springframework.util.ReflectionUtils;
16
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;
22
23 public class SpecialInjectionTest {
24     private IInjectionController ic;
25
26     @Before
27     public void before() {
28         ic = InjectionControllerFactory.getNewStandaloneInstance();
29     }
30
31     /**
32      * Attempts to create and initialize two singletons of the same time.
33      */
34     @Test
35     public void testInitializeSingletonTwice() {
36         // Initializing a singleton component also registers it for further use
37         ic.initialize(new SimpleSingleton());
38         try {
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) {
43             // expected
44         }
45     }
46
47     /**
48      * Attempts to initialize a singleton manually twice and retrieves it from the {@link IInjectionController}.
49      */
50     @Test
51     public void testInitializeSingletonManually() {
52         SimpleSingleton singleton = new SimpleSingleton();
53         ic.initialize(singleton);
54         try {
55             // Initializing a singleton instance twice results in an InjectionException
56             ic.initialize(singleton);
57             fail(InjectionException.class.getSimpleName() + " expected.");
58         } catch (InjectionException e) {
59             // expected
60         }
61
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));
64     }
65
66     /**
67      * Initializes a prototype twice.
68      * <p/>
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.
74      */
75     @Test
76     public void testInitializePrototypeTwice() {
77         // Create an initialize the container
78         Container container = new Container();
79         ic.initialize(container);
80
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);
84
85         // Re-initialize the same object
86         ic.initialize(container);
87
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);
91
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);
95
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);
99
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.";
103
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);
110     }
111
112     /**
113      * Tests the type qualifier of the {@link dst.ass2.di.annotation.Inject} annotation.
114      */
115     @Test
116     public void testQualifier() {
117         ComplexComponent component = new ComplexComponent();
118         ic.initialize(component);
119
120         // Required components
121
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);
128
129         // Optional components
130
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);
137     }
138
139     /**
140      * Tests whether private hidden fields of super types are injected.
141      */
142     @Test
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);
147
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);
151
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")));
157
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"));
163     }
164 }