IVGCVSW-3596 Register the dynamic backends in the BackendRegistry

 * Added getter for the factory function in the DynamicBackend class
 * Added new RegisterDynamicBackends method in utils class
 * Added dynamic backend registration process in the Runtime class
 * Added new dummy dynamic backend objects for testing
 * Added unit tests for dynamic backend registration
 * Added convenience methods to BackendId

Change-Id: I01e147d1d6f01bf56747ad946f73f867af5770c4
Signed-off-by: Matteo Martincigh <matteo.martincigh@arm.com>
diff --git a/src/backends/backendsCommon/test/CMakeLists.txt b/src/backends/backendsCommon/test/CMakeLists.txt
index 6714a20..f517356 100644
--- a/src/backends/backendsCommon/test/CMakeLists.txt
+++ b/src/backends/backendsCommon/test/CMakeLists.txt
@@ -215,6 +215,14 @@
 set_target_properties(Arm_TestValid4_backend PROPERTIES PREFIX "")
 set_target_properties(Arm_TestValid4_backend PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/backendsTestPath6)
 
+add_library_ex(Arm_TestValid5_backend MODULE ${testDynamicBackend_sources})
+target_compile_definitions(Arm_TestValid5_backend PRIVATE -DVALID_TEST_DYNAMIC_BACKEND_5)
+target_include_directories(Arm_TestValid5_backend PRIVATE ${PROJECT_SOURCE_DIR}/src/armnn)
+target_include_directories(Arm_TestValid5_backend PRIVATE ${PROJECT_SOURCE_DIR}/src/backends)
+target_link_libraries(Arm_TestValid5_backend armnn)
+set_target_properties(Arm_TestValid5_backend PROPERTIES PREFIX "")
+set_target_properties(Arm_TestValid5_backend PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/backendsTestPath6)
+
 add_library_ex(Arm_TestInvalid9_backend MODULE ${testDynamicBackend_sources})
 target_compile_definitions(Arm_TestInvalid9_backend PRIVATE -DINVALID_TEST_DYNAMIC_BACKEND_9)
 target_include_directories(Arm_TestInvalid9_backend PRIVATE ${PROJECT_SOURCE_DIR}/src/armnn)
@@ -223,4 +231,20 @@
 set_target_properties(Arm_TestInvalid9_backend PROPERTIES PREFIX "")
 set_target_properties(Arm_TestInvalid9_backend PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/backendsTestPath6)
 
+add_library_ex(Arm_TestInvalid10_backend MODULE ${testDynamicBackend_sources})
+target_compile_definitions(Arm_TestInvalid10_backend PRIVATE -DINVALID_TEST_DYNAMIC_BACKEND_10)
+target_include_directories(Arm_TestInvalid10_backend PRIVATE ${PROJECT_SOURCE_DIR}/src/armnn)
+target_include_directories(Arm_TestInvalid10_backend PRIVATE ${PROJECT_SOURCE_DIR}/src/backends)
+target_link_libraries(Arm_TestInvalid10_backend armnn)
+set_target_properties(Arm_TestInvalid10_backend PROPERTIES PREFIX "")
+set_target_properties(Arm_TestInvalid10_backend PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/backendsTestPath9)
+
+add_library_ex(Arm_TestInvalid11_backend MODULE ${testDynamicBackend_sources})
+target_compile_definitions(Arm_TestInvalid11_backend PRIVATE -DINVALID_TEST_DYNAMIC_BACKEND_11)
+target_include_directories(Arm_TestInvalid11_backend PRIVATE ${PROJECT_SOURCE_DIR}/src/armnn)
+target_include_directories(Arm_TestInvalid11_backend PRIVATE ${PROJECT_SOURCE_DIR}/src/backends)
+target_link_libraries(Arm_TestInvalid11_backend armnn)
+set_target_properties(Arm_TestInvalid11_backend PROPERTIES PREFIX "")
+set_target_properties(Arm_TestInvalid11_backend PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/backendsTestPath9)
+
 file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/backendsTestPath7)
diff --git a/src/backends/backendsCommon/test/DynamicBackendTests.cpp b/src/backends/backendsCommon/test/DynamicBackendTests.cpp
index b5d159a..21ce2db 100644
--- a/src/backends/backendsCommon/test/DynamicBackendTests.cpp
+++ b/src/backends/backendsCommon/test/DynamicBackendTests.cpp
@@ -50,4 +50,9 @@
 ARMNN_SIMPLE_TEST_CASE(CreateDynamicBackendsAllInvalid, CreateDynamicBackendsAllInvalidTestImpl);
 ARMNN_SIMPLE_TEST_CASE(CreateDynamicBackendsMixedTypes, CreateDynamicBackendsMixedTypesTestImpl);
 
+ARMNN_SIMPLE_TEST_CASE(RegisterSingleDynamicBackend, RegisterSingleDynamicBackendTestImpl);
+ARMNN_SIMPLE_TEST_CASE(RegisterMultipleDynamicBackends, RegisterMultipleDynamicBackendsTestImpl);
+ARMNN_SIMPLE_TEST_CASE(RegisterMultipleInvalidDynamicBackends, RegisterMultipleInvalidDynamicBackendsTestImpl);
+ARMNN_SIMPLE_TEST_CASE(RegisterMixedDynamicBackends, RegisterMixedDynamicBackendsTestImpl);
+
 BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/backends/backendsCommon/test/DynamicBackendTests.hpp b/src/backends/backendsCommon/test/DynamicBackendTests.hpp
