Added PersistentJsonStorageClass

PersistentJsonStorage is used to store persistent information in
json format. This class will be used by ReportManager to save
persistent report configuration.

Tested:
  - Added unit tests for new functionality
  - All other unit tests are passing

Signed-off-by: Krzysztof Grobelny <krzysztof.grobelny@intel.com>
Change-Id: Ib496e6782e849d910fe37c02c355047afda5c79c
diff --git a/tests/src/mocks/json_storage.hpp b/tests/src/mocks/json_storage.hpp
new file mode 100644
index 0000000..295bc94
--- /dev/null
+++ b/tests/src/mocks/json_storage.hpp
@@ -0,0 +1,14 @@
+#pragma once
+
+#include "interfaces/json_storage.hpp"
+
+#include <gmock/gmock.h>
+
+class StorageMock : public interfaces::JsonStorage
+{
+  public:
+    MOCK_METHOD2(store, void(const FilePath&, const nlohmann::json&));
+    MOCK_METHOD1(remove, bool(const FilePath&));
+    MOCK_CONST_METHOD1(load, std::optional<nlohmann::json>(const FilePath&));
+    MOCK_CONST_METHOD1(list, std::vector<FilePath>(const DirectoryPath&));
+};
diff --git a/tests/src/test_persistent_json_storage.cpp b/tests/src/test_persistent_json_storage.cpp
new file mode 100644
index 0000000..f8b0557
--- /dev/null
+++ b/tests/src/test_persistent_json_storage.cpp
@@ -0,0 +1,108 @@
+#include "persistent_json_storage.hpp"
+
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+
+using namespace testing;
+
+class TestPersistentJsonStorage : public Test
+{
+  public:
+    using FilePath = interfaces::JsonStorage::FilePath;
+    using DirectoryPath = interfaces::JsonStorage::DirectoryPath;
+
+    static void SetUpTestSuite()
+    {
+        ASSERT_FALSE(std::filesystem::exists(directory));
+    }
+
+    void TearDown() override
+    {
+        if (std::filesystem::exists(directory))
+        {
+            std::filesystem::remove_all(directory);
+        }
+    }
+
+    const FilePath fileName = FilePath("report/1/file.txt");
+
+    static const DirectoryPath directory;
+    PersistentJsonStorage sut{directory};
+};
+
+const interfaces::JsonStorage::DirectoryPath
+    TestPersistentJsonStorage::directory =
+        interfaces::JsonStorage::DirectoryPath(std::tmpnam(nullptr));
+
+TEST_F(TestPersistentJsonStorage, storesJsonData)
+{
+    nlohmann::json data = nlohmann::json::object();
+    data["name"] = "kevin";
+    data["lastname"] = "mc calister";
+
+    sut.store(fileName, data);
+
+    ASSERT_THAT(sut.load(fileName), Eq(data));
+}
+
+TEST_F(TestPersistentJsonStorage, emptyListWhenNoReportsCreated)
+{
+    EXPECT_THAT(sut.list(DirectoryPath("report")), SizeIs(0u));
+}
+
+TEST_F(TestPersistentJsonStorage, listSavedReports)
+{
+    sut.store(FilePath("report/domain-1/name-1/conf-1.json"),
+              nlohmann::json("data-1a"));
+    sut.store(FilePath("report/domain-1/name-2/conf-1.json"),
+              nlohmann::json("data-2a"));
+    sut.store(FilePath("report/domain-1/name-2/conf-2.json"),
+              nlohmann::json("data-2b"));
+    sut.store(FilePath("report/domain-2/name-1/conf-1.json"),
+              nlohmann::json("data-3a"));
+
+    EXPECT_THAT(sut.list(DirectoryPath("report")),
+                UnorderedElementsAre(FilePath("report/domain-1/name-1"),
+                                     FilePath("report/domain-1/name-2"),
+                                     FilePath("report/domain-2/name-1")));
+}
+
+TEST_F(TestPersistentJsonStorage, listSavedReportsWithoutRemovedOnes)
+{
+    sut.store(FilePath("report/domain-1/name-1/conf-1.json"),
+              nlohmann::json("data-1a"));
+    sut.store(FilePath("report/domain-1/name-2/conf-1.json"),
+              nlohmann::json("data-2a"));
+    sut.store(FilePath("report/domain-1/name-2/conf-2.json"),
+              nlohmann::json("data-2b"));
+    sut.store(FilePath("report/domain-2/name-1/conf-1.json"),
+              nlohmann::json("data-3a"));
+    sut.remove(FilePath("report/domain-1/name-1/conf-1.json"));
+    sut.remove(FilePath("report/domain-1/name-2/conf-2.json"));
+
+    EXPECT_THAT(sut.list(DirectoryPath("report")),
+                UnorderedElementsAre(FilePath("report/domain-1/name-2"),
+                                     FilePath("report/domain-2/name-1")));
+}
+
+TEST_F(TestPersistentJsonStorage, removesStoredJson)
+{
+    nlohmann::json data = nlohmann::json::object();
+    data["name"] = "kevin";
+    data["lastname"] = "mc calister";
+
+    sut.store(fileName, data);
+
+    ASSERT_THAT(sut.remove(fileName), Eq(true));
+    ASSERT_THAT(sut.load(fileName), Eq(std::nullopt));
+}
+
+TEST_F(TestPersistentJsonStorage, returnsFalseWhenDeletingNonExistingFile)
+{
+    ASSERT_THAT(sut.remove(fileName), Eq(false));
+}
+
+TEST_F(TestPersistentJsonStorage, returnsNulloptWhenFileDoesntExist)
+{
+    ASSERT_THAT(sut.load(fileName), Eq(std::nullopt));
+}