IVGCVSW-3555 Add unit tests for the dynamic backend utility functions

 * Added a test library to exercise the utility functions that
   handle the shared objects

Signed-off-by: Matteo Martincigh <matteo.martincigh@arm.com>
Change-Id: Ic8095febca2a46050831eb42f55a714f3ae3bfe3
diff --git a/src/backends/backendsCommon/test/CMakeLists.txt b/src/backends/backendsCommon/test/CMakeLists.txt
index 3ddaaaf..4131b9e 100644
--- a/src/backends/backendsCommon/test/CMakeLists.txt
+++ b/src/backends/backendsCommon/test/CMakeLists.txt
@@ -64,3 +64,14 @@
 target_include_directories(armnnBackendsCommonUnitTests PRIVATE ${PROJECT_SOURCE_DIR}/src/armnn)
 target_include_directories(armnnBackendsCommonUnitTests PRIVATE ${PROJECT_SOURCE_DIR}/src/armnnUtils)
 target_include_directories(armnnBackendsCommonUnitTests PRIVATE ${PROJECT_SOURCE_DIR}/src/backends)
+
+# Dummy shared object for testing.
+# This is a simple library used to test the utility functions that will be used to handle the shared objects.
+
+list(APPEND armnnTestSharedObject_sources
+    TestSharedObject.cpp
+    TestSharedObject.hpp
+)
+
+add_library_ex(armnnTestSharedObject SHARED ${armnnTestSharedObject_sources})
+file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/libarmnnNoSharedObject.txt "This is not a shared object")
diff --git a/src/backends/backendsCommon/test/DynamicBackendTests.cpp b/src/backends/backendsCommon/test/DynamicBackendTests.cpp
index 5104d06..30622b6 100644
--- a/src/backends/backendsCommon/test/DynamicBackendTests.cpp
+++ b/src/backends/backendsCommon/test/DynamicBackendTests.cpp
@@ -7,6 +7,16 @@
 
 BOOST_AUTO_TEST_SUITE(DynamicBackendTests)
 
+ARMNN_SIMPLE_TEST_CASE(OpenCloseHandle, OpenCloseHandleTestImpl);
+ARMNN_SIMPLE_TEST_CASE(CloseInvalidHandle, CloseInvalidHandleTestImpl);
+ARMNN_SIMPLE_TEST_CASE(OpenEmptyFileName, OpenEmptyFileNameTestImpl);
+ARMNN_SIMPLE_TEST_CASE(OpenNotExistingFile, OpenNotExistingFileTestImpl);
+ARMNN_SIMPLE_TEST_CASE(OpenNotSharedObjectFile, OpenNotSharedObjectTestImpl);
+ARMNN_SIMPLE_TEST_CASE(GetValidEntryPoint, GetValidEntryPointTestImpl);
+ARMNN_SIMPLE_TEST_CASE(GetNameMangledEntryPoint, GetNameMangledEntryPointTestImpl);
+ARMNN_SIMPLE_TEST_CASE(GetNoExternEntryPoint, GetNoExternEntryPointTestImpl);
+ARMNN_SIMPLE_TEST_CASE(GetNotExistingEntryPoint, GetNotExistingEntryPointTestImpl);
+
 ARMNN_SIMPLE_TEST_CASE(BackendVersioning, BackendVersioningTestImpl);
 
 BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/backends/backendsCommon/test/DynamicBackendTests.hpp b/src/backends/backendsCommon/test/DynamicBackendTests.hpp
index 3b0c95b..9835113 100644
--- a/src/backends/backendsCommon/test/DynamicBackendTests.hpp
+++ b/src/backends/backendsCommon/test/DynamicBackendTests.hpp
@@ -9,37 +9,187 @@
 
 #include <test/UnitTests.hpp>
 
+#include <string>
+
 #include <boost/test/unit_test.hpp>
