IVGCVSW-3599 Create the GetSharedObjects method in DynamicBackendUtils
[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_TestDynamicBackendsFileParsingSubDir1  = "backendsTestPath1/";
37 static std::string g_TestDynamicBackendsFileParsingSubDir2  = "backendsTestPath2/";
38 static std::string g_TestDynamicBackendsFileParsingSubDir3  = "backendsTestPath3/";
39 static std::string g_TestDynamicBackendsFileParsingSubDir4  = "backendsTestPath4/";
40
41 std::string GetTestDirectoryBasePath()
42 {
43     using namespace boost::filesystem;
44
45     path programLocation = boost::dll::program_location().parent_path();
46     path sharedObjectPath = programLocation.append(g_TestBaseDir);
47     BOOST_CHECK(exists(sharedObjectPath));
48
49     return sharedObjectPath.string();
50 }
51
52 std::string GetTestSubDirectory(const std::string& subdir)
53 {
54     using namespace boost::filesystem;
55
56     std::string testDynamicBackendsBaseDir = GetTestDirectoryBasePath();
57     path testDynamicBackendsBasePath(testDynamicBackendsBaseDir);
58     path testDynamicBackendsSubDir = testDynamicBackendsBasePath.append(subdir);
59     // Do not check that the sub-directory exists because for testing reasons we may use non-existing paths
60
61     return testDynamicBackendsSubDir.string();
62 }
63
64 std::string GetTestFilePath(const std::string& directory, const std::string& fileName)
65 {
66     using namespace boost::filesystem;
67
68     path directoryPath(directory);
69     path fileNamePath = directoryPath.append(fileName);
70     BOOST_CHECK(exists(fileNamePath));
71
72     return fileNamePath.string();
73 }
74
75 void OpenCloseHandleTestImpl()
76 {
77     using namespace armnn;
78
79     std::string testSubDirectory = GetTestSubDirectory(g_TestSharedObjectSubDir);
80     std::string sharedObjectFilePath = GetTestFilePath(testSubDirectory, g_TestSharedObjectFileName);
81
82     void* sharedObjectHandle = nullptr;
83     BOOST_CHECK_NO_THROW(sharedObjectHandle = DynamicBackendUtils::OpenHandle(sharedObjectFilePath));
84     BOOST_TEST((sharedObjectHandle != nullptr));
85
86     DynamicBackendUtils::CloseHandle(sharedObjectHandle);
87 }
88
89 void CloseInvalidHandleTestImpl()
90 {
91     using namespace armnn;
92
93     // This calls must silently handle invalid handles and complete successfully (no segfaults, etc.)
94     DynamicBackendUtils::CloseHandle(nullptr);
95 }
96
97 void OpenEmptyFileNameTestImpl()
98 {
99     using namespace armnn;
100
101     void* sharedObjectHandle = nullptr;
102     BOOST_CHECK_THROW(sharedObjectHandle = DynamicBackendUtils::OpenHandle(""), RuntimeException);
103     BOOST_TEST((sharedObjectHandle == nullptr));
104 }
105
106 void OpenNotExistingFileTestImpl()
107 {
108     using namespace armnn;
109
110     void* sharedObjectHandle = nullptr;
111     BOOST_CHECK_THROW(sharedObjectHandle = DynamicBackendUtils::OpenHandle("NotExistingFileName"), RuntimeException);
112     BOOST_TEST((sharedObjectHandle == nullptr));
113 }
114
115 void OpenNotSharedObjectTestImpl()
116 {
117     using namespace armnn;
118
119     std::string testSubDirectory = GetTestSubDirectory(g_TestSharedObjectSubDir);
120     std::string notSharedObjectFilePath = GetTestFilePath(testSubDirectory, g_TestNoSharedObjectFileName);
121
122     void* sharedObjectHandle = nullptr;
123     BOOST_CHECK_THROW(sharedObjectHandle = DynamicBackendUtils::OpenHandle(notSharedObjectFilePath), RuntimeException);
124     BOOST_TEST((sharedObjectHandle == nullptr));
125 }
126
127 void GetValidEntryPointTestImpl()
128 {
129     using namespace armnn;
130
131     std::string testSubDirectory = GetTestSubDirectory(g_TestSharedObjectSubDir);
132     std::string sharedObjectFilePath = GetTestFilePath(testSubDirectory, g_TestSharedObjectFileName);
133
134     void* sharedObjectHandle = nullptr;
135     BOOST_CHECK_NO_THROW(sharedObjectHandle = DynamicBackendUtils::OpenHandle(sharedObjectFilePath));
136     BOOST_TEST((sharedObjectHandle != nullptr));
137
138     using TestFunctionType = int(*)(int);
139     TestFunctionType testFunctionPointer = nullptr;
140     BOOST_CHECK_NO_THROW(testFunctionPointer = DynamicBackendUtils::GetEntryPoint<TestFunctionType>(sharedObjectHandle,
141                                                                                                     "TestFunction1"));
142     BOOST_TEST((testFunctionPointer != nullptr));
143     BOOST_TEST(testFunctionPointer(7) == 7);
144
145     DynamicBackendUtils::CloseHandle(sharedObjectHandle);
146 }
147
148 void GetNameMangledEntryPointTestImpl()
149 {
150     using namespace armnn;
151
152     std::string testSubDirectory = GetTestSubDirectory(g_TestSharedObjectSubDir);
153     std::string sharedObjectFilePath = GetTestFilePath(testSubDirectory, g_TestSharedObjectFileName);
154
155     void* sharedObjectHandle = nullptr;
156     BOOST_CHECK_NO_THROW(sharedObjectHandle = DynamicBackendUtils::OpenHandle(sharedObjectFilePath));
157     BOOST_TEST((sharedObjectHandle != nullptr));
158
159     using TestFunctionType = int(*)(int);
160     TestFunctionType testFunctionPointer = nullptr;
161     BOOST_CHECK_THROW(testFunctionPointer = DynamicBackendUtils::GetEntryPoint<TestFunctionType>(sharedObjectHandle,
162                                                                                                  "TestFunction2"),
163                       RuntimeException);
164     BOOST_TEST((testFunctionPointer == nullptr));
165
166     DynamicBackendUtils::CloseHandle(sharedObjectHandle);
167 }
168
169 void GetNoExternEntryPointTestImpl()
170 {
171     using namespace armnn;
172
173     std::string testSubDirectory = GetTestSubDirectory(g_TestSharedObjectSubDir);
174     std::string sharedObjectFilePath = GetTestFilePath(testSubDirectory, g_TestSharedObjectFileName);
175
176     void* sharedObjectHandle = nullptr;
177     BOOST_CHECK_NO_THROW(sharedObjectHandle = DynamicBackendUtils::OpenHandle(sharedObjectFilePath));
178     BOOST_TEST((sharedObjectHandle != nullptr));
179
180     using TestFunctionType = int(*)(int);
181     TestFunctionType testFunctionPointer = nullptr;
182     BOOST_CHECK_THROW(testFunctionPointer = DynamicBackendUtils::GetEntryPoint<TestFunctionType>(sharedObjectHandle,
183                                                                                                  "TestFunction3"),
184                       RuntimeException);
185     BOOST_TEST((testFunctionPointer == nullptr));
186
187     DynamicBackendUtils::CloseHandle(sharedObjectHandle);
188 }
189
190 void GetNotExistingEntryPointTestImpl()
191 {
192     using namespace armnn;
193
194     std::string testSubDirectory = GetTestSubDirectory(g_TestSharedObjectSubDir);
195     std::string sharedObjectFilePath = GetTestFilePath(testSubDirectory, g_TestSharedObjectFileName);
196
197     void* sharedObjectHandle = nullptr;
198     BOOST_CHECK_NO_THROW(sharedObjectHandle = DynamicBackendUtils::OpenHandle(sharedObjectFilePath));
199     BOOST_TEST((sharedObjectHandle != nullptr));
200
201     using TestFunctionType = int(*)(int);
202     TestFunctionType testFunctionPointer = nullptr;
203     BOOST_CHECK_THROW(testFunctionPointer = DynamicBackendUtils::GetEntryPoint<TestFunctionType>(sharedObjectHandle,
204                                                                                                  "TestFunction4"),
205                       RuntimeException);
206     BOOST_TEST((testFunctionPointer == nullptr));
207
208     DynamicBackendUtils::CloseHandle(sharedObjectHandle);
209 }
210
211 void BackendVersioningTestImpl()
212 {
213     using namespace armnn;
214
215     class TestDynamicBackendUtils : public DynamicBackendUtils
216     {
217     public:
218         static bool IsBackendCompatibleTest(const BackendVersion& backendApiVersion,
219                                             const BackendVersion& backendVersion)
220         {
221             return IsBackendCompatibleImpl(backendApiVersion, backendVersion);
222         }
223     };
224
225     // The backend API version used for the tests
226     BackendVersion backendApiVersion{ 2, 4 };
227
228     // Same backend and backend API versions are compatible with the backend API
229     BackendVersion sameBackendVersion{ 2, 4 };
230     BOOST_TEST(sameBackendVersion == backendApiVersion);
231     BOOST_TEST(sameBackendVersion <= backendApiVersion);
232     BOOST_TEST(TestDynamicBackendUtils::IsBackendCompatibleTest(backendApiVersion, sameBackendVersion) == true);
233
234     // Backend versions that differ from the backend API version by major revision are not compatible
235     // with the backend API
236     BackendVersion laterMajorBackendVersion{ 3, 4 };
237     BOOST_TEST(!(laterMajorBackendVersion == backendApiVersion));
238     BOOST_TEST(!(laterMajorBackendVersion <= backendApiVersion));
239     BOOST_TEST(TestDynamicBackendUtils::IsBackendCompatibleTest(backendApiVersion, laterMajorBackendVersion) == false);
240
241     BackendVersion earlierMajorBackendVersion{ 1, 4 };
242     BOOST_TEST(!(earlierMajorBackendVersion == backendApiVersion));
243     BOOST_TEST(earlierMajorBackendVersion <= backendApiVersion);
244     BOOST_TEST(TestDynamicBackendUtils::IsBackendCompatibleTest(backendApiVersion,
245                                                                 earlierMajorBackendVersion) == false);
246
247     // Backend versions with the same major revision but later minor revision than
248     // the backend API version are not compatible with the backend API
249     BackendVersion laterMinorBackendVersion{ 2, 5 };
250     BOOST_TEST(!(laterMinorBackendVersion == backendApiVersion));
251     BOOST_TEST(!(laterMinorBackendVersion <= backendApiVersion));
252     BOOST_TEST(TestDynamicBackendUtils::IsBackendCompatibleTest(backendApiVersion, laterMinorBackendVersion) == false);
253
254     // Backend versions with the same major revision but earlier minor revision than
255     // the backend API version are compatible with the backend API
256     BackendVersion earlierMinorBackendVersion{ 2, 3 };
257     BOOST_TEST(!(earlierMinorBackendVersion == backendApiVersion));
258     BOOST_TEST(earlierMinorBackendVersion <= backendApiVersion);
259     BOOST_TEST(TestDynamicBackendUtils::IsBackendCompatibleTest(backendApiVersion, earlierMinorBackendVersion) == true);
260 }
261
262 void CreateValidDynamicBackendObjectTestImpl()
263 {
264     // Valid shared object handle
265     // Correct name mangling
266     // Correct interface
267     // Correct backend implementation
268
269     using namespace armnn;
270
271     std::string testSubDirectory = GetTestSubDirectory(g_TestDynamicBackendSubDir);
272     std::string sharedObjectFilePath = GetTestFilePath(testSubDirectory, g_TestValidTestDynamicBackendFileName);
273
274     void* sharedObjectHandle = nullptr;
275     BOOST_CHECK_NO_THROW(sharedObjectHandle = DynamicBackendUtils::OpenHandle(sharedObjectFilePath));
276     BOOST_TEST((sharedObjectHandle != nullptr));
277
278     std::unique_ptr<DynamicBackend> dynamicBackend;
279     BOOST_CHECK_NO_THROW(dynamicBackend.reset(new DynamicBackend(sharedObjectHandle)));
280     BOOST_TEST((dynamicBackend != nullptr));
281
282     BackendId dynamicBackendId;
283     BOOST_CHECK_NO_THROW(dynamicBackendId = dynamicBackend->GetBackendId());
284     BOOST_TEST((dynamicBackendId == "ValidTestDynamicBackend"));
285
286     BackendVersion dynamicBackendVersion;
287     BOOST_CHECK_NO_THROW(dynamicBackendVersion = dynamicBackend->GetBackendVersion());
288     BOOST_TEST((dynamicBackendVersion == BackendVersion({ 1, 0 })));
289
290     IBackendInternalUniquePtr dynamicBackendInstance;
291     BOOST_CHECK_NO_THROW(dynamicBackendInstance = dynamicBackend->GetBackend());
292     BOOST_TEST((dynamicBackendInstance != nullptr));
293
294     BOOST_TEST((dynamicBackendInstance->GetId() == "ValidTestDynamicBackend"));
295 }
296
297 void CreateDynamicBackendObjectInvalidHandleTestImpl()
298 {
299     // Invalid (null) shared object handle
300
301     using namespace armnn;
302
303     void* sharedObjectHandle = nullptr;
304     std::unique_ptr<DynamicBackend> dynamicBackend;
305     BOOST_CHECK_THROW(dynamicBackend.reset(new DynamicBackend(sharedObjectHandle)), InvalidArgumentException);
306     BOOST_TEST((dynamicBackend == nullptr));
307 }
308
309 void CreateDynamicBackendObjectInvalidInterface1TestImpl()
310 {
311     // Valid shared object handle
312     // Wrong (not C-style) name mangling
313
314     using namespace armnn;
315
316     std::string testSubDirectory = GetTestSubDirectory(g_TestDynamicBackendSubDir);
317     std::string sharedObjectFilePath = GetTestFilePath(testSubDirectory, g_TestInvalidTestDynamicBackend1FileName);
318
319     void* sharedObjectHandle = nullptr;
320     BOOST_CHECK_NO_THROW(sharedObjectHandle = DynamicBackendUtils::OpenHandle(sharedObjectFilePath));
321     BOOST_TEST((sharedObjectHandle != nullptr));
322
323     std::unique_ptr<DynamicBackend> dynamicBackend;
324     BOOST_CHECK_THROW(dynamicBackend.reset(new DynamicBackend(sharedObjectHandle)), RuntimeException);
325     BOOST_TEST((dynamicBackend == nullptr));
326 }
327
328 void CreateDynamicBackendObjectInvalidInterface2TestImpl()
329 {
330     // Valid shared object handle
331     // Correct name mangling
332     // Wrong interface (missing GetBackendId())
333
334     using namespace armnn;
335
336     std::string testSubDirectory = GetTestSubDirectory(g_TestDynamicBackendSubDir);
337     std::string sharedObjectFilePath = GetTestFilePath(testSubDirectory, g_TestInvalidTestDynamicBackend2FileName);
338
339     void* sharedObjectHandle = nullptr;
340     BOOST_CHECK_NO_THROW(sharedObjectHandle = DynamicBackendUtils::OpenHandle(sharedObjectFilePath));
341     BOOST_TEST((sharedObjectHandle != nullptr));
342
343     std::unique_ptr<DynamicBackend> dynamicBackend;
344     BOOST_CHECK_THROW(dynamicBackend.reset(new DynamicBackend(sharedObjectHandle)), RuntimeException);
345     BOOST_TEST((dynamicBackend == nullptr));
346 }
347
348 void CreateDynamicBackendObjectInvalidInterface3TestImpl()
349 {
350     // Valid shared object handle
351     // Correct name mangling
352     // Wrong interface (missing GetVersion())
353
354     using namespace armnn;
355
356     std::string testSubDirectory = GetTestSubDirectory(g_TestDynamicBackendSubDir);
357     std::string sharedObjectFilePath = GetTestFilePath(testSubDirectory, g_TestInvalidTestDynamicBackend3FileName);
358
359     void* sharedObjectHandle = nullptr;
360     BOOST_CHECK_NO_THROW(sharedObjectHandle = DynamicBackendUtils::OpenHandle(sharedObjectFilePath));
361     BOOST_TEST((sharedObjectHandle != nullptr));
362
363     std::unique_ptr<DynamicBackend> dynamicBackend;
364     BOOST_CHECK_THROW(dynamicBackend.reset(new DynamicBackend(sharedObjectHandle)), RuntimeException);
365     BOOST_TEST((dynamicBackend == nullptr));
366 }
367
368 void CreateDynamicBackendObjectInvalidInterface4TestImpl()
369 {
370     // Valid shared object handle
371     // Correct name mangling
372     // Wrong interface (missing BackendFactory())
373
374     using namespace armnn;
375
376     std::string testSubDirectory = GetTestSubDirectory(g_TestDynamicBackendSubDir);
377     std::string sharedObjectFilePath = GetTestFilePath(testSubDirectory, g_TestInvalidTestDynamicBackend4FileName);
378
379     void* sharedObjectHandle = nullptr;
380     BOOST_CHECK_NO_THROW(sharedObjectHandle = DynamicBackendUtils::OpenHandle(sharedObjectFilePath));
381     BOOST_TEST((sharedObjectHandle != nullptr));
382
383     std::unique_ptr<DynamicBackend> dynamicBackend;
384     BOOST_CHECK_THROW(dynamicBackend.reset(new DynamicBackend(sharedObjectHandle)), RuntimeException);
385     BOOST_TEST((dynamicBackend == nullptr));
386 }
387
388 void CreateDynamicBackendObjectInvalidInterface5TestImpl()
389 {
390     // Valid shared object handle
391     // Correct name mangling
392     // Correct interface
393     // Invalid (null) backend id returned by GetBackendId()
394
395     using namespace armnn;
396
397     std::string testSubDirectory = GetTestSubDirectory(g_TestDynamicBackendSubDir);
398     std::string sharedObjectFilePath = GetTestFilePath(testSubDirectory, g_TestInvalidTestDynamicBackend5FileName);
399
400     void* sharedObjectHandle = nullptr;
401     BOOST_CHECK_NO_THROW(sharedObjectHandle = DynamicBackendUtils::OpenHandle(sharedObjectFilePath));
402     BOOST_TEST((sharedObjectHandle != nullptr));
403
404     std::unique_ptr<DynamicBackend> dynamicBackend;
405     BOOST_CHECK_THROW(dynamicBackend.reset(new DynamicBackend(sharedObjectHandle)), RuntimeException);
406     BOOST_TEST((dynamicBackend == nullptr));
407 }
408
409 void CreateDynamicBackendObjectInvalidInterface6TestImpl()
410 {
411     // Valid shared object handle
412     // Correct name mangling
413     // Correct interface
414     // Invalid (null) backend instance returned by BackendFactory()
415
416     using namespace armnn;
417
418     std::string testSubDirectory = GetTestSubDirectory(g_TestDynamicBackendSubDir);
419     std::string sharedObjectFilePath = GetTestFilePath(testSubDirectory, g_TestInvalidTestDynamicBackend6FileName);
420
421     void* sharedObjectHandle = nullptr;
422     BOOST_CHECK_NO_THROW(sharedObjectHandle = DynamicBackendUtils::OpenHandle(sharedObjectFilePath));
423     BOOST_TEST((sharedObjectHandle != nullptr));
424
425     std::unique_ptr<DynamicBackend> dynamicBackend;
426     BOOST_CHECK_NO_THROW(dynamicBackend.reset(new DynamicBackend(sharedObjectHandle)));
427     BOOST_TEST((dynamicBackend != nullptr));
428
429     BackendId dynamicBackendId;
430     BOOST_CHECK_NO_THROW(dynamicBackendId = dynamicBackend->GetBackendId());
431     BOOST_TEST((dynamicBackendId == "InvalidTestDynamicBackend"));
432
433     BackendVersion dynamicBackendVersion;
434     BOOST_CHECK_NO_THROW(dynamicBackendVersion = dynamicBackend->GetBackendVersion());
435     BOOST_TEST((dynamicBackendVersion == BackendVersion({ 1, 0 })));
436
437     IBackendInternalUniquePtr dynamicBackendInstance;
438     BOOST_CHECK_THROW(dynamicBackendInstance = dynamicBackend->GetBackend(), RuntimeException);
439     BOOST_TEST((dynamicBackendInstance == nullptr));
440 }
441
442 void CreateDynamicBackendObjectInvalidInterface7TestImpl()
443 {
444     // Valid shared object handle
445     // Correct name mangling
446     // Correct interface
447     // Invalid (incompatible backend API version) backend instance returned by BackendFactory()
448
449     using namespace armnn;
450
451     std::string testSubDirectory = GetTestSubDirectory(g_TestDynamicBackendSubDir);
452     std::string sharedObjectFilePath = GetTestFilePath(testSubDirectory, g_TestInvalidTestDynamicBackend7FileName);
453
454     void* sharedObjectHandle = nullptr;
455     BOOST_CHECK_NO_THROW(sharedObjectHandle = DynamicBackendUtils::OpenHandle(sharedObjectFilePath));
456     BOOST_TEST((sharedObjectHandle != nullptr));
457
458     std::unique_ptr<DynamicBackend> dynamicBackend;
459     BOOST_CHECK_THROW(dynamicBackend.reset(new DynamicBackend(sharedObjectHandle)), RuntimeException);
460     BOOST_TEST((dynamicBackend == nullptr));
461 }
462
463 void GetBackendPathsTestImpl()
464 {
465     using namespace armnn;
466     using namespace boost::filesystem;
467
468     // The test covers four directories:
469     // <unit test path>/src/backends/backendsCommon/test/
470     //                                                ├─ backendsTestPath1/   -> existing, contains files
471     //                                                ├─ backendsTestPath2/   -> existing, contains files
472     //                                                ├─ backendsTestPath3/   -> existing, but empty
473     //                                                └─ backendsTestPath4/   -> not existing
474
475     std::string subDir1 = GetTestSubDirectory(g_TestDynamicBackendsFileParsingSubDir1);
476     std::string subDir2 = GetTestSubDirectory(g_TestDynamicBackendsFileParsingSubDir2);
477     std::string subDir3 = GetTestSubDirectory(g_TestDynamicBackendsFileParsingSubDir3);
478     std::string subDir4 = GetTestSubDirectory(g_TestDynamicBackendsFileParsingSubDir4);
479
480     BOOST_CHECK(exists(subDir1));
481     BOOST_CHECK(exists(subDir2));
482     BOOST_CHECK(exists(subDir3));
483     BOOST_CHECK(!exists(subDir4));
484
485     class TestDynamicBackendUtils : public DynamicBackendUtils
486     {
487     public:
488         static std::vector<std::string> GetBackendPathsImplTest(const std::string& path)
489         {
490             return GetBackendPathsImpl(path);
491         }
492     };
493
494     // No path
495     BOOST_TEST(TestDynamicBackendUtils::GetBackendPathsImplTest("").empty());
496
497     // Malformed path
498     std::string malformedDir(subDir1 + "/" + subDir1);
499     BOOST_TEST(TestDynamicBackendUtils::GetBackendPathsImplTest(malformedDir).size()==0);
500
501     // Single valid path
502     std::vector<std::string> DynamicBackendPaths2 = TestDynamicBackendUtils::GetBackendPathsImplTest(subDir1);
503     BOOST_TEST(DynamicBackendPaths2.size() == 1);
504     BOOST_TEST(DynamicBackendPaths2[0] == subDir1);
505
506     // Multiple equal and valid paths
507     std::string multipleEqualDirs(subDir1 + ":" + subDir1);
508     std::vector<std::string> DynamicBackendPaths3 = TestDynamicBackendUtils::GetBackendPathsImplTest(multipleEqualDirs);
509     BOOST_TEST(DynamicBackendPaths3.size() == 1);
510     BOOST_TEST(DynamicBackendPaths3[0] == subDir1);
511
512     // Multiple empty paths
513     BOOST_TEST(TestDynamicBackendUtils::GetBackendPathsImplTest(":::").empty());
514
515     // Multiple valid paths
516     std::string multipleValidPaths(subDir1 + ":" + subDir2 + ":" + subDir3);
517     std::vector<std::string> DynamicBackendPaths5 =
518         TestDynamicBackendUtils::GetBackendPathsImplTest(multipleValidPaths);
519     BOOST_TEST(DynamicBackendPaths5.size() == 3);
520     BOOST_TEST(DynamicBackendPaths5[0] == subDir1);
521     BOOST_TEST(DynamicBackendPaths5[1] == subDir2);
522     BOOST_TEST(DynamicBackendPaths5[2] == subDir3);
523
524     // Valid among empty paths
525     std::string validAmongEmptyDirs("::" + subDir1 + ":");
526     std::vector<std::string> DynamicBackendPaths6 =
527         TestDynamicBackendUtils::GetBackendPathsImplTest(validAmongEmptyDirs);
528     BOOST_TEST(DynamicBackendPaths6.size() == 1);
529     BOOST_TEST(DynamicBackendPaths6[0] == subDir1);
530
531     // Invalid among empty paths
532     std::string invalidAmongEmptyDirs(":" + subDir4 + "::");
533     BOOST_TEST(TestDynamicBackendUtils::GetBackendPathsImplTest(invalidAmongEmptyDirs).empty());
534
535     // Valid, invalid and empty paths
536     std::string validInvalidEmptyDirs(subDir1 + ":" + subDir4 + ":");
537     std::vector<std::string> DynamicBackendPaths8 =
538         TestDynamicBackendUtils::GetBackendPathsImplTest(validInvalidEmptyDirs);
539     BOOST_TEST(DynamicBackendPaths8.size() == 1);
540     BOOST_TEST(DynamicBackendPaths8[0] == subDir1);
541
542     // Mix of duplicates of valid, invalid and empty paths
543     std::string duplicateValidInvalidEmptyDirs(validInvalidEmptyDirs + ":" + validInvalidEmptyDirs + ":" +
544                                                subDir2 + ":" + subDir2);
545     std::vector<std::string> DynamicBackendPaths9 =
546         TestDynamicBackendUtils::GetBackendPathsImplTest(duplicateValidInvalidEmptyDirs);
547     BOOST_TEST(DynamicBackendPaths9.size() == 2);
548     BOOST_TEST(DynamicBackendPaths9[0] == subDir1);
549     BOOST_TEST(DynamicBackendPaths9[1] == subDir2);
550 }
551
552 void GetBackendPathsOverrideTestImpl()
553 {
554     using namespace armnn;
555     using namespace boost::filesystem;
556
557     std::string subDir1 = GetTestSubDirectory(g_TestDynamicBackendsFileParsingSubDir1);
558     std::string subDir4 = GetTestSubDirectory(g_TestDynamicBackendsFileParsingSubDir4);
559
560     BOOST_CHECK(exists(subDir1));
561     BOOST_CHECK(!exists(subDir4));
562
563     // Override with valid path
564     std::vector<std::string> validResult = DynamicBackendUtils::GetBackendPaths(subDir1);
565     BOOST_TEST(validResult.size() == 1);
566     BOOST_TEST(validResult[0] == subDir1);
567
568     // Override with invalid path
569     std::vector<std::string> invalidResult = DynamicBackendUtils::GetBackendPaths(subDir4);
570     BOOST_TEST(invalidResult.empty());
571 }
572
573 void GetSharedObjectsTestImpl()
574 {
575     using namespace armnn;
576     using namespace boost::filesystem;
577
578     //
579     // The test sub-directory backendsTestPath1/ contains the following test files:
580     //
581     // Arm_GpuAcc_backend.so                                       -> valid (basic backend name)
582     // Arm_GpuAcc_backend.so.1                                     -> valid (single field version number)
583     // Arm_GpuAcc_backend.so.1.2                                   -> valid (multiple field version number)
584     // Arm_GpuAcc_backend.so.1.2.3                                 -> valid (multiple field version number)
585     // Arm_GpuAcc_backend.so.10.1.27                               -> valid (Multiple digit version)
586     // Arm_GpuAcc_backend.so.10.1.33.                              -> not valid (dot not followed by version number)
587     // Arm_GpuAcc_backend.so.3.4..5                                -> not valid (dot not followed by version number)
588     // Arm_GpuAcc_backend.so.1,1.1                                 -> not valid (comma instead of dot in the version)
589     //
590     // Arm123_GpuAcc_backend.so                                    -> valid (digits in vendor name are allowed)
591     // Arm_GpuAcc456_backend.so                                    -> valid (digits in backend id are allowed)
592     // Arm%Co_GpuAcc_backend.so                                    -> not valid (invalid character in vendor name)
593     // Arm_Gpu.Acc_backend.so                                      -> not valid (invalid character in backend id)
594     //
595     // GpuAcc_backend.so                                           -> not valid (missing vendor name)
596     // _GpuAcc_backend.so                                          -> not valid (missing vendor name)
597     // Arm__backend.so                                             -> not valid (missing backend id)
598     // Arm_GpuAcc.so                                               -> not valid (missing "backend" at the end)
599     // __backend.so                                                -> not valid (missing vendor name and backend id)
600     // __.so                                                       -> not valid (missing all fields)
601     //
602     // Arm_GpuAcc_backend                                          -> not valid (missing at least ".so" at the end)
603     // Arm_GpuAcc_backend_v1.2.so                                  -> not valid (extra version info at the end)
604     //
605     // The test sub-directory backendsTestPath1/ contains the following test files:
606     //
607     // Arm_CpuAcc_backend.so                                       -> valid (basic backend name)
608     // Arm_CpuAcc_backend.so.1 -> Arm_CpuAcc_backend.so            -> valid (symlink to valid backend file)
609     // Arm_CpuAcc_backend.so.1.2 -> Arm_CpuAcc_backend.so.1        -> valid (symlink to valid symlink)
610     // Arm_CpuAcc_backend.so.1.2.3 -> Arm_CpuAcc_backend.so.1.2    -> valid (symlink to valid symlink)
611     //
612     // Arm_no_backend.so -> nothing                                -> not valid (symlink resolves to non-existent file)
613     //
614     // Arm_GpuAcc_backend.so                                       -> valid (but duplicated from backendsTestPath1/)
615
616     std::string testDynamicBackendsSubDir1 = GetTestSubDirectory(g_TestDynamicBackendsFileParsingSubDir1);
617     std::string testDynamicBackendsSubDir2 = GetTestSubDirectory(g_TestDynamicBackendsFileParsingSubDir2);
618     std::string testDynamicBackendsSubDir3 = GetTestSubDirectory(g_TestDynamicBackendsFileParsingSubDir3);
619     std::string testDynamicBackendsSubDir4 = GetTestSubDirectory(g_TestDynamicBackendsFileParsingSubDir4);
620     BOOST_CHECK(exists(testDynamicBackendsSubDir1));
621     BOOST_CHECK(exists(testDynamicBackendsSubDir2));
622     BOOST_CHECK(exists(testDynamicBackendsSubDir3));
623     BOOST_CHECK(!exists(testDynamicBackendsSubDir4));
624
625     std::vector<std::string> backendPaths
626     {
627         testDynamicBackendsSubDir1,
628         testDynamicBackendsSubDir2,
629         testDynamicBackendsSubDir3,
630         testDynamicBackendsSubDir4
631     };
632     std::vector<std::string> sharedObjects = DynamicBackendUtils::GetSharedObjects(backendPaths);
633     std::unordered_set<std::string> expectedSharedObjects
634     {
635         testDynamicBackendsSubDir1 + "Arm_GpuAcc_backend.so",         // Basic backend name
636         testDynamicBackendsSubDir1 + "Arm_GpuAcc_backend.so.1",       // Single field version number
637         testDynamicBackendsSubDir1 + "Arm_GpuAcc_backend.so.1.2",     // Multiple field version number
638         testDynamicBackendsSubDir1 + "Arm_GpuAcc_backend.so.1.2.3",   // Multiple field version number
639         testDynamicBackendsSubDir1 + "Arm_GpuAcc_backend.so.10.1.27", // Multiple digit version
640         testDynamicBackendsSubDir1 + "Arm123_GpuAcc_backend.so",      // Digits in vendor name are allowed
641         testDynamicBackendsSubDir1 + "Arm_GpuAcc456_backend.so",      // Digits in backend id are allowed
642         testDynamicBackendsSubDir2 + "Arm_CpuAcc_backend.so",         // Duplicate symlinks removed
643         testDynamicBackendsSubDir2 + "Arm_GpuAcc_backend.so"          // Duplicates on different paths are allowed
644     };
645
646     BOOST_TEST(sharedObjects.size() == expectedSharedObjects.size());
647     for (const std::string& sharedObject : sharedObjects)
648     {
649         auto it = expectedSharedObjects.find(sharedObject);
650         BOOST_TEST((it != expectedSharedObjects.end()));
651     }
652 }