index e3fbe31..ae922bc 100644
--- a/src/backends/backendsCommon/test/DynamicBackendTests.hpp
+++ b/src/backends/backendsCommon/test/DynamicBackendTests.hpp
@@ -36,17 +36,43 @@
 static std::string g_TestValidBackend2FileName              = "Arm_TestValid2_backend.so";
 static std::string g_TestValidBackend3FileName              = "Arm_TestValid3_backend.so";
 static std::string g_TestValidBackend4FileName              = "Arm_TestValid4_backend.so";
+static std::string g_TestValidBackend5FileName              = "Arm_TestValid5_backend.so";
 static std::string g_TestInvalidBackend8FileName            = "Arm_TestInvalid8_backend.so";
 static std::string g_TestInvalidBackend9FileName            = "Arm_TestInvalid9_backend.so";
+static std::string g_TestInvalidBackend10FileName           = "Arm_TestInvalid10_backend.so";
+static std::string g_TestInvalidBackend11FileName           = "Arm_TestInvalid11_backend.so";
 
-static std::string g_TestDynamicBackendsFileParsingSubDir1  = "backendsTestPath1/";
-static std::string g_TestDynamicBackendsFileParsingSubDir2  = "backendsTestPath2/";
-static std::string g_TestDynamicBackendsFileParsingSubDir3  = "backendsTestPath3/";
-static std::string g_TestDynamicBackendsFileParsingSubDir4  = "backendsTestPath4/";
-static std::string g_TestDynamicBackendsFileParsingSubDir5  = "backendsTestPath5/";
-static std::string g_TestDynamicBackendsFileParsingSubDir6  = "backendsTestPath6/";
-static std::string g_TestDynamicBackendsFileParsingSubDir7  = "backendsTestPath7/";
-static std::string g_TestDynamicBackendsFileParsingSubDir8  = "backendsTestPath8/";
+static std::string g_TestDynamicBackendsSubDir1  = "backendsTestPath1/";
+static std::string g_TestDynamicBackendsSubDir2  = "backendsTestPath2/";
+static std::string g_TestDynamicBackendsSubDir3  = "backendsTestPath3/";
+static std::string g_TestDynamicBackendsSubDir4  = "backendsTestPath4/";
+static std::string g_TestDynamicBackendsSubDir5  = "backendsTestPath5/";
+static std::string g_TestDynamicBackendsSubDir6  = "backendsTestPath6/";
+static std::string g_TestDynamicBackendsSubDir7  = "backendsTestPath7/";
+static std::string g_TestDynamicBackendsSubDir8  = "backendsTestPath8/";
+static std::string g_TestDynamicBackendsSubDir9  = "backendsTestPath9/";
+
+// Wrapper class used for testing
+class TestDynamicBackendUtils : public armnn::DynamicBackendUtils
+{
+public:
+    static bool IsBackendCompatibleTest(const armnn::BackendVersion& backendApiVersion,
+                                        const armnn::BackendVersion& backendVersion)
+    {
+        return IsBackendCompatibleImpl(backendApiVersion, backendVersion);
+    }
+
+    static std::vector<std::string> GetBackendPathsImplTest(const std::string& path)
+    {
+        return GetBackendPathsImpl(path);
+    }
+
+    static void RegisterDynamicBackendsImplTest(armnn::BackendRegistry& backendRegistry,
+                                                const std::vector<armnn::DynamicBackendPtr>& dynamicBackends)
+    {
+        RegisterDynamicBackendsImpl(backendRegistry, dynamicBackends);
+    }
+};
 
 std::string GetTestDirectoryBasePath()
 {
@@ -222,16 +248,6 @@
 {
     using namespace armnn;
 
-    class TestDynamicBackendUtils : public DynamicBackendUtils
-    {
-    public:
-        static bool IsBackendCompatibleTest(const BackendVersion& backendApiVersion,
-                                            const BackendVersion& backendVersion)
-        {
-            return IsBackendCompatibleImpl(backendApiVersion, backendVersion);
-        }
-    };
-
     // The backend API version used for the tests
     BackendVersion backendApiVersion{ 2, 4 };
 
@@ -297,11 +313,20 @@
     BOOST_CHECK_NO_THROW(dynamicBackendVersion = dynamicBackend->GetBackendVersion());
     BOOST_TEST((dynamicBackendVersion == IBackendInternal::GetApiVersion()));
 
-    IBackendInternalUniquePtr dynamicBackendInstance;
-    BOOST_CHECK_NO_THROW(dynamicBackendInstance = dynamicBackend->GetBackend());
-    BOOST_TEST((dynamicBackendInstance != nullptr));
+    IBackendInternalUniquePtr dynamicBackendInstance1;
+    BOOST_CHECK_NO_THROW(dynamicBackendInstance1 = dynamicBackend->GetBackend());
+    BOOST_TEST((dynamicBackendInstance1 != nullptr));
 
-    BOOST_TEST((dynamicBackendInstance->GetId() == "ValidTestDynamicBackend"));
+    BackendRegistry::FactoryFunction dynamicBackendFactoryFunction = nullptr;
+    BOOST_CHECK_NO_THROW(dynamicBackendFactoryFunction = dynamicBackend->GetFactoryFunction());
+    BOOST_TEST((dynamicBackendFactoryFunction != nullptr));
+
+    IBackendInternalUniquePtr dynamicBackendInstance2;
+    BOOST_CHECK_NO_THROW(dynamicBackendInstance2 = dynamicBackendFactoryFunction());
+    BOOST_TEST((dynamicBackendInstance2 != nullptr));
+
+    BOOST_TEST((dynamicBackendInstance1->GetId() == "ValidTestDynamicBackend"));
+    BOOST_TEST((dynamicBackendInstance2->GetId() == "ValidTestDynamicBackend"));
 }
 
 void CreateDynamicBackendObjectInvalidHandleTestImpl()
@@ -444,9 +469,17 @@
     BOOST_CHECK_NO_THROW(dynamicBackendVersion = dynamicBackend->GetBackendVersion());
     BOOST_TEST((dynamicBackendVersion == BackendVersion({ 1, 0 })));
 
-    IBackendInternalUniquePtr dynamicBackendInstance;
-    BOOST_CHECK_THROW(dynamicBackendInstance = dynamicBackend->GetBackend(), RuntimeException);
-    BOOST_TEST((dynamicBackendInstance == nullptr));
+    IBackendInternalUniquePtr dynamicBackendInstance1;
+    BOOST_CHECK_THROW(dynamicBackendInstance1 = dynamicBackend->GetBackend(), RuntimeException);
+    BOOST_TEST((dynamicBackendInstance1 == nullptr));
+
+    BackendRegistry::FactoryFunction dynamicBackendFactoryFunction = nullptr;
+    BOOST_CHECK_NO_THROW(dynamicBackendFactoryFunction = dynamicBackend->GetFactoryFunction());
+    BOOST_TEST((dynamicBackendFactoryFunction != nullptr));
+
+    IBackendInternalUniquePtr dynamicBackendInstance2;
+    BOOST_CHECK_THROW(dynamicBackendInstance2 = dynamicBackendFactoryFunction(), RuntimeException);
+    BOOST_TEST((dynamicBackendInstance2 == nullptr));
 }
 
 void CreateDynamicBackendObjectInvalidInterface7TestImpl()