+#include <boost/filesystem.hpp>
+
+static std::string g_TestSharedObjectSubDir = "src/backends/backendsCommon/test/";
+static std::string g_TestSharedObjectFileName = "libarmnnTestSharedObject.so";
+
+std::string GetTestFilePath(const std::string& fileName)
+{
+    using namespace boost::filesystem;
+
+    path currentPath(current_path());
+    path sharedObjectPath = currentPath.append(g_TestSharedObjectSubDir);
+    path sharedObjectFile = sharedObjectPath.append(fileName);
+    BOOST_TEST(exists(sharedObjectFile));
+
+    return sharedObjectFile.string();
+}
+
+void OpenCloseHandleTestImpl()
+{
+    using namespace armnn;
+
+    std::string sharedObjectFilePath = GetTestFilePath(g_TestSharedObjectFileName);
+
+    void* sharedObjectHandle = nullptr;
+    BOOST_CHECK_NO_THROW(sharedObjectHandle = DynamicBackendUtils::OpenHandle(sharedObjectFilePath));
+    BOOST_TEST((sharedObjectHandle != nullptr));
+
+    DynamicBackendUtils::CloseHandle(sharedObjectHandle);
+}
+
+void CloseInvalidHandleTestImpl()
+{
+    using namespace armnn;
+
+    // This calls must silently handle invalid handles and complete successfully (no segfaults, etc.)
+    DynamicBackendUtils::CloseHandle(nullptr);
+}
+
+void OpenEmptyFileNameTestImpl()
+{
+    using namespace armnn;
+
+    void* sharedObjectHandle = nullptr;
+    BOOST_CHECK_THROW(sharedObjectHandle = DynamicBackendUtils::OpenHandle(""), RuntimeException);
+    BOOST_TEST((sharedObjectHandle == nullptr));
+}
+
+void OpenNotExistingFileTestImpl()
+{
+    using namespace armnn;
+
+    void* sharedObjectHandle = nullptr;
+    BOOST_CHECK_THROW(sharedObjectHandle = DynamicBackendUtils::OpenHandle("NotExistingFileName"), RuntimeException);
+    BOOST_TEST((sharedObjectHandle == nullptr));
+}
+
+void OpenNotSharedObjectTestImpl()
+{
+    using namespace armnn;
+
+    std::string notSharedObjectFilePath = GetTestFilePath("libarmnnNoSharedObject.txt");
+
+    void* sharedObjectHandle = nullptr;
+    BOOST_CHECK_THROW(sharedObjectHandle = DynamicBackendUtils::OpenHandle(notSharedObjectFilePath), RuntimeException);
+    BOOST_TEST((sharedObjectHandle == nullptr));
+}
+
+void GetValidEntryPointTestImpl()
+{
+    using namespace armnn;
+
+    std::string sharedObjectFilePath = GetTestFilePath(g_TestSharedObjectFileName);
+
+    void* sharedObjectHandle = nullptr;
+    BOOST_CHECK_NO_THROW(sharedObjectHandle = DynamicBackendUtils::OpenHandle(sharedObjectFilePath));
+    BOOST_TEST((sharedObjectHandle != nullptr));
+
+    using TestFunctionType = int(*)(int);
+    TestFunctionType testFunctionPointer = nullptr;
+    BOOST_CHECK_NO_THROW(testFunctionPointer = DynamicBackendUtils::GetEntryPoint<TestFunctionType>(sharedObjectHandle,
+                                                                                                    "TestFunction1"));
+    BOOST_TEST((testFunctionPointer != nullptr));
+    BOOST_TEST(testFunctionPointer(7) == 7);
+
+    DynamicBackendUtils::CloseHandle(sharedObjectHandle);
+}
+
+void GetNameMangledEntryPointTestImpl()
+{
+    using namespace armnn;
+
+    std::string sharedObjectFilePath = GetTestFilePath(g_TestSharedObjectFileName);
+
+    void* sharedObjectHandle = nullptr;
+    BOOST_CHECK_NO_THROW(sharedObjectHandle = DynamicBackendUtils::OpenHandle(sharedObjectFilePath));
+    BOOST_TEST((sharedObjectHandle != nullptr));
+
+    using TestFunctionType = int(*)(int);
+    TestFunctionType testFunctionPointer = nullptr;
+    BOOST_CHECK_THROW(testFunctionPointer = DynamicBackendUtils::GetEntryPoint<TestFunctionType>(sharedObjectHandle,
+                                                                                                 "TestFunction2"),
+                      RuntimeException);
+    BOOST_TEST((testFunctionPointer == nullptr));
+
+    DynamicBackendUtils::CloseHandle(sharedObjectHandle);
+}
+
+void GetNoExternEntryPointTestImpl()
+{
+    using namespace armnn;
+
+    std::string sharedObjectFilePath = GetTestFilePath(g_TestSharedObjectFileName);
+
+    void* sharedObjectHandle = nullptr;
+    BOOST_CHECK_NO_THROW(sharedObjectHandle = DynamicBackendUtils::OpenHandle(sharedObjectFilePath));
+    BOOST_TEST((sharedObjectHandle != nullptr));
+
+    using TestFunctionType = int(*)(int);
+    TestFunctionType testFunctionPointer = nullptr;
+    BOOST_CHECK_THROW(testFunctionPointer = DynamicBackendUtils::GetEntryPoint<TestFunctionType>(sharedObjectHandle,
+                                                                                                 "TestFunction3"),
+                      RuntimeException);
+    BOOST_TEST((testFunctionPointer == nullptr));
+
+    DynamicBackendUtils::CloseHandle(sharedObjectHandle);
+}
+
+void GetNotExistingEntryPointTestImpl()
+{
+    using namespace armnn;
+
+    std::string sharedObjectFilePath = GetTestFilePath(g_TestSharedObjectFileName);
+
+    void* sharedObjectHandle = nullptr;
+    BOOST_CHECK_NO_THROW(sharedObjectHandle = DynamicBackendUtils::OpenHandle(sharedObjectFilePath));
+    BOOST_TEST((sharedObjectHandle != nullptr));
+
+    using TestFunctionType = int(*)(int);
+    TestFunctionType testFunctionPointer = nullptr;
+    BOOST_CHECK_THROW(testFunctionPointer = DynamicBackendUtils::GetEntryPoint<TestFunctionType>(sharedObjectHandle,
+                                                                                                 "TestFunction4"),
+                      RuntimeException);
+    BOOST_TEST((testFunctionPointer == nullptr));
+
+    DynamicBackendUtils::CloseHandle(sharedObjectHandle);
+}
 
 void BackendVersioningTestImpl()
 {
-    class TestDynamicBackendUtils : public armnn::DynamicBackendUtils
+    using namespace armnn;
+
+    class TestDynamicBackendUtils : public DynamicBackendUtils
     {
     public:
-        static bool IsBackendCompatibleTest(const armnn::BackendVersion& backendApiVersion,
-                                            const armnn::BackendVersion& backendVersion)
+        static bool IsBackendCompatibleTest(const BackendVersion& backendApiVersion,
+                                            const BackendVersion& backendVersion)
         {
             return IsBackendCompatibleImpl(backendApiVersion, backendVersion);
         }
     };
 
     // The backend API version used for the tests
-    armnn::BackendVersion backendApiVersion{ 2, 4 };
+    BackendVersion backendApiVersion{ 2, 4 };
 
     // Same backend and backend API versions are compatible with the backend API
-    armnn::BackendVersion sameBackendVersion{ 2, 4 };
+    BackendVersion sameBackendVersion{ 2, 4 };
     BOOST_TEST(sameBackendVersion == backendApiVersion);
     BOOST_TEST(sameBackendVersion <= backendApiVersion);
     BOOST_TEST(TestDynamicBackendUtils::IsBackendCompatibleTest(backendApiVersion, sameBackendVersion) == true);
 
     // Backend versions that differ from the backend API version by major revision are not compatible
     // with the backend API
-    armnn::BackendVersion laterMajorBackendVersion{ 3, 4 };
+    BackendVersion laterMajorBackendVersion{ 3, 4 };
     BOOST_TEST(!(laterMajorBackendVersion == backendApiVersion));
     BOOST_TEST(!(laterMajorBackendVersion <= backendApiVersion));
     BOOST_TEST(TestDynamicBackendUtils::IsBackendCompatibleTest(backendApiVersion, laterMajorBackendVersion) == false);
 
-    armnn::BackendVersion earlierMajorBackendVersion{ 1, 4 };
+    BackendVersion earlierMajorBackendVersion{ 1, 4 };
     BOOST_TEST(!(earlierMajorBackendVersion == backendApiVersion));
     BOOST_TEST(earlierMajorBackendVersion <= backendApiVersion);
     BOOST_TEST(TestDynamicBackendUtils::IsBackendCompatibleTest(backendApiVersion,
@@ -47,14 +197,14 @@
 
     // Backend versions with the same major revision but later minor revision than
     // the backend API version are not compatible with the backend API
-    armnn::BackendVersion laterMinorBackendVersion{ 2, 5 };
+    BackendVersion laterMinorBackendVersion{ 2, 5 };
     BOOST_TEST(!(laterMinorBackendVersion == backendApiVersion));
     BOOST_TEST(!(laterMinorBackendVersion <= backendApiVersion));
     BOOST_TEST(TestDynamicBackendUtils::IsBackendCompatibleTest(backendApiVersion, laterMinorBackendVersion) == false);
 
     // Backend versions with the same major revision but earlier minor revision than
     // the backend API version are compatible with the backend API
-    armnn::BackendVersion earlierMinorBackendVersion{ 2, 3 };
+    BackendVersion earlierMinorBackendVersion{ 2, 3 };
     BOOST_TEST(!(earlierMinorBackendVersion == backendApiVersion));
     BOOST_TEST(earlierMinorBackendVersion <= backendApiVersion);
     BOOST_TEST(TestDynamicBackendUtils::IsBackendCompatibleTest(backendApiVersion, earlierMinorBackendVersion) == true);
diff --git a/src/backends/backendsCommon/test/TestSharedObject.cpp b/src/backends/backendsCommon/test/TestSharedObject.cpp
new file mode 100644
index 0000000..d6b593c
--- /dev/null
+++ b/src/backends/backendsCommon/test/TestSharedObject.cpp
@@ -0,0 +1,21 @@
+//
+// Copyright © 2017 Arm Ltd. All rights reserved.
+// SPDX-License-Identifier: MIT
+//
+
+#include "TestSharedObject.hpp"
+
+int TestFunction1(int i)
+{
+    return i;
+}
+
+int TestFunction2(int i)
+{
+    return i;
+}
+
+int TestFunction3(int i)
+{
+    return i;
+}
diff --git a/src/backends/backendsCommon/test/TestSharedObject.hpp b/src/backends/backendsCommon/test/TestSharedObject.hpp
new file mode 100644
index 0000000..b2c515b
--- /dev/null
+++ b/src/backends/backendsCommon/test/TestSharedObject.hpp
@@ -0,0 +1,20 @@
+//
+// Copyright © 2017 Arm Ltd. All rights reserved.
+// SPDX-License-Identifier: MIT
+//
+
+#pragma once
+
+#include <cstdint>
+
+// No name mangling
+extern "C"
+{
+int TestFunction1(int i);
+}
+
+// C++ name mangling
+extern int TestFunction2(int i);
+
+// No external linkage
+int TestFunction3(int i);