1/*
2 * Copyright (C) 2009 The JSR-330 Expert Group
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package org.atinject.tck.auto;
18
19import junit.framework.TestCase;
20import org.atinject.tck.auto.accessories.Cupholder;
21import org.atinject.tck.auto.accessories.SpareTire;
22import org.atinject.tck.auto.accessories.RoundThing;
23
24import javax.inject.Inject;
25import javax.inject.Named;
26import javax.inject.Provider;
27
28public class Convertible implements Car {
29
30    @Inject @Drivers Seat driversSeatA;
31    @Inject @Drivers Seat driversSeatB;
32    @Inject SpareTire spareTire;
33    @Inject Cupholder cupholder;
34    @Inject Provider<Engine> engineProvider;
35
36    private boolean methodWithZeroParamsInjected;
37    private boolean methodWithMultipleParamsInjected;
38    private boolean methodWithNonVoidReturnInjected;
39
40    private Seat constructorPlainSeat;
41    private Seat constructorDriversSeat;
42    private Tire constructorPlainTire;
43    private Tire constructorSpareTire;
44    private Provider<Seat> constructorPlainSeatProvider = nullProvider();
45    private Provider<Seat> constructorDriversSeatProvider = nullProvider();
46    private Provider<Tire> constructorPlainTireProvider = nullProvider();
47    private Provider<Tire> constructorSpareTireProvider = nullProvider();
48
49    @Inject Seat fieldPlainSeat;
50    @Inject @Drivers Seat fieldDriversSeat;
51    @Inject Tire fieldPlainTire;
52    @Inject @Named("spare") Tire fieldSpareTire;
53    @Inject Provider<Seat> fieldPlainSeatProvider = nullProvider();
54    @Inject @Drivers Provider<Seat> fieldDriversSeatProvider = nullProvider();
55    @Inject Provider<Tire> fieldPlainTireProvider = nullProvider();
56    @Inject @Named("spare") Provider<Tire> fieldSpareTireProvider = nullProvider();
57
58    private Seat methodPlainSeat;
59    private Seat methodDriversSeat;
60    private Tire methodPlainTire;
61    private Tire methodSpareTire;
62    private Provider<Seat> methodPlainSeatProvider = nullProvider();
63    private Provider<Seat> methodDriversSeatProvider = nullProvider();
64    private Provider<Tire> methodPlainTireProvider = nullProvider();
65    private Provider<Tire> methodSpareTireProvider = nullProvider();
66
67    @Inject static Seat staticFieldPlainSeat;
68    @Inject @Drivers static Seat staticFieldDriversSeat;
69    @Inject static Tire staticFieldPlainTire;
70    @Inject @Named("spare") static Tire staticFieldSpareTire;
71    @Inject static Provider<Seat> staticFieldPlainSeatProvider = nullProvider();
72    @Inject @Drivers static Provider<Seat> staticFieldDriversSeatProvider = nullProvider();
73    @Inject static Provider<Tire> staticFieldPlainTireProvider = nullProvider();
74    @Inject @Named("spare") static Provider<Tire> staticFieldSpareTireProvider = nullProvider();
75
76    private static Seat staticMethodPlainSeat;
77    private static Seat staticMethodDriversSeat;
78    private static Tire staticMethodPlainTire;
79    private static Tire staticMethodSpareTire;
80    private static Provider<Seat> staticMethodPlainSeatProvider = nullProvider();
81    private static Provider<Seat> staticMethodDriversSeatProvider = nullProvider();
82    private static Provider<Tire> staticMethodPlainTireProvider = nullProvider();
83    private static Provider<Tire> staticMethodSpareTireProvider = nullProvider();
84
85    @Inject Convertible(
86            Seat plainSeat,
87            @Drivers Seat driversSeat,
88            Tire plainTire,
89            @Named("spare") Tire spareTire,
90            Provider<Seat> plainSeatProvider,
91            @Drivers Provider<Seat> driversSeatProvider,
92            Provider<Tire> plainTireProvider,
93            @Named("spare") Provider<Tire> spareTireProvider) {
94        constructorPlainSeat = plainSeat;
95        constructorDriversSeat = driversSeat;
96        constructorPlainTire = plainTire;
97        constructorSpareTire = spareTire;
98        constructorPlainSeatProvider = plainSeatProvider;
99        constructorDriversSeatProvider = driversSeatProvider;
100        constructorPlainTireProvider = plainTireProvider;
101        constructorSpareTireProvider = spareTireProvider;
102    }
103
104    Convertible() {
105        throw new AssertionError("Unexpected call to non-injectable constructor");
106    }
107
108    void setSeat(Seat unused) {
109        throw new AssertionError("Unexpected call to non-injectable method");
110    }
111
112    @Inject void injectMethodWithZeroArgs() {
113        methodWithZeroParamsInjected = true;
114    }
115
116    @Inject String injectMethodWithNonVoidReturn() {
117        methodWithNonVoidReturnInjected = true;
118        return "unused";
119    }
120
121    @Inject void injectInstanceMethodWithManyArgs(
122            Seat plainSeat,
123            @Drivers Seat driversSeat,
124            Tire plainTire,
125            @Named("spare") Tire spareTire,
126            Provider<Seat> plainSeatProvider,
127            @Drivers Provider<Seat> driversSeatProvider,
128            Provider<Tire> plainTireProvider,
129            @Named("spare") Provider<Tire> spareTireProvider) {
130        methodWithMultipleParamsInjected = true;
131
132        methodPlainSeat = plainSeat;
133        methodDriversSeat = driversSeat;
134        methodPlainTire = plainTire;
135        methodSpareTire = spareTire;
136        methodPlainSeatProvider = plainSeatProvider;
137        methodDriversSeatProvider = driversSeatProvider;
138        methodPlainTireProvider = plainTireProvider;
139        methodSpareTireProvider = spareTireProvider;
140    }
141
142    @Inject static void injectStaticMethodWithManyArgs(
143            Seat plainSeat,
144            @Drivers Seat driversSeat,
145            Tire plainTire,
146            @Named("spare") Tire spareTire,
147            Provider<Seat> plainSeatProvider,
148            @Drivers Provider<Seat> driversSeatProvider,
149            Provider<Tire> plainTireProvider,
150            @Named("spare") Provider<Tire> spareTireProvider) {
151        staticMethodPlainSeat = plainSeat;
152        staticMethodDriversSeat = driversSeat;
153        staticMethodPlainTire = plainTire;
154        staticMethodSpareTire = spareTire;
155        staticMethodPlainSeatProvider = plainSeatProvider;
156        staticMethodDriversSeatProvider = driversSeatProvider;
157        staticMethodPlainTireProvider = plainTireProvider;
158        staticMethodSpareTireProvider = spareTireProvider;
159    }
160
161    /**
162     * Returns a provider that always returns null. This is used as a default
163     * value to avoid null checks for omitted provider injections.
164     */
165    private static <T> Provider<T> nullProvider() {
166        return new Provider<T>() {
167            public T get() {
168                return null;
169            }
170        };
171    }
172
173    public static ThreadLocal<Convertible> localConvertible
174            = new ThreadLocal<Convertible>();
175
176    public static class Tests extends TestCase {
177
178        private final Convertible car = localConvertible.get();
179        private final Cupholder cupholder = car.cupholder;
180        private final SpareTire spareTire = car.spareTire;
181        private final Tire plainTire = car.fieldPlainTire;
182        private final Engine engine = car.engineProvider.get();
183
184        // smoke tests: if these fail all bets are off
185
186        public void testFieldsInjected() {
187            assertTrue(cupholder != null && spareTire != null);
188        }
189
190        public void testProviderReturnedValues() {
191            assertTrue(engine != null);
192        }
193
194        // injecting different kinds of members
195
196        public void testMethodWithZeroParametersInjected() {
197            assertTrue(car.methodWithZeroParamsInjected);
198        }
199
200        public void testMethodWithMultipleParametersInjected() {
201            assertTrue(car.methodWithMultipleParamsInjected);
202        }
203
204        public void testNonVoidMethodInjected() {
205            assertTrue(car.methodWithNonVoidReturnInjected);
206        }
207
208        public void testPublicNoArgsConstructorInjected() {
209            assertTrue(engine.publicNoArgsConstructorInjected);
210        }
211
212        public void testSubtypeFieldsInjected() {
213            assertTrue(spareTire.hasSpareTireBeenFieldInjected());
214        }
215
216        public void testSubtypeMethodsInjected() {
217            assertTrue(spareTire.hasSpareTireBeenMethodInjected());
218        }
219
220        public void testSupertypeFieldsInjected() {
221            assertTrue(spareTire.hasTireBeenFieldInjected());
222        }
223
224        public void testSupertypeMethodsInjected() {
225            assertTrue(spareTire.hasTireBeenMethodInjected());
226        }
227
228        public void testTwiceOverriddenMethodInjectedWhenMiddleLacksAnnotation() {
229            assertTrue(engine.overriddenTwiceWithOmissionInMiddleInjected);
230        }
231
232        // injected values
233
234        public void testQualifiersNotInheritedFromOverriddenMethod() {
235            assertFalse(engine.qualifiersInheritedFromOverriddenMethod);
236        }
237
238        public void testConstructorInjectionWithValues() {
239            assertFalse("Expected unqualified value",
240                    car.constructorPlainSeat instanceof DriversSeat);
241            assertFalse("Expected unqualified value",
242                    car.constructorPlainTire instanceof SpareTire);
243            assertTrue("Expected qualified value",
244                    car.constructorDriversSeat instanceof DriversSeat);
245            assertTrue("Expected qualified value",
246                    car.constructorSpareTire instanceof SpareTire);
247        }
248
249        public void testFieldInjectionWithValues() {
250            assertFalse("Expected unqualified value",
251                    car.fieldPlainSeat instanceof DriversSeat);
252            assertFalse("Expected unqualified value",
253                    car.fieldPlainTire instanceof SpareTire);
254            assertTrue("Expected qualified value",
255                    car.fieldDriversSeat instanceof DriversSeat);
256            assertTrue("Expected qualified value",
257                    car.fieldSpareTire instanceof SpareTire);
258        }
259
260        public void testMethodInjectionWithValues() {
261            assertFalse("Expected unqualified value",
262                    car.methodPlainSeat instanceof DriversSeat);
263            assertFalse("Expected unqualified value",
264                    car.methodPlainTire instanceof SpareTire);
265            assertTrue("Expected qualified value",
266                    car.methodDriversSeat instanceof DriversSeat);
267            assertTrue("Expected qualified value",
268                    car.methodSpareTire instanceof SpareTire);
269        }
270
271        // injected providers
272
273        public void testConstructorInjectionWithProviders() {
274            assertFalse("Expected unqualified value",
275                    car.constructorPlainSeatProvider.get() instanceof DriversSeat);
276            assertFalse("Expected unqualified value",
277                    car.constructorPlainTireProvider.get() instanceof SpareTire);
278            assertTrue("Expected qualified value",
279                    car.constructorDriversSeatProvider.get() instanceof DriversSeat);
280            assertTrue("Expected qualified value",
281                    car.constructorSpareTireProvider.get() instanceof SpareTire);
282        }
283
284        public void testFieldInjectionWithProviders() {
285            assertFalse("Expected unqualified value",
286                    car.fieldPlainSeatProvider.get() instanceof DriversSeat);
287            assertFalse("Expected unqualified value",
288                    car.fieldPlainTireProvider.get() instanceof SpareTire);
289            assertTrue("Expected qualified value",
290                    car.fieldDriversSeatProvider.get() instanceof DriversSeat);
291            assertTrue("Expected qualified value",
292                    car.fieldSpareTireProvider.get() instanceof SpareTire);
293        }
294
295        public void testMethodInjectionWithProviders() {
296            assertFalse("Expected unqualified value",
297                    car.methodPlainSeatProvider.get() instanceof DriversSeat);
298            assertFalse("Expected unqualified value",
299                    car.methodPlainTireProvider.get() instanceof SpareTire);
300            assertTrue("Expected qualified value",
301                    car.methodDriversSeatProvider.get() instanceof DriversSeat);
302            assertTrue("Expected qualified value",
303                    car.methodSpareTireProvider.get() instanceof SpareTire);
304        }
305
306
307        // singletons
308
309        public void testConstructorInjectedProviderYieldsSingleton() {
310            assertSame("Expected same value",
311                    car.constructorPlainSeatProvider.get(), car.constructorPlainSeatProvider.get());
312        }
313
314        public void testFieldInjectedProviderYieldsSingleton() {
315            assertSame("Expected same value",
316                    car.fieldPlainSeatProvider.get(), car.fieldPlainSeatProvider.get());
317        }
318
319        public void testMethodInjectedProviderYieldsSingleton() {
320            assertSame("Expected same value",
321                    car.methodPlainSeatProvider.get(), car.methodPlainSeatProvider.get());
322        }
323
324        public void testCircularlyDependentSingletons() {
325            // uses provider.get() to get around circular deps
326            assertSame(cupholder.seatProvider.get().getCupholder(), cupholder);
327        }
328
329
330        // non singletons
331
332        public void testSingletonAnnotationNotInheritedFromSupertype() {
333            assertNotSame(car.driversSeatA, car.driversSeatB);
334        }
335
336        public void testConstructorInjectedProviderYieldsDistinctValues() {
337            assertNotSame("Expected distinct values",
338                    car.constructorDriversSeatProvider.get(), car.constructorDriversSeatProvider.get());
339            assertNotSame("Expected distinct values",
340                    car.constructorPlainTireProvider.get(), car.constructorPlainTireProvider.get());
341            assertNotSame("Expected distinct values",
342                    car.constructorSpareTireProvider.get(), car.constructorSpareTireProvider.get());
343        }
344
345        public void testFieldInjectedProviderYieldsDistinctValues() {
346            assertNotSame("Expected distinct values",
347                    car.fieldDriversSeatProvider.get(), car.fieldDriversSeatProvider.get());
348            assertNotSame("Expected distinct values",
349                    car.fieldPlainTireProvider.get(), car.fieldPlainTireProvider.get());
350            assertNotSame("Expected distinct values",
351                    car.fieldSpareTireProvider.get(), car.fieldSpareTireProvider.get());
352        }
353
354        public void testMethodInjectedProviderYieldsDistinctValues() {
355            assertNotSame("Expected distinct values",
356                    car.methodDriversSeatProvider.get(), car.methodDriversSeatProvider.get());
357            assertNotSame("Expected distinct values",
358                    car.methodPlainTireProvider.get(), car.methodPlainTireProvider.get());
359            assertNotSame("Expected distinct values",
360                    car.methodSpareTireProvider.get(), car.methodSpareTireProvider.get());
361        }
362
363
364        // mix inheritance + visibility
365
366        public void testPackagePrivateMethodInjectedDifferentPackages() {
367            assertTrue(spareTire.subPackagePrivateMethodInjected);
368            assertTrue(spareTire.superPackagePrivateMethodInjected);
369        }
370
371        public void testOverriddenProtectedMethodInjection() {
372            assertTrue(spareTire.subProtectedMethodInjected);
373            assertFalse(spareTire.superProtectedMethodInjected);
374        }
375
376        public void testOverriddenPublicMethodNotInjected() {
377            assertTrue(spareTire.subPublicMethodInjected);
378            assertFalse(spareTire.superPublicMethodInjected);
379        }
380
381
382        // inject in order
383
384        public void testFieldsInjectedBeforeMethods() {
385            assertFalse(spareTire.methodInjectedBeforeFields);
386        }
387
388        public void testSupertypeMethodsInjectedBeforeSubtypeFields() {
389            assertFalse(spareTire.subtypeFieldInjectedBeforeSupertypeMethods);
390        }
391
392        public void testSupertypeMethodInjectedBeforeSubtypeMethods() {
393            assertFalse(spareTire.subtypeMethodInjectedBeforeSupertypeMethods);
394        }
395
396
397        // necessary injections occur
398
399        public void testPackagePrivateMethodInjectedEvenWhenSimilarMethodLacksAnnotation() {
400            assertTrue(spareTire.subPackagePrivateMethodForOverrideInjected);
401        }
402
403
404        // override or similar method without @Inject
405
406        public void testPrivateMethodNotInjectedWhenSupertypeHasAnnotatedSimilarMethod() {
407            assertFalse(spareTire.superPrivateMethodForOverrideInjected);
408        }
409
410        public void testPackagePrivateMethodNotInjectedWhenOverrideLacksAnnotation() {
411            assertFalse(engine.subPackagePrivateMethodForOverrideInjected);
412            assertFalse(engine.superPackagePrivateMethodForOverrideInjected);
413        }
414
415        public void testPackagePrivateMethodNotInjectedWhenSupertypeHasAnnotatedSimilarMethod() {
416            assertFalse(spareTire.superPackagePrivateMethodForOverrideInjected);
417        }
418
419        public void testProtectedMethodNotInjectedWhenOverrideNotAnnotated() {
420            assertFalse(spareTire.protectedMethodForOverrideInjected);
421        }
422
423        public void testPublicMethodNotInjectedWhenOverrideNotAnnotated() {
424            assertFalse(spareTire.publicMethodForOverrideInjected);
425        }
426
427        public void testTwiceOverriddenMethodNotInjectedWhenOverrideLacksAnnotation() {
428            assertFalse(engine.overriddenTwiceWithOmissionInSubclassInjected);
429        }
430
431        public void testOverriddingMixedWithPackagePrivate2() {
432            assertTrue(spareTire.packagePrivateMethod2Injected);
433            assertTrue(((Tire) spareTire).packagePrivateMethod2Injected);
434            assertFalse(((RoundThing) spareTire).packagePrivateMethod2Injected);
435
436            assertTrue(plainTire.packagePrivateMethod2Injected);
437            assertTrue(((RoundThing) plainTire).packagePrivateMethod2Injected);
438        }
439
440        public void testOverriddingMixedWithPackagePrivate3() {
441            assertFalse(spareTire.packagePrivateMethod3Injected);
442            assertTrue(((Tire) spareTire).packagePrivateMethod3Injected);
443            assertFalse(((RoundThing) spareTire).packagePrivateMethod3Injected);
444
445            assertTrue(plainTire.packagePrivateMethod3Injected);
446            assertTrue(((RoundThing) plainTire).packagePrivateMethod3Injected);
447        }
448
449        public void testOverriddingMixedWithPackagePrivate4() {
450            assertFalse(plainTire.packagePrivateMethod4Injected);
451            assertTrue(((RoundThing) plainTire).packagePrivateMethod4Injected);
452        }
453
454        // inject only once
455
456        public void testOverriddenPackagePrivateMethodInjectedOnlyOnce() {
457            assertFalse(engine.overriddenPackagePrivateMethodInjectedTwice);
458        }
459
460        public void testSimilarPackagePrivateMethodInjectedOnlyOnce() {
461            assertFalse(spareTire.similarPackagePrivateMethodInjectedTwice);
462        }
463
464        public void testOverriddenProtectedMethodInjectedOnlyOnce() {
465            assertFalse(spareTire.overriddenProtectedMethodInjectedTwice);
466        }
467
468        public void testOverriddenPublicMethodInjectedOnlyOnce() {
469            assertFalse(spareTire.overriddenPublicMethodInjectedTwice);
470        }
471
472    }
473
474    public static class StaticTests extends TestCase {
475
476        public void testSubtypeStaticFieldsInjected() {
477            assertTrue(SpareTire.hasBeenStaticFieldInjected());
478        }
479
480        public void testSubtypeStaticMethodsInjected() {
481            assertTrue(SpareTire.hasBeenStaticMethodInjected());
482        }
483
484        public void testSupertypeStaticFieldsInjected() {
485            assertTrue(Tire.hasBeenStaticFieldInjected());
486        }
487
488        public void testSupertypeStaticMethodsInjected() {
489            assertTrue(Tire.hasBeenStaticMethodInjected());
490        }
491
492        public void testStaticFieldInjectionWithValues() {
493            assertFalse("Expected unqualified value",
494                    staticFieldPlainSeat instanceof DriversSeat);
495            assertFalse("Expected unqualified value",
496                    staticFieldPlainTire instanceof SpareTire);
497            assertTrue("Expected qualified value",
498                    staticFieldDriversSeat instanceof DriversSeat);
499            assertTrue("Expected qualified value",
500                    staticFieldSpareTire instanceof SpareTire);
501        }
502
503        public void testStaticMethodInjectionWithValues() {
504            assertFalse("Expected unqualified value",
505                    staticMethodPlainSeat instanceof DriversSeat);
506            assertFalse("Expected unqualified value",
507                    staticMethodPlainTire instanceof SpareTire);
508            assertTrue("Expected qualified value",
509                    staticMethodDriversSeat instanceof DriversSeat);
510            assertTrue("Expected qualified value",
511                    staticMethodSpareTire instanceof SpareTire);
512        }
513
514        public void testStaticFieldsInjectedBeforeMethods() {
515            assertFalse(SpareTire.staticMethodInjectedBeforeStaticFields);
516        }
517
518        public void testSupertypeStaticMethodsInjectedBeforeSubtypeStaticFields() {
519            assertFalse(SpareTire.subtypeStaticFieldInjectedBeforeSupertypeStaticMethods);
520        }
521
522        public void testSupertypeStaticMethodsInjectedBeforeSubtypeStaticMethods() {
523            assertFalse(SpareTire.subtypeStaticMethodInjectedBeforeSupertypeStaticMethods);
524        }
525
526        public void testStaticFieldInjectionWithProviders() {
527            assertFalse("Expected unqualified value",
528                    staticFieldPlainSeatProvider.get() instanceof DriversSeat);
529            assertFalse("Expected unqualified value",
530                    staticFieldPlainTireProvider.get() instanceof SpareTire);
531            assertTrue("Expected qualified value",
532                    staticFieldDriversSeatProvider.get() instanceof DriversSeat);
533            assertTrue("Expected qualified value",
534                    staticFieldSpareTireProvider.get() instanceof SpareTire);
535        }
536
537        public void testStaticMethodInjectionWithProviders() {
538            assertFalse("Expected unqualified value",
539                    staticMethodPlainSeatProvider.get() instanceof DriversSeat);
540            assertFalse("Expected unqualified value",
541                    staticMethodPlainTireProvider.get() instanceof SpareTire);
542            assertTrue("Expected qualified value",
543                    staticMethodDriversSeatProvider.get() instanceof DriversSeat);
544            assertTrue("Expected qualified value",
545                    staticMethodSpareTireProvider.get() instanceof SpareTire);
546        }
547    }
548
549    public static class PrivateTests extends TestCase {
550
551        private final Convertible car = localConvertible.get();
552        private final Engine engine = car.engineProvider.get();
553        private final SpareTire spareTire = car.spareTire;
554
555        public void testSupertypePrivateMethodInjected() {
556            assertTrue(spareTire.superPrivateMethodInjected);
557            assertTrue(spareTire.subPrivateMethodInjected);
558        }
559
560        public void testPackagePrivateMethodInjectedSamePackage() {
561            assertTrue(engine.subPackagePrivateMethodInjected);
562            assertFalse(engine.superPackagePrivateMethodInjected);
563        }
564
565        public void testPrivateMethodInjectedEvenWhenSimilarMethodLacksAnnotation() {
566            assertTrue(spareTire.subPrivateMethodForOverrideInjected);
567        }
568
569        public void testSimilarPrivateMethodInjectedOnlyOnce() {
570            assertFalse(spareTire.similarPrivateMethodInjectedTwice);
571        }
572    }
573}
574