@@ -482,25 +515,16 @@
     //                                                ├─ backendsTestPath3/   -> exists, but empty
     //                                                └─ backendsTestPath4/   -> does not exist
 
-    std::string subDir1 = GetTestSubDirectory(g_TestDynamicBackendsFileParsingSubDir1);
-    std::string subDir2 = GetTestSubDirectory(g_TestDynamicBackendsFileParsingSubDir2);
-    std::string subDir3 = GetTestSubDirectory(g_TestDynamicBackendsFileParsingSubDir3);
-    std::string subDir4 = GetTestSubDirectory(g_TestDynamicBackendsFileParsingSubDir4);
+    std::string subDir1 = GetTestSubDirectory(g_TestDynamicBackendsSubDir1);
+    std::string subDir2 = GetTestSubDirectory(g_TestDynamicBackendsSubDir2);
+    std::string subDir3 = GetTestSubDirectory(g_TestDynamicBackendsSubDir3);
+    std::string subDir4 = GetTestSubDirectory(g_TestDynamicBackendsSubDir4);
 
     BOOST_CHECK(exists(subDir1));
     BOOST_CHECK(exists(subDir2));
     BOOST_CHECK(exists(subDir3));
     BOOST_CHECK(!exists(subDir4));
 
-    class TestDynamicBackendUtils : public DynamicBackendUtils
-    {
-    public:
-        static std::vector<std::string> GetBackendPathsImplTest(const std::string& path)
-        {
-            return GetBackendPathsImpl(path);
-        }
-    };
-
     // No path
     BOOST_TEST(TestDynamicBackendUtils::GetBackendPathsImplTest("").empty());
 
@@ -564,8 +588,8 @@
     using namespace armnn;
     using namespace boost::filesystem;
 
-    std::string subDir1 = GetTestSubDirectory(g_TestDynamicBackendsFileParsingSubDir1);
-    std::string subDir4 = GetTestSubDirectory(g_TestDynamicBackendsFileParsingSubDir4);
+    std::string subDir1 = GetTestSubDirectory(g_TestDynamicBackendsSubDir1);
+    std::string subDir4 = GetTestSubDirectory(g_TestDynamicBackendsSubDir4);
 
     BOOST_CHECK(exists(subDir1));
     BOOST_CHECK(!exists(subDir4));
@@ -629,10 +653,10 @@
     //
     // Arm_GpuAcc_backend.so                                       -> valid (but duplicated from backendsTestPath1/)
 
-    std::string testDynamicBackendsSubDir1 = GetTestSubDirectory(g_TestDynamicBackendsFileParsingSubDir1);
-    std::string testDynamicBackendsSubDir2 = GetTestSubDirectory(g_TestDynamicBackendsFileParsingSubDir2);
-    std::string testDynamicBackendsSubDir3 = GetTestSubDirectory(g_TestDynamicBackendsFileParsingSubDir3);
-    std::string testDynamicBackendsSubDir4 = GetTestSubDirectory(g_TestDynamicBackendsFileParsingSubDir4);
+    std::string testDynamicBackendsSubDir1 = GetTestSubDirectory(g_TestDynamicBackendsSubDir1);
+    std::string testDynamicBackendsSubDir2 = GetTestSubDirectory(g_TestDynamicBackendsSubDir2);
+    std::string testDynamicBackendsSubDir3 = GetTestSubDirectory(g_TestDynamicBackendsSubDir3);
+    std::string testDynamicBackendsSubDir4 = GetTestSubDirectory(g_TestDynamicBackendsSubDir4);
     BOOST_CHECK(exists(testDynamicBackendsSubDir1));
     BOOST_CHECK(exists(testDynamicBackendsSubDir2));
     BOOST_CHECK(exists(testDynamicBackendsSubDir3));
