6c093fc952179c2507aebfd7fad2870abbcaeaf2
[platform/upstream/armnn.git] / src / backends / backendsCommon / test / DynamicBackendTests.hpp
1 //
2 // Copyright © 2017 Arm Ltd. All rights reserved.
3 // SPDX-License-Identifier: MIT
4 //
5
6 #pragma once
7
8 #include <backendsCommon/DynamicBackend.hpp>
9 #include <backendsCommon/DynamicBackendUtils.hpp>
10 #include <backendsCommon/BackendRegistry.hpp>
11 #include <backendsCommon/CpuTensorHandle.hpp>
12
13 #include <armnn/ILayerSupport.hpp>
14
15 #include <reference/workloads/RefConvolution2dWorkload.hpp>
16
17 #include <Runtime.hpp>
18
19 #include <string>
20 #include <memory>
21 #include <string>
22
23 #include <boost/test/unit_test.hpp>
24 #include <boost/filesystem.hpp>
25 #include <boost/dll.hpp>
26
27 static std::string g_TestBaseDir                            = "src/backends/backendsCommon/test/";
28
29 static std::string g_TestSharedObjectSubDir                 = "testSharedObject/";
30 static std::string g_TestDynamicBackendSubDir               = "testDynamicBackend/";
31
32 static std::string g_TestSharedObjectFileName               = "libTestSharedObject.so";
33 static std::string g_TestNoSharedObjectFileName             = "libNoSharedObject.txt";
34
35 static std::string g_TestValidTestDynamicBackendFileName    = "libValidTestDynamicBackend.so";
36 static std::string g_TestInvalidTestDynamicBackend1FileName = "libInvalidTestDynamicBackend1.so";
37 static std::string g_TestInvalidTestDynamicBackend2FileName = "libInvalidTestDynamicBackend2.so";
38 static std::string g_TestInvalidTestDynamicBackend3FileName = "libInvalidTestDynamicBackend3.so";
39 static std::string g_TestInvalidTestDynamicBackend4FileName = "libInvalidTestDynamicBackend4.so";
40 static std::string g_TestInvalidTestDynamicBackend5FileName = "libInvalidTestDynamicBackend5.so";
41 static std::string g_TestInvalidTestDynamicBackend6FileName = "libInvalidTestDynamicBackend6.so";
42 static std::string g_TestInvalidTestDynamicBackend7FileName = "libInvalidTestDynamicBackend7.so";
43
44 static std::string g_TestValidBackend2FileName              = "Arm_TestValid2_backend.so";
45 static std::string g_TestValidBackend3FileName              = "Arm_TestValid3_backend.so";
46 static std::string g_TestValidBackend4FileName              = "Arm_TestValid4_backend.so";
47 static std::string g_TestValidBackend5FileName              = "Arm_TestValid5_backend.so";
48 static std::string g_TestInvalidBackend8FileName            = "Arm_TestInvalid8_backend.so";
49 static std::string g_TestInvalidBackend9FileName            = "Arm_TestInvalid9_backend.so";
50 static std::string g_TestInvalidBackend10FileName           = "Arm_TestInvalid10_backend.so";
51 static std::string g_TestInvalidBackend11FileName           = "Arm_TestInvalid11_backend.so";
52
53 static std::string g_TestDynamicBackendsSubDir1  = "backendsTestPath1/";
54 static std::string g_TestDynamicBackendsSubDir2  = "backendsTestPath2/";
55 static std::string g_TestDynamicBackendsSubDir3  = "backendsTestPath3/";
56 static std::string g_TestDynamicBackendsSubDir4  = "backendsTestPath4/";
57 static std::string g_TestDynamicBackendsSubDir5  = "backendsTestPath5/";
58 static std::string g_TestDynamicBackendsSubDir6  = "backendsTestPath6/";
59 static std::string g_TestDynamicBackendsSubDir7  = "backendsTestPath7/";
60 static std::string g_TestDynamicBackendsSubDir8  = "backendsTestPath8/";
61 static std::string g_TestDynamicBackendsSubDir9  = "backendsTestPath9/";
62
63 static std::string g_DynamicBackendsBaseDir                 = "src/backends/dynamic";
64 static std::string g_ReferenceDynamicBackendSubDir          = "reference/";
65 static std::string g_ReferenceBackendFileName               = "Arm_CpuRef_backend.so";
66
67 // DynamicBackendUtils wrapper class used for testing (allows to directly invoke the protected methods)
68 class TestDynamicBackendUtils : public armnn::DynamicBackendUtils
69 {
70 public:
71     static bool IsBackendCompatibleTest(const armnn::BackendVersion& backendApiVersion,
72                                         const armnn::BackendVersion& backendVersion)
73     {
74         return IsBackendCompatibleImpl(backendApiVersion, backendVersion);
75     }
76
77     static std::vector<std::string> GetBackendPathsImplTest(const std::string& path)
78     {
79         return GetBackendPathsImpl(path);
80     }
81
82     static armnn::BackendIdSet RegisterDynamicBackendsImplTest(
83             armnn::BackendRegistry& backendRegistry,
84             const std::vector<armnn::DynamicBackendPtr>& dynamicBackends)
85     {
86         return RegisterDynamicBackendsImpl(backendRegistry, dynamicBackends);
87     }
88 };
89
90 // BackendRegistry wrapper class used for testing (swaps the underlying factory storage)
91 class TestBackendRegistry : public armnn::BackendRegistry
92 {
93 public:
94     TestBackendRegistry() : armnn::BackendRegistry()
95     {
96         Swap(armnn::BackendRegistryInstance(), m_TempStorage);
97     }
98
99     ~TestBackendRegistry()
100     {
101         Swap(armnn::BackendRegistryInstance(), m_TempStorage);
102     }
103
104 private:
105     FactoryStorage m_TempStorage;
106 };
107
108 std::string GetBasePath(const std::string& basePath)
109 {
110     using namespace boost::filesystem;
111
112     path programLocation = boost::dll::program_location().parent_path();
113     path sharedObjectPath = programLocation.append(basePath);
114     BOOST_CHECK(exists(sharedObjectPath));
115
116     return sharedObjectPath.string();
117 }
118
119 std::string GetTestDirectoryBasePath()
120 {
121     return GetBasePath(g_TestBaseDir);
122 }
123
124 std::string GetDynamicBackendsBasePath()
125 {
126     return GetBasePath(g_DynamicBackendsBaseDir);
127 }
128
129 std::string GetTestSubDirectory(const std::string& subdir)
130 {
131     using namespace boost::filesystem;
132
133     std::string testDynamicBackendsBaseDir = GetTestDirectoryBasePath();
134     path testDynamicBackendsBasePath(testDynamicBackendsBaseDir);
135     path testDynamicBackendsSubDir = testDynamicBackendsBasePath.append(subdir);
136     // Do not check that the sub-directory exists because for testing reasons we may use non-existing paths
137
138     return testDynamicBackendsSubDir.string();
139 }
140
141 std::string GetTestSubDirectory(const std::string& basePath, const std::string& subdir)
142 {
143     using namespace boost::filesystem;
144
145     path testDynamicBackendsBasePath(basePath);
146     path testDynamicBackendsSubDir = testDynamicBackendsBasePath.append(subdir);
147     // Do not check that the sub-directory exists because for testing reasons we may use non-existing paths
148
149     return testDynamicBackendsSubDir.string();
150 }
151
152 std::string GetTestFilePath(const std::string& directory, const std::string& fileName)
153 {
154     using namespace boost::filesystem;
155
156     path directoryPath(directory);
157     path fileNamePath = directoryPath.append(fileName);
158     BOOST_CHECK(exists(fileNamePath));
159
160     return fileNamePath.string();
161 }
162
163 void OpenCloseHandleTestImpl()
164 {
165     using namespace armnn;
166
167     std::string testSubDirectory = GetTestSubDirectory(g_TestSharedObjectSubDir);
168     std::string sharedObjectFilePath = GetTestFilePath(testSubDirectory, g_TestSharedObjectFileName);
169
170     void* sharedObjectHandle = nullptr;
171     BOOST_CHECK_NO_THROW(sharedObjectHandle = DynamicBackendUtils::OpenHandle(sharedObjectFilePath));
172     BOOST_TEST((sharedObjectHandle != nullptr));
173
174     DynamicBackendUtils::CloseHandle(sharedObjectHandle);
175 }
176
177 void CloseInvalidHandleTestImpl()
178 {
179     using namespace armnn;
180
181     // This calls must silently handle invalid handles and complete successfully (no segfaults, etc.)
182     DynamicBackendUtils::CloseHandle(nullptr);
183 }
184
185 void OpenEmptyFileNameTestImpl()
186 {
187     using namespace armnn;
188
189     void* sharedObjectHandle = nullptr;
190     BOOST_CHECK_THROW(sharedObjectHandle = DynamicBackendUtils::OpenHandle(""), RuntimeException);
191     BOOST_TEST((sharedObjectHandle == nullptr));
192 }
193
194 void OpenNotExistingFileTestImpl()
195 {
196     using namespace armnn;
197
198     void* sharedObjectHandle = nullptr;
199     BOOST_CHECK_THROW(sharedObjectHandle = DynamicBackendUtils::OpenHandle("NotExistingFileName"), RuntimeException);
200     BOOST_TEST((sharedObjectHandle == nullptr));
201 }
202
203 void OpenNotSharedObjectTestImpl()
204 {
205     using namespace armnn;
206
207     std::string testSubDirectory = GetTestSubDirectory(g_TestSharedObjectSubDir);
208     std::string notSharedObjectFilePath = GetTestFilePath(testSubDirectory, g_TestNoSharedObjectFileName);
209
210     void* sharedObjectHandle = nullptr;
211     BOOST_CHECK_THROW(sharedObjectHandle = DynamicBackendUtils::OpenHandle(notSharedObjectFilePath), RuntimeException);
212     BOOST_TEST((sharedObjectHandle == nullptr));
213 }
214
215 void GetValidEntryPointTestImpl()
216 {
217     using namespace armnn;
218
219     std::string testSubDirectory = GetTestSubDirectory(g_TestSharedObjectSubDir);
220     std::string sharedObjectFilePath = GetTestFilePath(testSubDirectory, g_TestSharedObjectFileName);
221
222     void* sharedObjectHandle = nullptr;
223     BOOST_CHECK_NO_THROW(sharedObjectHandle = DynamicBackendUtils::OpenHandle(sharedObjectFilePath));
224     BOOST_TEST((sharedObjectHandle != nullptr));
225
226     using TestFunctionType = int(*)(int);
227     TestFunctionType testFunctionPointer = nullptr;
228     BOOST_CHECK_NO_THROW(testFunctionPointer = DynamicBackendUtils::GetEntryPoint<TestFunctionType>(sharedObjectHandle,
229                                                                                                     "TestFunction1"));
230     BOOST_TEST((testFunctionPointer != nullptr));
231     BOOST_TEST(testFunctionPointer(7) == 7);
232
233     DynamicBackendUtils::CloseHandle(sharedObjectHandle);
234 }
235
236 void GetNameMangledEntryPointTestImpl()
237 {
238     using namespace armnn;
239
240     std::string testSubDirectory = GetTestSubDirectory(g_TestSharedObjectSubDir);
241     std::string sharedObjectFilePath = GetTestFilePath(testSubDirectory, g_TestSharedObjectFileName);
242
243     void* sharedObjectHandle = nullptr;
244     BOOST_CHECK_NO_THROW(sharedObjectHandle = DynamicBackendUtils::OpenHandle(sharedObjectFilePath));
245     BOOST_TEST((sharedObjectHandle != nullptr));
246
247     using TestFunctionType = int(*)(int);
248     TestFunctionType testFunctionPointer = nullptr;
249     BOOST_CHECK_THROW(testFunctionPointer = DynamicBackendUtils::GetEntryPoint<TestFunctionType>(sharedObjectHandle,
250                                                                                                  "TestFunction2"),
251                       RuntimeException);
252     BOOST_TEST((testFunctionPointer == nullptr));
253
254     DynamicBackendUtils::CloseHandle(sharedObjectHandle);
255 }
256
257 void GetNoExternEntryPointTestImpl()
258 {
259     using namespace armnn;
260
261     std::string testSubDirectory = GetTestSubDirectory(g_TestSharedObjectSubDir);
262     std::string sharedObjectFilePath = GetTestFilePath(testSubDirectory, g_TestSharedObjectFileName);
263
264     void* sharedObjectHandle = nullptr;
265     BOOST_CHECK_NO_THROW(sharedObjectHandle = DynamicBackendUtils::OpenHandle(sharedObjectFilePath));
266     BOOST_TEST((sharedObjectHandle != nullptr));
267
268     using TestFunctionType = int(*)(int);
269     TestFunctionType testFunctionPointer = nullptr;
270     BOOST_CHECK_THROW(testFunctionPointer = DynamicBackendUtils::GetEntryPoint<TestFunctionType>(sharedObjectHandle,
271                                                                                                  "TestFunction3"),
272                       RuntimeException);
273     BOOST_TEST((testFunctionPointer == nullptr));
274
275     DynamicBackendUtils::CloseHandle(sharedObjectHandle);
276 }
277
278 void GetNotExistingEntryPointTestImpl()
279 {
280     using namespace armnn;
281
282     std::string testSubDirectory = GetTestSubDirectory(g_TestSharedObjectSubDir);
283     std::string sharedObjectFilePath = GetTestFilePath(testSubDirectory, g_TestSharedObjectFileName);
284
285     void* sharedObjectHandle = nullptr;
286     BOOST_CHECK_NO_THROW(sharedObjectHandle = DynamicBackendUtils::OpenHandle(sharedObjectFilePath));
287     BOOST_TEST((sharedObjectHandle != nullptr));
288
289     using TestFunctionType = int(*)(int);
290     TestFunctionType testFunctionPointer = nullptr;
291     BOOST_CHECK_THROW(testFunctionPointer = DynamicBackendUtils::GetEntryPoint<TestFunctionType>(sharedObjectHandle,
292                                                                                                  "TestFunction4"),
293                       RuntimeException);
294     BOOST_TEST((testFunctionPointer == nullptr));
295
296     DynamicBackendUtils::CloseHandle(sharedObjectHandle);
297 }
298
299 void BackendVersioningTestImpl()
300 {
301     using namespace armnn;
302
303     // The backend API version used for the tests
304     BackendVersion backendApiVersion{ 2, 4 };
305
306     // Same backend and backend API versions are compatible with the backend API
307     BackendVersion sameBackendVersion{ 2, 4 };
308     BOOST_TEST(sameBackendVersion == backendApiVersion);
309     BOOST_TEST(sameBackendVersion <= backendApiVersion);
310     BOOST_TEST(TestDynamicBackendUtils::IsBackendCompatibleTest(backendApiVersion, sameBackendVersion) == true);
311
312     // Backend versions that differ from the backend API version by major revision are not compatible
313     // with the backend API
314     BackendVersion laterMajorBackendVersion{ 3, 4 };
315     BOOST_TEST(!(laterMajorBackendVersion == backendApiVersion));
316     BOOST_TEST(!(laterMajorBackendVersion <= backendApiVersion));
317     BOOST_TEST(TestDynamicBackendUtils::IsBackendCompatibleTest(backendApiVersion, laterMajorBackendVersion) == false);
318
319     BackendVersion earlierMajorBackendVersion{ 1, 4 };
320     BOOST_TEST(!(earlierMajorBackendVersion == backendApiVersion));
321     BOOST_TEST(earlierMajorBackendVersion <= backendApiVersion);
322     BOOST_TEST(TestDynamicBackendUtils::IsBackendCompatibleTest(backendApiVersion,
323                                                                 earlierMajorBackendVersion) == false);
324
325     // Backend versions with the same major revision but later minor revision than
326     // the backend API version are not compatible with the backend API
327     BackendVersion laterMinorBackendVersion{ 2, 5 };
328     BOOST_TEST(!(laterMinorBackendVersion == backendApiVersion));
329     BOOST_TEST(!(laterMinorBackendVersion <= backendApiVersion));
330     BOOST_TEST(TestDynamicBackendUtils::IsBackendCompatibleTest(backendApiVersion, laterMinorBackendVersion) == false);
331
332     // Backend versions with the same major revision but earlier minor revision than
333     // the backend API version are compatible with the backend API
334     BackendVersion earlierMinorBackendVersion{ 2, 3 };
335     BOOST_TEST(!(earlierMinorBackendVersion == backendApiVersion));
336     BOOST_TEST(earlierMinorBackendVersion <= backendApiVersion);
337     BOOST_TEST(TestDynamicBackendUtils::IsBackendCompatibleTest(backendApiVersion, earlierMinorBackendVersion) == true);
338 }
339
340 void CreateValidDynamicBackendObjectTestImpl()
341 {
342     // Valid shared object handle
343     // Correct name mangling
344     // Correct interface
345     // Correct backend implementation
346
347     using namespace armnn;
348
349     std::string testSubDirectory = GetTestSubDirectory(g_TestDynamicBackendSubDir);
350     std::string sharedObjectFilePath = GetTestFilePath(testSubDirectory, g_TestValidTestDynamicBackendFileName);
351
352     void* sharedObjectHandle = nullptr;
353     BOOST_CHECK_NO_THROW(sharedObjectHandle = DynamicBackendUtils::OpenHandle(sharedObjectFilePath));
354     BOOST_TEST((sharedObjectHandle != nullptr));
355
356     DynamicBackendPtr dynamicBackend;
357     BOOST_CHECK_NO_THROW(dynamicBackend.reset(new DynamicBackend(sharedObjectHandle)));
358     BOOST_TEST((dynamicBackend != nullptr));
359
360     BackendId dynamicBackendId;
361     BOOST_CHECK_NO_THROW(dynamicBackendId = dynamicBackend->GetBackendId());
362     BOOST_TEST((dynamicBackendId == "ValidTestDynamicBackend"));
363
364     BackendVersion dynamicBackendVersion;
365     BOOST_CHECK_NO_THROW(dynamicBackendVersion = dynamicBackend->GetBackendVersion());
366     BOOST_TEST((dynamicBackendVersion == IBackendInternal::GetApiVersion()));
367
368     IBackendInternalUniquePtr dynamicBackendInstance1;
369     BOOST_CHECK_NO_THROW(dynamicBackendInstance1 = dynamicBackend->GetBackend());
370     BOOST_TEST((dynamicBackendInstance1 != nullptr));
371
372     BackendRegistry::FactoryFunction dynamicBackendFactoryFunction = nullptr;
373     BOOST_CHECK_NO_THROW(dynamicBackendFactoryFunction = dynamicBackend->GetFactoryFunction());
374     BOOST_TEST((dynamicBackendFactoryFunction != nullptr));
375
376     IBackendInternalUniquePtr dynamicBackendInstance2;
377     BOOST_CHECK_NO_THROW(dynamicBackendInstance2 = dynamicBackendFactoryFunction());
378     BOOST_TEST((dynamicBackendInstance2 != nullptr));
379
380     BOOST_TEST((dynamicBackendInstance1->GetId() == "ValidTestDynamicBackend"));
381     BOOST_TEST((dynamicBackendInstance2->GetId() == "ValidTestDynamicBackend"));
382 }
383
384 void CreateDynamicBackendObjectInvalidHandleTestImpl()
385 {
386     // Invalid (null) shared object handle
387
388     using namespace armnn;
389
390     void* sharedObjectHandle = nullptr;
391     DynamicBackendPtr dynamicBackend;
392     BOOST_CHECK_THROW(dynamicBackend.reset(new DynamicBackend(sharedObjectHandle)), InvalidArgumentException);
393     BOOST_TEST((dynamicBackend == nullptr));
394 }
395
396 void CreateDynamicBackendObjectInvalidInterface1TestImpl()
397 {
398     // Valid shared object handle
399     // Wrong (not C-style) name mangling
400
401     using namespace armnn;
402
403     std::string testSubDirectory = GetTestSubDirectory(g_TestDynamicBackendSubDir);
404     std::string sharedObjectFilePath = GetTestFilePath(testSubDirectory, g_TestInvalidTestDynamicBackend1FileName);
405
406     void* sharedObjectHandle = nullptr;
407     BOOST_CHECK_NO_THROW(sharedObjectHandle = DynamicBackendUtils::OpenHandle(sharedObjectFilePath));
408     BOOST_TEST((sharedObjectHandle != nullptr));
409
410     DynamicBackendPtr dynamicBackend;
411     BOOST_CHECK_THROW(dynamicBackend.reset(new DynamicBackend(sharedObjectHandle)), RuntimeException);
412     BOOST_TEST((dynamicBackend == nullptr));
413 }
414
415 void CreateDynamicBackendObjectInvalidInterface2TestImpl()
416 {
417     // Valid shared object handle
418     // Correct name mangling
419     // Wrong interface (missing GetBackendId())
420
421     using namespace armnn;
422
423     std::string testSubDirectory = GetTestSubDirectory(g_TestDynamicBackendSubDir);
424     std::string sharedObjectFilePath = GetTestFilePath(testSubDirectory, g_TestInvalidTestDynamicBackend2FileName);
425
426     void* sharedObjectHandle = nullptr;
427     BOOST_CHECK_NO_THROW(sharedObjectHandle = DynamicBackendUtils::OpenHandle(sharedObjectFilePath));
428     BOOST_TEST((sharedObjectHandle != nullptr));
429
430     DynamicBackendPtr dynamicBackend;
431     BOOST_CHECK_THROW(dynamicBackend.reset(new DynamicBackend(sharedObjectHandle)), RuntimeException);
432     BOOST_TEST((dynamicBackend == nullptr));
433 }
434
435 void CreateDynamicBackendObjectInvalidInterface3TestImpl()
436 {
437     // Valid shared object handle
438     // Correct name mangling
439     // Wrong interface (missing GetVersion())
440
441     using namespace armnn;
442
443     std::string testSubDirectory = GetTestSubDirectory(g_TestDynamicBackendSubDir);
444     std::string sharedObjectFilePath = GetTestFilePath(testSubDirectory, g_TestInvalidTestDynamicBackend3FileName);
445
446     void* sharedObjectHandle = nullptr;
447     BOOST_CHECK_NO_THROW(sharedObjectHandle = DynamicBackendUtils::OpenHandle(sharedObjectFilePath));
448     BOOST_TEST((sharedObjectHandle != nullptr));
449
450     DynamicBackendPtr dynamicBackend;
451     BOOST_CHECK_THROW(dynamicBackend.reset(new DynamicBackend(sharedObjectHandle)), RuntimeException);
452     BOOST_TEST((dynamicBackend == nullptr));
453 }
454
455 void CreateDynamicBackendObjectInvalidInterface4TestImpl()
456 {
457     // Valid shared object handle
458     // Correct name mangling
459     // Wrong interface (missing BackendFactory())
460
461     using namespace armnn;
462
463     std::string testSubDirectory = GetTestSubDirectory(g_TestDynamicBackendSubDir);
464     std::string sharedObjectFilePath = GetTestFilePath(testSubDirectory, g_TestInvalidTestDynamicBackend4FileName);
465
466     void* sharedObjectHandle = nullptr;
467     BOOST_CHECK_NO_THROW(sharedObjectHandle = DynamicBackendUtils::OpenHandle(sharedObjectFilePath));
468     BOOST_TEST((sharedObjectHandle != nullptr));
469
470     DynamicBackendPtr dynamicBackend;
471     BOOST_CHECK_THROW(dynamicBackend.reset(new DynamicBackend(sharedObjectHandle)), RuntimeException);
472     BOOST_TEST((dynamicBackend == nullptr));
473 }
474
475 void CreateDynamicBackendObjectInvalidInterface5TestImpl()
476 {
477     // Valid shared object handle
478     // Correct name mangling
479     // Correct interface
480     // Invalid (null) backend id returned by GetBackendId()
481
482     using namespace armnn;
483
484     std::string testSubDirectory = GetTestSubDirectory(g_TestDynamicBackendSubDir);
485     std::string sharedObjectFilePath = GetTestFilePath(testSubDirectory, g_TestInvalidTestDynamicBackend5FileName);
486
487     void* sharedObjectHandle = nullptr;
488     BOOST_CHECK_NO_THROW(sharedObjectHandle = DynamicBackendUtils::OpenHandle(sharedObjectFilePath));
489     BOOST_TEST((sharedObjectHandle != nullptr));
490
491     DynamicBackendPtr dynamicBackend;
492     BOOST_CHECK_THROW(dynamicBackend.reset(new DynamicBackend(sharedObjectHandle)), RuntimeException);
493     BOOST_TEST((dynamicBackend == nullptr));
494 }
495
496 void CreateDynamicBackendObjectInvalidInterface6TestImpl()
497 {
498     // Valid shared object handle
499     // Correct name mangling
500     // Correct interface
501     // Invalid (null) backend instance returned by BackendFactory()
502
503     using namespace armnn;
504
505     std::string testSubDirectory = GetTestSubDirectory(g_TestDynamicBackendSubDir);
506     std::string sharedObjectFilePath = GetTestFilePath(testSubDirectory, g_TestInvalidTestDynamicBackend6FileName);
507
508     void* sharedObjectHandle = nullptr;
509     BOOST_CHECK_NO_THROW(sharedObjectHandle = DynamicBackendUtils::OpenHandle(sharedObjectFilePath));
510     BOOST_TEST((sharedObjectHandle != nullptr));
511
512     DynamicBackendPtr dynamicBackend;
513     BOOST_CHECK_NO_THROW(dynamicBackend.reset(new DynamicBackend(sharedObjectHandle)));
514     BOOST_TEST((dynamicBackend != nullptr));
515
516     BackendId dynamicBackendId;
517     BOOST_CHECK_NO_THROW(dynamicBackendId = dynamicBackend->GetBackendId());
518     BOOST_TEST((dynamicBackendId == "InvalidTestDynamicBackend"));
519
520     BackendVersion dynamicBackendVersion;
521     BOOST_CHECK_NO_THROW(dynamicBackendVersion = dynamicBackend->GetBackendVersion());
522     BOOST_TEST((dynamicBackendVersion == BackendVersion({ 1, 0 })));
523
524     IBackendInternalUniquePtr dynamicBackendInstance1;
525     BOOST_CHECK_THROW(dynamicBackendInstance1 = dynamicBackend->GetBackend(), RuntimeException);
526     BOOST_TEST((dynamicBackendInstance1 == nullptr));
527
528     BackendRegistry::FactoryFunction dynamicBackendFactoryFunction = nullptr;
529     BOOST_CHECK_NO_THROW(dynamicBackendFactoryFunction = dynamicBackend->GetFactoryFunction());
530     BOOST_TEST((dynamicBackendFactoryFunction != nullptr));
531
532     IBackendInternalUniquePtr dynamicBackendInstance2;
533     BOOST_CHECK_THROW(dynamicBackendInstance2 = dynamicBackendFactoryFunction(), RuntimeException);
534     BOOST_TEST((dynamicBackendInstance2 == nullptr));
535 }
536
537 void CreateDynamicBackendObjectInvalidInterface7TestImpl()
538 {
539     // Valid shared object handle
540     // Correct name mangling
541     // Correct interface
542     // Invalid (incompatible backend API version) backend instance returned by BackendFactory()
543
544     using namespace armnn;
545
546     std::string testSubDirectory = GetTestSubDirectory(g_TestDynamicBackendSubDir);
547     std::string sharedObjectFilePath = GetTestFilePath(testSubDirectory, g_TestInvalidTestDynamicBackend7FileName);
548
549     void* sharedObjectHandle = nullptr;
550     BOOST_CHECK_NO_THROW(sharedObjectHandle = DynamicBackendUtils::OpenHandle(sharedObjectFilePath));
551     BOOST_TEST((sharedObjectHandle != nullptr));
552
553     DynamicBackendPtr dynamicBackend;
554     BOOST_CHECK_THROW(dynamicBackend.reset(new DynamicBackend(sharedObjectHandle)), RuntimeException);
555     BOOST_TEST((dynamicBackend == nullptr));
556 }
557
558 void GetBackendPathsTestImpl()
559 {
560     using namespace armnn;
561     using namespace boost::filesystem;
562
563     // The test covers four directories:
564     // <unit test path>/src/backends/backendsCommon/test/
565     //                                                ├─ backendsTestPath1/   -> exists, contains files
566     //                                                ├─ backendsTestPath2/   -> exists, contains files
567     //                                                ├─ backendsTestPath3/   -> exists, but empty
568     //                                                └─ backendsTestPath4/   -> does not exist
569
570     std::string subDir1 = GetTestSubDirectory(g_TestDynamicBackendsSubDir1);
571     std::string subDir2 = GetTestSubDirectory(g_TestDynamicBackendsSubDir2);
572     std::string subDir3 = GetTestSubDirectory(g_TestDynamicBackendsSubDir3);
573     std::string subDir4 = GetTestSubDirectory(g_TestDynamicBackendsSubDir4);
574
575     BOOST_CHECK(exists(subDir1));
576     BOOST_CHECK(exists(subDir2));
577     BOOST_CHECK(exists(subDir3));
578     BOOST_CHECK(!exists(subDir4));
579
580     // No path
581     BOOST_TEST(TestDynamicBackendUtils::GetBackendPathsImplTest("").empty());
582
583     // Malformed path
584     std::string malformedDir(subDir1 + "/" + subDir1);
585     BOOST_TEST(TestDynamicBackendUtils::GetBackendPathsImplTest(malformedDir).size()==0);
586
587     // Single valid path
588     std::vector<std::string> DynamicBackendPaths2 = TestDynamicBackendUtils::GetBackendPathsImplTest(subDir1);
589     BOOST_TEST(DynamicBackendPaths2.size() == 1);
590     BOOST_TEST(DynamicBackendPaths2[0] == subDir1);
591
592     // Multiple equal and valid paths
593     std::string multipleEqualDirs(subDir1 + ":" + subDir1);
594     std::vector<std::string> DynamicBackendPaths3 = TestDynamicBackendUtils::GetBackendPathsImplTest(multipleEqualDirs);
595     BOOST_TEST(DynamicBackendPaths3.size() == 1);
596     BOOST_TEST(DynamicBackendPaths3[0] == subDir1);
597
598     // Multiple empty paths
599     BOOST_TEST(TestDynamicBackendUtils::GetBackendPathsImplTest(":::").empty());
600
601     // Multiple valid paths
602     std::string multipleValidPaths(subDir1 + ":" + subDir2 + ":" + subDir3);
603     std::vector<std::string> DynamicBackendPaths5 =
604         TestDynamicBackendUtils::GetBackendPathsImplTest(multipleValidPaths);
605     BOOST_TEST(DynamicBackendPaths5.size() == 3);
606     BOOST_TEST(DynamicBackendPaths5[0] == subDir1);
607     BOOST_TEST(DynamicBackendPaths5[1] == subDir2);
608     BOOST_TEST(DynamicBackendPaths5[2] == subDir3);
609
610     // Valid among empty paths
611     std::string validAmongEmptyDirs("::" + subDir1 + ":");
612     std::vector<std::string> DynamicBackendPaths6 =
613         TestDynamicBackendUtils::GetBackendPathsImplTest(validAmongEmptyDirs);
614     BOOST_TEST(DynamicBackendPaths6.size() == 1);
615     BOOST_TEST(DynamicBackendPaths6[0] == subDir1);
616
617     // Invalid among empty paths
618     std::string invalidAmongEmptyDirs(":" + subDir4 + "::");
619     BOOST_TEST(TestDynamicBackendUtils::GetBackendPathsImplTest(invalidAmongEmptyDirs).empty());
620
621     // Valid, invalid and empty paths
622     std::string validInvalidEmptyDirs(subDir1 + ":" + subDir4 + ":");
623     std::vector<std::string> DynamicBackendPaths8 =
624         TestDynamicBackendUtils::GetBackendPathsImplTest(validInvalidEmptyDirs);
625     BOOST_TEST(DynamicBackendPaths8.size() == 1);
626     BOOST_TEST(DynamicBackendPaths8[0] == subDir1);
627
628     // Mix of duplicates of valid, invalid and empty paths
629     std::string duplicateValidInvalidEmptyDirs(validInvalidEmptyDirs + ":" + validInvalidEmptyDirs + ":" +
630                                                subDir2 + ":" + subDir2);
631     std::vector<std::string> DynamicBackendPaths9 =
632         TestDynamicBackendUtils::GetBackendPathsImplTest(duplicateValidInvalidEmptyDirs);
633     BOOST_TEST(DynamicBackendPaths9.size() == 2);
634     BOOST_TEST(DynamicBackendPaths9[0] == subDir1);
635     BOOST_TEST(DynamicBackendPaths9[1] == subDir2);
636 }
637
638 void GetBackendPathsOverrideTestImpl()
639 {
640     using namespace armnn;
641     using namespace boost::filesystem;
642
643     std::string subDir1 = GetTestSubDirectory(g_TestDynamicBackendsSubDir1);
644     std::string subDir4 = GetTestSubDirectory(g_TestDynamicBackendsSubDir4);
645
646     BOOST_CHECK(exists(subDir1));
647     BOOST_CHECK(!exists(subDir4));
648
649     // Override with valid path
650     std::vector<std::string> validResult = DynamicBackendUtils::GetBackendPaths(subDir1);
651     BOOST_TEST(validResult.size() == 1);
652     BOOST_TEST(validResult[0] == subDir1);
653
654     // Override with invalid path
655     std::vector<std::string> invalidResult = DynamicBackendUtils::GetBackendPaths(subDir4);
656     BOOST_TEST(invalidResult.empty());
657 }
658
659 void GetSharedObjectsTestImpl()
660 {
661     using namespace armnn;
662     using namespace boost::filesystem;
663
664     // The test covers four directories:
665     // <unit test path>/src/backends/backendsCommon/test/
666     //                                                ├─ backendsTestPath1/   -> exists, contains files
667     //                                                ├─ backendsTestPath2/   -> exists, contains files
668     //                                                ├─ backendsTestPath3/   -> exists, but empty
669     //                                                └─ backendsTestPath4/   -> does not exist
670     //
671     // The test sub-directory backendsTestPath1/ contains the following test files:
672     //
673     // Arm_GpuAcc_backend.so                                       -> valid (basic backend name)
674     // Arm_GpuAcc_backend.so.1                                     -> valid (single field version number)
675     // Arm_GpuAcc_backend.so.1.2                                   -> valid (multiple field version number)
676     // Arm_GpuAcc_backend.so.1.2.3                                 -> valid (multiple field version number)
677     // Arm_GpuAcc_backend.so.10.1.27                               -> valid (Multiple digit version)
678     // Arm_GpuAcc_backend.so.10.1.33.                              -> not valid (dot not followed by version number)
679     // Arm_GpuAcc_backend.so.3.4..5                                -> not valid (dot not followed by version number)
680     // Arm_GpuAcc_backend.so.1,1.1                                 -> not valid (comma instead of dot in the version)
681     //
682     // Arm123_GpuAcc_backend.so                                    -> valid (digits in vendor name are allowed)
683     // Arm_GpuAcc456_backend.so                                    -> valid (digits in backend id are allowed)
684     // Arm%Co_GpuAcc_backend.so                                    -> not valid (invalid character in vendor name)
685     // Arm_Gpu.Acc_backend.so                                      -> not valid (invalid character in backend id)
686     //
687     // GpuAcc_backend.so                                           -> not valid (missing vendor name)
688     // _GpuAcc_backend.so                                          -> not valid (missing vendor name)
689     // Arm__backend.so                                             -> not valid (missing backend id)
690     // Arm_GpuAcc.so                                               -> not valid (missing "backend" at the end)
691     // __backend.so                                                -> not valid (missing vendor name and backend id)
692     // __.so                                                       -> not valid (missing all fields)
693     //
694     // Arm_GpuAcc_backend                                          -> not valid (missing at least ".so" at the end)
695     // Arm_GpuAcc_backend_v1.2.so                                  -> not valid (extra version info at the end)
696     //
697     // The test sub-directory backendsTestPath1/ contains the following test files:
698     //
699     // Arm_CpuAcc_backend.so                                       -> valid (basic backend name)
700     // Arm_CpuAcc_backend.so.1 -> Arm_CpuAcc_backend.so            -> valid (symlink to valid backend file)
701     // Arm_CpuAcc_backend.so.1.2 -> Arm_CpuAcc_backend.so.1        -> valid (symlink to valid symlink)
702     // Arm_CpuAcc_backend.so.1.2.3 -> Arm_CpuAcc_backend.so.1.2    -> valid (symlink to valid symlink)
703     //
704     // Arm_no_backend.so -> nothing                                -> not valid (symlink resolves to non-existent file)
705     //
706     // Arm_GpuAcc_backend.so                                       -> valid (but duplicated from backendsTestPath1/)
707
708     std::string testDynamicBackendsSubDir1 = GetTestSubDirectory(g_TestDynamicBackendsSubDir1);
709     std::string testDynamicBackendsSubDir2 = GetTestSubDirectory(g_TestDynamicBackendsSubDir2);
710     std::string testDynamicBackendsSubDir3 = GetTestSubDirectory(g_TestDynamicBackendsSubDir3);
711     std::string testDynamicBackendsSubDir4 = GetTestSubDirectory(g_TestDynamicBackendsSubDir4);
712     BOOST_CHECK(exists(testDynamicBackendsSubDir1));
713     BOOST_CHECK(exists(testDynamicBackendsSubDir2));
714     BOOST_CHECK(exists(testDynamicBackendsSubDir3));
715     BOOST_CHECK(!exists(testDynamicBackendsSubDir4));
716
717     std::vector<std::string> backendPaths
718     {
719         testDynamicBackendsSubDir1,
720         testDynamicBackendsSubDir2,
721         testDynamicBackendsSubDir3,
722         testDynamicBackendsSubDir4
723     };
724     std::vector<std::string> sharedObjects = DynamicBackendUtils::GetSharedObjects(backendPaths);
725     std::vector<std::string> expectedSharedObjects
726     {
727         testDynamicBackendsSubDir1 + "Arm123_GpuAcc_backend.so",      // Digits in vendor name are allowed
728         testDynamicBackendsSubDir1 + "Arm_GpuAcc456_backend.so",      // Digits in backend id are allowed
729         testDynamicBackendsSubDir1 + "Arm_GpuAcc_backend.so",         // Basic backend name
730         testDynamicBackendsSubDir1 + "Arm_GpuAcc_backend.so.1",       // Single field version number
731         testDynamicBackendsSubDir1 + "Arm_GpuAcc_backend.so.1.2",     // Multiple field version number
732         testDynamicBackendsSubDir1 + "Arm_GpuAcc_backend.so.1.2.3",   // Multiple field version number
733         testDynamicBackendsSubDir1 + "Arm_GpuAcc_backend.so.10.1.27", // Multiple digit version
734         testDynamicBackendsSubDir2 + "Arm_CpuAcc_backend.so",         // Duplicate symlinks removed
735         testDynamicBackendsSubDir2 + "Arm_GpuAcc_backend.so"          // Duplicates on different paths are allowed
736     };
737
738     BOOST_TEST(sharedObjects.size() == expectedSharedObjects.size());
739     BOOST_TEST(sharedObjects[0] == expectedSharedObjects[0]);
740     BOOST_TEST(sharedObjects[1] == expectedSharedObjects[1]);
741     BOOST_TEST(sharedObjects[2] == expectedSharedObjects[2]);
742     BOOST_TEST(sharedObjects[3] == expectedSharedObjects[3]);
743     BOOST_TEST(sharedObjects[4] == expectedSharedObjects[4]);
744     BOOST_TEST(sharedObjects[5] == expectedSharedObjects[5]);
745     BOOST_TEST(sharedObjects[6] == expectedSharedObjects[6]);
746     BOOST_TEST(sharedObjects[7] == expectedSharedObjects[7]);
747     BOOST_TEST(sharedObjects[8] == expectedSharedObjects[8]);
748 }
749
750 void CreateDynamicBackendsTestImpl()
751 {
752     using namespace armnn;
753     using namespace boost::filesystem;
754
755     // The test covers four directories:
756     // <unit test path>/src/backends/backendsCommon/test/
757     //                                                ├─ backendsTestPath5/   -> exists, contains files
758     //                                                ├─ backendsTestPath6/   -> exists, contains files
759     //                                                ├─ backendsTestPath7/   -> exists, but empty
760     //                                                └─ backendsTestPath8/   -> does not exist
761     //
762     // The test sub-directory backendsTestPath5/ contains the following test files:
763     //
764     // Arm_TestValid2_backend.so   -> valid (basic backend name)
765     // Arm_TestValid3_backend.so   -> valid (basic backend name)
766     // Arm_TestInvalid8_backend.so -> not valid (invalid backend id)
767     //
768     // The test sub-directory backendsTestPath6/ contains the following test files:
769     //
770     // Arm_TestValid2_backend.so   -> valid (but duplicated from backendsTestPath5/)
771     // Arm_TestValid4_backend.so   -> valid (it has a different filename,
772     //                                       but it has the same backend id of Arm_TestValid2_backend.so
773     //                                       and the same version)
774     // Arm_TestValid5_backend.so   -> valid (basic backend name)
775     // Arm_TestInvalid9_backend.so -> not valid (it has a different filename,
776     //                                           but it has the same backend id of Arm_TestValid2_backend.so
777     //                                           and a version incompatible with the Backend API)
778
779     std::string testDynamicBackendsSubDir5 = GetTestSubDirectory(g_TestDynamicBackendsSubDir5);
780     std::string testDynamicBackendsSubDir6 = GetTestSubDirectory(g_TestDynamicBackendsSubDir6);
781     std::string testDynamicBackendsSubDir7 = GetTestSubDirectory(g_TestDynamicBackendsSubDir7);
782     std::string testDynamicBackendsSubDir8 = GetTestSubDirectory(g_TestDynamicBackendsSubDir8);
783     BOOST_CHECK(exists(testDynamicBackendsSubDir5));
784     BOOST_CHECK(exists(testDynamicBackendsSubDir6));
785     BOOST_CHECK(exists(testDynamicBackendsSubDir7));
786     BOOST_CHECK(!exists(testDynamicBackendsSubDir8));
787
788     std::vector<std::string> backendPaths
789     {
790         testDynamicBackendsSubDir5,
791         testDynamicBackendsSubDir6,
792         testDynamicBackendsSubDir7,
793         testDynamicBackendsSubDir8
794     };
795     std::vector<std::string> sharedObjects = DynamicBackendUtils::GetSharedObjects(backendPaths);
796     std::vector<DynamicBackendPtr> dynamicBackends = DynamicBackendUtils::CreateDynamicBackends(sharedObjects);
797
798     BOOST_TEST(dynamicBackends.size() == 5);
799     BOOST_TEST((dynamicBackends[0] != nullptr));
800     BOOST_TEST((dynamicBackends[1] != nullptr));
801     BOOST_TEST((dynamicBackends[2] != nullptr));
802     BOOST_TEST((dynamicBackends[3] != nullptr));
803     BOOST_TEST((dynamicBackends[4] != nullptr));
804
805     // Duplicates are allowed here, they will be skipped later during the backend registration
806     BOOST_TEST((dynamicBackends[0]->GetBackendId() == "TestValid2"));
807     BOOST_TEST((dynamicBackends[1]->GetBackendId() == "TestValid3"));
808     BOOST_TEST((dynamicBackends[2]->GetBackendId() == "TestValid2")); // From duplicate Arm_TestValid2_backend.so
809     BOOST_TEST((dynamicBackends[3]->GetBackendId() == "TestValid2")); // From Arm_TestValid4_backend.so
810     BOOST_TEST((dynamicBackends[4]->GetBackendId() == "TestValid5"));
811 }
812
813 void CreateDynamicBackendsNoPathsTestImpl()
814 {
815     using namespace armnn;
816
817     std::vector<DynamicBackendPtr> dynamicBackends = DynamicBackendUtils::CreateDynamicBackends({});
818
819     BOOST_TEST(dynamicBackends.empty());
820 }
821
822 void CreateDynamicBackendsAllInvalidTestImpl()
823 {
824     using namespace armnn;
825
826     std::vector<std::string> sharedObjects
827     {
828         "InvalidSharedObject1",
829         "InvalidSharedObject2",
830         "InvalidSharedObject3",
831     };
832     std::vector<DynamicBackendPtr> dynamicBackends = DynamicBackendUtils::CreateDynamicBackends(sharedObjects);
833
834     BOOST_TEST(dynamicBackends.empty());
835 }
836
837 void CreateDynamicBackendsMixedTypesTestImpl()
838 {
839     using namespace armnn;
840     using namespace boost::filesystem;
841
842     std::string testDynamicBackendsSubDir5 = GetTestSubDirectory(g_TestDynamicBackendsSubDir5);
843     std::string testDynamicBackendsSubDir6 = GetTestSubDirectory(g_TestDynamicBackendsSubDir6);
844     BOOST_CHECK(exists(testDynamicBackendsSubDir5));
845     BOOST_CHECK(exists(testDynamicBackendsSubDir6));
846
847     std::string testValidBackend2FilePath = GetTestFilePath(testDynamicBackendsSubDir5,
848                                                             g_TestValidBackend2FileName);
849     std::string testInvalidBackend8FilePath = GetTestFilePath(testDynamicBackendsSubDir5,
850                                                               g_TestInvalidBackend8FileName);
851     std::string testInvalidBackend9FilePath = GetTestFilePath(testDynamicBackendsSubDir6,
852                                                               g_TestInvalidBackend9FileName);
853     BOOST_CHECK(exists(testValidBackend2FilePath));
854     BOOST_CHECK(exists(testInvalidBackend8FilePath));
855     BOOST_CHECK(exists(testInvalidBackend9FilePath));
856
857     std::vector<std::string> sharedObjects
858     {
859         testValidBackend2FilePath,   // Arm_TestValid2_backend.so     -> valid (basic backend name)
860         testInvalidBackend8FilePath, // Arm_TestInvalid8_backend.so   -> not valid (invalid backend id)
861         testInvalidBackend9FilePath, // Arm_TestInvalid9_backend.so   -> not valid (incompatible version)
862         "InvalidSharedObject",       // The file does not exist
863     };
864     std::vector<DynamicBackendPtr> dynamicBackends = DynamicBackendUtils::CreateDynamicBackends(sharedObjects);
865
866     BOOST_TEST(dynamicBackends.size() == 1);
867     BOOST_TEST((dynamicBackends[0] != nullptr));
868     BOOST_TEST((dynamicBackends[0]->GetBackendId() == "TestValid2"));
869 }
870
871 void RegisterSingleDynamicBackendTestImpl()
872 {
873     using namespace armnn;
874     using namespace boost::filesystem;
875
876     // Register one valid dynamic backend
877
878     // Dummy registry used for testing
879     BackendRegistry backendRegistry;
880     BOOST_TEST(backendRegistry.Size() == 0);
881
882     std::string testDynamicBackendsSubDir5 = GetTestSubDirectory(g_TestDynamicBackendsSubDir5);
883     BOOST_CHECK(exists(testDynamicBackendsSubDir5));
884
885     std::string testValidBackend2FilePath = GetTestFilePath(testDynamicBackendsSubDir5, g_TestValidBackend2FileName);
886     BOOST_CHECK(exists(testValidBackend2FilePath));
887
888     std::vector<std::string> sharedObjects{ testValidBackend2FilePath };
889     std::vector<DynamicBackendPtr> dynamicBackends = TestDynamicBackendUtils::CreateDynamicBackends(sharedObjects);
890
891     BOOST_TEST(dynamicBackends.size() == 1);
892     BOOST_TEST((dynamicBackends[0] != nullptr));
893
894     BackendId dynamicBackendId = dynamicBackends[0]->GetBackendId();
895     BOOST_TEST((dynamicBackendId == "TestValid2"));
896
897     BackendVersion dynamicBackendVersion = dynamicBackends[0]->GetBackendVersion();
898     BOOST_TEST(TestDynamicBackendUtils::IsBackendCompatible(dynamicBackendVersion));
899
900     BackendIdSet registeredBackendIds = TestDynamicBackendUtils::RegisterDynamicBackendsImplTest(backendRegistry,
901                                                                                                  dynamicBackends);
902     BOOST_TEST(backendRegistry.Size() == 1);
903     BOOST_TEST(registeredBackendIds.size() == 1);
904
905     BackendIdSet backendIds = backendRegistry.GetBackendIds();
906     BOOST_TEST(backendIds.size() == 1);
907     BOOST_TEST((backendIds.find(dynamicBackendId) != backendIds.end()));
908     BOOST_TEST((registeredBackendIds.find(dynamicBackendId) != registeredBackendIds.end()));
909
910     auto dynamicBackendFactoryFunction = backendRegistry.GetFactory(dynamicBackendId);
911     BOOST_TEST((dynamicBackendFactoryFunction != nullptr));
912
913     IBackendInternalUniquePtr dynamicBackend = dynamicBackendFactoryFunction();
914     BOOST_TEST((dynamicBackend != nullptr));
915     BOOST_TEST((dynamicBackend->GetId() == dynamicBackendId));
916 }
917
918 void RegisterMultipleDynamicBackendsTestImpl()
919 {
920     using namespace armnn;
921     using namespace boost::filesystem;
922
923     // Register many valid dynamic backends
924
925     std::string testDynamicBackendsSubDir5 = GetTestSubDirectory(g_TestDynamicBackendsSubDir5);
926     std::string testDynamicBackendsSubDir6 = GetTestSubDirectory(g_TestDynamicBackendsSubDir6);
927     BOOST_CHECK(exists(testDynamicBackendsSubDir5));
928     BOOST_CHECK(exists(testDynamicBackendsSubDir6));
929
930     std::string testValidBackend2FilePath = GetTestFilePath(testDynamicBackendsSubDir5, g_TestValidBackend2FileName);
931     std::string testValidBackend3FilePath = GetTestFilePath(testDynamicBackendsSubDir5, g_TestValidBackend3FileName);
932     std::string testValidBackend5FilePath = GetTestFilePath(testDynamicBackendsSubDir6, g_TestValidBackend5FileName);
933     BOOST_CHECK(exists(testValidBackend2FilePath));
934     BOOST_CHECK(exists(testValidBackend3FilePath));
935     BOOST_CHECK(exists(testValidBackend5FilePath));
936
937     std::vector<std::string> sharedObjects
938     {
939         testValidBackend2FilePath,
940         testValidBackend3FilePath,
941         testValidBackend5FilePath
942     };
943     std::vector<DynamicBackendPtr> dynamicBackends = TestDynamicBackendUtils::CreateDynamicBackends(sharedObjects);
944
945     BOOST_TEST(dynamicBackends.size() == 3);
946     BOOST_TEST((dynamicBackends[0] != nullptr));
947     BOOST_TEST((dynamicBackends[1] != nullptr));
948     BOOST_TEST((dynamicBackends[2] != nullptr));
949
950     BackendId dynamicBackendId1 = dynamicBackends[0]->GetBackendId();
951     BackendId dynamicBackendId2 = dynamicBackends[1]->GetBackendId();
952     BackendId dynamicBackendId3 = dynamicBackends[2]->GetBackendId();
953     BOOST_TEST((dynamicBackendId1 == "TestValid2"));
954     BOOST_TEST((dynamicBackendId2 == "TestValid3"));
955     BOOST_TEST((dynamicBackendId3 == "TestValid5"));
956
957     for (size_t i = 0; i < dynamicBackends.size(); i++)
958     {
959         BackendVersion dynamicBackendVersion = dynamicBackends[i]->GetBackendVersion();
960         BOOST_TEST(TestDynamicBackendUtils::IsBackendCompatible(dynamicBackendVersion));
961     }
962
963     // Dummy registry used for testing
964     BackendRegistry backendRegistry;
965     BOOST_TEST(backendRegistry.Size() == 0);
966
967     BackendIdSet registeredBackendIds = TestDynamicBackendUtils::RegisterDynamicBackendsImplTest(backendRegistry,
968                                                                                                  dynamicBackends);
969     BOOST_TEST(backendRegistry.Size() == 3);
970     BOOST_TEST(registeredBackendIds.size() == 3);
971
972     BackendIdSet backendIds = backendRegistry.GetBackendIds();
973     BOOST_TEST(backendIds.size() == 3);
974     BOOST_TEST((backendIds.find(dynamicBackendId1) != backendIds.end()));
975     BOOST_TEST((backendIds.find(dynamicBackendId2) != backendIds.end()));
976     BOOST_TEST((backendIds.find(dynamicBackendId3) != backendIds.end()));
977     BOOST_TEST((registeredBackendIds.find(dynamicBackendId1) != registeredBackendIds.end()));
978     BOOST_TEST((registeredBackendIds.find(dynamicBackendId2) != registeredBackendIds.end()));
979     BOOST_TEST((registeredBackendIds.find(dynamicBackendId3) != registeredBackendIds.end()));
980
981     for (size_t i = 0; i < dynamicBackends.size(); i++)
982     {
983         BackendId dynamicBackendId = dynamicBackends[i]->GetBackendId();
984
985         auto dynamicBackendFactoryFunction = backendRegistry.GetFactory(dynamicBackendId);
986         BOOST_TEST((dynamicBackendFactoryFunction != nullptr));
987
988         IBackendInternalUniquePtr dynamicBackend = dynamicBackendFactoryFunction();
989         BOOST_TEST((dynamicBackend != nullptr));
990         BOOST_TEST((dynamicBackend->GetId() == dynamicBackendId));
991     }
992 }
993
994 void RegisterMultipleInvalidDynamicBackendsTestImpl()
995 {
996     using namespace armnn;
997     using namespace boost::filesystem;
998
999     // Try to register many invalid dynamic backends
1000
1001     // The test covers one directory:
1002     // <unit test path>/src/backends/backendsCommon/test/
1003     //                                                └─ backendsTestPath9/   -> exists, contains files
1004     //
1005     // The test sub-directory backendsTestPath9/ contains the following test files:
1006     //
1007     // Arm_TestInvalid10_backend.so -> not valid (invalid backend id)
1008     // Arm_TestInvalid11_backend.so -> not valid (invalid backend id)
1009
1010     std::string testDynamicBackendsSubDir9 = GetTestSubDirectory(g_TestDynamicBackendsSubDir9);
1011     BOOST_CHECK(exists(testDynamicBackendsSubDir9));
1012
1013     std::string testInvalidBackend10FilePath = GetTestFilePath(testDynamicBackendsSubDir9,
1014                                                                g_TestInvalidBackend10FileName);
1015     std::string testInvalidBackend11FilePath = GetTestFilePath(testDynamicBackendsSubDir9,
1016                                                                g_TestInvalidBackend11FileName);
1017     BOOST_CHECK(exists(testInvalidBackend10FilePath));
1018     BOOST_CHECK(exists(testInvalidBackend11FilePath));
1019
1020     std::vector<std::string> sharedObjects
1021     {
1022         testInvalidBackend10FilePath,
1023         testInvalidBackend11FilePath,
1024         "InvalidSharedObject"
1025     };
1026     std::vector<DynamicBackendPtr> dynamicBackends = TestDynamicBackendUtils::CreateDynamicBackends(sharedObjects);
1027
1028     BOOST_TEST(dynamicBackends.size() == 2);
1029     BOOST_TEST((dynamicBackends[0] != nullptr));
1030     BOOST_TEST((dynamicBackends[1] != nullptr));
1031
1032     BackendId dynamicBackendId1 = dynamicBackends[0]->GetBackendId();
1033     BackendId dynamicBackendId2 = dynamicBackends[1]->GetBackendId();
1034     BOOST_TEST((dynamicBackendId1 == ""));
1035     BOOST_TEST((dynamicBackendId2 == "Unknown"));
1036
1037     for (size_t i = 0; i < dynamicBackends.size(); i++)
1038     {
1039         BackendVersion dynamicBackendVersion = dynamicBackends[i]->GetBackendVersion();
1040         BOOST_TEST(TestDynamicBackendUtils::IsBackendCompatible(dynamicBackendVersion));
1041     }
1042
1043     // Dummy registry used for testing
1044     BackendRegistry backendRegistry;
1045     BOOST_TEST(backendRegistry.Size() == 0);
1046
1047     // Check that no dynamic backend got registered
1048     BackendIdSet registeredBackendIds = TestDynamicBackendUtils::RegisterDynamicBackendsImplTest(backendRegistry,
1049                                                                                                  dynamicBackends);
1050     BOOST_TEST(backendRegistry.Size() == 0);
1051     BOOST_TEST(registeredBackendIds.empty());
1052 }
1053
1054 void RegisterMixedDynamicBackendsTestImpl()
1055 {
1056     using namespace armnn;
1057     using namespace boost::filesystem;
1058
1059     // The test covers five directories:
1060     // <unit test path>/src/backends/backendsCommon/test/
1061     //                                                ├─ backendsTestPath5/   -> exists, contains files
1062     //                                                ├─ backendsTestPath6/   -> exists, contains files
1063     //                                                ├─ backendsTestPath7/   -> exists, but empty
1064     //                                                ├─ backendsTestPath8/   -> does not exist
1065     //                                                └─ backendsTestPath9/   -> exists, contains files
1066     //
1067     // The test sub-directory backendsTestPath5/ contains the following test files:
1068     //
1069     // Arm_TestValid2_backend.so   -> valid (basic backend name)
1070     // Arm_TestValid3_backend.so   -> valid (basic backend name)
1071     // Arm_TestInvalid8_backend.so -> not valid (invalid backend id)
1072     //
1073     // The test sub-directory backendsTestPath6/ contains the following test files:
1074     //
1075     // Arm_TestValid2_backend.so   -> valid (but duplicated from backendsTestPath5/)
1076     // Arm_TestValid4_backend.so   -> valid (it has a different filename,
1077     //                                       but it has the same backend id of Arm_TestValid2_backend.so
1078     //                                       and the same version)
1079     // Arm_TestValid5_backend.so   -> valid (basic backend name)
1080     // Arm_TestInvalid9_backend.so -> not valid (it has a different filename,
1081     //                                           but it has the same backend id of Arm_TestValid2_backend.so
1082     //                                           and a version incompatible with the Backend API)
1083     //
1084     // The test sub-directory backendsTestPath9/ contains the following test files:
1085     //
1086     // Arm_TestInvalid10_backend.so -> not valid (empty backend id)
1087     // Arm_TestInvalid11_backend.so -> not valid ("Unknown" backend id)
1088
1089     std::string testDynamicBackendsSubDir5 = GetTestSubDirectory(g_TestDynamicBackendsSubDir5);
1090     std::string testDynamicBackendsSubDir6 = GetTestSubDirectory(g_TestDynamicBackendsSubDir6);
1091     std::string testDynamicBackendsSubDir7 = GetTestSubDirectory(g_TestDynamicBackendsSubDir7);
1092     std::string testDynamicBackendsSubDir8 = GetTestSubDirectory(g_TestDynamicBackendsSubDir8);
1093     std::string testDynamicBackendsSubDir9 = GetTestSubDirectory(g_TestDynamicBackendsSubDir9);
1094     BOOST_CHECK(exists(testDynamicBackendsSubDir5));
1095     BOOST_CHECK(exists(testDynamicBackendsSubDir6));
1096     BOOST_CHECK(exists(testDynamicBackendsSubDir7));
1097     BOOST_CHECK(!exists(testDynamicBackendsSubDir8));
1098     BOOST_CHECK(exists(testDynamicBackendsSubDir9));
1099
1100     std::string testValidBackend2FilePath    = GetTestFilePath(testDynamicBackendsSubDir5, g_TestValidBackend2FileName);
1101     std::string testValidBackend3FilePath    = GetTestFilePath(testDynamicBackendsSubDir5, g_TestValidBackend3FileName);
1102     std::string testValidBackend2DupFilePath = GetTestFilePath(testDynamicBackendsSubDir6, g_TestValidBackend2FileName);
1103     std::string testValidBackend4FilePath    = GetTestFilePath(testDynamicBackendsSubDir6, g_TestValidBackend4FileName);
1104     std::string testValidBackend5FilePath    = GetTestFilePath(testDynamicBackendsSubDir6, g_TestValidBackend5FileName);
1105     std::string testInvalidBackend8FilePath  = GetTestFilePath(testDynamicBackendsSubDir5,
1106                                                                g_TestInvalidBackend8FileName);
1107     std::string testInvalidBackend9FilePath  = GetTestFilePath(testDynamicBackendsSubDir6,
1108                                                                g_TestInvalidBackend9FileName);
1109     std::string testInvalidBackend10FilePath = GetTestFilePath(testDynamicBackendsSubDir9,
1110                                                                g_TestInvalidBackend10FileName);
1111     std::string testInvalidBackend11FilePath = GetTestFilePath(testDynamicBackendsSubDir9,
1112                                                                g_TestInvalidBackend11FileName);
1113     BOOST_CHECK(exists(testValidBackend2FilePath));
1114     BOOST_CHECK(exists(testValidBackend3FilePath));
1115     BOOST_CHECK(exists(testValidBackend2DupFilePath));
1116     BOOST_CHECK(exists(testValidBackend4FilePath));
1117     BOOST_CHECK(exists(testValidBackend5FilePath));
1118     BOOST_CHECK(exists(testInvalidBackend8FilePath));
1119     BOOST_CHECK(exists(testInvalidBackend9FilePath));
1120     BOOST_CHECK(exists(testInvalidBackend10FilePath));
1121     BOOST_CHECK(exists(testInvalidBackend11FilePath));
1122
1123     std::vector<std::string> sharedObjects
1124     {
1125         testValidBackend2FilePath,
1126         testValidBackend3FilePath,
1127         testValidBackend2DupFilePath,
1128         testValidBackend4FilePath,
1129         testValidBackend5FilePath,
1130         testInvalidBackend8FilePath,
1131         testInvalidBackend9FilePath,
1132         testInvalidBackend10FilePath,
1133         testInvalidBackend11FilePath,
1134         "InvalidSharedObject"
1135     };
1136     std::vector<DynamicBackendPtr> dynamicBackends = TestDynamicBackendUtils::CreateDynamicBackends(sharedObjects);
1137
1138     BOOST_TEST(dynamicBackends.size() == 7);
1139     BOOST_TEST((dynamicBackends[0] != nullptr));
1140     BOOST_TEST((dynamicBackends[1] != nullptr));
1141     BOOST_TEST((dynamicBackends[2] != nullptr));
1142     BOOST_TEST((dynamicBackends[3] != nullptr));
1143     BOOST_TEST((dynamicBackends[4] != nullptr));
1144     BOOST_TEST((dynamicBackends[5] != nullptr));
1145     BOOST_TEST((dynamicBackends[6] != nullptr));
1146
1147     BackendId dynamicBackendId1 = dynamicBackends[0]->GetBackendId();
1148     BackendId dynamicBackendId2 = dynamicBackends[1]->GetBackendId();
1149     BackendId dynamicBackendId3 = dynamicBackends[2]->GetBackendId();
1150     BackendId dynamicBackendId4 = dynamicBackends[3]->GetBackendId();
1151     BackendId dynamicBackendId5 = dynamicBackends[4]->GetBackendId();
1152     BackendId dynamicBackendId6 = dynamicBackends[5]->GetBackendId();
1153     BackendId dynamicBackendId7 = dynamicBackends[6]->GetBackendId();
1154     BOOST_TEST((dynamicBackendId1 == "TestValid2"));
1155     BOOST_TEST((dynamicBackendId2 == "TestValid3"));
1156     BOOST_TEST((dynamicBackendId3 == "TestValid2")); // From duplicate Arm_TestValid2_backend.so
1157     BOOST_TEST((dynamicBackendId4 == "TestValid2")); // From Arm_TestValid4_backend.so
1158     BOOST_TEST((dynamicBackendId5 == "TestValid5"));
1159     BOOST_TEST((dynamicBackendId6 == ""));
1160     BOOST_TEST((dynamicBackendId7 == "Unknown"));
1161
1162     for (size_t i = 0; i < dynamicBackends.size(); i++)
1163     {
1164         BackendVersion dynamicBackendVersion = dynamicBackends[i]->GetBackendVersion();
1165         BOOST_TEST(TestDynamicBackendUtils::IsBackendCompatible(dynamicBackendVersion));
1166     }
1167
1168     // Dummy registry used for testing
1169     BackendRegistry backendRegistry;
1170     BOOST_TEST(backendRegistry.Size() == 0);
1171
1172     std::vector<BackendId> expectedRegisteredbackendIds
1173     {
1174         "TestValid2",
1175         "TestValid3",
1176         "TestValid5"
1177     };
1178
1179     BackendIdSet registeredBackendIds = TestDynamicBackendUtils::RegisterDynamicBackendsImplTest(backendRegistry,
1180                                                                                                  dynamicBackends);
1181     BOOST_TEST(backendRegistry.Size() == expectedRegisteredbackendIds.size());
1182     BOOST_TEST(registeredBackendIds.size() == expectedRegisteredbackendIds.size());
1183
1184     BackendIdSet backendIds = backendRegistry.GetBackendIds();
1185     BOOST_TEST(backendIds.size() == expectedRegisteredbackendIds.size());
1186     for (const BackendId& expectedRegisteredbackendId : expectedRegisteredbackendIds)
1187     {
1188         BOOST_TEST((backendIds.find(expectedRegisteredbackendId) != backendIds.end()));
1189         BOOST_TEST((registeredBackendIds.find(expectedRegisteredbackendId) != registeredBackendIds.end()));
1190
1191         auto dynamicBackendFactoryFunction = backendRegistry.GetFactory(expectedRegisteredbackendId);
1192         BOOST_TEST((dynamicBackendFactoryFunction != nullptr));
1193
1194         IBackendInternalUniquePtr dynamicBackend = dynamicBackendFactoryFunction();
1195         BOOST_TEST((dynamicBackend != nullptr));
1196         BOOST_TEST((dynamicBackend->GetId() == expectedRegisteredbackendId));
1197     }
1198 }
1199
1200 void RuntimeEmptyTestImpl()
1201 {
1202     using namespace armnn;
1203
1204     // Swapping the backend registry storage for testing
1205     TestBackendRegistry testBackendRegistry;
1206
1207     const BackendRegistry& backendRegistry = BackendRegistryInstance();
1208     BOOST_TEST(backendRegistry.Size() == 0);
1209
1210     IRuntime::CreationOptions creationOptions;
1211     IRuntimePtr runtime = IRuntime::Create(creationOptions);
1212
1213     const DeviceSpec& deviceSpec = *boost::polymorphic_downcast<const DeviceSpec*>(&runtime->GetDeviceSpec());
1214     BackendIdSet supportedBackendIds = deviceSpec.GetSupportedBackends();
1215     BOOST_TEST(supportedBackendIds.empty());
1216
1217     BOOST_TEST(backendRegistry.Size() == 0);
1218 }
1219
1220 void RuntimeDynamicBackendsTestImpl()
1221 {
1222     using namespace armnn;
1223     using namespace boost::filesystem;
1224
1225     // Swapping the backend registry storage for testing
1226     TestBackendRegistry testBackendRegistry;
1227
1228     // This directory contains valid and invalid backends
1229     std::string testDynamicBackendsSubDir5 = GetTestSubDirectory(g_TestDynamicBackendsSubDir5);
1230     BOOST_CHECK(exists(testDynamicBackendsSubDir5));
1231
1232     // Using the path override in CreationOptions to load some test dynamic backends
1233     IRuntime::CreationOptions creationOptions;
1234     creationOptions.m_DynamicBackendsPath = testDynamicBackendsSubDir5;
1235     IRuntimePtr runtime = IRuntime::Create(creationOptions);
1236
1237     std::vector<BackendId> expectedRegisteredbackendIds
1238     {
1239         "TestValid2",
1240         "TestValid3"
1241     };
1242
1243     const BackendRegistry& backendRegistry = BackendRegistryInstance();
1244     BOOST_TEST(backendRegistry.Size() == expectedRegisteredbackendIds.size());
1245
1246     BackendIdSet backendIds = backendRegistry.GetBackendIds();
1247     for (const BackendId& expectedRegisteredbackendId : expectedRegisteredbackendIds)
1248     {
1249         BOOST_TEST((backendIds.find(expectedRegisteredbackendId) != backendIds.end()));
1250     }
1251
1252     const DeviceSpec& deviceSpec = *boost::polymorphic_downcast<const DeviceSpec*>(&runtime->GetDeviceSpec());
1253     BackendIdSet supportedBackendIds = deviceSpec.GetSupportedBackends();
1254     BOOST_TEST(supportedBackendIds.size() == expectedRegisteredbackendIds.size());
1255     for (const BackendId& expectedRegisteredbackendId : expectedRegisteredbackendIds)
1256     {
1257         BOOST_TEST((supportedBackendIds.find(expectedRegisteredbackendId) != supportedBackendIds.end()));
1258     }
1259 }
1260
1261 void RuntimeDuplicateDynamicBackendsTestImpl()
1262 {
1263     using namespace armnn;
1264     using namespace boost::filesystem;
1265
1266     // Swapping the backend registry storage for testing
1267     TestBackendRegistry testBackendRegistry;
1268
1269     // This directory contains valid, invalid and duplicate backends
1270     std::string testDynamicBackendsSubDir6 = GetTestSubDirectory(g_TestDynamicBackendsSubDir6);
1271     BOOST_CHECK(exists(testDynamicBackendsSubDir6));
1272
1273     // Using the path override in CreationOptions to load some test dynamic backends
1274     IRuntime::CreationOptions creationOptions;
1275     creationOptions.m_DynamicBackendsPath = testDynamicBackendsSubDir6;
1276     IRuntimePtr runtime = IRuntime::Create(creationOptions);
1277
1278     std::vector<BackendId> expectedRegisteredbackendIds
1279     {
1280         "TestValid2",
1281         "TestValid5"
1282     };
1283
1284     const BackendRegistry& backendRegistry = BackendRegistryInstance();
1285     BOOST_TEST(backendRegistry.Size() == expectedRegisteredbackendIds.size());
1286
1287     BackendIdSet backendIds = backendRegistry.GetBackendIds();
1288     for (const BackendId& expectedRegisteredbackendId : expectedRegisteredbackendIds)
1289     {
1290         BOOST_TEST((backendIds.find(expectedRegisteredbackendId) != backendIds.end()));
1291     }
1292
1293     const DeviceSpec& deviceSpec = *boost::polymorphic_downcast<const DeviceSpec*>(&runtime->GetDeviceSpec());
1294     BackendIdSet supportedBackendIds = deviceSpec.GetSupportedBackends();
1295     BOOST_TEST(supportedBackendIds.size() == expectedRegisteredbackendIds.size());
1296     for (const BackendId& expectedRegisteredbackendId : expectedRegisteredbackendIds)
1297     {
1298         BOOST_TEST((supportedBackendIds.find(expectedRegisteredbackendId) != supportedBackendIds.end()));
1299     }
1300 }
1301
1302 void RuntimeInvalidDynamicBackendsTestImpl()
1303 {
1304     using namespace armnn;
1305     using namespace boost::filesystem;
1306
1307     // Swapping the backend registry storage for testing
1308     TestBackendRegistry testBackendRegistry;
1309
1310     // This directory contains only invalid backends
1311     std::string testDynamicBackendsSubDir9 = GetTestSubDirectory(g_TestDynamicBackendsSubDir9);
1312     BOOST_CHECK(exists(testDynamicBackendsSubDir9));
1313
1314     // Using the path override in CreationOptions to load some test dynamic backends
1315     IRuntime::CreationOptions creationOptions;
1316     creationOptions.m_DynamicBackendsPath = testDynamicBackendsSubDir9;
1317     IRuntimePtr runtime = IRuntime::Create(creationOptions);
1318
1319     const BackendRegistry& backendRegistry = BackendRegistryInstance();
1320     BOOST_TEST(backendRegistry.Size() == 0);
1321
1322     const DeviceSpec& deviceSpec = *boost::polymorphic_downcast<const DeviceSpec*>(&runtime->GetDeviceSpec());
1323     BackendIdSet supportedBackendIds = deviceSpec.GetSupportedBackends();
1324     BOOST_TEST(supportedBackendIds.empty());
1325 }
1326
1327 void RuntimeInvalidOverridePathTestImpl()
1328 {
1329     using namespace armnn;
1330
1331     // Swapping the backend registry storage for testing
1332     TestBackendRegistry testBackendRegistry;
1333
1334     // Using the path override in CreationOptions to load some test dynamic backends
1335     IRuntime::CreationOptions creationOptions;
1336     creationOptions.m_DynamicBackendsPath = "InvalidPath";
1337     IRuntimePtr runtime = IRuntime::Create(creationOptions);
1338
1339     const BackendRegistry& backendRegistry = BackendRegistryInstance();
1340     BOOST_TEST(backendRegistry.Size() == 0);
1341
1342     const DeviceSpec& deviceSpec = *boost::polymorphic_downcast<const DeviceSpec*>(&runtime->GetDeviceSpec());
1343     BackendIdSet supportedBackendIds = deviceSpec.GetSupportedBackends();
1344     BOOST_TEST(supportedBackendIds.empty());
1345 }
1346
1347 #if defined(ARMCOMPUTEREF_ENABLED)
1348
1349 // This test unit needs the reference backend, it's not available if the reference backend is not built
1350
1351 void CreateReferenceDynamicBackendTestImpl()
1352 {
1353     using namespace armnn;
1354     using namespace boost::filesystem;
1355
1356     // Swapping the backend registry storage for testing
1357     TestBackendRegistry testBackendRegistry;
1358
1359     // This directory contains the reference dynamic backend
1360     std::string dynamicBackendsBaseDir = GetDynamicBackendsBasePath();
1361     std::string referenceDynamicBackendSubDir = GetTestSubDirectory(dynamicBackendsBaseDir,
1362                                                                     g_ReferenceDynamicBackendSubDir);
1363     BOOST_CHECK(exists(referenceDynamicBackendSubDir));
1364
1365     // Check that the reference dynamic backend file exists
1366     std::string referenceBackendFilePath = GetTestFilePath(referenceDynamicBackendSubDir,
1367                                                            g_ReferenceBackendFileName);
1368     BOOST_CHECK(exists(referenceBackendFilePath));
1369
1370     // Using the path override in CreationOptions to load the reference dynamic backend
1371     IRuntime::CreationOptions creationOptions;
1372     creationOptions.m_DynamicBackendsPath = referenceDynamicBackendSubDir;
1373     IRuntimePtr runtime = IRuntime::Create(creationOptions);
1374
1375     const BackendRegistry& backendRegistry = BackendRegistryInstance();
1376     BOOST_TEST(backendRegistry.Size() == 1);
1377
1378     BackendIdSet backendIds = backendRegistry.GetBackendIds();
1379     BOOST_TEST((backendIds.find("CpuRef") != backendIds.end()));
1380
1381     const DeviceSpec& deviceSpec = *boost::polymorphic_downcast<const DeviceSpec*>(&runtime->GetDeviceSpec());
1382     BackendIdSet supportedBackendIds = deviceSpec.GetSupportedBackends();
1383     BOOST_TEST(supportedBackendIds.size() == 1);
1384     BOOST_TEST((supportedBackendIds.find("CpuRef") != supportedBackendIds.end()));
1385
1386     // Get the factory function
1387     auto referenceDynamicBackendFactoryFunction = backendRegistry.GetFactory("CpuRef");
1388     BOOST_TEST((referenceDynamicBackendFactoryFunction != nullptr));
1389
1390     // Use the factory function to create an instance of the reference backend
1391     IBackendInternalUniquePtr referenceDynamicBackend = referenceDynamicBackendFactoryFunction();
1392     BOOST_TEST((referenceDynamicBackend != nullptr));
1393     BOOST_TEST((referenceDynamicBackend->GetId() == "CpuRef"));
1394
1395     // Test the backend instance by querying the layer support
1396     IBackendInternal::ILayerSupportSharedPtr referenceLayerSupport = referenceDynamicBackend->GetLayerSupport();
1397     BOOST_TEST((referenceLayerSupport != nullptr));
1398
1399     TensorShape inputShape {  1, 16, 16, 16 };
1400     TensorShape outputShape{  1, 16, 16, 16 };
1401     TensorShape weightShape{ 16,  1,  1, 16 };
1402     TensorInfo inputInfo (inputShape,  DataType::Float32);
1403     TensorInfo outputInfo(outputShape, DataType::Float32);
1404     TensorInfo weightInfo(weightShape, DataType::Float32);
1405     Convolution2dDescriptor convolution2dDescriptor;
1406     bool referenceConvolution2dSupported =
1407             referenceLayerSupport->IsConvolution2dSupported(inputInfo,
1408                                                             outputInfo,
1409                                                             convolution2dDescriptor,
1410                                                             weightInfo,
1411                                                             EmptyOptional());
1412     BOOST_TEST(referenceConvolution2dSupported);
1413
1414     // Test the backend instance by creating a workload
1415     IBackendInternal::IWorkloadFactoryPtr referenceWorkloadFactory = referenceDynamicBackend->CreateWorkloadFactory();
1416     BOOST_TEST((referenceWorkloadFactory != nullptr));
1417
1418     // Create dummy settings for the workload
1419     Convolution2dQueueDescriptor convolution2dQueueDescriptor;
1420     WorkloadInfo workloadInfo
1421     {
1422         { inputInfo },
1423         { outputInfo }
1424     };
1425     convolution2dQueueDescriptor.m_Inputs.push_back(nullptr);
1426     auto weights = std::make_unique<ScopedCpuTensorHandle>(weightInfo);
1427     convolution2dQueueDescriptor.m_Weight = weights.get();
1428
1429     // Create a convolution workload with the dummy settings
1430     auto workload = referenceWorkloadFactory->CreateConvolution2d(convolution2dQueueDescriptor, workloadInfo);
1431     BOOST_TEST((workload != nullptr));
1432     BOOST_TEST(workload.get() == boost::polymorphic_downcast<RefConvolution2dWorkload*>(workload.get()));
1433 }
1434
1435 #endif