Arcane  4.1.12.0
Developer documentation
Loading...
Searching...
No Matches
TestDependencyInjection.cc
1// -*- tab-width: 2; indent-tabs-mode: nil; coding: utf-8-with-signature -*-
2//-----------------------------------------------------------------------------
3// Copyright 2000-2026 CEA (www.cea.fr) IFPEN (www.ifpenergiesnouvelles.com)
4// See the top-level COPYRIGHT file for details.
5// SPDX-License-Identifier: Apache-2.0
6//-----------------------------------------------------------------------------
7
8#include <gtest/gtest.h>
9
10#include "arccore/base/internal/DependencyInjection.h"
11#include "arcane/utils/FatalErrorException.h"
12
13#include "arcane/utils/ITraceMng.h"
14
15/*---------------------------------------------------------------------------*/
16/*---------------------------------------------------------------------------*/
17
18using namespace Arcane;
19
20namespace DI_Test
21{
22using namespace Arcane::DependencyInjection;
23
24class IA
25{
26 public:
27
28 virtual ~IA() = default;
29 virtual int value() const = 0;
30};
31
32class IB
33{
34 public:
35
36 virtual ~IB() = default;
37 virtual int value() const = 0;
38};
39
40class IA2
41{
42 public:
43
44 virtual ~IA2() = default;
45 virtual int value() const = 0;
46 virtual IB* bValue() const = 0;
47};
48
49class IB2
50{
51 public:
52
53 virtual ~IB2() = default;
54 virtual int value() const = 0;
55 virtual String stringValue() const = 0;
56};
57
58class IC
59{
60 public:
61
62 virtual ~IC() = default;
63 virtual int value() const = 0;
64};
65
66class ID
67{
68 public:
69
70 virtual ~ID() = default;
71};
72
73class IE
74{
75 public:
76
77 virtual ~IE() = default;
78 virtual int intValue() const = 0;
79 virtual String stringValue() const = 0;
80};
81
82class INone
83{
84 public:
85
86 virtual ~INone() = default;
87};
88
89class AImpl
90: public IA
91{
92 public:
93
94 AImpl() {}
95 int value() const override { return 5; }
96};
97
98class BImpl
99: public IB
100{
101 public:
102
103 BImpl() {}
104 int value() const override { return 12; }
105};
106
107class B2Impl
108: public IB2
109{
110 public:
111
112 B2Impl(const String& x)
113 : m_test(x)
114 {}
115 int value() const override { return 32; }
116 String stringValue() const override { return m_test; }
117
118 private:
119
120 String m_test;
121};
122
123class EImpl
124: public IE
125{
126 public:
127
128 EImpl(Int32 int_value, const String& string_value)
129 : m_string_value(string_value)
130 , m_int_value(int_value)
131 {
132 }
133 int intValue() const override { return m_int_value; }
134 String stringValue() const override { return m_string_value; }
135
136 private:
137
138 String m_string_value;
139 Int32 m_int_value;
140};
141
142class CDImpl
143: public ID
144, public IC
145{
146 public:
147
148 CDImpl(int a, double b)
149 : m_int_value(a + (int)b)
150 {}
151 CDImpl(int a)
152 : m_int_value(a)
153 {}
154 CDImpl()
155 : m_int_value(2)
156 {}
157 int value() const override { return m_int_value; }
158
159 private:
160
161 int m_int_value;
162};
163
164class A2Impl
165: public IA2
166{
167 public:
168
169 A2Impl(int a, IB* ib, IA*)
170 : m_a(a)
171 , m_ib(ib)
172 {}
173 A2Impl(int a, IB* ib)
174 : m_a(a)
175 , m_ib(ib)
176 {}
177
178 public:
179
180 int value() const override { return m_a; }
181 IB* bValue() const override { return m_ib; }
182
183 private:
184
185 int m_a;
186 IB* m_ib;
187};
188
189ARCANE_DI_REGISTER_PROVIDER(AImpl,
190 ProviderProperty("AImplProvider"),
191 ARCANE_DI_INTERFACES(IA),
192 ARCANE_DI_EMPTY_CONSTRUCTOR());
193
194ARCANE_DI_REGISTER_PROVIDER(BImpl,
195 ProviderProperty("BImplProvider"),
196 ARCANE_DI_INTERFACES(IB),
197 ARCANE_DI_EMPTY_CONSTRUCTOR());
198
199ARCANE_DI_REGISTER_PROVIDER(B2Impl,
200 ProviderProperty("B2ImplProvider"),
201 ARCANE_DI_INTERFACES(IB2),
202 ARCANE_DI_CONSTRUCTOR(String));
203
204ARCANE_DI_REGISTER_PROVIDER(EImpl,
205 ProviderProperty("EImplProvider"),
206 ARCANE_DI_INTERFACES(IE),
207 ARCANE_DI_CONSTRUCTOR(Int32, String));
208
209ARCANE_DI_REGISTER_PROVIDER(A2Impl,
210 ProviderProperty("A2ImplProvider"),
211 ARCANE_DI_INTERFACES(IA2),
212 ARCANE_DI_CONSTRUCTOR(int, IB*));
213
214ARCANE_DI_REGISTER_PROVIDER(CDImpl,
215 ProviderProperty("CDImplProvider2"),
216 ARCANE_DI_INTERFACES(IC, ID),
217 ARCANE_DI_CONSTRUCTOR(int));
218
219ARCANE_DI_REGISTER_PROVIDER(CDImpl,
220 ProviderProperty("CDImplProvider3"),
221 ARCANE_DI_INTERFACES(IC),
222 ARCANE_DI_EMPTY_CONSTRUCTOR());
223
224ARCANE_DI_REGISTER_PROVIDER(CDImpl,
225 ProviderProperty("CDImplProvider4"),
226 ARCANE_DI_INTERFACES(IC, ID),
227 ARCANE_DI_CONSTRUCTOR(int),
228 ARCANE_DI_CONSTRUCTOR(int, double),
229 ARCANE_DI_EMPTY_CONSTRUCTOR());
230} // namespace DI_Test
231
232TEST(DependencyInjection, TestPrintFactories)
233{
234 using namespace Arcane::DependencyInjection;
235 Injector injector;
236 injector.fillWithGlobalFactories();
237
238 std::cout << "FACTORIES=" << injector.printFactories() << "\n";
239}
240
241namespace
242{
243template <typename T> void
244_testNotFoundThrow(Arcane::DependencyInjection::Injector& injector)
245{
246 try {
247 Ref<T> ic = injector.createInstance<T>("Test1");
248 FAIL() << "Expected FatalErrorException";
249 }
250 catch (const FatalErrorException& ex) {
251 std::cout << "EX=" << ex << "\n";
252 }
253 catch (...) {
254 FAIL() << "Expected FatalErrorException";
255 }
256}
257} // namespace
258
259TEST(DependencyInjection, TestNotFound)
260{
261 using namespace Arcane::DependencyInjection;
262 using namespace DI_Test;
263 Injector injector;
264 injector.fillWithGlobalFactories();
265
266 _testNotFoundThrow<INone>(injector);
267 _testNotFoundThrow<IA>(injector);
268 _testNotFoundThrow<IC>(injector);
269 Ref<IC> ic2 = injector.createInstance<IC>("Test1", true);
270 ASSERT_EQ(ic2.get(), nullptr);
271}
272
273TEST(DependencyInjection, TestBind1)
274{
275 using namespace Arcane::DependencyInjection;
276 std::cout << "INJECTOR TEST\n";
277 Injector injector;
278 ITraceMng* tm = Arccore::arccoreCreateDefaultTraceMng();
280 injector.bind(ref_tm);
281 Ref<ITraceMng> tm2 = injector.get<Ref<ITraceMng>>();
282 std::cout << "TM=" << tm << "TM2=" << tm2.get() << "\n";
283 ASSERT_EQ(tm, tm2.get()) << "Bad Get Reference";
284}
285
286TEST(DependencyInjection, ProcessGlobalProviders)
287{
288 using namespace Arcane::DependencyInjection;
289 using namespace DI_Test;
290
291 Injector injector;
292 injector.fillWithGlobalFactories();
293
294 Ref<IA> ia = injector.createInstance<IA>({});
295 EXPECT_TRUE(ia.get());
296 ASSERT_EQ(ia->value(), 5);
297
298 Ref<IA> ia2 = injector.createInstance<IA>("AImplProvider");
299 EXPECT_TRUE(ia2.get());
300 ASSERT_EQ(ia2->value(), 5);
301
302 Ref<IB> ib = injector.createInstance<IB>({});
303 EXPECT_TRUE(ib.get());
304 ASSERT_EQ(ib->value(), 12);
305}
306
307void _TestBindValue()
308{
309 using namespace Arcane::DependencyInjection;
310 using namespace DI_Test;
311
312 {
313 Injector injector;
314 injector.fillWithGlobalFactories();
315 String wanted_string("Toto");
316
317 injector.bind(wanted_string);
318
319 Ref<IB2> ib = injector.createInstance<IB2>({});
320 EXPECT_TRUE(ib.get());
321 ASSERT_EQ(ib->value(), 32);
322 ASSERT_EQ(ib->stringValue(), wanted_string);
323 }
324
325 {
326 Injector injector;
327 injector.fillWithGlobalFactories();
328 String wanted_string{ "Tata" };
329 Int32 wanted_int{ 25 };
330
332 injector.bind(wanted_string, "Name");
333 injector.bind(wanted_int, "Value");
334
336 //injector.bind("FalseString","AnyName");
337 //injector.bind(38,"SomeName");
338 //injector.bind(3.2,"DoubleName");
339
340 Ref<IE> ie = injector.createInstance<IE>("EImplProvider");
341 EXPECT_TRUE(ie.get());
342 ASSERT_EQ(ie->intValue(), wanted_int);
343 ASSERT_EQ(ie->stringValue(), wanted_string);
344 }
345}
346
347TEST(DependencyInjection, TestBindValue)
348{
349 try {
350 _TestBindValue();
351 }
352 catch (const Exception& ex) {
353 std::cerr << "ERROR=" << ex << "\n";
354 throw;
355 }
356}
357
358TEST(DependencyInjection, ConstructorCall)
359{
360 using namespace DI_Test;
361 namespace di = Arcane::DependencyInjection;
362 using ConstructorType = di::impl::ConstructorRegisterer<int, IB*>;
363
364 di::impl::ConcreteFactory<IA2, A2Impl, ConstructorType> c2f;
365
366 int x = 3;
367
368 try {
369 Injector injector;
370 std::unique_ptr<IB> ib{ std::make_unique<BImpl>() };
371 injector.bind(ib.get());
372 injector.bind(x);
373 Ref<IA2> a2 = c2f.createReference(injector);
375 ASSERT_EQ(a2->value(), 3);
376 ASSERT_EQ(a2->bValue(), ib.get());
377 }
378 catch (const Exception& ex) {
379 std::cerr << "ERROR=" << ex << "\n";
380 throw;
381 }
382}
383
384TEST(DependencyInjection, Impl2)
385{
386 using namespace DI_Test;
387 namespace di = Arcane::DependencyInjection;
388
389 try {
390 {
391 // Test with the CDImpl(int) constructor
392 Injector injector;
393 injector.fillWithGlobalFactories();
394
395 injector.bind<int>(25);
396 Ref<IC> ic = injector.createInstance<IC>("CDImplProvider2");
397 ARCANE_CHECK_POINTER(ic.get());
398 ASSERT_EQ(ic->value(), 25);
399 }
400 {
401 // Test with the no-argument constructor (CDImpl())
402 // In this case, the IC::value() must be 2
403 // (see CDImpl constructor)
404 Injector injector;
405 injector.fillWithGlobalFactories();
406 Ref<IC> ic = injector.createInstance<IC>("CDImplProvider3");
408 ASSERT_EQ(ic->value(), 2);
409 }
410 {
411 // Test with the constructor having 2 arguments (CDImpl(int,double))
412 // In this case, the IC::value() must be 25+12
413 // (see CDImpl constructor)
414 Injector injector;
415 injector.fillWithGlobalFactories();
416 injector.bind<int>(25);
417 injector.bind<double>(12.0);
418 Ref<IC> ic = injector.createInstance<IC>("CDImplProvider4");
419 ARCANE_CHECK_POINTER(ic.get());
420 ASSERT_EQ(ic->value(), 37);
421 }
422 }
423 catch (const Exception& ex) {
424 std::cerr << "ERROR=" << ex << "\n";
425 throw;
426 }
427}
428
429/*---------------------------------------------------------------------------*/
430/*---------------------------------------------------------------------------*/
#define ARCANE_CHECK_POINTER(ptr)
Macro returning the pointer ptr if it is not null or throwing an exception if it is null.
InstanceType * get() const
Associated instance or nullptr if none.
Reference to an instance.
-- tab-width: 2; indent-tabs-mode: nil; coding: utf-8-with-signature --
Ref< InstanceType > makeRefFromInstance(InstanceType2 *t)
Retrieves a reference on the pointer t.