@@ -676,7 +700,7 @@
     using namespace armnn;
     using namespace boost::filesystem;
 
-    // The test covers three directories:
+    // The test covers four directories:
     // <unit test path>/src/backends/backendsCommon/test/
     //                                                ├─ backendsTestPath5/   -> exists, contains files
     //                                                ├─ backendsTestPath6/   -> exists, contains files
@@ -695,14 +719,15 @@
     // Arm_TestValid4_backend.so   -> valid (it has a different filename,
     //                                       but it has the same backend id of Arm_TestValid2_backend.so
     //                                       and the same version)
+    // Arm_TestValid5_backend.so   -> valid (basic backend name)
     // Arm_TestInvalid9_backend.so -> not valid (it has a different filename,
     //                                           but it has the same backend id of Arm_TestValid2_backend.so
     //                                           and a version incompatible with the Backend API)
 
-    std::string testDynamicBackendsSubDir5 = GetTestSubDirectory(g_TestDynamicBackendsFileParsingSubDir5);
-    std::string testDynamicBackendsSubDir6 = GetTestSubDirectory(g_TestDynamicBackendsFileParsingSubDir6);
-    std::string testDynamicBackendsSubDir7 = GetTestSubDirectory(g_TestDynamicBackendsFileParsingSubDir7);
-    std::string testDynamicBackendsSubDir8 = GetTestSubDirectory(g_TestDynamicBackendsFileParsingSubDir8);
+    std::string testDynamicBackendsSubDir5 = GetTestSubDirectory(g_TestDynamicBackendsSubDir5);
+    std::string testDynamicBackendsSubDir6 = GetTestSubDirectory(g_TestDynamicBackendsSubDir6);
+    std::string testDynamicBackendsSubDir7 = GetTestSubDirectory(g_TestDynamicBackendsSubDir7);
+    std::string testDynamicBackendsSubDir8 = GetTestSubDirectory(g_TestDynamicBackendsSubDir8);
     BOOST_CHECK(exists(testDynamicBackendsSubDir5));
     BOOST_CHECK(exists(testDynamicBackendsSubDir6));
     BOOST_CHECK(exists(testDynamicBackendsSubDir7));
@@ -718,17 +743,19 @@
     std::vector<std::string> sharedObjects = DynamicBackendUtils::GetSharedObjects(backendPaths);
     std::vector<DynamicBackendPtr> dynamicBackends = DynamicBackendUtils::CreateDynamicBackends(sharedObjects);
 
-    BOOST_TEST(dynamicBackends.size() == 4);
+    BOOST_TEST(dynamicBackends.size() == 5);
     BOOST_TEST((dynamicBackends[0] != nullptr));
     BOOST_TEST((dynamicBackends[1] != nullptr));
     BOOST_TEST((dynamicBackends[2] != nullptr));
     BOOST_TEST((dynamicBackends[3] != nullptr));
+    BOOST_TEST((dynamicBackends[4] != nullptr));
 
     // Duplicates are allowed here, they will be skipped later during the backend registration
     BOOST_TEST((dynamicBackends[0]->GetBackendId() == "TestValid2"));
     BOOST_TEST((dynamicBackends[1]->GetBackendId() == "TestValid3"));
     BOOST_TEST((dynamicBackends[2]->GetBackendId() == "TestValid2")); // From duplicate Arm_TestValid2_backend.so
     BOOST_TEST((dynamicBackends[3]->GetBackendId() == "TestValid2")); // From Arm_TestValid4_backend.so
+    BOOST_TEST((dynamicBackends[4]->GetBackendId() == "TestValid5"));
 }
 
 void CreateDynamicBackendsNoPathsTestImpl()
@@ -760,8 +787,8 @@
     using namespace armnn;
     using namespace boost::filesystem;
 
-    std::string testDynamicBackendsSubDir5 = GetTestSubDirectory(g_TestDynamicBackendsFileParsingSubDir5);
-    std::string testDynamicBackendsSubDir6 = GetTestSubDirectory(g_TestDynamicBackendsFileParsingSubDir6);
+    std::string testDynamicBackendsSubDir5 = GetTestSubDirectory(g_TestDynamicBackendsSubDir5);
+    std::string testDynamicBackendsSubDir6 = GetTestSubDirectory(g_TestDynamicBackendsSubDir6);
     BOOST_CHECK(exists(testDynamicBackendsSubDir5));
     BOOST_CHECK(exists(testDynamicBackendsSubDir6));
 
@@ -788,3 +815,319 @@
     BOOST_TEST((dynamicBackends[0] != nullptr));
     BOOST_TEST((dynamicBackends[0]->GetBackendId() == "TestValid2"));
 }
