IVGCVSW-6635 Expose a new MockWorkloadFactory and MockMemManager (Part 1)

* Create a MockBackend in armnnTestUtils.
* Create corresponding WorkloadFactory, TensorHandle, TensorHandleFactory
  MemoryManager and WorkloadFactoryHelper classes.

Signed-off-by: Colm Donelan <colm.donelan@arm.com>
Change-Id: I884731b109bc623a7272e5ad333ff754f8c13ae1
diff --git a/include/armnnTestUtils/MockBackend.hpp b/include/armnnTestUtils/MockBackend.hpp
new file mode 100644
index 0000000..8bc41b3
--- /dev/null
+++ b/include/armnnTestUtils/MockBackend.hpp
@@ -0,0 +1,115 @@
+//
+// Copyright © 2022 Arm Ltd and Contributors. All rights reserved.
+// SPDX-License-Identifier: MIT
+//
+#pragma once
+
+#include <armnn/backends/IBackendInternal.hpp>
+#include <armnn/backends/MemCopyWorkload.hpp>
+#include <armnnTestUtils/MockTensorHandle.hpp>
+
+namespace armnn
+{
+
+// A bare bones Mock backend to enable unit testing of simple tensor manipulation features.
+class MockBackend : public IBackendInternal
+{
+public:
+    MockBackend() = default;
+
+    ~MockBackend() = default;
+
+    static const BackendId& GetIdStatic();
+
+    const BackendId& GetId() const override
+    {
+        return GetIdStatic();
+    }
+    IBackendInternal::IWorkloadFactoryPtr
+        CreateWorkloadFactory(const IBackendInternal::IMemoryManagerSharedPtr& memoryManager = nullptr) const override
+    {
+        IgnoreUnused(memoryManager);
+        return nullptr;
+    }
+
+    IBackendInternal::ILayerSupportSharedPtr GetLayerSupport() const override
+    {
+        return nullptr;
+    };
+};
+
+class MockWorkloadFactory : public IWorkloadFactory
+{
+
+public:
+    explicit MockWorkloadFactory(const std::shared_ptr<MockMemoryManager>& memoryManager);
+    MockWorkloadFactory();
+
+    ~MockWorkloadFactory()
+    {}
+
+    const BackendId& GetBackendId() const override;
+
+    bool SupportsSubTensors() const override
+    {
+        return false;
+    }
+
+    ARMNN_DEPRECATED_MSG("Use ITensorHandleFactory::CreateSubTensorHandle instead")
+    std::unique_ptr<ITensorHandle> CreateSubTensorHandle(ITensorHandle&,
+                                                         TensorShape const&,
+                                                         unsigned int const*) const override
+    {
+        return nullptr;
+    }
+
+    ARMNN_DEPRECATED_MSG("Use ITensorHandleFactory::CreateTensorHandle instead")
+    std::unique_ptr<ITensorHandle> CreateTensorHandle(const TensorInfo& tensorInfo,
+                                                      const bool IsMemoryManaged = true) const override
+    {
+        IgnoreUnused(IsMemoryManaged);
+        return std::make_unique<MockTensorHandle>(tensorInfo, m_MemoryManager);
+    };
+
+    ARMNN_DEPRECATED_MSG("Use ITensorHandleFactory::CreateTensorHandle instead")
+    std::unique_ptr<ITensorHandle> CreateTensorHandle(const TensorInfo& tensorInfo,
+                                                      DataLayout dataLayout,
+                                                      const bool IsMemoryManaged = true) const override
+    {
+        IgnoreUnused(dataLayout, IsMemoryManaged);
+        return std::make_unique<MockTensorHandle>(tensorInfo, static_cast<unsigned int>(MemorySource::Malloc));
+    };
+
+    ARMNN_DEPRECATED_MSG_REMOVAL_DATE(
+        "Use ABI stable "
+        "CreateWorkload(LayerType, const QueueDescriptor&, const WorkloadInfo& info) instead.",
+        "22.11")
+    std::unique_ptr<IWorkload> CreateInput(const InputQueueDescriptor& descriptor,
+                                           const WorkloadInfo& info) const override
+    {
+        if (info.m_InputTensorInfos.empty())
+        {
+            throw InvalidArgumentException("MockWorkloadFactory::CreateInput: Input cannot be zero length");
+        }
+        if (info.m_OutputTensorInfos.empty())
+        {
+            throw InvalidArgumentException("MockWorkloadFactory::CreateInput: Output cannot be zero length");
+        }
+
+        if (info.m_InputTensorInfos[0].GetNumBytes() != info.m_OutputTensorInfos[0].GetNumBytes())
+        {
+            throw InvalidArgumentException(
+                "MockWorkloadFactory::CreateInput: data input and output differ in byte count.");
+        }
+
+        return std::make_unique<CopyMemGenericWorkload>(descriptor, info);
+    };
+
+    std::unique_ptr<IWorkload>
+        CreateWorkload(LayerType type, const QueueDescriptor& descriptor, const WorkloadInfo& info) const override;
+
+private:
+    mutable std::shared_ptr<MockMemoryManager> m_MemoryManager;
+};
+
+}    // namespace armnn
diff --git a/include/armnnTestUtils/MockMemoryManager.hpp b/include/armnnTestUtils/MockMemoryManager.hpp
new file mode 100644
index 0000000..38cd567
--- /dev/null
+++ b/include/armnnTestUtils/MockMemoryManager.hpp
@@ -0,0 +1,59 @@
+//
+// Copyright © 2022 Arm Ltd and Contributors. All rights reserved.
+// SPDX-License-Identifier: MIT
+//
+#pragma once
+
+#include <armnn/backends/IMemoryManager.hpp>
+
+#include <forward_list>
+#include <vector>
+
+namespace armnn
+{
+
+// An implementation of IMemoryManager to be used with MockTensorHandle
+class MockMemoryManager : public IMemoryManager
+{
+public:
+    MockMemoryManager();
+    virtual ~MockMemoryManager();
+
+    class Pool;
+
+    Pool* Manage(unsigned int numBytes);
+
+    void Allocate(Pool* pool);
+
+    void* GetPointer(Pool* pool);
+
+    void Acquire() override;
+    void Release() override;
+
+    class Pool
+    {
+    public:
+        Pool(unsigned int numBytes);
+        ~Pool();
+
+        void Acquire();
+        void Release();
+
+        void* GetPointer();
+
+        void Reserve(unsigned int numBytes);
+
+    private:
+        unsigned int m_Size;
+        void* m_Pointer;
+    };
+
+private:
+    MockMemoryManager(const MockMemoryManager&) = delete;               // Noncopyable
+    MockMemoryManager& operator=(const MockMemoryManager&) = delete;    // Noncopyable
+
+    std::forward_list<Pool> m_Pools;
+    std::vector<Pool*> m_FreePools;
+};
+
+}    // namespace armnn
diff --git a/include/armnnTestUtils/MockTensorHandle.hpp b/include/armnnTestUtils/MockTensorHandle.hpp
new file mode 100644
index 0000000..9a7518b
--- /dev/null
+++ b/include/armnnTestUtils/MockTensorHandle.hpp
@@ -0,0 +1,81 @@
+//
+// Copyright © 2022 Arm Ltd and Contributors. All rights reserved.
+// SPDX-License-Identifier: MIT
+//
+#pragma once
+
+#include "MockMemoryManager.hpp"
+#include <armnn/backends/TensorHandle.hpp>
+
+namespace armnn
+{
+
+// An implementation of ITensorHandle with simple "bump the pointer" memory-management behaviour
+class MockTensorHandle : public ITensorHandle
+{
+public:
+    MockTensorHandle(const TensorInfo& tensorInfo, std::shared_ptr<MockMemoryManager>& memoryManager);
+
+    MockTensorHandle(const TensorInfo& tensorInfo, MemorySourceFlags importFlags);
+
+    ~MockTensorHandle() override;
+
+    void Manage() override;
+
+    void Allocate() override;
+
+    ITensorHandle* GetParent() const override
+    {
+        return nullptr;
+    }
+
+    const void* Map(bool /* blocking = true */) const override;
+    using ITensorHandle::Map;
+
+    void Unmap() const override
+    {}
+
+    TensorShape GetStrides() const override
+    {
+        return GetUnpaddedTensorStrides(m_TensorInfo);
+    }
+
+    TensorShape GetShape() const override
+    {
+        return m_TensorInfo.GetShape();
+    }
+
+    const TensorInfo& GetTensorInfo() const
+    {
+        return m_TensorInfo;
+    }
+
+    MemorySourceFlags GetImportFlags() const override
+    {
+        return m_ImportFlags;
+    }
+
+    bool Import(void* memory, MemorySource source) override;
+    bool CanBeImported(void* memory, MemorySource source) override;
+
+private:
+    // Only used for testing
+    void CopyOutTo(void*) const override;
+    void CopyInFrom(const void*) override;
+
+    void* GetPointer() const;
+
+    MockTensorHandle(const MockTensorHandle& other) = delete;               // noncopyable
+    MockTensorHandle& operator=(const MockTensorHandle& other) = delete;    //noncopyable
+
+    TensorInfo m_TensorInfo;
+
+    std::shared_ptr<MockMemoryManager> m_MemoryManager;
+    MockMemoryManager::Pool* m_Pool;
+    mutable void* m_UnmanagedMemory;
+    MemorySourceFlags m_ImportFlags;
+    bool m_Imported;
+    bool m_IsImportEnabled;
+};
+
+}    // namespace armnn
diff --git a/src/armnnTestUtils/CMakeLists.txt b/src/armnnTestUtils/CMakeLists.txt
index fae7452..cab0ba3 100755
--- a/src/armnnTestUtils/CMakeLists.txt
+++ b/src/armnnTestUtils/CMakeLists.txt
@@ -8,6 +8,9 @@
 list(APPEND armnnTestUtils_sources
         ../../include/armnnTestUtils/DataLayoutUtils.hpp
         ../../include/armnnTestUtils/LayerTestResult.hpp
+        ../../include/armnnTestUtils/MockBackend.hpp
+        ../../include/armnnTestUtils/MockMemoryManager.hpp
+        ../../include/armnnTestUtils/MockTensorHandle.hpp
         ../../include/armnnTestUtils/PredicateResult.hpp
         ../../include/armnnTestUtils/TensorCopyUtils.hpp
         ../../include/armnnTestUtils/WorkloadTestUtils.hpp
@@ -18,6 +21,12 @@
         DataTypeUtils.hpp
         GraphUtils.cpp
         GraphUtils.hpp
+        MockBackend.cpp
+        MockMemoryManager.cpp
+        MockTensorHandle.cpp
+        MockTensorHandleFactory.hpp
+        MockTensorHandleFactory.cpp
+        MockWorkloadFactoryHelper.hpp
         TensorCopyUtils.cpp
         TestUtils.cpp
         TestUtils.hpp
diff --git a/src/armnnTestUtils/MockBackend.cpp b/src/armnnTestUtils/MockBackend.cpp
new file mode 100644
index 0000000..40f97cd
--- /dev/null
+++ b/src/armnnTestUtils/MockBackend.cpp
@@ -0,0 +1,55 @@
+//
+// Copyright © 2022 Arm Ltd and Contributors. All rights reserved.
+// SPDX-License-Identifier: MIT
+//
+
+#include <armnn/backends/MemCopyWorkload.hpp>
+#include <armnnTestUtils/MockBackend.hpp>
+#include <armnnTestUtils/MockTensorHandle.hpp>
+
+namespace armnn
+{
+
+constexpr const char* MockBackendId()
+{
+    return "CpuMock";
+}
+
+namespace
+{
+static const BackendId s_Id{ MockBackendId() };
+}
+
+MockWorkloadFactory::MockWorkloadFactory(const std::shared_ptr<MockMemoryManager>& memoryManager)
+    : m_MemoryManager(memoryManager)
+{}
+
+MockWorkloadFactory::MockWorkloadFactory()
+    : m_MemoryManager(new MockMemoryManager())
+{}
+
+const BackendId& MockWorkloadFactory::GetBackendId() const
+{
+    return s_Id;
+}
+
+std::unique_ptr<IWorkload> MockWorkloadFactory::CreateWorkload(LayerType type,
+                                                               const QueueDescriptor& descriptor,
+                                                               const WorkloadInfo& info) const
+{
+    switch (type)
+    {
+        case LayerType::MemCopy: {
+            auto memCopyQueueDescriptor = PolymorphicDowncast<const MemCopyQueueDescriptor*>(&descriptor);
+            if (descriptor.m_Inputs.empty())
+            {
+                throw InvalidArgumentException("MockWorkloadFactory: CreateMemCopy() expected an input tensor.");
+            }
+            return std::make_unique<CopyMemGenericWorkload>(*memCopyQueueDescriptor, info);
+        }
+        default:
+            return nullptr;
+    }
+}
+
+}    // namespace armnn
\ No newline at end of file
diff --git a/src/armnnTestUtils/MockMemoryManager.cpp b/src/armnnTestUtils/MockMemoryManager.cpp
new file mode 100644
index 0000000..3ff6ec8
--- /dev/null
+++ b/src/armnnTestUtils/MockMemoryManager.cpp
@@ -0,0 +1,93 @@
+//
+// Copyright © 2022 Arm Ltd and Contributors. All rights reserved.
+// SPDX-License-Identifier: MIT
+//
+
+#include "armnnTestUtils/MockMemoryManager.hpp"
+
+namespace armnn
+{
+
+MockMemoryManager::MockMemoryManager()
+{}
+
+MockMemoryManager::~MockMemoryManager()
+{}
+
+MockMemoryManager::Pool* MockMemoryManager::Manage(unsigned int numBytes)
+{
+    if (!m_FreePools.empty())
+    {
+        Pool* res = m_FreePools.back();
+        m_FreePools.pop_back();
+        res->Reserve(numBytes);
+        return res;
+    }
+    else
+    {
+        m_Pools.push_front(Pool(numBytes));
+        return &m_Pools.front();
+    }
+}
+
+void MockMemoryManager::Allocate(MockMemoryManager::Pool* pool)
+{
+    m_FreePools.push_back(pool);
+}
+
+void* MockMemoryManager::GetPointer(MockMemoryManager::Pool* pool)
+{
+    return pool->GetPointer();
+}
+
+void MockMemoryManager::Acquire()
+{
+    for (Pool& pool : m_Pools)
+    {
+        pool.Acquire();
+    }
+}
+
+void MockMemoryManager::Release()
+{
+    for (Pool& pool : m_Pools)
+    {
+        pool.Release();
+    }
+}
+
+MockMemoryManager::Pool::Pool(unsigned int numBytes)
+    : m_Size(numBytes)
+    , m_Pointer(nullptr)
+{}
+
+MockMemoryManager::Pool::~Pool()
+{
+    if (m_Pointer)
+    {
+        Release();
+    }
+}
+
+void* MockMemoryManager::Pool::GetPointer()
+{
+    return m_Pointer;
+}
+
+void MockMemoryManager::Pool::Reserve(unsigned int numBytes)
+{
+    m_Size = std::max(m_Size, numBytes);
+}
+
+void MockMemoryManager::Pool::Acquire()
+{
+    m_Pointer = ::operator new(size_t(m_Size));
+}
+
+void MockMemoryManager::Pool::Release()
+{
+    ::operator delete(m_Pointer);
+    m_Pointer = nullptr;
+}
+
+}    // namespace armnn
diff --git a/src/armnnTestUtils/MockTensorHandle.cpp b/src/armnnTestUtils/MockTensorHandle.cpp
new file mode 100644
index 0000000..be4d5a8
--- /dev/null
+++ b/src/armnnTestUtils/MockTensorHandle.cpp
@@ -0,0 +1,176 @@
+//
+// Copyright © 2022 Arm Ltd and Contributors. All rights reserved.
+// SPDX-License-Identifier: MIT
+//
+
+#include "armnnTestUtils/MockTensorHandle.hpp"
+
+namespace armnn
+{
+
+MockTensorHandle::MockTensorHandle(const TensorInfo& tensorInfo, std::shared_ptr<MockMemoryManager>& memoryManager)
+    : m_TensorInfo(tensorInfo)
+    , m_MemoryManager(memoryManager)
+    , m_Pool(nullptr)
+    , m_UnmanagedMemory(nullptr)
+    , m_ImportFlags(static_cast<MemorySourceFlags>(MemorySource::Undefined))
+    , m_Imported(false)
+    , m_IsImportEnabled(false)
+{}
+
+MockTensorHandle::MockTensorHandle(const TensorInfo& tensorInfo, MemorySourceFlags importFlags)
+    : m_TensorInfo(tensorInfo)
+    , m_Pool(nullptr)
+    , m_UnmanagedMemory(nullptr)
+    , m_ImportFlags(importFlags)
+    , m_Imported(false)
+    , m_IsImportEnabled(true)
+{}
+
+MockTensorHandle::~MockTensorHandle()
+{
+    if (!m_Pool)
+    {
+        // unmanaged
+        if (!m_Imported)
+        {
+            ::operator delete(m_UnmanagedMemory);
+        }
+    }
+}
+
+void MockTensorHandle::Manage()
+{
+    if (!m_IsImportEnabled)
+    {
+        ARMNN_ASSERT_MSG(!m_Pool, "MockTensorHandle::Manage() called twice");
+        ARMNN_ASSERT_MSG(!m_UnmanagedMemory, "MockTensorHandle::Manage() called after Allocate()");
+
+        m_Pool = m_MemoryManager->Manage(m_TensorInfo.GetNumBytes());
+    }
+}
+
+void MockTensorHandle::Allocate()
+{
+    // If import is enabled, do not allocate the tensor
+    if (!m_IsImportEnabled)
+    {
+
+        if (!m_UnmanagedMemory)
+        {
+            if (!m_Pool)
+            {
+                // unmanaged
+                m_UnmanagedMemory = ::operator new(m_TensorInfo.GetNumBytes());
+            }
+            else
+            {
+                m_MemoryManager->Allocate(m_Pool);
+            }
+        }
+        else
+        {
+            throw InvalidArgumentException("MockTensorHandle::Allocate Trying to allocate a MockTensorHandle"
+                                           "that already has allocated memory.");
+        }
+    }
+}
+
+const void* MockTensorHandle::Map(bool /*unused*/) const
+{
+    return GetPointer();
+}
+
+void* MockTensorHandle::GetPointer() const
+{
+    if (m_UnmanagedMemory)
+    {
+        return m_UnmanagedMemory;
+    }
+    else if (m_Pool)
+    {
+        return m_MemoryManager->GetPointer(m_Pool);
+    }
+    else
+    {
+        throw NullPointerException("MockTensorHandle::GetPointer called on unmanaged, unallocated tensor handle");
+    }
+}
+
+void MockTensorHandle::CopyOutTo(void* dest) const
+{
+    const void* src = GetPointer();
+    ARMNN_ASSERT(src);
+    memcpy(dest, src, m_TensorInfo.GetNumBytes());
+}
+
+void MockTensorHandle::CopyInFrom(const void* src)
+{
+    void* dest = GetPointer();
+    ARMNN_ASSERT(dest);
+    memcpy(dest, src, m_TensorInfo.GetNumBytes());
+}
+
+bool MockTensorHandle::Import(void* memory, MemorySource source)
+{
+    if (m_ImportFlags & static_cast<MemorySourceFlags>(source))
+    {
+        if (m_IsImportEnabled && source == MemorySource::Malloc)
+        {
+            // Check memory alignment
+            if (!CanBeImported(memory, source))
+            {
+                if (m_Imported)
+                {
+                    m_Imported        = false;
+                    m_UnmanagedMemory = nullptr;
+                }
+
+                return false;
+            }
+
+            // m_UnmanagedMemory not yet allocated.
+            if (!m_Imported && !m_UnmanagedMemory)
+            {
+                m_UnmanagedMemory = memory;
+                m_Imported        = true;
+                return true;
+            }
+
+            // m_UnmanagedMemory initially allocated with Allocate().
+            if (!m_Imported && m_UnmanagedMemory)
+            {
+                return false;
+            }
+
+            // m_UnmanagedMemory previously imported.
+            if (m_Imported)
+            {
+                m_UnmanagedMemory = memory;
+                return true;
+            }
+        }
+    }
+
+    return false;
+}
+
+bool MockTensorHandle::CanBeImported(void* memory, MemorySource source)
+{
+    if (m_ImportFlags & static_cast<MemorySourceFlags>(source))
+    {
+        if (m_IsImportEnabled && source == MemorySource::Malloc)
+        {
+            uintptr_t alignment = GetDataTypeSize(m_TensorInfo.GetDataType());
+            if (reinterpret_cast<uintptr_t>(memory) % alignment)
+            {
+                return false;
+            }
+
+            return true;
+        }
+    }
+    return false;
+}
+
+}    // namespace armnn
diff --git a/src/armnnTestUtils/MockTensorHandleFactory.cpp b/src/armnnTestUtils/MockTensorHandleFactory.cpp
new file mode 100644
index 0000000..e90f318
--- /dev/null
+++ b/src/armnnTestUtils/MockTensorHandleFactory.cpp
@@ -0,0 +1,87 @@
+//
+// Copyright © 2022 Arm Ltd and Contributors. All rights reserved.
+// SPDX-License-Identifier: MIT
+//
+
+#include "MockTensorHandleFactory.hpp"
+#include <armnnTestUtils/MockTensorHandle.hpp>
+
+namespace armnn
+{
+
+using FactoryId = ITensorHandleFactory::FactoryId;
+
+const FactoryId& MockTensorHandleFactory::GetIdStatic()
+{
+    static const FactoryId s_Id(MockTensorHandleFactoryId());
+    return s_Id;
+}
+
+std::unique_ptr<ITensorHandle> MockTensorHandleFactory::CreateSubTensorHandle(ITensorHandle&,
+                                                                              TensorShape const&,
+                                                                              unsigned int const*) const
+{
+    return nullptr;
+}
+
+std::unique_ptr<ITensorHandle> MockTensorHandleFactory::CreateTensorHandle(const TensorInfo& tensorInfo) const
+{
+    return std::make_unique<MockTensorHandle>(tensorInfo, m_MemoryManager);
+}
+
+std::unique_ptr<ITensorHandle> MockTensorHandleFactory::CreateTensorHandle(const TensorInfo& tensorInfo,
+                                                                           DataLayout dataLayout) const
+{
+    IgnoreUnused(dataLayout);
+    return std::make_unique<MockTensorHandle>(tensorInfo, m_MemoryManager);
+}
+
+std::unique_ptr<ITensorHandle> MockTensorHandleFactory::CreateTensorHandle(const TensorInfo& tensorInfo,
+                                                                           const bool IsMemoryManaged) const
+{
+    if (IsMemoryManaged)
+    {
+        return std::make_unique<MockTensorHandle>(tensorInfo, m_MemoryManager);
+    }
+    else
+    {
+        return std::make_unique<MockTensorHandle>(tensorInfo, m_ImportFlags);
+    }
+}
+
+std::unique_ptr<ITensorHandle> MockTensorHandleFactory::CreateTensorHandle(const TensorInfo& tensorInfo,
+                                                                           DataLayout dataLayout,
+                                                                           const bool IsMemoryManaged) const
+{
+    IgnoreUnused(dataLayout);
+    if (IsMemoryManaged)
+    {
+        return std::make_unique<MockTensorHandle>(tensorInfo, m_MemoryManager);
+    }
+    else
+    {
+        return std::make_unique<MockTensorHandle>(tensorInfo, m_ImportFlags);
+    }
+}
+
+const FactoryId& MockTensorHandleFactory::GetId() const
+{
+    return GetIdStatic();
+}
+
+bool MockTensorHandleFactory::SupportsSubTensors() const
+{
+    return false;
+}
+
+MemorySourceFlags MockTensorHandleFactory::GetExportFlags() const
+{
+    return m_ExportFlags;
+}
+
+MemorySourceFlags MockTensorHandleFactory::GetImportFlags() const
+{
+    return m_ImportFlags;
+}
+
+}    // namespace armnn
\ No newline at end of file
diff --git a/src/armnnTestUtils/MockTensorHandleFactory.hpp b/src/armnnTestUtils/MockTensorHandleFactory.hpp
new file mode 100644
index 0000000..ffe7c8b
--- /dev/null
+++ b/src/armnnTestUtils/MockTensorHandleFactory.hpp
@@ -0,0 +1,61 @@
+//
+// Copyright © 2022 Arm Ltd and Contributors. All rights reserved.
+// SPDX-License-Identifier: MIT
+//
+
+#pragma once
+
+#include <armnn/backends/ITensorHandleFactory.hpp>
+#include <armnnTestUtils/MockMemoryManager.hpp>
+
+namespace armnn
+{
+
+constexpr const char* MockTensorHandleFactoryId()
+{
+    return "Arm/Mock/TensorHandleFactory";
+}
+
+class MockTensorHandleFactory : public ITensorHandleFactory
+{
+
+public:
+    explicit MockTensorHandleFactory(std::shared_ptr<MockMemoryManager> mgr)
+        : m_MemoryManager(mgr)
+        , m_ImportFlags(static_cast<MemorySourceFlags>(MemorySource::Malloc))
+        , m_ExportFlags(static_cast<MemorySourceFlags>(MemorySource::Malloc))
+    {}
+
+    std::unique_ptr<ITensorHandle> CreateSubTensorHandle(ITensorHandle& parent,
+                                                         TensorShape const& subTensorShape,
+                                                         unsigned int const* subTensorOrigin) const override;
+
+    std::unique_ptr<ITensorHandle> CreateTensorHandle(const TensorInfo& tensorInfo) const override;
+
+    std::unique_ptr<ITensorHandle> CreateTensorHandle(const TensorInfo& tensorInfo,
+                                                      DataLayout dataLayout) const override;
+
+    std::unique_ptr<ITensorHandle> CreateTensorHandle(const TensorInfo& tensorInfo,
+                                                      const bool IsMemoryManaged) const override;
+
+    std::unique_ptr<ITensorHandle> CreateTensorHandle(const TensorInfo& tensorInfo,
+                                                      DataLayout dataLayout,
+                                                      const bool IsMemoryManaged) const override;
+
+    static const FactoryId& GetIdStatic();
+
+    const FactoryId& GetId() const override;
+
+    bool SupportsSubTensors() const override;
+
+    MemorySourceFlags GetExportFlags() const override;
+
+    MemorySourceFlags GetImportFlags() const override;
+
+private:
+    mutable std::shared_ptr<MockMemoryManager> m_MemoryManager;
+    MemorySourceFlags m_ImportFlags;
+    MemorySourceFlags m_ExportFlags;
+};
+
+}    // namespace armnn
diff --git a/src/armnnTestUtils/MockWorkloadFactoryHelper.hpp b/src/armnnTestUtils/MockWorkloadFactoryHelper.hpp
new file mode 100644
index 0000000..6b61cf6
--- /dev/null
+++ b/src/armnnTestUtils/MockWorkloadFactoryHelper.hpp
@@ -0,0 +1,41 @@
+//
+// Copyright © 2022 Arm Ltd and Contributors. All rights reserved.
+// SPDX-License-Identifier: MIT
+//
+
+#pragma once
+
+#include <MockTensorHandleFactory.hpp>
+#include <armnnTestUtils/MockBackend.hpp>
+#include <backendsCommon/test/WorkloadFactoryHelper.hpp>
+
+namespace
+{
+
+template <>
+struct WorkloadFactoryHelper<armnn::MockWorkloadFactory>
+{
+    static armnn::IBackendInternal::IMemoryManagerSharedPtr GetMemoryManager()
+    {
+        armnn::MockBackend backend;
+        return backend.CreateMemoryManager();
+    }
+
+    static armnn::MockWorkloadFactory
+        GetFactory(const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager = nullptr)
+    {
+        IgnoreUnused(memoryManager);
+        return armnn::MockWorkloadFactory();
+    }
+
+    static armnn::MockTensorHandleFactory
+        GetTensorHandleFactory(const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager = nullptr)
+    {
+
+        return armnn::MockTensorHandleFactory(std::static_pointer_cast<armnn::MockMemoryManager>(memoryManager));
+    }
+};
+
+using MockWorkloadFactoryHelper = WorkloadFactoryHelper<armnn::MockWorkloadFactory>;
+
+}    // anonymous namespace