IVGCVSW-3595 Implement the LoadDynamicBackends function in the Runtime class
[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
11 #include <string>
12 #include <memory>
13 #include <string>
14
15 #include <boost/test/unit_test.hpp>
16 #include <boost/filesystem.hpp>
17 #include <boost/dll.hpp>
18
19 static std::string g_TestBaseDir                            = "src/backends/backendsCommon/test/";
20
21 static std::string g_TestSharedObjectSubDir                 = "testSharedObject/";
22 static std::string g_TestDynamicBackendSubDir               = "testDynamicBackend/";
23
24 static std::string g_TestSharedObjectFileName               = "libTestSharedObject.so";
25 static std::string g_TestNoSharedObjectFileName             = "libNoSharedObject.txt";
26
27 static std::string g_TestValidTestDynamicBackendFileName    = "libValidTestDynamicBackend.so";
28 static std::string g_TestInvalidTestDynamicBackend1FileName = "libInvalidTestDynamicBackend1.so";
29 static std::string g_TestInvalidTestDynamicBackend2FileName = "libInvalidTestDynamicBackend2.so";
30 static std::string g_TestInvalidTestDynamicBackend3FileName = "libInvalidTestDynamicBackend3.so";
31 static std::string g_TestInvalidTestDynamicBackend4FileName = "libInvalidTestDynamicBackend4.so";
32 static std::string g_TestInvalidTestDynamicBackend5FileName = "libInvalidTestDynamicBackend5.so";
33 static std::string g_TestInvalidTestDynamicBackend6FileName = "libInvalidTestDynamicBackend6.so";
34 static std::string g_TestInvalidTestDynamicBackend7FileName = "libInvalidTestDynamicBackend7.so";
35
36 static std::string g_TestValidBackend2FileName              = "Arm_TestValid2_backend.so";
37 static std::string g_TestValidBackend3FileName              = "Arm_TestValid3_backend.so";
38 static std::string g_TestValidBackend4FileName              = "Arm_TestValid4_backend.so";
39 static std::string g_TestInvalidBackend8FileName            = "Arm_TestInvalid8_backend.so";
40 static std::string g_TestInvalidBackend9FileName            = "Arm_TestInvalid9_backend.so";
41
42 static std::string g_TestDynamicBackendsFileParsingSubDir1  = "backendsTestPath1/";
43 static std::string g_TestDynamicBackendsFileParsingSubDir2  = "backendsTestPath2/";
44 static std::string g_TestDynamicBackendsFileParsingSubDir3  = "backendsTestPath3/";
45 static std::string g_TestDynamicBackendsFileParsingSubDir4  = "backendsTestPath4/";
46 static std::string g_TestDynamicBackendsFileParsingSubDir5  = "backendsTestPath5/";
47 static std::string g_TestDynamicBackendsFileParsingSubDir6  = "backendsTestPath6/";
48 static std::string g_TestDynamicBackendsFileParsingSubDir7  = "backendsTestPath7/";
49 static std::string g_TestDynamicBackendsFileParsingSubDir8  = "backendsTestPath8/";
50
51 std::string GetTestDirectoryBasePath()
52 {
53     using namespace boost::filesystem;
54
55     path programLocation = boost::dll::program_location().parent_path();
56     path sharedObjectPath = programLocation.append(g_TestBaseDir);
57     BOOST_CHECK(exists(sharedObjectPath));
58
59     return sharedObjectPath.string();
60 }
61
62 std::string GetTestSubDirectory(const std::string& subdir)
63 {
64     using namespace boost::filesystem;
65
66     std::string testDynamicBackendsBaseDir = GetTestDirectoryBasePath();
67     path testDynamicBackendsBasePath(testDynamicBackendsBaseDir);
68     path testDynamicBackendsSubDir = testDynamicBackendsBasePath.append(subdir);
69     // Do not check that the sub-directory exists because for testing reasons we may use non-existing paths
70
71     return testDynamicBackendsSubDir.string();
72 }
73
74 std::string GetTestFilePath(const std::string& directory, const std::string& fileName)
75 {
76     using namespace boost::filesystem;
77
78     path directoryPath(directory);
79     path fileNamePath = directoryPath.append(fileName);
80     BOOST_CHECK(exists(fileNamePath));
81
82     return fileNamePath.string();
83 }
84
85 void OpenCloseHandleTestImpl()
86 {
87     using namespace armnn;
88
89     std::string testSubDirectory = GetTestSubDirectory(g_TestSharedObjectSubDir);
90     std::string sharedObjectFilePath = GetTestFilePath(testSubDirectory, g_TestSharedObjectFileName);
91
92     void* sharedObjectHandle = nullptr;
93     BOOST_CHECK_NO_THROW(sharedObjectHandle = DynamicBackendUtils::OpenHandle(sharedObjectFilePath));
94     BOOST_TEST((sharedObjectHandle != nullptr));
95
96     DynamicBackendUtils::CloseHandle(sharedObjectHandle);
97 }
98
99 void CloseInvalidHandleTestImpl()
100 {
101     using namespace armnn;
102
103     // This calls must silently handle invalid handles and complete successfully (no segfaults, etc.)
104     DynamicBackendUtils::CloseHandle(nullptr);
105 }
106
107 void OpenEmptyFileNameTestImpl()
108 {
109     using namespace armnn;
110
111     void* sharedObjectHandle = nullptr;
112     BOOST_CHECK_THROW(sharedObjectHandle = DynamicBackendUtils::OpenHandle(""), RuntimeException);
113     BOOST_TEST((sharedObjectHandle == nullptr));
114 }
115
116 void OpenNotExistingFileTestImpl()
117 {
118     using namespace armnn;
119
120     void* sharedObjectHandle = nullptr;
121     BOOST_CHECK_THROW(sharedObjectHandle = DynamicBackendUtils::OpenHandle("NotExistingFileName"), RuntimeException);
122     BOOST_TEST((sharedObjectHandle == nullptr));
123 }
124
125 void OpenNotSharedObjectTestImpl()
126 {
127     using namespace armnn;
128
129     std::string testSubDirectory = GetTestSubDirectory(g_TestSharedObjectSubDir);
130     std::string notSharedObjectFilePath = GetTestFilePath(testSubDirectory, g_TestNoSharedObjectFileName);
131
132     void* sharedObjectHandle = nullptr;
133     BOOST_CHECK_THROW(sharedObjectHandle = DynamicBackendUtils::OpenHandle(notSharedObjectFilePath), RuntimeException);
134     BOOST_TEST((sharedObjectHandle == nullptr));
135 }
136
137 void GetValidEntryPointTestImpl()
138 {
139     using namespace armnn;
140
141     std::string testSubDirectory = GetTestSubDirectory(g_TestSharedObjectSubDir);
142     std::string sharedObjectFilePath = GetTestFilePath(testSubDirectory, g_TestSharedObjectFileName);
143
144     void* sharedObjectHandle = nullptr;
145     BOOST_CHECK_NO_THROW(sharedObjectHandle = DynamicBackendUtils::OpenHandle(sharedObjectFilePath));
146     BOOST_TEST((sharedObjectHandle != nullptr));
147
148     using TestFunctionType = int(*)(int);
149     TestFunctionType testFunctionPointer = nullptr;
150     BOOST_CHECK_NO_THROW(testFunctionPointer = DynamicBackendUtils::GetEntryPoint<TestFunctionType>(sharedObjectHandle,
151                                                                                                     "TestFunction1"));
152     BOOST_TEST((testFunctionPointer != nullptr));
153     BOOST_TEST(testFunctionPointer(7) == 7);
154
155     DynamicBackendUtils::CloseHandle(sharedObjectHandle);
156 }
157
158 void GetNameMangledEntryPointTestImpl()
159 {
160     using namespace armnn;
161
162     std::string testSubDirectory = GetTestSubDirectory(g_TestSharedObjectSubDir);
163     std::string sharedObjectFilePath = GetTestFilePath(testSubDirectory, g_TestSharedObjectFileName);
164
165     void* sharedObjectHandle = nullptr;
166     BOOST_CHECK_NO_THROW(sharedObjectHandle = DynamicBackendUtils::OpenHandle(sharedObjectFilePath));
167     BOOST_TEST((sharedObjectHandle != nullptr));
168
169     using TestFunctionType = int(*)(int);
170     TestFunctionType testFunctionPointer = nullptr;
171     BOOST_CHECK_THROW(testFunctionPointer = DynamicBackendUtils::GetEntryPoint<TestFunctionType>(sharedObjectHandle,
172                                                                                                  "TestFunction2"),
173                       RuntimeException);
174     BOOST_TEST((testFunctionPointer == nullptr));
175
176     DynamicBackendUtils::CloseHandle(sharedObjectHandle);
177 }
178
179 void GetNoExternEntryPointTestImpl()
180 {
181     using namespace armnn;
182
183     std::string testSubDirectory = GetTestSubDirectory(g_TestSharedObjectSubDir);
184     std::string sharedObjectFilePath = GetTestFilePath(testSubDirectory, g_TestSharedObjectFileName);
185
186     void* sharedObjectHandle = nullptr;
187     BOOST_CHECK_NO_THROW(sharedObjectHandle = DynamicBackendUtils::OpenHandle(sharedObjectFilePath));
188     BOOST_TEST((sharedObjectHandle != nullptr));
189
190     using TestFunctionType = int(*)(int);
191     TestFunctionType testFunctionPointer = nullptr;
192     BOOST_CHECK_THROW(testFunctionPointer = DynamicBackendUtils::GetEntryPoint<TestFunctionType>(sharedObjectHandle,
193                                                                                                  "TestFunction3"),
194                       RuntimeException);
195     BOOST_TEST((testFunctionPointer == nullptr));
196
197     DynamicBackendUtils::CloseHandle(sharedObjectHandle);
198 }
199
200 void GetNotExistingEntryPointTestImpl()
201 {
202     using namespace armnn;
203
204     std::string testSubDirectory = GetTestSubDirectory(g_TestSharedObjectSubDir);
205     std::string sharedObjectFilePath = GetTestFilePath(testSubDirectory, g_TestSharedObjectFileName);
206
207     void* sharedObjectHandle = nullptr;
208     BOOST_CHECK_NO_THROW(sharedObjectHandle = DynamicBackendUtils::OpenHandle(sharedObjectFilePath));
209     BOOST_TEST((sharedObjectHandle != nullptr));
210
211     using TestFunctionType = int(*)(int);
212     TestFunctionType testFunctionPointer = nullptr;
213     BOOST_CHECK_THROW(testFunctionPointer = DynamicBackendUtils::GetEntryPoint<TestFunctionType>(sharedObjectHandle,
214                                                                                                  "TestFunction4"),
215                       RuntimeException);
216     BOOST_TEST((testFunctionPointer == nullptr));
217
218     DynamicBackendUtils::CloseHandle(sharedObjectHandle);
219 }
220
221 void BackendVersioningTestImpl()
222 {
223     using namespace armnn;
224
225     class TestDynamicBackendUtils : public DynamicBackendUtils
226     {
227     public:
228         static bool IsBackendCompatibleTest(const BackendVersion& backendApiVersion,
229                                             const BackendVersion& backendVersion)
230         {
231             return IsBackendCompatibleImpl(backendApiVersion, backendVersion);
232         }
233     };
234
235     // The backend API version used for the tests
236     BackendVersion backendApiVersion{ 2, 4 };
237
238     // Same backend and backend API versions are compatible with the backend API
239     BackendVersion sameBackendVersion{ 2, 4 };
240     BOOST_TEST(sameBackendVersion == backendApiVersion);
241     BOOST_TEST(sameBackendVersion <= backendApiVersion);
242     BOOST_TEST(TestDynamicBackendUtils::IsBackendCompatibleTest(backendApiVersion, sameBackendVersion) == true);
243
244     // Backend versions that differ from the backend API version by major revision are not compatible
245     // with the backend API
246     BackendVersion laterMajorBackendVersion{ 3, 4 };
247     BOOST_TEST(!(laterMajorBackendVersion == backendApiVersion));
248     BOOST_TEST(!(laterMajorBackendVersion <= backendApiVersion));
249     BOOST_TEST(TestDynamicBackendUtils::IsBackendCompatibleTest(backendApiVersion, laterMajorBackendVersion) == false);
250
251     BackendVersion earlierMajorBackendVersion{ 1, 4 };
252     BOOST_TEST(!(earlierMajorBackendVersion == backendApiVersion));
253     BOOST_TEST(earlierMajorBackendVersion <= backendApiVersion);
254     BOOST_TEST(TestDynamicBackendUtils::IsBackendCompatibleTest(backendApiVersion,
255                                                                 earlierMajorBackendVersion) == false);
256
257     // Backend versions with the same major revision but later minor revision than
258     // the backend API version are not compatible with the backend API
259     BackendVersion laterMinorBackendVersion{ 2, 5 };
260     BOOST_TEST(!(laterMinorBackendVersion == backendApiVersion));
261     BOOST_TEST(!(laterMinorBackendVersion <= backendApiVersion));
262     BOOST_TEST(TestDynamicBackendUtils::IsBackendCompatibleTest(backendApiVersion, laterMinorBackendVersion) == false);
263
264     // Backend versions with the same major revision but earlier minor revision than
265     // the backend API version are compatible with the backend API
266     BackendVersion earlierMinorBackendVersion{ 2, 3 };
267     BOOST_TEST(!(earlierMinorBackendVersion == backendApiVersion));
268     BOOST_TEST(earlierMinorBackendVersion <= backendApiVersion);
269     BOOST_TEST(TestDynamicBackendUtils::IsBackendCompatibleTest(backendApiVersion, earlierMinorBackendVersion) == true);
270 }
271
272 void CreateValidDynamicBackendObjectTestImpl()
273 {
274     // Valid shared object handle
275     // Correct name mangling
276     // Correct interface
277     // Correct backend implementation
278
279     using namespace armnn;
280
281     std::string testSubDirectory = GetTestSubDirectory(g_TestDynamicBackendSubDir);
282     std::string sharedObjectFilePath = GetTestFilePath(testSubDirectory, g_TestValidTestDynamicBackendFileName);
283
284     void* sharedObjectHandle = nullptr;
285     BOOST_CHECK_NO_THROW(sharedObjectHandle = DynamicBackendUtils::OpenHandle(sharedObjectFilePath));
286     BOOST_TEST((sharedObjectHandle != nullptr));
287
288     DynamicBackendPtr dynamicBackend;
289     BOOST_CHECK_NO_THROW(dynamicBackend.reset(new DynamicBackend(sharedObjectHandle)));
290     BOOST_TEST((dynamicBackend != nullptr));
291
292     BackendId dynamicBackendId;
293     BOOST_CHECK_NO_THROW(dynamicBackendId = dynamicBackend->GetBackendId());
294     BOOST_TEST((dynamicBackendId == "ValidTestDynamicBackend"));
295
296     BackendVersion dynamicBackendVersion;
297     BOOST_CHECK_NO_THROW(dynamicBackendVersion = dynamicBackend->GetBackendVersion());
298     BOOST_TEST((dynamicBackendVersion == IBackendInternal::GetApiVersion()));
299
300     IBackendInternalUniquePtr dynamicBackendInstance;
301     BOOST_CHECK_NO_THROW(dynamicBackendInstance = dynamicBackend->GetBackend());
302     BOOST_TEST((dynamicBackendInstance != nullptr));
303
304     BOOST_TEST((dynamicBackendInstance->GetId() == "ValidTestDynamicBackend"));
305 }
306
307 void CreateDynamicBackendObjectInvalidHandleTestImpl()
308 {
309     // Invalid (null) shared object handle
310
311     using namespace armnn;
312
313     void* sharedObjectHandle = nullptr;
314     DynamicBackendPtr dynamicBackend;
315     BOOST_CHECK_THROW(dynamicBackend.reset(new DynamicBackend(sharedObjectHandle)), InvalidArgumentException);
316     BOOST_TEST((dynamicBackend == nullptr));
317 }
318
319 void CreateDynamicBackendObjectInvalidInterface1TestImpl()
320 {
321     // Valid shared object handle
322     // Wrong (not C-style) name mangling
323
324     using namespace armnn;
325
326     std::string testSubDirectory = GetTestSubDirectory(g_TestDynamicBackendSubDir);
327     std::string sharedObjectFilePath = GetTestFilePath(testSubDirectory, g_TestInvalidTestDynamicBackend1FileName);
328
329     void* sharedObjectHandle = nullptr;
330     BOOST_CHECK_NO_THROW(sharedObjectHandle = DynamicBackendUtils::OpenHandle(sharedObjectFilePath));
331     BOOST_TEST((sharedObjectHandle != nullptr));
332
333     DynamicBackendPtr dynamicBackend;
334     BOOST_CHECK_THROW(dynamicBackend.reset(new DynamicBackend(sharedObjectHandle)), RuntimeException);
335     BOOST_TEST((dynamicBackend == nullptr));
336 }
337
338 void CreateDynamicBackendObjectInvalidInterface2TestImpl()
339 {
340     // Valid shared object handle
341     // Correct name mangling
342     // Wrong interface (missing GetBackendId())
343
344     using namespace armnn;
345
346     std::string testSubDirectory = GetTestSubDirectory(g_TestDynamicBackendSubDir);
347     std::string sharedObjectFilePath = GetTestFilePath(testSubDirectory, g_TestInvalidTestDynamicBackend2FileName);
348
349     void* sharedObjectHandle = nullptr;
350     BOOST_CHECK_NO_THROW(sharedObjectHandle = DynamicBackendUtils::OpenHandle(sharedObjectFilePath));
351     BOOST_TEST((sharedObjectHandle != nullptr));
352
353     DynamicBackendPtr dynamicBackend;
354     BOOST_CHECK_THROW(dynamicBackend.reset(new DynamicBackend(sharedObjectHandle)), RuntimeException);
355     BOOST_TEST((dynamicBackend == nullptr));
356 }
357
358 void CreateDynamicBackendObjectInvalidInterface3TestImpl()
359 {
360     // Valid shared object handle
361     // Correct name mangling
362     // Wrong interface (missing GetVersion())
363
364     using namespace armnn;
365
366     std::string testSubDirectory = GetTestSubDirectory(g_TestDynamicBackendSubDir);
367     std::string sharedObjectFilePath = GetTestFilePath(testSubDirectory, g_TestInvalidTestDynamicBackend3FileName);
368
369     void* sharedObjectHandle = nullptr;
370     BOOST_CHECK_NO_THROW(sharedObjectHandle = DynamicBackendUtils::OpenHandle(sharedObjectFilePath));
371     BOOST_TEST((sharedObjectHandle != nullptr));
372
373     DynamicBackendPtr dynamicBackend;
374     BOOST_CHECK_THROW(dynamicBackend.reset(new DynamicBackend(sharedObjectHandle)), RuntimeException);
375     BOOST_TEST((dynamicBackend == nullptr));
376 }
377
378 void CreateDynamicBackendObjectInvalidInterface4TestImpl()
379 {
380     // Valid shared object handle
381     // Correct name mangling
382     // Wrong interface (missing BackendFactory())
383
384     using namespace armnn;
385
386     std::string testSubDirectory = GetTestSubDirectory(g_TestDynamicBackendSubDir);
387     std::string sharedObjectFilePath = GetTestFilePath(testSubDirectory, g_TestInvalidTestDynamicBackend4FileName);
388
389     void* sharedObjectHandle = nullptr;
390     BOOST_CHECK_NO_THROW(sharedObjectHandle = DynamicBackendUtils::OpenHandle(sharedObjectFilePath));
391     BOOST_TEST((sharedObjectHandle != nullptr));
392
393     DynamicBackendPtr dynamicBackend;
394     BOOST_CHECK_THROW(dynamicBackend.reset(new DynamicBackend(sharedObjectHandle)), RuntimeException);
395     BOOST_TEST((dynamicBackend == nullptr));
396 }
397
398 void CreateDynamicBackendObjectInvalidInterface5TestImpl()
399 {
400     // Valid shared object handle
401     // Correct name mangling
402     // Correct interface
403     // Invalid (null) backend id returned by GetBackendId()
404
405     using namespace armnn;
406
407     std::string testSubDirectory = GetTestSubDirectory(g_TestDynamicBackendSubDir);
408     std::string sharedObjectFilePath = GetTestFilePath(testSubDirectory, g_TestInvalidTestDynamicBackend5FileName);
409
410     void* sharedObjectHandle = nullptr;
411     BOOST_CHECK_NO_THROW(sharedObjectHandle = DynamicBackendUtils::OpenHandle(sharedObjectFilePath));
412     BOOST_TEST((sharedObjectHandle != nullptr));
413
414     DynamicBackendPtr dynamicBackend;
415     BOOST_CHECK_THROW(dynamicBackend.reset(new DynamicBackend(sharedObjectHandle)), RuntimeException);
416     BOOST_TEST((dynamicBackend == nullptr));
417 }
418
419 void CreateDynamicBackendObjectInvalidInterface6TestImpl()
420 {
421     // Valid shared object handle
422     // Correct name mangling
423     // Correct interface
424     // Invalid (null) backend instance returned by BackendFactory()
425
426     using namespace armnn;
427
428     std::string testSubDirectory = GetTestSubDirectory(g_TestDynamicBackendSubDir);
429     std::string sharedObjectFilePath = GetTestFilePath(testSubDirectory, g_TestInvalidTestDynamicBackend6FileName);
430
431     void* sharedObjectHandle = nullptr;
432     BOOST_CHECK_NO_THROW(sharedObjectHandle = DynamicBackendUtils::OpenHandle(sharedObjectFilePath));
433     BOOST_TEST((sharedObjectHandle != nullptr));
434
435     DynamicBackendPtr dynamicBackend;
436     BOOST_CHECK_NO_THROW(dynamicBackend.reset(new DynamicBackend(sharedObjectHandle)));
437     BOOST_TEST((dynamicBackend != nullptr));
438
439     BackendId dynamicBackendId;
440     BOOST_CHECK_NO_THROW(dynamicBackendId = dynamicBackend->GetBackendId());
441     BOOST_TEST((dynamicBackendId == "InvalidTestDynamicBackend"));
442
443     BackendVersion dynamicBackendVersion;
444     BOOST_CHECK_NO_THROW(dynamicBackendVersion = dynamicBackend->GetBackendVersion());
445     BOOST_TEST((dynamicBackendVersion == BackendVersion({ 1, 0 })));
446
447     IBackendInternalUniquePtr dynamicBackendInstance;
448     BOOST_CHECK_THROW(dynamicBackendInstance = dynamicBackend->GetBackend(), RuntimeException);
449     BOOST_TEST((dynamicBackendInstance == nullptr));
450 }
451
452 void CreateDynamicBackendObjectInvalidInterface7TestImpl()
453 {
454     // Valid shared object handle
455     // Correct name mangling
456     // Correct interface
457     // Invalid (incompatible backend API version) backend instance returned by BackendFactory()
458
459     using namespace armnn;
460
461     std::string testSubDirectory = GetTestSubDirectory(g_TestDynamicBackendSubDir);
462     std::string sharedObjectFilePath = GetTestFilePath(testSubDirectory, g_TestInvalidTestDynamicBackend7FileName);
463
464     void* sharedObjectHandle = nullptr;
465     BOOST_CHECK_NO_THROW(sharedObjectHandle = DynamicBackendUtils::OpenHandle(sharedObjectFilePath));
466     BOOST_TEST((sharedObjectHandle != nullptr));
467
468     DynamicBackendPtr dynamicBackend;
469     BOOST_CHECK_THROW(dynamicBackend.reset(new DynamicBackend(sharedObjectHandle)), RuntimeException);
470     BOOST_TEST((dynamicBackend == nullptr));
471 }
472
473 void GetBackendPathsTestImpl()
474 {
475     using namespace armnn;
476     using namespace boost::filesystem;
477
478     // The test covers four directories:
479     // <unit test path>/src/backends/backendsCommon/test/
480     //                                                ├─ backendsTestPath1/   -> exists, contains files
481     //                                                ├─ backendsTestPath2/   -> exists, contains files
482     //                                                ├─ backendsTestPath3/   -> exists, but empty
483     //                                                └─ backendsTestPath4/   -> does not exist
484
485     std::string subDir1 = GetTestSubDirectory(g_TestDynamicBackendsFileParsingSubDir1);
486     std::string subDir2 = GetTestSubDirectory(g_TestDynamicBackendsFileParsingSubDir2);
487     std::string subDir3 = GetTestSubDirectory(g_TestDynamicBackendsFileParsingSubDir3);
488     std::string subDir4 = GetTestSubDirectory(g_TestDynamicBackendsFileParsingSubDir4);
489
490     BOOST_CHECK(exists(subDir1));
491     BOOST_CHECK(exists(subDir2));
492     BOOST_CHECK(exists(subDir3));
493     BOOST_CHECK(!exists(subDir4));
494
495     class TestDynamicBackendUtils : public DynamicBackendUtils
496     {
497     public:
498         static std::vector<std::string> GetBackendPathsImplTest(const std::string& path)
499         {
500             return GetBackendPathsImpl(path);
501         }
502     };
503
504     // No path
505     BOOST_TEST(TestDynamicBackendUtils::GetBackendPathsImplTest("").empty());
506
507     // Malformed path
508     std::string malformedDir(subDir1 + "/" + subDir1);
509     BOOST_TEST(TestDynamicBackendUtils::GetBackendPathsImplTest(malformedDir).size()==0);
510
511     // Single valid path
512     std::vector<std::string> DynamicBackendPaths2 = TestDynamicBackendUtils::GetBackendPathsImplTest(subDir1);
513     BOOST_TEST(DynamicBackendPaths2.size() == 1);
514     BOOST_TEST(DynamicBackendPaths2[0] == subDir1);
515
516     // Multiple equal and valid paths
517     std::string multipleEqualDirs(subDir1 + ":" + subDir1);
518     std::vector<std::string> DynamicBackendPaths3 = TestDynamicBackendUtils::GetBackendPathsImplTest(multipleEqualDirs);
519     BOOST_TEST(DynamicBackendPaths3.size() == 1);
520     BOOST_TEST(DynamicBackendPaths3[0] == subDir1);
521
522     // Multiple empty paths
523     BOOST_TEST(TestDynamicBackendUtils::GetBackendPathsImplTest(":::").empty());
524
525     // Multiple valid paths
526     std::string multipleValidPaths(subDir1 + ":" + subDir2 + ":" + subDir3);
527     std::vector<std::string> DynamicBackendPaths5 =
528         TestDynamicBackendUtils::GetBackendPathsImplTest(multipleValidPaths);
529     BOOST_TEST(DynamicBackendPaths5.size() == 3);
530     BOOST_TEST(DynamicBackendPaths5[0] == subDir1);
531     BOOST_TEST(DynamicBackendPaths5[1] == subDir2);
532     BOOST_TEST(DynamicBackendPaths5[2] == subDir3);
533
534     // Valid among empty paths
535     std::string validAmongEmptyDirs("::" + subDir1 + ":");
536     std::vector<std::string> DynamicBackendPaths6 =
537         TestDynamicBackendUtils::GetBackendPathsImplTest(validAmongEmptyDirs);
538     BOOST_TEST(DynamicBackendPaths6.size() == 1);
539     BOOST_TEST(DynamicBackendPaths6[0] == subDir1);
540
541     // Invalid among empty paths
542     std::string invalidAmongEmptyDirs(":" + subDir4 + "::");
543     BOOST_TEST(TestDynamicBackendUtils::GetBackendPathsImplTest(invalidAmongEmptyDirs).empty());
544
545     // Valid, invalid and empty paths
546     std::string validInvalidEmptyDirs(subDir1 + ":" + subDir4 + ":");
547     std::vector<std::string> DynamicBackendPaths8 =
548         TestDynamicBackendUtils::GetBackendPathsImplTest(validInvalidEmptyDirs);
549     BOOST_TEST(DynamicBackendPaths8.size() == 1);
550     BOOST_TEST(DynamicBackendPaths8[0] == subDir1);
551
552     // Mix of duplicates of valid, invalid and empty paths
553     std::string duplicateValidInvalidEmptyDirs(validInvalidEmptyDirs + ":" + validInvalidEmptyDirs + ":" +
554                                                subDir2 + ":" + subDir2);
555     std::vector<std::string> DynamicBackendPaths9 =
556         TestDynamicBackendUtils::GetBackendPathsImplTest(duplicateValidInvalidEmptyDirs);
557     BOOST_TEST(DynamicBackendPaths9.size() == 2);
558     BOOST_TEST(DynamicBackendPaths9[0] == subDir1);
559     BOOST_TEST(DynamicBackendPaths9[1] == subDir2);
560 }
561
562 void GetBackendPathsOverrideTestImpl()
563 {
564     using namespace armnn;
565     using namespace boost::filesystem;
566
567     std::string subDir1 = GetTestSubDirectory(g_TestDynamicBackendsFileParsingSubDir1);
568     std::string subDir4 = GetTestSubDirectory(g_TestDynamicBackendsFileParsingSubDir4);
569
570     BOOST_CHECK(exists(subDir1));
571     BOOST_CHECK(!exists(subDir4));
572
573     // Override with valid path
574     std::vector<std::string> validResult = DynamicBackendUtils::GetBackendPaths(subDir1);
575     BOOST_TEST(validResult.size() == 1);
576     BOOST_TEST(validResult[0] == subDir1);
577
578     // Override with invalid path
579     std::vector<std::string> invalidResult = DynamicBackendUtils::GetBackendPaths(subDir4);
580     BOOST_TEST(invalidResult.empty());
581 }
582
583 void GetSharedObjectsTestImpl()
584 {
585     using namespace armnn;
586     using namespace boost::filesystem;
587
588     // The test covers four directories:
589     // <unit test path>/src/backends/backendsCommon/test/
590     //                                                ├─ backendsTestPath1/   -> exists, contains files
591     //                                                ├─ backendsTestPath2/   -> exists, contains files
592     //                                                ├─ backendsTestPath3/   -> exists, but empty
593     //                                                └─ backendsTestPath4/   -> does not exist
594     //
595     // The test sub-directory backendsTestPath1/ contains the following test files:
596     //
597     // Arm_GpuAcc_backend.so                                       -> valid (basic backend name)
598     // Arm_GpuAcc_backend.so.1                                     -> valid (single field version number)
599     // Arm_GpuAcc_backend.so.1.2                                   -> valid (multiple field version number)
600     // Arm_GpuAcc_backend.so.1.2.3                                 -> valid (multiple field version number)
601     // Arm_GpuAcc_backend.so.10.1.27                               -> valid (Multiple digit version)
602     // Arm_GpuAcc_backend.so.10.1.33.                              -> not valid (dot not followed by version number)
603     // Arm_GpuAcc_backend.so.3.4..5                                -> not valid (dot not followed by version number)
604     // Arm_GpuAcc_backend.so.1,1.1                                 -> not valid (comma instead of dot in the version)
605     //
606     // Arm123_GpuAcc_backend.so                                    -> valid (digits in vendor name are allowed)
607     // Arm_GpuAcc456_backend.so                                    -> valid (digits in backend id are allowed)
608     // Arm%Co_GpuAcc_backend.so                                    -> not valid (invalid character in vendor name)
609     // Arm_Gpu.Acc_backend.so                                      -> not valid (invalid character in backend id)
610     //
611     // GpuAcc_backend.so                                           -> not valid (missing vendor name)
612     // _GpuAcc_backend.so                                          -> not valid (missing vendor name)
613     // Arm__backend.so                                             -> not valid (missing backend id)
614     // Arm_GpuAcc.so                                               -> not valid (missing "backend" at the end)
615     // __backend.so                                                -> not valid (missing vendor name and backend id)
616     // __.so                                                       -> not valid (missing all fields)
617     //
618     // Arm_GpuAcc_backend                                          -> not valid (missing at least ".so" at the end)
619     // Arm_GpuAcc_backend_v1.2.so                                  -> not valid (extra version info at the end)
620     //
621     // The test sub-directory backendsTestPath1/ contains the following test files:
622     //
623     // Arm_CpuAcc_backend.so                                       -> valid (basic backend name)
624     // Arm_CpuAcc_backend.so.1 -> Arm_CpuAcc_backend.so            -> valid (symlink to valid backend file)
625     // Arm_CpuAcc_backend.so.1.2 -> Arm_CpuAcc_backend.so.1        -> valid (symlink to valid symlink)
626     // Arm_CpuAcc_backend.so.1.2.3 -> Arm_CpuAcc_backend.so.1.2    -> valid (symlink to valid symlink)
627     //
628     // Arm_no_backend.so -> nothing                                -> not valid (symlink resolves to non-existent file)
629     //
630     // Arm_GpuAcc_backend.so                                       -> valid (but duplicated from backendsTestPath1/)
631
632     std::string testDynamicBackendsSubDir1 = GetTestSubDirectory(g_TestDynamicBackendsFileParsingSubDir1);
633     std::string testDynamicBackendsSubDir2 = GetTestSubDirectory(g_TestDynamicBackendsFileParsingSubDir2);
634     std::string testDynamicBackendsSubDir3 = GetTestSubDirectory(g_TestDynamicBackendsFileParsingSubDir3);
635     std::string testDynamicBackendsSubDir4 = GetTestSubDirectory(g_TestDynamicBackendsFileParsingSubDir4);
636     BOOST_CHECK(exists(testDynamicBackendsSubDir1));
637     BOOST_CHECK(exists(testDynamicBackendsSubDir2));
638     BOOST_CHECK(exists(testDynamicBackendsSubDir3));
639     BOOST_CHECK(!exists(testDynamicBackendsSubDir4));
640
641     std::vector<std::string> backendPaths
642     {
643         testDynamicBackendsSubDir1,
644         testDynamicBackendsSubDir2,
645         testDynamicBackendsSubDir3,
646         testDynamicBackendsSubDir4
647     };
648     std::vector<std::string> sharedObjects = DynamicBackendUtils::GetSharedObjects(backendPaths);
649     std::vector<std::string> expectedSharedObjects
650     {
651         testDynamicBackendsSubDir1 + "Arm123_GpuAcc_backend.so",      // Digits in vendor name are allowed
652         testDynamicBackendsSubDir1 + "Arm_GpuAcc456_backend.so",      // Digits in backend id are allowed
653         testDynamicBackendsSubDir1 + "Arm_GpuAcc_backend.so",         // Basic backend name
654         testDynamicBackendsSubDir1 + "Arm_GpuAcc_backend.so.1",       // Single field version number
655         testDynamicBackendsSubDir1 + "Arm_GpuAcc_backend.so.1.2",     // Multiple field version number
656         testDynamicBackendsSubDir1 + "Arm_GpuAcc_backend.so.1.2.3",   // Multiple field version number
657         testDynamicBackendsSubDir1 + "Arm_GpuAcc_backend.so.10.1.27", // Multiple digit version
658         testDynamicBackendsSubDir2 + "Arm_CpuAcc_backend.so",         // Duplicate symlinks removed
659         testDynamicBackendsSubDir2 + "Arm_GpuAcc_backend.so"          // Duplicates on different paths are allowed
660     };
661
662     BOOST_TEST(sharedObjects.size() == expectedSharedObjects.size());
663     BOOST_TEST(sharedObjects[0] == expectedSharedObjects[0]);
664     BOOST_TEST(sharedObjects[1] == expectedSharedObjects[1]);
665     BOOST_TEST(sharedObjects[2] == expectedSharedObjects[2]);
666     BOOST_TEST(sharedObjects[3] == expectedSharedObjects[3]);
667     BOOST_TEST(sharedObjects[4] == expectedSharedObjects[4]);
668     BOOST_TEST(sharedObjects[5] == expectedSharedObjects[5]);
669     BOOST_TEST(sharedObjects[6] == expectedSharedObjects[6]);
670     BOOST_TEST(sharedObjects[7] == expectedSharedObjects[7]);
671     BOOST_TEST(sharedObjects[8] == expectedSharedObjects[8]);
672 }
673
674 void CreateDynamicBackendsTestImpl()
675 {
676     using namespace armnn;
677     using namespace boost::filesystem;
678
679     // The test covers three directories:
680     // <unit test path>/src/backends/backendsCommon/test/
681     //                                                ├─ backendsTestPath5/   -> exists, contains files
682     //                                                ├─ backendsTestPath6/   -> exists, contains files
683     //                                                ├─ backendsTestPath7/   -> exists, but empty
684     //                                                └─ backendsTestPath8/   -> does not exist
685     //
686     // The test sub-directory backendsTestPath5/ contains the following test files:
687     //
688     // Arm_TestValid2_backend.so   -> valid (basic backend name)
689     // Arm_TestValid3_backend.so   -> valid (basic backend name)
690     // Arm_TestInvalid8_backend.so -> not valid (invalid backend id)
691     //
692     // The test sub-directory backendsTestPath6/ contains the following test files:
693     //
694     // Arm_TestValid2_backend.so   -> valid (but duplicated from backendsTestPath5/)
695     // Arm_TestValid4_backend.so   -> valid (it has a different filename,
696     //                                       but it has the same backend id of Arm_TestValid2_backend.so
697     //                                       and the same version)
698     // Arm_TestInvalid9_backend.so -> not valid (it has a different filename,
699     //                                           but it has the same backend id of Arm_TestValid2_backend.so
700     //                                           and a version incompatible with the Backend API)
701
702     std::string testDynamicBackendsSubDir5 = GetTestSubDirectory(g_TestDynamicBackendsFileParsingSubDir5);
703     std::string testDynamicBackendsSubDir6 = GetTestSubDirectory(g_TestDynamicBackendsFileParsingSubDir6);
704     std::string testDynamicBackendsSubDir7 = GetTestSubDirectory(g_TestDynamicBackendsFileParsingSubDir7);
705     std::string testDynamicBackendsSubDir8 = GetTestSubDirectory(g_TestDynamicBackendsFileParsingSubDir8);
706     BOOST_CHECK(exists(testDynamicBackendsSubDir5));
707     BOOST_CHECK(exists(testDynamicBackendsSubDir6));
708     BOOST_CHECK(exists(testDynamicBackendsSubDir7));
709     BOOST_CHECK(!exists(testDynamicBackendsSubDir8));
710
711     std::vector<std::string> backendPaths
712     {
713         testDynamicBackendsSubDir5,
714         testDynamicBackendsSubDir6,
715         testDynamicBackendsSubDir7,
716         testDynamicBackendsSubDir8
717     };
718     std::vector<std::string> sharedObjects = DynamicBackendUtils::GetSharedObjects(backendPaths);
719     std::vector<DynamicBackendPtr> dynamicBackends = DynamicBackendUtils::CreateDynamicBackends(sharedObjects);
720
721     BOOST_TEST(dynamicBackends.size() == 4);
722     BOOST_TEST((dynamicBackends[0] != nullptr));
723     BOOST_TEST((dynamicBackends[1] != nullptr));
724     BOOST_TEST((dynamicBackends[2] != nullptr));
725     BOOST_TEST((dynamicBackends[3] != nullptr));
726
727     // Duplicates are allowed here, they will be skipped later during the backend registration
728     BOOST_TEST((dynamicBackends[0]->GetBackendId() == "TestValid2"));
729     BOOST_TEST((dynamicBackends[1]->GetBackendId() == "TestValid3"));
730     BOOST_TEST((dynamicBackends[2]->GetBackendId() == "TestValid2")); // From duplicate Arm_TestValid2_backend.so
731     BOOST_TEST((dynamicBackends[3]->GetBackendId() == "TestValid2")); // From Arm_TestValid4_backend.so
732 }
733
734 void CreateDynamicBackendsNoPathsTestImpl()
735 {
736     using namespace armnn;
737
738     std::vector<DynamicBackendPtr> dynamicBackends = DynamicBackendUtils::CreateDynamicBackends({});
739
740     BOOST_TEST(dynamicBackends.empty());
741 }
742
743 void CreateDynamicBackendsAllInvalidTestImpl()
744 {
745     using namespace armnn;
746
747     std::vector<std::string> sharedObjects
748     {
749         "InvalidSharedObject1",
750         "InvalidSharedObject2",
751         "InvalidSharedObject3",
752     };
753     std::vector<DynamicBackendPtr> dynamicBackends = DynamicBackendUtils::CreateDynamicBackends(sharedObjects);
754
755     BOOST_TEST(dynamicBackends.empty());
756 }
757
758 void CreateDynamicBackendsMixedTypesTestImpl()
759 {
760     using namespace armnn;
761     using namespace boost::filesystem;
762
763     std::string testDynamicBackendsSubDir5 = GetTestSubDirectory(g_TestDynamicBackendsFileParsingSubDir5);
764     std::string testDynamicBackendsSubDir6 = GetTestSubDirectory(g_TestDynamicBackendsFileParsingSubDir6);
765     BOOST_CHECK(exists(testDynamicBackendsSubDir5));
766     BOOST_CHECK(exists(testDynamicBackendsSubDir6));
767
768     std::string testValidBackend2FilePath = GetTestFilePath(testDynamicBackendsSubDir5,
769                                                             g_TestValidBackend2FileName);
770     std::string testInvalidBackend8FilePath = GetTestFilePath(testDynamicBackendsSubDir5,
771                                                               g_TestInvalidBackend8FileName);
772     std::string testInvalidBackend9FilePath = GetTestFilePath(testDynamicBackendsSubDir6,
773                                                               g_TestInvalidBackend9FileName);
774     BOOST_CHECK(exists(testValidBackend2FilePath));
775     BOOST_CHECK(exists(testInvalidBackend8FilePath));
776     BOOST_CHECK(exists(testInvalidBackend9FilePath));
777
778     std::vector<std::string> sharedObjects
779     {
780         testValidBackend2FilePath,   // Arm_TestValid2_backend.so     -> valid (basic backend name)
781         testInvalidBackend8FilePath, // Arm_TestInvalid8_backend.so   -> not valid (invalid backend id)
782         testInvalidBackend9FilePath, // Arm_TestInvalid9_backend.so   -> not valid (incompatible version)
783         "InvalidSharedObject",       // The file does not exist
784     };
785     std::vector<DynamicBackendPtr> dynamicBackends = DynamicBackendUtils::CreateDynamicBackends(sharedObjects);
786
787     BOOST_TEST(dynamicBackends.size() == 1);
788     BOOST_TEST((dynamicBackends[0] != nullptr));
789     BOOST_TEST((dynamicBackends[0]->GetBackendId() == "TestValid2"));
790 }