+
+void RegisterSingleDynamicBackendTestImpl()
+{
+    using namespace armnn;
+    using namespace boost::filesystem;
+
+    // Register one valid dynamic backend
+
+    // Dummy registry used for testing
+    BackendRegistry backendRegistry;
+    BOOST_TEST(backendRegistry.Size() == 0);
+
+    std::string testDynamicBackendsSubDir5 = GetTestSubDirectory(g_TestDynamicBackendsSubDir5);
+    BOOST_CHECK(exists(testDynamicBackendsSubDir5));
+
+    std::string testValidBackend2FilePath = GetTestFilePath(testDynamicBackendsSubDir5, g_TestValidBackend2FileName);
+    BOOST_CHECK(exists(testValidBackend2FilePath));
+
+    std::vector<std::string> sharedObjects{ testValidBackend2FilePath };
+    std::vector<DynamicBackendPtr> dynamicBackends = TestDynamicBackendUtils::CreateDynamicBackends(sharedObjects);
+
+    BOOST_TEST(dynamicBackends.size() == 1);
+    BOOST_TEST((dynamicBackends[0] != nullptr));
+
+    BackendId dynamicBackendId = dynamicBackends[0]->GetBackendId();
+    BOOST_TEST((dynamicBackendId == "TestValid2"));
+
+    BackendVersion dynamicBackendVersion = dynamicBackends[0]->GetBackendVersion();
+    BOOST_TEST(TestDynamicBackendUtils::IsBackendCompatible(dynamicBackendVersion));
+
+    TestDynamicBackendUtils::RegisterDynamicBackendsImplTest(backendRegistry, dynamicBackends);
+    BOOST_TEST(backendRegistry.Size() == 1);
+
+    BackendIdSet backendIds = backendRegistry.GetBackendIds();
+    BOOST_TEST(backendIds.size() == 1);
+    BOOST_TEST((backendIds.find(dynamicBackendId) != backendIds.end()));
+
+    auto dynamicBackendFactoryFunction = backendRegistry.GetFactory(dynamicBackendId);
+    BOOST_TEST((dynamicBackendFactoryFunction != nullptr));
+
+    IBackendInternalUniquePtr dynamicBackend = dynamicBackendFactoryFunction();
+    BOOST_TEST((dynamicBackend != nullptr));
+    BOOST_TEST((dynamicBackend->GetId() == dynamicBackendId));
+}
+
+void RegisterMultipleDynamicBackendsTestImpl()
+{
+    using namespace armnn;
+    using namespace boost::filesystem;
+
+    // Register many valid dynamic backends
+
+    std::string testDynamicBackendsSubDir5 = GetTestSubDirectory(g_TestDynamicBackendsSubDir5);
+    std::string testDynamicBackendsSubDir6 = GetTestSubDirectory(g_TestDynamicBackendsSubDir6);
+    BOOST_CHECK(exists(testDynamicBackendsSubDir5));
+    BOOST_CHECK(exists(testDynamicBackendsSubDir6));
+
+    std::string testValidBackend2FilePath = GetTestFilePath(testDynamicBackendsSubDir5, g_TestValidBackend2FileName);
+    std::string testValidBackend3FilePath = GetTestFilePath(testDynamicBackendsSubDir5, g_TestValidBackend3FileName);
+    std::string testValidBackend5FilePath = GetTestFilePath(testDynamicBackendsSubDir6, g_TestValidBackend5FileName);
+    BOOST_CHECK(exists(testValidBackend2FilePath));
+    BOOST_CHECK(exists(testValidBackend3FilePath));
+    BOOST_CHECK(exists(testValidBackend5FilePath));
+
+    std::vector<std::string> sharedObjects
+    {
+        testValidBackend2FilePath,
+        testValidBackend3FilePath,
+        testValidBackend5FilePath
+    };
+    std::vector<DynamicBackendPtr> dynamicBackends = TestDynamicBackendUtils::CreateDynamicBackends(sharedObjects);
+
+    BOOST_TEST(dynamicBackends.size() == 3);
+    BOOST_TEST((dynamicBackends[0] != nullptr));
+    BOOST_TEST((dynamicBackends[1] != nullptr));
+    BOOST_TEST((dynamicBackends[2] != nullptr));
+
+    BackendId dynamicBackendId1 = dynamicBackends[0]->GetBackendId();
+    BackendId dynamicBackendId2 = dynamicBackends[1]->GetBackendId();
+    BackendId dynamicBackendId3 = dynamicBackends[2]->GetBackendId();
+    BOOST_TEST((dynamicBackendId1 == "TestValid2"));
+    BOOST_TEST((dynamicBackendId2 == "TestValid3"));
+    BOOST_TEST((dynamicBackendId3 == "TestValid5"));
+
+    for (size_t i = 0; i < dynamicBackends.size(); i++)
+    {
+        BackendVersion dynamicBackendVersion = dynamicBackends[i]->GetBackendVersion();
+        BOOST_TEST(TestDynamicBackendUtils::IsBackendCompatible(dynamicBackendVersion));
+    }
+
+    // Dummy registry used for testing
+    BackendRegistry backendRegistry;
+    BOOST_TEST(backendRegistry.Size() == 0);
+
+    TestDynamicBackendUtils::RegisterDynamicBackendsImplTest(backendRegistry, dynamicBackends);
+    BOOST_TEST(backendRegistry.Size() == 3);
+
+    BackendIdSet backendIds = backendRegistry.GetBackendIds();
+    BOOST_TEST(backendIds.size() == 3);
+    BOOST_TEST((backendIds.find(dynamicBackendId1) != backendIds.end()));
+    BOOST_TEST((backendIds.find(dynamicBackendId2) != backendIds.end()));
+    BOOST_TEST((backendIds.find(dynamicBackendId3) != backendIds.end()));
+
+    for (size_t i = 0; i < dynamicBackends.size(); i++)
+    {
+        BackendId dynamicBackendId = dynamicBackends[i]->GetBackendId();
+
+        auto dynamicBackendFactoryFunction = backendRegistry.GetFactory(dynamicBackendId);
+        BOOST_TEST((dynamicBackendFactoryFunction != nullptr));
+
+        IBackendInternalUniquePtr dynamicBackend = dynamicBackendFactoryFunction();
+        BOOST_TEST((dynamicBackend != nullptr));
+        BOOST_TEST((dynamicBackend->GetId() == dynamicBackendId));
+    }
+}
+
+void RegisterMultipleInvalidDynamicBackendsTestImpl()
+{
+    using namespace armnn;
+    using namespace boost::filesystem;
+
+    // Try to register many invalid dynamic backends
+
+    // The test covers one directory:
+    // <unit test path>/src/backends/backendsCommon/test/
+    //                                                └─ backendsTestPath9/   -> exists, contains files
+    //
+    // The test sub-directory backendsTestPath9/ contains the following test files:
+    //
+    // Arm_TestInvalid10_backend.so -> not valid (invalid backend id)
+    // Arm_TestInvalid11_backend.so -> not valid (invalid backend id)
+
+    std::string testDynamicBackendsSubDir9 = GetTestSubDirectory(g_TestDynamicBackendsSubDir9);
+    BOOST_CHECK(exists(testDynamicBackendsSubDir9));
+
+    std::string testInvalidBackend10FilePath = GetTestFilePath(testDynamicBackendsSubDir9,
+                                                               g_TestInvalidBackend10FileName);
+    std::string testInvalidBackend11FilePath = GetTestFilePath(testDynamicBackendsSubDir9,
+                                                               g_TestInvalidBackend11FileName);
+    BOOST_CHECK(exists(testInvalidBackend10FilePath));
+    BOOST_CHECK(exists(testInvalidBackend11FilePath));
+
+    std::vector<std::string> sharedObjects
+    {
+        testInvalidBackend10FilePath,
+        testInvalidBackend11FilePath,
+        "InvalidSharedObject"
+    };
+    std::vector<DynamicBackendPtr> dynamicBackends = TestDynamicBackendUtils::CreateDynamicBackends(sharedObjects);
+
+    BOOST_TEST(dynamicBackends.size() == 2);
+    BOOST_TEST((dynamicBackends[0] != nullptr));
+    BOOST_TEST((dynamicBackends[1] != nullptr));
+
+    BackendId dynamicBackendId1 = dynamicBackends[0]->GetBackendId();
+    BackendId dynamicBackendId2 = dynamicBackends[1]->GetBackendId();
+    BOOST_TEST((dynamicBackendId1 == ""));
+    BOOST_TEST((dynamicBackendId2 == "Unknown"));
+
+    for (size_t i = 0; i < dynamicBackends.size(); i++)
+    {
+        BackendVersion dynamicBackendVersion = dynamicBackends[i]->GetBackendVersion();
+        BOOST_TEST(TestDynamicBackendUtils::IsBackendCompatible(dynamicBackendVersion));
+    }
+
+    // Dummy registry used for testing
+    BackendRegistry backendRegistry;
+    BOOST_TEST(backendRegistry.Size() == 0);
+
+    // Check that no dynamic backend got registered
+    TestDynamicBackendUtils::RegisterDynamicBackendsImplTest(backendRegistry, dynamicBackends);
+    BOOST_TEST(backendRegistry.Size() == 0);
+}
+
+void RegisterMixedDynamicBackendsTestImpl()
+{
+    using namespace armnn;
+    using namespace boost::filesystem;
+
+    // The test covers five directories:
+    // <unit test path>/src/backends/backendsCommon/test/
+    //                                                ├─ backendsTestPath5/   -> exists, contains files
+    //                                                ├─ backendsTestPath6/   -> exists, contains files
+    //                                                ├─ backendsTestPath7/   -> exists, but empty
+    //                                                ├─ backendsTestPath8/   -> does not exist
+    //                                                └─ backendsTestPath9/   -> exists, contains files
+    //
+    // The test sub-directory backendsTestPath5/ contains the following test files:
+    //
+    // Arm_TestValid2_backend.so   -> valid (basic backend name)
+    // Arm_TestValid3_backend.so   -> valid (basic backend name)
+    // Arm_TestInvalid8_backend.so -> not valid (invalid backend id)
+    //
+    // The test sub-directory backendsTestPath6/ contains the following test files:
+    //
+    // Arm_TestValid2_backend.so   -> valid (but duplicated from backendsTestPath5/)
+    // Arm_TestValid4_backend.so   -> valid (it has a different filename,
+    //                                       but it has the same backend id of Arm_TestValid2_backend.so
+    //                                       and the same version)
+    // Arm_TestValid5_backend.so   -> valid (basic backend name)
+    // Arm_TestInvalid9_backend.so -> not valid (it has a different filename,
+    //                                           but it has the same backend id of Arm_TestValid2_backend.so
+    //                                           and a version incompatible with the Backend API)
+    //
+    // The test sub-directory backendsTestPath9/ contains the following test files:
+    //
+    // Arm_TestInvalid10_backend.so -> not valid (empty backend id)
+    // Arm_TestInvalid11_backend.so -> not valid ("Unknown" backend id)
+
+    std::string testDynamicBackendsSubDir5 = GetTestSubDirectory(g_TestDynamicBackendsSubDir5);
+    std::string testDynamicBackendsSubDir6 = GetTestSubDirectory(g_TestDynamicBackendsSubDir6);
+    std::string testDynamicBackendsSubDir7 = GetTestSubDirectory(g_TestDynamicBackendsSubDir7);
+    std::string testDynamicBackendsSubDir8 = GetTestSubDirectory(g_TestDynamicBackendsSubDir8);
+    std::string testDynamicBackendsSubDir9 = GetTestSubDirectory(g_TestDynamicBackendsSubDir9);
+    BOOST_CHECK(exists(testDynamicBackendsSubDir5));
+    BOOST_CHECK(exists(testDynamicBackendsSubDir6));
+    BOOST_CHECK(exists(testDynamicBackendsSubDir7));
+    BOOST_CHECK(!exists(testDynamicBackendsSubDir8));
+    BOOST_CHECK(exists(testDynamicBackendsSubDir9));
+
+    std::string testValidBackend2FilePath    = GetTestFilePath(testDynamicBackendsSubDir5, g_TestValidBackend2FileName);
+    std::string testValidBackend3FilePath    = GetTestFilePath(testDynamicBackendsSubDir5, g_TestValidBackend3FileName);
+    std::string testValidBackend2DupFilePath = GetTestFilePath(testDynamicBackendsSubDir6, g_TestValidBackend2FileName);
+    std::string testValidBackend4FilePath    = GetTestFilePath(testDynamicBackendsSubDir6, g_TestValidBackend4FileName);
+    std::string testValidBackend5FilePath    = GetTestFilePath(testDynamicBackendsSubDir6, g_TestValidBackend5FileName);
+    std::string testInvalidBackend8FilePath  = GetTestFilePath(testDynamicBackendsSubDir5,
+                                                               g_TestInvalidBackend8FileName);
+    std::string testInvalidBackend9FilePath  = GetTestFilePath(testDynamicBackendsSubDir6,
+                                                               g_TestInvalidBackend9FileName);
+    std::string testInvalidBackend10FilePath = GetTestFilePath(testDynamicBackendsSubDir9,
+                                                               g_TestInvalidBackend10FileName);
+    std::string testInvalidBackend11FilePath = GetTestFilePath(testDynamicBackendsSubDir9,
+                                                               g_TestInvalidBackend11FileName);
+    BOOST_CHECK(exists(testValidBackend2FilePath));
+    BOOST_CHECK(exists(testValidBackend3FilePath));
+    BOOST_CHECK(exists(testValidBackend2DupFilePath));
+    BOOST_CHECK(exists(testValidBackend4FilePath));
+    BOOST_CHECK(exists(testValidBackend5FilePath));
+    BOOST_CHECK(exists(testInvalidBackend8FilePath));
+    BOOST_CHECK(exists(testInvalidBackend9FilePath));
+    BOOST_CHECK(exists(testInvalidBackend10FilePath));
+    BOOST_CHECK(exists(testInvalidBackend11FilePath));
+
+    std::vector<std::string> sharedObjects
+    {
+        testValidBackend2FilePath,
+        testValidBackend3FilePath,
+        testValidBackend2DupFilePath,
+        testValidBackend4FilePath,
+        testValidBackend5FilePath,
+        testInvalidBackend8FilePath,
+        testInvalidBackend9FilePath,
+        testInvalidBackend10FilePath,
+        testInvalidBackend11FilePath,
+        "InvalidSharedObject"
+    };
+    std::vector<DynamicBackendPtr> dynamicBackends = TestDynamicBackendUtils::CreateDynamicBackends(sharedObjects);
+
+    BOOST_TEST(dynamicBackends.size() == 7);
+    BOOST_TEST((dynamicBackends[0] != nullptr));
+    BOOST_TEST((dynamicBackends[1] != nullptr));
+    BOOST_TEST((dynamicBackends[2] != nullptr));
+    BOOST_TEST((dynamicBackends[3] != nullptr));
+    BOOST_TEST((dynamicBackends[4] != nullptr));
+    BOOST_TEST((dynamicBackends[5] != nullptr));
+    BOOST_TEST((dynamicBackends[6] != nullptr));
+
+    BackendId dynamicBackendId1 = dynamicBackends[0]->GetBackendId();
+    BackendId dynamicBackendId2 = dynamicBackends[1]->GetBackendId();
+    BackendId dynamicBackendId3 = dynamicBackends[2]->GetBackendId();
+    BackendId dynamicBackendId4 = dynamicBackends[3]->GetBackendId();
+    BackendId dynamicBackendId5 = dynamicBackends[4]->GetBackendId();
+    BackendId dynamicBackendId6 = dynamicBackends[5]->GetBackendId();
+    BackendId dynamicBackendId7 = dynamicBackends[6]->GetBackendId();
+    BOOST_TEST((dynamicBackendId1 == "TestValid2"));
+    BOOST_TEST((dynamicBackendId2 == "TestValid3"));
+    BOOST_TEST((dynamicBackendId3 == "TestValid2")); // From duplicate Arm_TestValid2_backend.so
+    BOOST_TEST((dynamicBackendId4 == "TestValid2")); // From Arm_TestValid4_backend.so
+    BOOST_TEST((dynamicBackendId5 == "TestValid5"));
+    BOOST_TEST((dynamicBackendId6 == ""));
+    BOOST_TEST((dynamicBackendId7 == "Unknown"));
+
+    for (size_t i = 0; i < dynamicBackends.size(); i++)
+    {
+        BackendVersion dynamicBackendVersion = dynamicBackends[i]->GetBackendVersion();
+        BOOST_TEST(TestDynamicBackendUtils::IsBackendCompatible(dynamicBackendVersion));
+    }
+
+    // Dummy registry used for testing
+    BackendRegistry backendRegistry;
+    BOOST_TEST(backendRegistry.Size() == 0);
+
+    std::vector<BackendId> expectedRegisteredbackendIds
+    {
+        "TestValid2",
+        "TestValid3",
+        "TestValid5"
+    };
+
+    TestDynamicBackendUtils::RegisterDynamicBackendsImplTest(backendRegistry, dynamicBackends);
+    BOOST_TEST(backendRegistry.Size() == expectedRegisteredbackendIds.size());
+
+    BackendIdSet backendIds = backendRegistry.GetBackendIds();
+    BOOST_TEST(backendIds.size() == expectedRegisteredbackendIds.size());
+    for (const BackendId& expectedRegisteredbackendId : expectedRegisteredbackendIds)
+    {
+        BOOST_TEST((backendIds.find(expectedRegisteredbackendId) != backendIds.end()));
+
+        auto dynamicBackendFactoryFunction = backendRegistry.GetFactory(expectedRegisteredbackendId);
+        BOOST_TEST((dynamicBackendFactoryFunction != nullptr));
+
+        IBackendInternalUniquePtr dynamicBackend = dynamicBackendFactoryFunction();
+        BOOST_TEST((dynamicBackend != nullptr));
+        BOOST_TEST((dynamicBackend->GetId() == expectedRegisteredbackendId));
+    }
+}
diff --git a/src/backends/backendsCommon/test/TestDynamicBackend.cpp b/src/backends/backendsCommon/test/TestDynamicBackend.cpp
index bdbc174..7230702 100644
--- a/src/backends/backendsCommon/test/TestDynamicBackend.cpp
+++ b/src/backends/backendsCommon/test/TestDynamicBackend.cpp
@@ -28,6 +28,21 @@
     // The test dynamic backend 3 is a different backend than the test dynamic backend 2
     return "TestValid3";
 
