1 /**
2  * Poodinis Dependency Injection Framework
3  * Copyright 2014-2025 Mike Bierlee
4  * This software is licensed under the terms of the MIT license.
5  * The full terms of the license can be found in the LICENSE file.
6  */
7 
8 module poodinis.testclasses;
9 
10 version (unittest)  :  //
11 
12 import poodinis;
13 import poodinis.foreigndependencies;
14 
15 class ComponentA {
16 }
17 
18 class ComponentB {
19     @Inject ComponentA componentA;
20 }
21 
22 interface InterfaceA {
23 }
24 
25 class ComponentC : InterfaceA {
26 }
27 
28 class ComponentD {
29     @Inject InterfaceA componentC = null;
30     private @Inject InterfaceA _privateComponentC = null;
31 
32     InterfaceA privateComponentC() {
33         return _privateComponentC;
34     }
35 }
36 
37 class DummyAttribute {
38 }
39 
40 class ComponentE {
41     @DummyAttribute ComponentC componentC;
42 }
43 
44 class ComponentDeclarationCocktail {
45     alias noomer = int;
46 
47     @Inject ComponentA componentA;
48 
49     void doesNothing() {
50     }
51 
52     ~this() {
53     }
54 }
55 
56 class ComponentX : InterfaceA {
57 }
58 
59 class ComponentZ : ComponentB {
60 }
61 
62 class MonkeyShine {
63     @Inject!ComponentX InterfaceA component;
64 }
65 
66 class BootstrapBootstrap {
67     @Inject!ComponentX InterfaceA componentX;
68 
69     @Inject!ComponentC InterfaceA componentC;
70 }
71 
72 class LordOfTheComponents {
73     @Inject InterfaceA[] components;
74 }
75 
76 class ComponentCharlie {
77     @Inject @AssignNewInstance ComponentA componentA;
78 }
79 
80 class OuttaTime {
81     @Inject @OptionalDependency InterfaceA interfaceA;
82 
83     @Inject @OptionalDependency ComponentA componentA;
84 
85     @Inject @OptionalDependency ComponentC[] componentCs;
86 }
87 
88 class ValuedClass {
89     @Value("values.int")
90     int intValue;
91 
92     @Inject ComponentA unrelated;
93 }
94 
95 class TestInjector : ValueInjector!int {
96     override int get(string key) {
97         assert(key == "values.int");
98         return 8;
99     }
100 }
101 
102 interface TestInterface {
103 }
104 
105 class TestClass : TestInterface {
106 }
107 
108 class TestClassDeux : TestInterface {
109     @Inject UnrelatedClass unrelated;
110 }
111 
112 class UnrelatedClass {
113 }
114 
115 class FailOnCreationClass {
116     this() {
117         throw new Exception("This class should not be instantiated");
118     }
119 }
120 
121 class AutowiredClass {
122 }
123 
124 class ComponentClass {
125     @Inject AutowiredClass autowiredClass;
126 }
127 
128 class ComponentCat {
129     @Inject ComponentMouse mouse;
130 }
131 
132 class ComponentMouse {
133     @Inject ComponentCat cat;
134 }
135 
136 class Eenie {
137     @Inject Meenie meenie;
138 }
139 
140 class Meenie {
141     @Inject Moe moe;
142 }
143 
144 class Moe {
145     @Inject Eenie eenie;
146 }
147 
148 class Ittie {
149     @Inject Bittie bittie;
150 }
151 
152 class Bittie {
153     @Inject Bunena banana;
154 }
155 
156 class Bunena {
157     @Inject Bittie bittie;
158 }
159 
160 interface SuperInterface {
161 }
162 
163 class SuperImplementation : SuperInterface {
164     @Inject Bunena banana;
165 }
166 
167 interface Color {
168 }
169 
170 class Blue : Color {
171 }
172 
173 class Red : Color {
174 }
175 
176 class Spiders {
177     @Inject TestInterface testMember;
178 }
179 
180 class Recursive {
181     @Inject Recursive recursive;
182 }
183 
184 class Moolah {
185 }
186 
187 class Wants {
188     @Inject Moolah moolah;
189 }
190 
191 class John {
192     @Inject Wants wants;
193 }
194 
195 class Cocktail {
196     @Inject Moolah moolah;
197 
198     Red red;
199 
200     this(Red red) {
201         this.red = red;
202     }
203 }
204 
205 class Wallpaper {
206     Color color;
207 
208     this(Color color) {
209         this.color = color;
210     }
211 }
212 
213 class Pot {
214     this(Kettle kettle) {
215     }
216 }
217 
218 class Kettle {
219     this(Pot pot) {
220     }
221 }
222 
223 class Rock {
224     this(Scissors scissors) {
225     }
226 }
227 
228 class Paper {
229     this(Rock rock) {
230     }
231 }
232 
233 class Scissors {
234     this(Paper paper) {
235     }
236 }
237 
238 class Hello {
239     this(Ola ola) {
240     }
241 }
242 
243 class PostConstructionDependency {
244     bool postConstructWasCalled = false;
245 
246     @PostConstruct void callMeMaybe() {
247         postConstructWasCalled = true;
248     }
249 }
250 
251 class ChildOfPostConstruction : PostConstructionDependency {
252 }
253 
254 interface ThereWillBePostConstruction {
255     @PostConstruct void constructIt();
256 }
257 
258 class ButThereWontBe : ThereWillBePostConstruction {
259     bool postConstructWasCalled = false;
260 
261     override void constructIt() {
262         postConstructWasCalled = true;
263     }
264 }
265 
266 class PostConstructWithAutowiring {
267     @Inject private PostConstructionDependency dependency;
268 
269     @Value("")
270     private int theNumber = 1;
271 
272     @PostConstruct void doIt() {
273         assert(theNumber == 8783);
274         assert(dependency !is null);
275     }
276 }
277 
278 class PreDestroyerOfFates {
279     bool preDestroyWasCalled = false;
280 
281     @PreDestroy void callMeMaybe() {
282         preDestroyWasCalled = true;
283     }
284 }
285 
286 class PostConstructingIntInjector : ValueInjector!int {
287     int get(string key) {
288         return 8783;
289     }
290 }
291 
292 interface Fruit {
293     string getShape();
294 }
295 
296 interface Animal {
297     string getYell();
298 }
299 
300 class Banana {
301     string color;
302 
303     this(string color) {
304         this.color = color;
305     }
306 }
307 
308 class Apple {
309 }
310 
311 class Pear : Fruit {
312     override string getShape() {
313         return "Pear shaped";
314     }
315 }
316 
317 class Rabbit : Animal {
318     override string getYell() {
319         return "Squeeeeeel";
320     }
321 }
322 
323 class Wolf : Animal {
324     override string getYell() {
325         return "Wooooooooooo";
326     }
327 }
328 
329 class PieChart {
330 }
331 
332 class CakeChart : PieChart {
333 }
334 
335 class ClassWrapper {
336     Object someClass;
337 
338     this(Object someClass) {
339         this.someClass = someClass;
340     }
341 }
342 
343 class ClassWrapperWrapper {
344     ClassWrapper wrapper;
345 
346     this(ClassWrapper wrapper) {
347         this.wrapper = wrapper;
348     }
349 }
350 
351 class SimpleContext : ApplicationContext {
352     override void registerDependencies(shared(DependencyContainer) container) {
353         container.register!CakeChart;
354     }
355 
356     @Component Apple apple() {
357         return new Apple();
358     }
359 }
360 
361 class ComplexAutowiredTestContext : ApplicationContext {
362 
363     @Inject private Apple apple;
364 
365     @Inject protected ClassWrapper classWrapper;
366 
367     override void registerDependencies(shared(DependencyContainer) container) {
368         container.register!Apple;
369     }
370 
371     @Component ClassWrapper wrapper() {
372         return new ClassWrapper(apple);
373     }
374 
375     @Component ClassWrapperWrapper wrapperWrapper() {
376         return new ClassWrapperWrapper(classWrapper);
377     }
378 
379 }
380 
381 class AutowiredTestContext : ApplicationContext {
382 
383     @Inject private Apple apple;
384 
385     @Component ClassWrapper wrapper() {
386         return new ClassWrapper(apple);
387     }
388 }
389 
390 class TestContext : ApplicationContext {
391 
392     @Component Banana banana() {
393         return new Banana("Yellow");
394     }
395 
396     Apple apple() {
397         return new Apple();
398     }
399 
400     @Component @RegisterByType!Fruit Pear pear() {
401         return new Pear();
402     }
403 
404     @Component @RegisterByType!Animal Rabbit rabbit() {
405         return new Rabbit();
406     }
407 
408     @Component @RegisterByType!Animal Wolf wolf() {
409         return new Wolf();
410     }
411 
412     @Component @Prototype PieChart pieChart() {
413         return new PieChart();
414     }
415 }
416 
417 class TestImplementation : TestInterface {
418     string someContent = "";
419 }
420 
421 class SomeOtherClassThen {
422 }
423 
424 class ClassWithConstructor {
425     TestImplementation testImplementation;
426 
427     this(TestImplementation testImplementation) {
428         this.testImplementation = testImplementation;
429     }
430 }
431 
432 class ClassWithMultipleConstructors {
433     SomeOtherClassThen someOtherClassThen;
434     TestImplementation testImplementation;
435 
436     this(SomeOtherClassThen someOtherClassThen) {
437         this.someOtherClassThen = someOtherClassThen;
438     }
439 
440     this(SomeOtherClassThen someOtherClassThen, TestImplementation testImplementation) {
441         this.someOtherClassThen = someOtherClassThen;
442         this.testImplementation = testImplementation;
443     }
444 }
445 
446 class ClassWithConstructorWithMultipleParameters {
447     SomeOtherClassThen someOtherClassThen;
448     TestImplementation testImplementation;
449 
450     this(SomeOtherClassThen someOtherClassThen, TestImplementation testImplementation) {
451         this.someOtherClassThen = someOtherClassThen;
452         this.testImplementation = testImplementation;
453     }
454 }
455 
456 class ClassWithPrimitiveConstructor {
457     SomeOtherClassThen someOtherClassThen;
458 
459     this(string willNotBePicked) {
460     }
461 
462     this(SomeOtherClassThen someOtherClassThen) {
463         this.someOtherClassThen = someOtherClassThen;
464     }
465 }
466 
467 class ClassWithEmptyConstructor {
468     SomeOtherClassThen someOtherClassThen;
469 
470     this() {
471     }
472 
473     this(SomeOtherClassThen someOtherClassThen) {
474         this.someOtherClassThen = someOtherClassThen;
475     }
476 }
477 
478 class ClassWithNonInjectableConstructor {
479     this(string myName) {
480     }
481 }
482 
483 class ClassWithStructConstructor {
484     SomeOtherClassThen someOtherClassThen;
485 
486     this(Thing willNotBePicked) {
487     }
488 
489     this(SomeOtherClassThen someOtherClassThen) {
490         this.someOtherClassThen = someOtherClassThen;
491     }
492 }
493 
494 class TestType {
495 }
496 
497 class Dependency {
498 }
499 
500 struct Thing {
501     int x;
502 }
503 
504 class MyConfig {
505     @Value("conf.stuffs")
506     int stuffs;
507 
508     @Value("conf.name")
509     string name;
510 
511     @Value("conf.thing")
512     Thing thing;
513 }
514 
515 class ConfigWithDefaults {
516     @Value("conf.missing")
517     int noms = 9;
518 }
519 
520 class ConfigWithMandatory {
521     @MandatoryValue("conf.mustbethere")
522     int nums;
523 }
524 
525 class IntInjector : ValueInjector!int {
526     override int get(string key) {
527         assert(key == "conf.stuffs");
528         return 364;
529     }
530 }
531 
532 class StringInjector : ValueInjector!string {
533     override string get(string key) {
534         assert(key == "conf.name");
535         return "Le Chef";
536     }
537 }
538 
539 class ThingInjector : ValueInjector!Thing {
540     override Thing get(string key) {
541         assert(key == "conf.thing");
542         return Thing(8899);
543     }
544 }
545 
546 class DefaultIntInjector : ValueInjector!int {
547     override int get(string key) {
548         throw new ValueNotAvailableException(key);
549     }
550 }
551 
552 class MandatoryAvailableIntInjector : ValueInjector!int {
553     override int get(string key) {
554         return 7466;
555     }
556 }
557 
558 class MandatoryUnavailableIntInjector : ValueInjector!int {
559     override int get(string key) {
560         throw new ValueNotAvailableException(key);
561     }
562 }
563 
564 class DependencyInjectedIntInjector : ValueInjector!int {
565     @Inject Dependency dependency;
566 
567     override int get(string key) {
568         return 2345;
569     }
570 }
571 
572 class CircularIntInjector : ValueInjector!int {
573     @Inject ValueInjector!int dependency;
574 
575     private int count = 0;
576 
577     override int get(string key) {
578         count += 1;
579         if (count >= 3) {
580             return count;
581         }
582         return dependency.get(key);
583     }
584 }
585 
586 class ValueInjectedIntInjector : ValueInjector!int {
587     @Value("five")
588     int count = 0;
589 
590     override int get(string key) {
591         if (key == "five") {
592             return 5;
593         }
594 
595         return count;
596     }
597 }
598 
599 class DependencyValueInjectedIntInjector : ValueInjector!int {
600     @Inject ConfigWithDefaults config;
601 
602     override int get(string key) {
603         if (key == "conf.missing") {
604             return 8899;
605         }
606 
607         return 0;
608     }
609 }
610 
611 class TemplatedComponent(T) {
612     @Inject T instance;
613 }
614 
615 class CircularTemplateComponentA : TemplatedComponent!CircularTemplateComponentB {
616 
617 }
618 
619 class CircularTemplateComponentB : TemplatedComponent!CircularTemplateComponentA {
620 
621 }
622 
623 class ClassWithTemplatedConstructorArg(T) {
624     TemplatedComponent!T dependency;
625 
626     this(TemplatedComponent!T assignedDependency) {
627         this.dependency = assignedDependency;
628     }
629 }
630 
631 class Grandma {
632 
633 }
634 
635 class Mommy : Grandma {
636 
637 }
638 
639 class Kid : Mommy {
640 
641 }
642 
643 class AutowiredMethod {
644     @Inject
645     int lala() {
646         return 42;
647     }
648 
649     @Inject
650     int lala(int valla) {
651         return valla;
652     }
653 }
654 
655 class WithAutowireAttribute {
656     @Autowire ComponentA componentA;
657 }