mirror of
https://github.com/ComodoSecurity/openedr/
synced 2026-06-06 15:24:33 +00:00
377 lines
9.3 KiB
C++
377 lines
9.3 KiB
C++
//
|
|
// edrav2.ut_libcore project
|
|
//
|
|
// Author: Yury Ermakov (23.02.2019)
|
|
// Reviewer:
|
|
//
|
|
|
|
#include "pch.h"
|
|
#include "../src/dictionarymixer.h"
|
|
|
|
using namespace openEdr;
|
|
|
|
//
|
|
//
|
|
//
|
|
TEST_CASE("DictionaryMixer.create")
|
|
{
|
|
auto fnScenario = [&](Variant vConfig, Variant vEthalon)
|
|
{
|
|
auto pObj = createObject(CLSID_DictionaryMixer, vConfig);
|
|
auto pDictProxy = queryInterface<variant::IDictionaryProxy>(pObj);
|
|
auto dict = Dictionary(pObj);
|
|
REQUIRE(dict == vEthalon);
|
|
};
|
|
|
|
const std::map<const std::string, std::tuple<Variant, Variant>> mapData{
|
|
// sName: vConfig, vEthalon
|
|
{ "blank", { Dictionary({ { "layers", Sequence({
|
|
Dictionary()
|
|
}) }, }),
|
|
Dictionary(),
|
|
} },
|
|
{ "2layers", { Dictionary({ { "layers", Sequence({
|
|
Dictionary({
|
|
{ "a", 0 },
|
|
{ "b", Dictionary({ { "b1", 1 } }) },
|
|
{ "c", Dictionary({ { "c1", 11 }, { "c2", 2 } }) },
|
|
}),
|
|
Dictionary({
|
|
{ "b", 2 },
|
|
{ "c", Dictionary({ { "c1", 1 }, { "c3", 3 }, }) },
|
|
{ "d", Dictionary({ { "d1", 1 }, { "d2", 3 }, }) },
|
|
{ "e", 42 }
|
|
}),
|
|
}) }, }),
|
|
Dictionary({
|
|
{ "a", 0 },
|
|
{ "b", Dictionary({ { "b1", 1 } }) },
|
|
{ "c", Dictionary({ { "c1", 11 }, { "c2", 2 }, { "c3", 3 }, }) },
|
|
{ "d", Dictionary({ { "d1", 1 }, { "d2", 3 } }) },
|
|
{ "e", 42 }
|
|
}),
|
|
} },
|
|
};
|
|
|
|
for (const auto& [sName, params] : mapData)
|
|
{
|
|
const auto& [vConfig, vEthalon] = params;
|
|
DYNAMIC_SECTION(sName)
|
|
{
|
|
REQUIRE_NOTHROW(fnScenario(vConfig, vEthalon));
|
|
}
|
|
}
|
|
|
|
const std::map<std::string, std::tuple<std::string, Variant, Variant>> mapBad{
|
|
// sName: sMsg, vConfig, vEthalon
|
|
// TODO: if behaviour of has() on non-dictionary will be changed
|
|
{ "config_not_dictionary", { "has() is not applicable for current type <Integer>. Key: <layers>", 42, nullptr } },
|
|
{ "missing_layers", { "Missing field <layers>", Dictionary(), nullptr } },
|
|
{ "invalid_layers", { "Layers must be a sequence", Dictionary({ { "layers", 42 } }), nullptr } },
|
|
{ "no_layers", { "No layers found", Dictionary({ { "layers", Sequence() } }), nullptr } },
|
|
{ "invalid_layer", { "Layer must be a dictionary", Dictionary({ { "layers", Sequence({ 42 }) } }), nullptr } },
|
|
};
|
|
|
|
for (const auto& [sName, params] : mapBad)
|
|
{
|
|
const auto& [sMsg, vConfig, vEthalon] = params;
|
|
DYNAMIC_SECTION(sName)
|
|
{
|
|
REQUIRE_THROWS_WITH(fnScenario(vConfig, vEthalon), sMsg);
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
//
|
|
//
|
|
TEST_CASE("DictionaryMixer.basic_operations")
|
|
{
|
|
auto fnScenario = [&](Variant vConfig, Variant vEthalon)
|
|
{
|
|
auto pObj = createObject(CLSID_DictionaryMixer, vConfig);
|
|
auto pDictProxy = queryInterface<variant::IDictionaryProxy>(pObj);
|
|
auto dict = Dictionary(pObj);
|
|
dict.put("x", Dictionary({ { "x1", 1 }, { "x2", 2 }, { "x3", 3 } }));
|
|
auto dictX = dict.get("x");
|
|
REQUIRE(dictX.getSize() == 3);
|
|
REQUIRE(dictX.erase("x2") == 1);
|
|
REQUIRE(dictX.erase("x2") == 0);
|
|
REQUIRE(dictX.getSize() == 2);
|
|
variant::deleteByPath(dict, "x.x3");
|
|
REQUIRE(dictX.getSize() == 1);
|
|
dictX.put("x4", Dictionary({ { "x41", 41 } }));
|
|
REQUIRE(dict == vEthalon);
|
|
};
|
|
|
|
const std::map<const std::string, std::tuple<Variant, Variant>> mapData{
|
|
// sName: vConfig, vEthalon
|
|
{ "blank", { Dictionary({ { "layers", Sequence({
|
|
Dictionary()
|
|
}) }, }),
|
|
Dictionary({ { "x", Dictionary({ { "x1", 1 }, { "x4", Dictionary({ { "x41", 41 } }) } }) }
|
|
}),
|
|
} },
|
|
{ "2layers", { Dictionary({ { "layers", Sequence({
|
|
Dictionary({ { "a", 42 } }),
|
|
Dictionary({ { "b", 2 }, { "x", 42 }, { "y", 0 } }),
|
|
}) }, }),
|
|
Dictionary({
|
|
{ "a", 42 },
|
|
{ "b", 2 },
|
|
{ "x", Dictionary({ { "x1", 1 }, { "x4", Dictionary({ { "x41", 41 } }) } }) },
|
|
{ "y", 0 }
|
|
}),
|
|
} },
|
|
};
|
|
|
|
for (const auto& [sName, params] : mapData)
|
|
{
|
|
const auto& [vConfig, vEthalon] = params;
|
|
DYNAMIC_SECTION(sName)
|
|
{
|
|
REQUIRE_NOTHROW(fnScenario(vConfig, vEthalon));
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
//
|
|
//
|
|
TEST_CASE("DictionaryMixer.putByPath")
|
|
{
|
|
auto fnScenario = [&](Variant vConfig, std::string_view sPath, Variant vValue, Variant vEthalon)
|
|
{
|
|
auto pObj = createObject(CLSID_DictionaryMixer, vConfig);
|
|
auto pDictProxy = queryInterface<variant::IDictionaryProxy>(pObj);
|
|
auto dictResult = Dictionary(pDictProxy);
|
|
variant::putByPath(dictResult, sPath, vValue, /* fCreatePaths */ true);
|
|
REQUIRE(dictResult == vEthalon);
|
|
};
|
|
|
|
const auto c_dictConfig = Dictionary({ { "layers", Sequence({
|
|
Dictionary({
|
|
{ "a", 42 },
|
|
{ "x", Dictionary({ { "x1", 1 } }) }
|
|
}),
|
|
Dictionary({
|
|
{ "b", 2 },
|
|
{ "x", 42 },
|
|
{ "y", Dictionary({ { "y1", 1 } }) }
|
|
}),
|
|
}) }, });
|
|
|
|
const std::map<const std::string, std::tuple<Variant, std::string, Variant, Variant>> mapData{
|
|
// sName: vConfig, sPath, vValue, vEthalon
|
|
{ "new_simple", { c_dictConfig,
|
|
"z",
|
|
2,
|
|
Dictionary({
|
|
{ "a", 42 },
|
|
{ "b", 2 },
|
|
{ "x", Dictionary({ { "x1", 1 } }) },
|
|
{ "y", Dictionary({ { "y1", 1 } }) },
|
|
{ "z", 2 }
|
|
}),
|
|
} },
|
|
{ "new_intermediate_paths", { c_dictConfig,
|
|
"z.z1.z11",
|
|
2,
|
|
Dictionary({
|
|
{ "a", 42 },
|
|
{ "b", 2 },
|
|
{ "x", Dictionary({ { "x1", 1 } }) },
|
|
{ "y", Dictionary({ { "y1", 1 } }) },
|
|
{ "z", Dictionary({ { "z1", Dictionary({ { "z11", 2 } }) } }) }
|
|
}),
|
|
} },
|
|
{ "update_l0", { c_dictConfig,
|
|
"a",
|
|
Sequence(),
|
|
Dictionary({
|
|
{ "a", Sequence() },
|
|
{ "b", 2 },
|
|
{ "x", Dictionary({ { "x1", 1 } }) },
|
|
{ "y", Dictionary({ { "y1", 1 } }) },
|
|
}),
|
|
} },
|
|
{ "new_l1", { c_dictConfig,
|
|
"y.y2",
|
|
2,
|
|
Dictionary({
|
|
{ "a", 42 },
|
|
{ "b", 2 },
|
|
{ "x", Dictionary({ { "x1", 1 } }) },
|
|
{ "y", Dictionary({ { "y1", 1 }, { "y2", 2 } }) },
|
|
}),
|
|
} },
|
|
{ "append_l1", { c_dictConfig,
|
|
"y.y2",
|
|
2,
|
|
Dictionary({
|
|
{ "a", 42 },
|
|
{ "b", 2 },
|
|
{ "x", Dictionary({ { "x1", 1 } }) },
|
|
{ "y", Dictionary({ { "y1", 1 }, { "y2", 2 } }) },
|
|
}),
|
|
} },
|
|
};
|
|
|
|
for (const auto& [sName, params] : mapData)
|
|
{
|
|
const auto& [vConfig, sPath, vValue, vEthalon] = params;
|
|
DYNAMIC_SECTION(sName)
|
|
{
|
|
REQUIRE_NOTHROW(fnScenario(vConfig, sPath, vValue, vEthalon));
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
//
|
|
//
|
|
TEST_CASE("DictionaryMixer.isEmpty")
|
|
{
|
|
auto fnScenario = [&](Variant vConfig, std::string_view sPath, bool fExpected)
|
|
{
|
|
auto pObj = createObject(CLSID_DictionaryMixer, vConfig);
|
|
auto pDictMixer = queryInterface<variant::IRootDictionaryProxy>(pObj);
|
|
pDictMixer->erase("x", "x1");
|
|
pDictMixer->erase("y", "y1");
|
|
auto fResult = pDictMixer->isEmpty(sPath);
|
|
REQUIRE(fResult == fExpected);
|
|
};
|
|
|
|
const auto c_dictConfig = Dictionary({ { "layers", Sequence({
|
|
Dictionary({
|
|
{ "a", 42 },
|
|
{ "x", Dictionary({ { "x1", 1 } }) }
|
|
}),
|
|
Dictionary({
|
|
{ "b", 2 },
|
|
{ "x", 42 },
|
|
{ "y", Dictionary({ { "y1", 1 } }) }
|
|
}),
|
|
}) }, });
|
|
|
|
const std::map<const std::string, std::tuple<Variant, std::string, bool>> mapData{
|
|
// sName: vConfig, sPath, fExpected
|
|
{ "l0", { c_dictConfig, "x", true } },
|
|
{ "l1", { c_dictConfig, "y", true } }
|
|
};
|
|
|
|
for (const auto& [sName, params] : mapData)
|
|
{
|
|
const auto& [vConfig, sPath, fExpected] = params;
|
|
DYNAMIC_SECTION(sName)
|
|
{
|
|
REQUIRE_NOTHROW(fnScenario(vConfig, sPath, fExpected));
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
//
|
|
//
|
|
TEST_CASE("DictionaryMixer.put_with_full_unerase")
|
|
{
|
|
auto fnScenario = [&](Variant vConfig)
|
|
{
|
|
auto pObj = createObject(CLSID_DictionaryMixer, vConfig);
|
|
auto pDictProxy = queryInterface<variant::IDictionaryProxy>(pObj);
|
|
pDictProxy->erase("x");
|
|
pDictProxy->put("x", Dictionary({ { "x1", 1 } }));
|
|
auto dictResult = pDictProxy->get("x");
|
|
REQUIRE(dictResult.getSize() == 1);
|
|
};
|
|
|
|
const auto c_dictConfig = Dictionary({ { "layers", Sequence({
|
|
Dictionary({
|
|
{ "a", 42 },
|
|
{ "x", Dictionary({ { "x1", 1 } }) }
|
|
}),
|
|
Dictionary({
|
|
{ "b", 2 },
|
|
{ "x", 42 },
|
|
{ "y", Dictionary({ { "y1", 1 } }) }
|
|
}),
|
|
}) }, });
|
|
|
|
REQUIRE_NOTHROW(fnScenario(c_dictConfig));
|
|
}
|
|
|
|
//
|
|
//
|
|
//
|
|
TEST_CASE("DictionaryMixer.clear")
|
|
{
|
|
auto fnScenario = [&](Variant vConfig)
|
|
{
|
|
auto pObj = createObject(CLSID_DictionaryMixer, vConfig);
|
|
auto pDictProxy = queryInterface<variant::IDictionaryProxy>(pObj);
|
|
pDictProxy->clear();
|
|
REQUIRE(pDictProxy->getSize() == 0);
|
|
};
|
|
|
|
const auto c_dictConfig = Dictionary({ { "layers", Sequence({
|
|
Dictionary({
|
|
{ "a", 42 },
|
|
{ "x", Dictionary({ { "x1", 1 } }) }
|
|
}),
|
|
Dictionary({
|
|
{ "b", 2 },
|
|
{ "x", 42 },
|
|
{ "y", Dictionary({ { "y1", 1 } }) }
|
|
}),
|
|
}) }, });
|
|
|
|
REQUIRE_NOTHROW(fnScenario(c_dictConfig));
|
|
}
|
|
|
|
//
|
|
//
|
|
//
|
|
TEST_CASE("DictionaryMixer.erase")
|
|
{
|
|
auto fnScenario = [&](Variant vConfig, std::string_view sPath, bool fExpected)
|
|
{
|
|
auto pObj = createObject(CLSID_DictionaryMixer, vConfig);
|
|
auto pDictMixer = queryInterface<variant::IRootDictionaryProxy>(pObj);
|
|
pDictMixer->erase("", "x");
|
|
pDictMixer->erase("", "y");
|
|
pDictMixer->erase("", "a");
|
|
pDictMixer->erase("", "b");
|
|
auto fResult = pDictMixer->isEmpty(sPath);
|
|
REQUIRE(fResult == fExpected);
|
|
};
|
|
|
|
const auto c_dictConfig = Dictionary({ { "layers", Sequence({
|
|
Dictionary({
|
|
{ "a", 42 },
|
|
{ "x", Dictionary({ { "x1", 1 } }) }
|
|
}),
|
|
Dictionary({
|
|
{ "b", 2 },
|
|
{ "x", 42 },
|
|
{ "y", Dictionary({ { "y1", 1 } }) }
|
|
}),
|
|
}) }, });
|
|
|
|
const std::map<const std::string, std::tuple<Variant, std::string, bool>> mapData{
|
|
// sName: vConfig, sPath, fExpected
|
|
{ "l0", { c_dictConfig, "x", true } },
|
|
{ "l0_only", { c_dictConfig, "a", true } },
|
|
{ "l1", { c_dictConfig, "y", true } },
|
|
{ "l1_only", { c_dictConfig, "b", true } },
|
|
};
|
|
|
|
for (const auto& [sName, params] : mapData)
|
|
{
|
|
const auto& [vConfig, sPath, fExpected] = params;
|
|
DYNAMIC_SECTION(sName)
|
|
{
|
|
REQUIRE_NOTHROW(fnScenario(vConfig, sPath, fExpected));
|
|
}
|
|
}
|
|
}
|