+#elif defined(VALID_TEST_DYNAMIC_BACKEND_5)
+
+    // The test dynamic backend 5 is a different backend than the test dynamic backend 2
+    return "TestValid5";
+
+#elif defined(INVALID_TEST_DYNAMIC_BACKEND_10)
+
+    // Empty backend id
+    return "";
+
+#elif defined(INVALID_TEST_DYNAMIC_BACKEND_11)
+
+    // "Unknown" backend id, "Unknown" is a reserved id in ArmNN
+    return "Unknown";
+
 #else
 
     return "InvalidTestDynamicBackend";
diff --git a/src/backends/backendsCommon/test/TestDynamicBackend.hpp b/src/backends/backendsCommon/test/TestDynamicBackend.hpp
index 74ab91b..61a6eaf 100644
--- a/src/backends/backendsCommon/test/TestDynamicBackend.hpp
+++ b/src/backends/backendsCommon/test/TestDynamicBackend.hpp
@@ -10,7 +10,8 @@
 #if defined(VALID_TEST_DYNAMIC_BACKEND_1) || \
     defined(VALID_TEST_DYNAMIC_BACKEND_2) || \
     defined(VALID_TEST_DYNAMIC_BACKEND_3) || \
-    defined(VALID_TEST_DYNAMIC_BACKEND_4)
+    defined(VALID_TEST_DYNAMIC_BACKEND_4) || \
+    defined(VALID_TEST_DYNAMIC_BACKEND_5)
 
 // Correct dynamic backend interface
 extern "C"
@@ -50,11 +51,13 @@
 const char* GetBackendId();
 void GetVersion(uint32_t* outMajor, uint32_t* outMinor);
 
-#elif defined(INVALID_TEST_DYNAMIC_BACKEND_5) || \
-      defined(INVALID_TEST_DYNAMIC_BACKEND_6) || \
-      defined(INVALID_TEST_DYNAMIC_BACKEND_7) || \
-      defined(INVALID_TEST_DYNAMIC_BACKEND_8) || \
-      defined(INVALID_TEST_DYNAMIC_BACKEND_9)
+#elif defined(INVALID_TEST_DYNAMIC_BACKEND_5)  || \
+      defined(INVALID_TEST_DYNAMIC_BACKEND_6)  || \
+      defined(INVALID_TEST_DYNAMIC_BACKEND_7)  || \
+      defined(INVALID_TEST_DYNAMIC_BACKEND_8)  || \
+      defined(INVALID_TEST_DYNAMIC_BACKEND_9)  || \
+      defined(INVALID_TEST_DYNAMIC_BACKEND_10) || \
+      defined(INVALID_TEST_DYNAMIC_BACKEND_11)
 
 // The interface is correct, the corresponding invalid changes are in the TestDynamicBackend.cpp file
 const char* GetBackendId();