Add AZ::Dom::Patch, a Generic DOM analog to JSON patch
- Currently supports JSON patch operations (add/remove/replace/copy/move/test) - `GenerateHierarchicalDeltaPatch` provides a patch generation mechanism that produces forward and inverse patches - Patch application comes with a `PatchApplicationStrategy` functor that allows customizing behavior for patch failure that may be useful for the prefab system - Serialization to/from JSON patch by way of `AZ::Dom::Value` is supported Benchmarks provided, split into three categories on the Dom value benchmark payload (payloads with up to 10k entries populated with strings up to 100 characters in length): - Patch generation based on a deep copy of the affected data ``` DomPatchBenchmark/AzDomPatch_Generate_SimpleReplace_DeepCopy/10/5 0.024 ms 0.024 ms 29867 items_per_second=41.5541k/s DomPatchBenchmark/AzDomPatch_Generate_SimpleReplace_DeepCopy/10/500 0.024 ms 0.024 ms 29867 items_per_second=41.5541k/s DomPatchBenchmark/AzDomPatch_Generate_SimpleReplace_DeepCopy/100/5 0.346 ms 0.345 ms 2036 items_per_second=2.89564k/s DomPatchBenchmark/AzDomPatch_Generate_SimpleReplace_DeepCopy/100/500 0.375 ms 0.377 ms 1867 items_per_second=2.65529k/s DomPatchBenchmark/AzDomPatch_Generate_TopLevelReplace/10/5 0.003 ms 0.003 ms 203636 items_per_second=289.616k/s DomPatchBenchmark/AzDomPatch_Generate_TopLevelReplace/10/500 0.004 ms 0.004 ms 194783 items_per_second=283.321k/s DomPatchBenchmark/AzDomPatch_Generate_TopLevelReplace/100/5 0.003 ms 0.003 ms 203636 items_per_second=289.616k/s DomPatchBenchmark/AzDomPatch_Generate_TopLevelReplace/100/500 0.004 ms 0.004 ms 194783 items_per_second=271.002k/s DomPatchBenchmark/AzDomPatch_Generate_KeyRemove_DeepCopy/10/5 0.023 ms 0.024 ms 29867 items_per_second=42.4775k/s DomPatchBenchmark/AzDomPatch_Generate_KeyRemove_DeepCopy/10/500 0.023 ms 0.023 ms 28000 items_per_second=42.6667k/s DomPatchBenchmark/AzDomPatch_Generate_KeyRemove_DeepCopy/100/5 0.341 ms 0.337 ms 2133 items_per_second=2.96765k/s DomPatchBenchmark/AzDomPatch_Generate_KeyRemove_DeepCopy/100/500 0.365 ms 0.361 ms 1948 items_per_second=2.77049k/s DomPatchBenchmark/AzDomPatch_Generate_ArrayAppend_DeepCopy/10/5 0.023 ms 0.023 ms 29867 items_per_second=43.4429k/s DomPatchBenchmark/AzDomPatch_Generate_ArrayAppend_DeepCopy/10/500 0.023 ms 0.024 ms 29867 items_per_second=42.4775k/s DomPatchBenchmark/AzDomPatch_Generate_ArrayAppend_DeepCopy/100/5 0.330 ms 0.330 ms 2133 items_per_second=3.0336k/s DomPatchBenchmark/AzDomPatch_Generate_ArrayAppend_DeepCopy/100/500 0.359 ms 0.360 ms 1867 items_per_second=2.77879k/s DomPatchBenchmark/AzDomPatch_Generate_ArrayPrepend_DeepCopy/10/5 0.023 ms 0.022 ms 29867 items_per_second=44.4532k/s DomPatchBenchmark/AzDomPatch_Generate_ArrayPrepend_DeepCopy/10/500 0.023 ms 0.023 ms 32000 items_per_second=43.5745k/s DomPatchBenchmark/AzDomPatch_Generate_ArrayPrepend_DeepCopy/100/5 0.329 ms 0.330 ms 2133 items_per_second=3.0336k/s DomPatchBenchmark/AzDomPatch_Generate_ArrayPrepend_DeepCopy/100/500 0.357 ms 0.361 ms 1948 items_per_second=2.77049k/s ``` - Patch generation based on a shallow copy of the affected data (this is faster because when using Dom::Value to copy and mutate, we can bypass expensive array and object comparisons for identical values) ``` DomPatchBenchmark/AzDomPatch_Generate_SimpleReplace_ShallowCopy/10/5 0.010 ms 0.010 ms 74667 items_per_second=99.556k/s DomPatchBenchmark/AzDomPatch_Generate_SimpleReplace_ShallowCopy/10/500 0.010 ms 0.010 ms 74667 items_per_second=97.5242k/s DomPatchBenchmark/AzDomPatch_Generate_SimpleReplace_ShallowCopy/100/5 0.079 ms 0.078 ms 8960 items_per_second=12.7431k/s DomPatchBenchmark/AzDomPatch_Generate_SimpleReplace_ShallowCopy/100/500 0.087 ms 0.087 ms 8960 items_per_second=11.4688k/s DomPatchBenchmark/AzDomPatch_Generate_KeyRemove_ShallowCopy/10/5 0.009 ms 0.009 ms 74667 items_per_second=116.553k/s DomPatchBenchmark/AzDomPatch_Generate_KeyRemove_ShallowCopy/10/500 0.009 ms 0.009 ms 74667 items_per_second=113.778k/s DomPatchBenchmark/AzDomPatch_Generate_KeyRemove_ShallowCopy/100/5 0.072 ms 0.071 ms 8960 items_per_second=13.9863k/s DomPatchBenchmark/AzDomPatch_Generate_KeyRemove_ShallowCopy/100/500 0.087 ms 0.088 ms 7467 items_per_second=11.3783k/s DomPatchBenchmark/AzDomPatch_Generate_ArrayAppend_ShallowCopy/10/5 0.014 ms 0.014 ms 49778 items_per_second=72.4044k/s DomPatchBenchmark/AzDomPatch_Generate_ArrayAppend_ShallowCopy/10/500 0.014 ms 0.014 ms 56000 items_per_second=70.2745k/s DomPatchBenchmark/AzDomPatch_Generate_ArrayAppend_ShallowCopy/100/5 0.118 ms 0.117 ms 5600 items_per_second=8.53333k/s DomPatchBenchmark/AzDomPatch_Generate_ArrayAppend_ShallowCopy/100/500 0.140 ms 0.141 ms 4978 items_per_second=7.07982k/s DomPatchBenchmark/AzDomPatch_Generate_ArrayPrepend_ShallowCopy/10/5 0.009 ms 0.009 ms 89600 items_per_second=108.196k/s DomPatchBenchmark/AzDomPatch_Generate_ArrayPrepend_ShallowCopy/10/500 0.009 ms 0.009 ms 74667 items_per_second=108.607k/s DomPatchBenchmark/AzDomPatch_Generate_ArrayPrepend_ShallowCopy/100/5 0.068 ms 0.068 ms 11200 items_per_second=14.6286k/s DomPatchBenchmark/AzDomPatch_Generate_ArrayPrepend_ShallowCopy/100/500 0.082 ms 0.082 ms 8960 items_per_second=12.2009k/s ``` - Patch application ``` DomPatchBenchmark/AzDomPatch_Apply_SimpleReplace_ShallowCopy/10/5 0.001 ms 0.001 ms 560000 items_per_second=874.146k/s DomPatchBenchmark/AzDomPatch_Apply_SimpleReplace_ShallowCopy/10/500 0.001 ms 0.001 ms 560000 items_per_second=874.146k/s DomPatchBenchmark/AzDomPatch_Apply_SimpleReplace_ShallowCopy/100/5 0.004 ms 0.004 ms 172308 items_per_second=250.63k/s DomPatchBenchmark/AzDomPatch_Apply_SimpleReplace_ShallowCopy/100/500 0.004 ms 0.004 ms 179200 items_per_second=260.655k/s DomPatchBenchmark/AzDomPatch_Apply_SimpleReplace_DeepCopy/10/5 0.005 ms 0.005 ms 112000 items_per_second=193.73k/s DomPatchBenchmark/AzDomPatch_Apply_SimpleReplace_DeepCopy/10/500 0.005 ms 0.005 ms 112000 items_per_second=193.73k/s DomPatchBenchmark/AzDomPatch_Apply_SimpleReplace_DeepCopy/100/5 0.052 ms 0.052 ms 10000 items_per_second=19.3939k/s DomPatchBenchmark/AzDomPatch_Apply_SimpleReplace_DeepCopy/100/500 0.052 ms 0.052 ms 11200 items_per_second=19.373k/s DomPatchBenchmark/AzDomPatch_Apply_TopLevelReplace/10/5 0.001 ms 0.001 ms 640000 items_per_second=910.222k/s DomPatchBenchmark/AzDomPatch_Apply_TopLevelReplace/10/500 0.001 ms 0.001 ms 640000 items_per_second=910.222k/s DomPatchBenchmark/AzDomPatch_Apply_TopLevelReplace/100/5 0.001 ms 0.001 ms 640000 items_per_second=910.222k/s DomPatchBenchmark/AzDomPatch_Apply_TopLevelReplace/100/500 0.001 ms 0.001 ms 640000 items_per_second=910.222k/s DomPatchBenchmark/AzDomPatch_Apply_KeyRemove_ShallowCopy/10/5 0.001 ms 0.001 ms 560000 items_per_second=896k/s DomPatchBenchmark/AzDomPatch_Apply_KeyRemove_ShallowCopy/10/500 0.001 ms 0.001 ms 640000 items_per_second=871.489k/s DomPatchBenchmark/AzDomPatch_Apply_KeyRemove_ShallowCopy/100/5 0.004 ms 0.004 ms 160000 items_per_second=232.727k/s DomPatchBenchmark/AzDomPatch_Apply_KeyRemove_ShallowCopy/100/500 0.004 ms 0.004 ms 165926 items_per_second=235.984k/s DomPatchBenchmark/AzDomPatch_Apply_KeyRemove_DeepCopy/10/5 0.005 ms 0.005 ms 112000 items_per_second=193.73k/s DomPatchBenchmark/AzDomPatch_Apply_KeyRemove_DeepCopy/10/500 0.005 ms 0.005 ms 112000 items_per_second=193.73k/s DomPatchBenchmark/AzDomPatch_Apply_KeyRemove_DeepCopy/100/5 0.053 ms 0.053 ms 10000 items_per_second=18.8235k/s DomPatchBenchmark/AzDomPatch_Apply_KeyRemove_DeepCopy/100/500 0.051 ms 0.052 ms 10000 items_per_second=19.3939k/s DomPatchBenchmark/AzDomPatch_Apply_ArrayAppend_ShallowCopy/10/5 0.001 ms 0.001 ms 497778 items_per_second=692.561k/s DomPatchBenchmark/AzDomPatch_Apply_ArrayAppend_ShallowCopy/10/500 0.001 ms 0.001 ms 497778 items_per_second=692.561k/s DomPatchBenchmark/AzDomPatch_Apply_ArrayAppend_ShallowCopy/100/5 0.006 ms 0.006 ms 112000 items_per_second=174.829k/s DomPatchBenchmark/AzDomPatch_Apply_ArrayAppend_ShallowCopy/100/500 0.006 ms 0.006 ms 100000 items_per_second=177.778k/s DomPatchBenchmark/AzDomPatch_Apply_ArrayAppend_DeepCopy/10/5 0.005 ms 0.005 ms 112000 items_per_second=193.73k/s DomPatchBenchmark/AzDomPatch_Apply_ArrayAppend_DeepCopy/10/500 0.005 ms 0.005 ms 100000 items_per_second=188.235k/s DomPatchBenchmark/AzDomPatch_Apply_ArrayAppend_DeepCopy/100/5 0.053 ms 0.052 ms 11200 items_per_second=19.373k/s DomPatchBenchmark/AzDomPatch_Apply_ArrayAppend_DeepCopy/100/500 0.052 ms 0.053 ms 11200 items_per_second=18.8632k/s DomPatchBenchmark/AzDomPatch_Apply_ArrayPrepend_ShallowCopy/10/5 0.001 ms 0.001 ms 560000 items_per_second=874.146k/s DomPatchBenchmark/AzDomPatch_Apply_ArrayPrepend_ShallowCopy/10/500 0.001 ms 0.001 ms 560000 items_per_second=874.146k/s DomPatchBenchmark/AzDomPatch_Apply_ArrayPrepend_ShallowCopy/100/5 0.004 ms 0.004 ms 179200 items_per_second=260.655k/s DomPatchBenchmark/AzDomPatch_Apply_ArrayPrepend_ShallowCopy/100/500 0.004 ms 0.004 ms 179200 items_per_second=260.655k/s DomPatchBenchmark/AzDomPatch_Apply_ArrayPrepend_DeepCopy/10/5 0.005 ms 0.005 ms 100000 items_per_second=193.939k/s DomPatchBenchmark/AzDomPatch_Apply_ArrayPrepend_DeepCopy/10/500 0.005 ms 0.005 ms 100000 items_per_second=193.939k/s DomPatchBenchmark/AzDomPatch_Apply_ArrayPrepend_DeepCopy/100/5 0.052 ms 0.052 ms 11200 items_per_second=19.373k/s DomPatchBenchmark/AzDomPatch_Apply_ArrayPrepend_DeepCopy/100/500 0.053 ms 0.053 ms 10000 items_per_second=18.8235k/s ``` At a glance, patch generation using `GenerateHierarchicalDeltaPatch` is slower than applying its created patches, but not prohibitively so. Ideally patches shouldn't be recreated unnecessarily, but especially when diffing `Value`s that have been copied and then mutated, a generate + apply operation similar to what prefabs currently do is reasonably fast. Signed-off-by: Nicholas Van Sickle <nvsickle@amazon.com>
This commit is contained in:
@@ -0,0 +1,179 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project.
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#include <AzCore/DOM/DomPatch.h>
|
||||
#include <AzCore/DOM/DomUtils.h>
|
||||
#include <AzCore/DOM/DomValue.h>
|
||||
#include <AzCore/Name/NameDictionary.h>
|
||||
#include <AzCore/UnitTest/TestTypes.h>
|
||||
#include <Tests/DOM/DomFixtures.h>
|
||||
|
||||
namespace AZ::Dom::Benchmark
|
||||
{
|
||||
class DomPatchBenchmark : public Tests::DomBenchmarkFixture
|
||||
{
|
||||
public:
|
||||
void TearDownHarness() override
|
||||
{
|
||||
m_before = {};
|
||||
m_after = {};
|
||||
Tests::DomBenchmarkFixture::TearDownHarness();
|
||||
}
|
||||
|
||||
void SimpleReplace(benchmark::State& state, bool deepCopy, bool apply)
|
||||
{
|
||||
m_before = GenerateDomBenchmarkPayload(state.range(0), state.range(1));
|
||||
m_after = deepCopy ? Utils::DeepCopy(m_before) : m_before;
|
||||
m_after["entries"]["Key0"] = Value("replacement string", true);
|
||||
|
||||
RunBenchmarkInternal(state, apply);
|
||||
}
|
||||
|
||||
void TopLevelReplace(benchmark::State& state, bool apply)
|
||||
{
|
||||
m_before = GenerateDomBenchmarkPayload(state.range(0), state.range(1));
|
||||
m_after = Value(Type::Object);
|
||||
m_after["UnrelatedKey"] = Value(42);
|
||||
|
||||
RunBenchmarkInternal(state, apply);
|
||||
}
|
||||
|
||||
void KeyRemove(benchmark::State& state, bool deepCopy, bool apply)
|
||||
{
|
||||
m_before = GenerateDomBenchmarkPayload(state.range(0), state.range(1));
|
||||
m_after = deepCopy ? Utils::DeepCopy(m_before) : m_before;
|
||||
m_after["entries"].RemoveMember("Key1");
|
||||
|
||||
RunBenchmarkInternal(state, apply);
|
||||
}
|
||||
|
||||
void ArrayAppend(benchmark::State& state, bool deepCopy, bool apply)
|
||||
{
|
||||
m_before = GenerateDomBenchmarkPayload(state.range(0), state.range(1));
|
||||
m_after = deepCopy ? Utils::DeepCopy(m_before) : m_before;
|
||||
m_after["entries"]["Key2"].ArrayPushBack(Value(0));
|
||||
|
||||
RunBenchmarkInternal(state, apply);
|
||||
}
|
||||
|
||||
void ArrayPrepend(benchmark::State& state, bool deepCopy, bool apply)
|
||||
{
|
||||
m_before = GenerateDomBenchmarkPayload(state.range(0), state.range(1));
|
||||
m_after = deepCopy ? Utils::DeepCopy(m_before) : m_before;
|
||||
auto& arr = m_after["entries"]["Key2"].GetMutableArray();
|
||||
arr.insert(arr.begin(), Value(42));
|
||||
|
||||
RunBenchmarkInternal(state, apply);
|
||||
}
|
||||
|
||||
private:
|
||||
void RunBenchmarkInternal(benchmark::State& state, bool apply)
|
||||
{
|
||||
if (apply)
|
||||
{
|
||||
auto patchInfo = GenerateHierarchicalDeltaPatch(m_before, m_after);
|
||||
for (auto _ : state)
|
||||
{
|
||||
auto patchResult = patchInfo.m_forwardPatches.Apply(m_before);
|
||||
benchmark::DoNotOptimize(patchResult);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (auto _ : state)
|
||||
{
|
||||
auto patchInfo = GenerateHierarchicalDeltaPatch(m_before, m_after);
|
||||
benchmark::DoNotOptimize(patchInfo);
|
||||
}
|
||||
}
|
||||
|
||||
state.SetItemsProcessed(state.iterations());
|
||||
}
|
||||
|
||||
Value m_before;
|
||||
Value m_after;
|
||||
};
|
||||
|
||||
BENCHMARK_DEFINE_F(DomPatchBenchmark, AzDomPatch_Generate_SimpleReplace_ShallowCopy)(benchmark::State& state)
|
||||
{
|
||||
SimpleReplace(state, false, false);
|
||||
}
|
||||
DOM_REGISTER_SERIALIZATION_BENCHMARK_MS(DomPatchBenchmark, AzDomPatch_Generate_SimpleReplace_ShallowCopy)
|
||||
|
||||
BENCHMARK_DEFINE_F(DomPatchBenchmark, AzDomPatch_Generate_SimpleReplace_DeepCopy)(benchmark::State& state)
|
||||
{
|
||||
SimpleReplace(state, true, false);
|
||||
}
|
||||
DOM_REGISTER_SERIALIZATION_BENCHMARK_MS(DomPatchBenchmark, AzDomPatch_Generate_SimpleReplace_DeepCopy)
|
||||
|
||||
BENCHMARK_DEFINE_F(DomPatchBenchmark, AzDomPatch_Generate_TopLevelReplace)(benchmark::State& state)
|
||||
{
|
||||
TopLevelReplace(state, false);
|
||||
}
|
||||
DOM_REGISTER_SERIALIZATION_BENCHMARK_MS(DomPatchBenchmark, AzDomPatch_Generate_TopLevelReplace)
|
||||
|
||||
BENCHMARK_DEFINE_F(DomPatchBenchmark, AzDomPatch_Generate_KeyRemove_ShallowCopy)(benchmark::State& state)
|
||||
{
|
||||
KeyRemove(state, false, false);
|
||||
}
|
||||
DOM_REGISTER_SERIALIZATION_BENCHMARK_MS(DomPatchBenchmark, AzDomPatch_Generate_KeyRemove_ShallowCopy)
|
||||
|
||||
BENCHMARK_DEFINE_F(DomPatchBenchmark, AzDomPatch_Generate_KeyRemove_DeepCopy)(benchmark::State& state)
|
||||
{
|
||||
KeyRemove(state, true, false);
|
||||
}
|
||||
DOM_REGISTER_SERIALIZATION_BENCHMARK_MS(DomPatchBenchmark, AzDomPatch_Generate_KeyRemove_DeepCopy)
|
||||
|
||||
BENCHMARK_DEFINE_F(DomPatchBenchmark, AzDomPatch_Generate_ArrayAppend_ShallowCopy)(benchmark::State& state)
|
||||
{
|
||||
ArrayAppend(state, false, false);
|
||||
}
|
||||
DOM_REGISTER_SERIALIZATION_BENCHMARK_MS(DomPatchBenchmark, AzDomPatch_Generate_ArrayAppend_ShallowCopy)
|
||||
|
||||
BENCHMARK_DEFINE_F(DomPatchBenchmark, AzDomPatch_Generate_ArrayAppend_DeepCopy)(benchmark::State& state)
|
||||
{
|
||||
ArrayAppend(state, true, false);
|
||||
}
|
||||
DOM_REGISTER_SERIALIZATION_BENCHMARK_MS(DomPatchBenchmark, AzDomPatch_Generate_ArrayAppend_DeepCopy)
|
||||
|
||||
BENCHMARK_DEFINE_F(DomPatchBenchmark, AzDomPatch_Generate_ArrayPrepend)(benchmark::State& state)
|
||||
{
|
||||
ArrayPrepend(state, true, false);
|
||||
}
|
||||
DOM_REGISTER_SERIALIZATION_BENCHMARK_MS(DomPatchBenchmark, AzDomPatch_Generate_ArrayPrepend)
|
||||
|
||||
BENCHMARK_DEFINE_F(DomPatchBenchmark, AzDomPatch_Apply_SimpleReplace)(benchmark::State& state)
|
||||
{
|
||||
SimpleReplace(state, true, true);
|
||||
}
|
||||
DOM_REGISTER_SERIALIZATION_BENCHMARK_MS(DomPatchBenchmark, AzDomPatch_Apply_SimpleReplace)
|
||||
|
||||
BENCHMARK_DEFINE_F(DomPatchBenchmark, AzDomPatch_Apply_TopLevelReplace)(benchmark::State& state)
|
||||
{
|
||||
TopLevelReplace(state, true);
|
||||
}
|
||||
DOM_REGISTER_SERIALIZATION_BENCHMARK_MS(DomPatchBenchmark, AzDomPatch_Apply_TopLevelReplace)
|
||||
|
||||
BENCHMARK_DEFINE_F(DomPatchBenchmark, AzDomPatch_Apply_KeyRemove)(benchmark::State& state)
|
||||
{
|
||||
KeyRemove(state, true, true);
|
||||
}
|
||||
DOM_REGISTER_SERIALIZATION_BENCHMARK_MS(DomPatchBenchmark, AzDomPatch_Apply_KeyRemove)
|
||||
|
||||
BENCHMARK_DEFINE_F(DomPatchBenchmark, AzDomPatch_Apply_ArrayAppend)(benchmark::State& state)
|
||||
{
|
||||
ArrayAppend(state, true, true);
|
||||
}
|
||||
DOM_REGISTER_SERIALIZATION_BENCHMARK_MS(DomPatchBenchmark, AzDomPatch_Apply_ArrayAppend)
|
||||
|
||||
BENCHMARK_DEFINE_F(DomPatchBenchmark, AzDomPatch_Apply_ArrayPrepend)(benchmark::State& state)
|
||||
{
|
||||
ArrayPrepend(state, true, true);
|
||||
}
|
||||
DOM_REGISTER_SERIALIZATION_BENCHMARK_MS(DomPatchBenchmark, AzDomPatch_Apply_ArrayPrepend)
|
||||
} // namespace AZ::Dom::Benchmark
|
||||
@@ -0,0 +1,562 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project.
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#include <AzCore/DOM/DomPatch.h>
|
||||
#include <Tests/DOM/DomFixtures.h>
|
||||
|
||||
namespace AZ::Dom::Tests
|
||||
{
|
||||
class DomPatchTests : public DomTestFixture
|
||||
{
|
||||
public:
|
||||
void SetUp() override
|
||||
{
|
||||
DomTestFixture::SetUp();
|
||||
|
||||
m_dataset = Value(Type::Object);
|
||||
m_dataset["arr"].SetArray();
|
||||
|
||||
m_dataset["node"].SetNode("SomeNode");
|
||||
m_dataset["node"]["int"] = 5;
|
||||
m_dataset["node"]["null"] = Value();
|
||||
|
||||
for (int i = 0; i < 5; ++i)
|
||||
{
|
||||
m_dataset["arr"].ArrayPushBack(Value(i));
|
||||
m_dataset["node"].ArrayPushBack(Value(i * 2));
|
||||
}
|
||||
|
||||
m_dataset["obj"].SetObject();
|
||||
m_dataset["obj"]["foo"] = true;
|
||||
m_dataset["obj"]["bar"] = false;
|
||||
|
||||
m_deltaDataset = m_dataset;
|
||||
}
|
||||
|
||||
void TearDown() override
|
||||
{
|
||||
m_dataset = m_deltaDataset = Value();
|
||||
|
||||
DomTestFixture::TearDown();
|
||||
}
|
||||
|
||||
PatchInfo GenerateAndVerifyDelta()
|
||||
{
|
||||
PatchInfo info = GenerateHierarchicalDeltaPatch(m_dataset, m_deltaDataset);
|
||||
|
||||
auto result = info.m_forwardPatches.Apply(m_dataset);
|
||||
EXPECT_TRUE(result.IsSuccess());
|
||||
EXPECT_TRUE(Utils::DeepCompareIsEqual(result.GetValue(), m_deltaDataset));
|
||||
|
||||
result = info.m_inversePatches.Apply(result.GetValue());
|
||||
EXPECT_TRUE(result.IsSuccess());
|
||||
EXPECT_TRUE(Utils::DeepCompareIsEqual(result.GetValue(), m_dataset));
|
||||
|
||||
// Verify serialization of the patches
|
||||
auto VerifySerialization = [](const Patch& patch)
|
||||
{
|
||||
Value serializedPatch = patch.GetDomRepresentation();
|
||||
auto deserializePatchResult = Patch::CreateFromDomRepresentation(serializedPatch);
|
||||
EXPECT_TRUE(deserializePatchResult.IsSuccess());
|
||||
EXPECT_EQ(deserializePatchResult.GetValue(), patch);
|
||||
};
|
||||
VerifySerialization(info.m_forwardPatches);
|
||||
VerifySerialization(info.m_inversePatches);
|
||||
|
||||
return info;
|
||||
}
|
||||
|
||||
Value m_dataset;
|
||||
Value m_deltaDataset;
|
||||
};
|
||||
|
||||
TEST_F(DomPatchTests, AddOperation_InsertInObject_Succeeds)
|
||||
{
|
||||
Path p("/obj/baz");
|
||||
PatchOperation op = PatchOperation::AddOperation(p, Value(42));
|
||||
auto result = op.Apply(m_dataset);
|
||||
ASSERT_TRUE(result.IsSuccess());
|
||||
EXPECT_EQ(result.GetValue()[p].GetInt64(), 42);
|
||||
}
|
||||
|
||||
TEST_F(DomPatchTests, AddOperation_ReplaceInObject_Succeeds)
|
||||
{
|
||||
Path p("/obj/foo");
|
||||
PatchOperation op = PatchOperation::AddOperation(p, Value(false));
|
||||
auto result = op.Apply(m_dataset);
|
||||
ASSERT_TRUE(result.IsSuccess());
|
||||
EXPECT_EQ(result.GetValue()[p].GetBool(), false);
|
||||
}
|
||||
|
||||
TEST_F(DomPatchTests, AddOperation_InsertObjectKeyInArray_Fails)
|
||||
{
|
||||
Path p("/arr/key");
|
||||
PatchOperation op = PatchOperation::AddOperation(p, Value(999));
|
||||
auto result = op.Apply(m_dataset);
|
||||
ASSERT_FALSE(result.IsSuccess());
|
||||
}
|
||||
|
||||
TEST_F(DomPatchTests, AddOperation_AppendInArray_Succeeds)
|
||||
{
|
||||
Path p("/arr/-");
|
||||
PatchOperation op = PatchOperation::AddOperation(p, Value(42));
|
||||
auto result = op.Apply(m_dataset);
|
||||
ASSERT_TRUE(result.IsSuccess());
|
||||
EXPECT_EQ(result.GetValue()["arr"][5].GetInt64(), 42);
|
||||
}
|
||||
|
||||
TEST_F(DomPatchTests, AddOperation_InsertKeyInNode_Succeeds)
|
||||
{
|
||||
Path p("/node/attr");
|
||||
PatchOperation op = PatchOperation::AddOperation(p, Value(500));
|
||||
auto result = op.Apply(m_dataset);
|
||||
ASSERT_TRUE(result.IsSuccess());
|
||||
EXPECT_EQ(result.GetValue()[p].GetInt64(), 500);
|
||||
}
|
||||
|
||||
TEST_F(DomPatchTests, AddOperation_ReplaceIndexInNode_Succeeds)
|
||||
{
|
||||
Path p("/node/0");
|
||||
PatchOperation op = PatchOperation::AddOperation(p, Value(42));
|
||||
auto result = op.Apply(m_dataset);
|
||||
ASSERT_TRUE(result.IsSuccess());
|
||||
EXPECT_EQ(result.GetValue()[p].GetInt64(), 42);
|
||||
}
|
||||
|
||||
TEST_F(DomPatchTests, AddOperation_AppendInNode_Succeeds)
|
||||
{
|
||||
Path p("/node/-");
|
||||
PatchOperation op = PatchOperation::AddOperation(p, Value(42));
|
||||
auto result = op.Apply(m_dataset);
|
||||
ASSERT_TRUE(result.IsSuccess());
|
||||
EXPECT_EQ(result.GetValue()["node"][5].GetInt64(), 42);
|
||||
}
|
||||
|
||||
TEST_F(DomPatchTests, AddOperation_InvalidPath_Fails)
|
||||
{
|
||||
Path p("/non/existent/path");
|
||||
PatchOperation op = PatchOperation::AddOperation(p, Value(0));
|
||||
auto result = op.Apply(m_dataset);
|
||||
ASSERT_FALSE(result.IsSuccess());
|
||||
}
|
||||
|
||||
TEST_F(DomPatchTests, RemoveOperation_RemoveKeyFromObject_Succeeds)
|
||||
{
|
||||
Path p("/obj/foo");
|
||||
PatchOperation op = PatchOperation::RemoveOperation(p);
|
||||
auto result = op.Apply(m_dataset);
|
||||
ASSERT_TRUE(result.IsSuccess());
|
||||
EXPECT_FALSE(result.GetValue()["obj"].HasMember("foo"));
|
||||
}
|
||||
|
||||
TEST_F(DomPatchTests, RemoveOperation_RemoveIndexFromArray_Succeeds)
|
||||
{
|
||||
Path p("/arr/0");
|
||||
PatchOperation op = PatchOperation::RemoveOperation(p);
|
||||
auto result = op.Apply(m_dataset);
|
||||
ASSERT_TRUE(result.IsSuccess());
|
||||
EXPECT_EQ(result.GetValue()["arr"].ArraySize(), 4);
|
||||
EXPECT_EQ(result.GetValue()["arr"][0].GetInt64(), 1);
|
||||
}
|
||||
|
||||
TEST_F(DomPatchTests, RemoveOperation_PopArray_Succeeds)
|
||||
{
|
||||
Path p("/arr/-");
|
||||
PatchOperation op = PatchOperation::RemoveOperation(p);
|
||||
auto result = op.Apply(m_dataset);
|
||||
EXPECT_EQ(result.GetValue()["arr"].ArraySize(), 4);
|
||||
}
|
||||
|
||||
TEST_F(DomPatchTests, RemoveOperation_RemoveKeyFromNode_Succeeds)
|
||||
{
|
||||
Path p("/node/int");
|
||||
PatchOperation op = PatchOperation::RemoveOperation(p);
|
||||
auto result = op.Apply(m_dataset);
|
||||
ASSERT_TRUE(result.IsSuccess());
|
||||
EXPECT_FALSE(result.GetValue()["node"].HasMember("int"));
|
||||
}
|
||||
|
||||
TEST_F(DomPatchTests, RemoveOperation_RemoveIndexFromNode_Succeeds)
|
||||
{
|
||||
Path p("/node/1");
|
||||
PatchOperation op = PatchOperation::RemoveOperation(p);
|
||||
auto result = op.Apply(m_dataset);
|
||||
ASSERT_TRUE(result.IsSuccess());
|
||||
EXPECT_EQ(result.GetValue()["node"].ArraySize(), 4);
|
||||
EXPECT_EQ(result.GetValue()["node"][1].GetInt64(), 4);
|
||||
}
|
||||
|
||||
TEST_F(DomPatchTests, RemoveOperation_PopIndexFromNode_Succeeds)
|
||||
{
|
||||
Path p("/node/-");
|
||||
PatchOperation op = PatchOperation::RemoveOperation(p);
|
||||
auto result = op.Apply(m_dataset);
|
||||
ASSERT_TRUE(result.IsSuccess());
|
||||
EXPECT_EQ(result.GetValue()["node"].ArraySize(), 4);
|
||||
}
|
||||
|
||||
TEST_F(DomPatchTests, RemoveOperation_RemoveKeyFromArray_Fails)
|
||||
{
|
||||
Path p("/arr/foo");
|
||||
PatchOperation op = PatchOperation::RemoveOperation(p);
|
||||
auto result = op.Apply(m_dataset);
|
||||
ASSERT_FALSE(result.IsSuccess());
|
||||
}
|
||||
|
||||
TEST_F(DomPatchTests, RemoveOperation_InvalidPath_Fails)
|
||||
{
|
||||
Path p("/non/existent/path");
|
||||
PatchOperation op = PatchOperation::RemoveOperation(p);
|
||||
auto result = op.Apply(m_dataset);
|
||||
ASSERT_FALSE(result.IsSuccess());
|
||||
}
|
||||
|
||||
TEST_F(DomPatchTests, ReplaceOperation_InsertInObject_Fails)
|
||||
{
|
||||
Path p("/obj/baz");
|
||||
PatchOperation op = PatchOperation::ReplaceOperation(p, Value(42));
|
||||
auto result = op.Apply(m_dataset);
|
||||
ASSERT_FALSE(result.IsSuccess());
|
||||
}
|
||||
|
||||
TEST_F(DomPatchTests, ReplaceOperation_ReplaceInObject_Succeeds)
|
||||
{
|
||||
Path p("/obj/foo");
|
||||
PatchOperation op = PatchOperation::ReplaceOperation(p, Value(false));
|
||||
auto result = op.Apply(m_dataset);
|
||||
ASSERT_TRUE(result.IsSuccess());
|
||||
EXPECT_EQ(result.GetValue()[p].GetBool(), false);
|
||||
}
|
||||
|
||||
TEST_F(DomPatchTests, ReplaceOperation_InsertObjectKeyInArray_Fails)
|
||||
{
|
||||
Path p("/arr/key");
|
||||
PatchOperation op = PatchOperation::ReplaceOperation(p, Value(999));
|
||||
auto result = op.Apply(m_dataset);
|
||||
ASSERT_FALSE(result.IsSuccess());
|
||||
}
|
||||
|
||||
TEST_F(DomPatchTests, ReplaceOperation_AppendInArray_Fails)
|
||||
{
|
||||
Path p("/arr/-");
|
||||
PatchOperation op = PatchOperation::ReplaceOperation(p, Value(42));
|
||||
auto result = op.Apply(m_dataset);
|
||||
ASSERT_FALSE(result.IsSuccess());
|
||||
}
|
||||
|
||||
TEST_F(DomPatchTests, ReplaceOperation_InsertKeyInNode_Fails)
|
||||
{
|
||||
Path p("/node/attr");
|
||||
PatchOperation op = PatchOperation::ReplaceOperation(p, Value(500));
|
||||
auto result = op.Apply(m_dataset);
|
||||
ASSERT_FALSE(result.IsSuccess());
|
||||
}
|
||||
|
||||
TEST_F(DomPatchTests, ReplaceOperation_ReplaceIndexInNode_Succeeds)
|
||||
{
|
||||
Path p("/node/0");
|
||||
PatchOperation op = PatchOperation::ReplaceOperation(p, Value(42));
|
||||
auto result = op.Apply(m_dataset);
|
||||
ASSERT_TRUE(result.IsSuccess());
|
||||
EXPECT_EQ(result.GetValue()[p].GetInt64(), 42);
|
||||
}
|
||||
|
||||
TEST_F(DomPatchTests, ReplaceOperation_AppendInNode_Fails)
|
||||
{
|
||||
Path p("/node/-");
|
||||
PatchOperation op = PatchOperation::ReplaceOperation(p, Value(42));
|
||||
auto result = op.Apply(m_dataset);
|
||||
ASSERT_FALSE(result.IsSuccess());
|
||||
}
|
||||
|
||||
TEST_F(DomPatchTests, ReplaceOperation_InvalidPath_Fails)
|
||||
{
|
||||
Path p("/non/existent/path");
|
||||
PatchOperation op = PatchOperation::ReplaceOperation(p, Value(0));
|
||||
auto result = op.Apply(m_dataset);
|
||||
ASSERT_FALSE(result.IsSuccess());
|
||||
}
|
||||
|
||||
TEST_F(DomPatchTests, CopyOperation_ArrayToObject_Succeeds)
|
||||
{
|
||||
Path dest("/obj/arr");
|
||||
Path src("/arr");
|
||||
PatchOperation op = PatchOperation::CopyOperation(dest, src);
|
||||
auto result = op.Apply(m_dataset);
|
||||
ASSERT_TRUE(result.IsSuccess());
|
||||
EXPECT_TRUE(Utils::DeepCompareIsEqual(m_dataset[src], result.GetValue()[dest]));
|
||||
EXPECT_TRUE(Utils::DeepCompareIsEqual(result.GetValue()[src], result.GetValue()[dest]));
|
||||
}
|
||||
|
||||
TEST_F(DomPatchTests, CopyOperation_ObjectToArrayInRange_Succeeds)
|
||||
{
|
||||
Path dest("/arr/0");
|
||||
Path src("/obj");
|
||||
PatchOperation op = PatchOperation::CopyOperation(dest, src);
|
||||
auto result = op.Apply(m_dataset);
|
||||
ASSERT_TRUE(result.IsSuccess());
|
||||
EXPECT_TRUE(Utils::DeepCompareIsEqual(m_dataset[src], result.GetValue()[dest]));
|
||||
EXPECT_TRUE(Utils::DeepCompareIsEqual(result.GetValue()[src], result.GetValue()[dest]));
|
||||
}
|
||||
|
||||
TEST_F(DomPatchTests, CopyOperation_ObjectToArrayOutOfRange_Fails)
|
||||
{
|
||||
Path dest("/arr/5");
|
||||
Path src("/obj");
|
||||
PatchOperation op = PatchOperation::CopyOperation(dest, src);
|
||||
auto result = op.Apply(m_dataset);
|
||||
ASSERT_FALSE(result.IsSuccess());
|
||||
}
|
||||
|
||||
TEST_F(DomPatchTests, CopyOperation_ObjectToNodeChildInRange_Succeeds)
|
||||
{
|
||||
Path dest("/node/0");
|
||||
Path src("/obj");
|
||||
PatchOperation op = PatchOperation::CopyOperation(dest, src);
|
||||
auto result = op.Apply(m_dataset);
|
||||
ASSERT_TRUE(result.IsSuccess());
|
||||
EXPECT_TRUE(Utils::DeepCompareIsEqual(m_dataset[src], result.GetValue()[dest]));
|
||||
EXPECT_TRUE(Utils::DeepCompareIsEqual(result.GetValue()[src], result.GetValue()[dest]));
|
||||
}
|
||||
|
||||
TEST_F(DomPatchTests, CopyOperation_ObjectToNodeChildOutOfRange_Fails)
|
||||
{
|
||||
Path dest("/node/5");
|
||||
Path src("/obj");
|
||||
PatchOperation op = PatchOperation::CopyOperation(dest, src);
|
||||
auto result = op.Apply(m_dataset);
|
||||
ASSERT_FALSE(result.IsSuccess());
|
||||
}
|
||||
|
||||
TEST_F(DomPatchTests, CopyOperation_InvalidSourcePath_Fails)
|
||||
{
|
||||
Path dest("/node/0");
|
||||
Path src("/invalid/path");
|
||||
PatchOperation op = PatchOperation::CopyOperation(dest, src);
|
||||
auto result = op.Apply(m_dataset);
|
||||
ASSERT_FALSE(result.IsSuccess());
|
||||
}
|
||||
|
||||
TEST_F(DomPatchTests, CopyOperation_InvalidDestinationPath_Fails)
|
||||
{
|
||||
Path dest("/invalid/path");
|
||||
Path src("/arr/0");
|
||||
PatchOperation op = PatchOperation::CopyOperation(dest, src);
|
||||
auto result = op.Apply(m_dataset);
|
||||
ASSERT_FALSE(result.IsSuccess());
|
||||
}
|
||||
|
||||
TEST_F(DomPatchTests, MoveOperation_ArrayToObject_Succeeds)
|
||||
{
|
||||
Path dest("/obj/arr");
|
||||
Path src("/arr");
|
||||
PatchOperation op = PatchOperation::MoveOperation(dest, src);
|
||||
auto result = op.Apply(m_dataset);
|
||||
ASSERT_TRUE(result.IsSuccess());
|
||||
EXPECT_TRUE(Utils::DeepCompareIsEqual(m_dataset[src], result.GetValue()[dest]));
|
||||
EXPECT_FALSE(result.GetValue().HasMember("arr"));
|
||||
}
|
||||
|
||||
TEST_F(DomPatchTests, MoveOperation_ObjectToArrayInRange_Succeeds)
|
||||
{
|
||||
Path dest("/arr/0");
|
||||
Path src("/obj");
|
||||
PatchOperation op = PatchOperation::MoveOperation(dest, src);
|
||||
auto result = op.Apply(m_dataset);
|
||||
ASSERT_TRUE(result.IsSuccess());
|
||||
EXPECT_TRUE(Utils::DeepCompareIsEqual(m_dataset[src], result.GetValue()[dest]));
|
||||
EXPECT_FALSE(result.GetValue().HasMember("obj"));
|
||||
}
|
||||
|
||||
TEST_F(DomPatchTests, MoveOperation_ObjectToArrayOutOfRange_Fails)
|
||||
{
|
||||
Path dest("/arr/5");
|
||||
Path src("/obj");
|
||||
PatchOperation op = PatchOperation::MoveOperation(dest, src);
|
||||
auto result = op.Apply(m_dataset);
|
||||
ASSERT_FALSE(result.IsSuccess());
|
||||
}
|
||||
|
||||
TEST_F(DomPatchTests, MoveOperation_ObjectToNodeChildInRange_Succeeds)
|
||||
{
|
||||
Path dest("/node/0");
|
||||
Path src("/obj");
|
||||
PatchOperation op = PatchOperation::MoveOperation(dest, src);
|
||||
auto result = op.Apply(m_dataset);
|
||||
ASSERT_TRUE(result.IsSuccess());
|
||||
EXPECT_TRUE(Utils::DeepCompareIsEqual(m_dataset[src], result.GetValue()[dest]));
|
||||
EXPECT_FALSE(result.GetValue().HasMember("obj"));
|
||||
}
|
||||
|
||||
TEST_F(DomPatchTests, MoveOperation_ObjectToNodeChildOutOfRange_Fails)
|
||||
{
|
||||
Path dest("/node/5");
|
||||
Path src("/obj");
|
||||
PatchOperation op = PatchOperation::MoveOperation(dest, src);
|
||||
auto result = op.Apply(m_dataset);
|
||||
ASSERT_FALSE(result.IsSuccess());
|
||||
}
|
||||
|
||||
TEST_F(DomPatchTests, MoveOperation_InvalidSourcePath_Fails)
|
||||
{
|
||||
Path dest("/node/0");
|
||||
Path src("/invalid/path");
|
||||
PatchOperation op = PatchOperation::MoveOperation(dest, src);
|
||||
auto result = op.Apply(m_dataset);
|
||||
ASSERT_FALSE(result.IsSuccess());
|
||||
}
|
||||
|
||||
TEST_F(DomPatchTests, MoveOperation_InvalidDestinationPath_Fails)
|
||||
{
|
||||
Path dest("/invalid/path");
|
||||
Path src("/arr/0");
|
||||
PatchOperation op = PatchOperation::MoveOperation(dest, src);
|
||||
auto result = op.Apply(m_dataset);
|
||||
ASSERT_FALSE(result.IsSuccess());
|
||||
}
|
||||
|
||||
TEST_F(DomPatchTests, TestOperation_TestCorrectValue_Succeeds)
|
||||
{
|
||||
Path path("/arr/1");
|
||||
Value value(1);
|
||||
PatchOperation op = PatchOperation::TestOperation(path, value);
|
||||
auto result = op.Apply(m_dataset);
|
||||
ASSERT_TRUE(result.IsSuccess());
|
||||
}
|
||||
|
||||
TEST_F(DomPatchTests, TestOperation_TestIncorrectValue_Fails)
|
||||
{
|
||||
Path path("/arr/1");
|
||||
Value value(55);
|
||||
PatchOperation op = PatchOperation::TestOperation(path, value);
|
||||
auto result = op.Apply(m_dataset);
|
||||
ASSERT_FALSE(result.IsSuccess());
|
||||
}
|
||||
|
||||
TEST_F(DomPatchTests, TestOperation_TestCorrectComplexValue_Succeeds)
|
||||
{
|
||||
Path path;
|
||||
Value value = m_dataset;
|
||||
PatchOperation op = PatchOperation::TestOperation(path, value);
|
||||
auto result = op.Apply(m_dataset);
|
||||
ASSERT_TRUE(result.IsSuccess());
|
||||
}
|
||||
|
||||
TEST_F(DomPatchTests, TestOperation_TestIncorrectComplexValue_Fails)
|
||||
{
|
||||
Path path;
|
||||
Value value = m_dataset;
|
||||
value["arr"][4] = 9;
|
||||
PatchOperation op = PatchOperation::TestOperation(path, value);
|
||||
auto result = op.Apply(m_dataset);
|
||||
ASSERT_FALSE(result.IsSuccess());
|
||||
}
|
||||
|
||||
TEST_F(DomPatchTests, TestOperation_TestInvalidPath_Fails)
|
||||
{
|
||||
Path path("/invalid/path");
|
||||
Value value;
|
||||
PatchOperation op = PatchOperation::TestOperation(path, value);
|
||||
auto result = op.Apply(m_dataset);
|
||||
ASSERT_FALSE(result.IsSuccess());
|
||||
}
|
||||
|
||||
TEST_F(DomPatchTests, TestOperation_TestInsertArrayPath_Fails)
|
||||
{
|
||||
Path path("/arr/-");
|
||||
Value value(4);
|
||||
PatchOperation op = PatchOperation::TestOperation(path, value);
|
||||
auto result = op.Apply(m_dataset);
|
||||
ASSERT_FALSE(result.IsSuccess());
|
||||
}
|
||||
|
||||
TEST_F(DomPatchTests, TestPatch_ReplaceArrayValue)
|
||||
{
|
||||
m_deltaDataset["arr"][0] = 5;
|
||||
GenerateAndVerifyDelta();
|
||||
}
|
||||
|
||||
TEST_F(DomPatchTests, TestPatch_AppendArrayValue)
|
||||
{
|
||||
m_deltaDataset["arr"].ArrayPushBack(Value(7));
|
||||
auto result = GenerateAndVerifyDelta();
|
||||
|
||||
// Ensure the generated patch uses the array append operation
|
||||
ASSERT_EQ(result.m_forwardPatches.Size(), 1);
|
||||
EXPECT_TRUE(result.m_forwardPatches[0].GetDestinationPath()[1].IsEndOfArray());
|
||||
}
|
||||
|
||||
TEST_F(DomPatchTests, TestPatch_AppendArrayValues)
|
||||
{
|
||||
m_deltaDataset["arr"].ArrayPushBack(Value(7));
|
||||
m_deltaDataset["arr"].ArrayPushBack(Value(8));
|
||||
m_deltaDataset["arr"].ArrayPushBack(Value(9));
|
||||
GenerateAndVerifyDelta();
|
||||
}
|
||||
|
||||
TEST_F(DomPatchTests, TestPatch_InsertArrayValue)
|
||||
{
|
||||
auto& arr = m_deltaDataset["arr"].GetMutableArray();
|
||||
arr.insert(arr.begin(), Value(42));
|
||||
GenerateAndVerifyDelta();
|
||||
}
|
||||
|
||||
TEST_F(DomPatchTests, TestPatch_InsertObjectKey)
|
||||
{
|
||||
m_deltaDataset["obj"]["newKey"].CopyFromString("test");
|
||||
GenerateAndVerifyDelta();
|
||||
}
|
||||
|
||||
TEST_F(DomPatchTests, TestPatch_DeleteObjectKey)
|
||||
{
|
||||
m_deltaDataset["obj"].RemoveMember("foo");
|
||||
GenerateAndVerifyDelta();
|
||||
}
|
||||
|
||||
TEST_F(DomPatchTests, TestPatch_AppendNodeValues)
|
||||
{
|
||||
m_deltaDataset["node"].ArrayPushBack(Value(7));
|
||||
m_deltaDataset["node"].ArrayPushBack(Value(8));
|
||||
m_deltaDataset["node"].ArrayPushBack(Value(9));
|
||||
GenerateAndVerifyDelta();
|
||||
}
|
||||
|
||||
TEST_F(DomPatchTests, TestPatch_InsertNodeValue)
|
||||
{
|
||||
auto& node = m_deltaDataset["node"].GetMutableNode();
|
||||
node.GetChildren().insert(node.GetChildren().begin(), Value(42));
|
||||
GenerateAndVerifyDelta();
|
||||
}
|
||||
|
||||
TEST_F(DomPatchTests, TestPatch_InsertNodeKey)
|
||||
{
|
||||
m_deltaDataset["node"]["newKey"].CopyFromString("test");
|
||||
GenerateAndVerifyDelta();
|
||||
}
|
||||
|
||||
TEST_F(DomPatchTests, TestPatch_DeleteNodeKey)
|
||||
{
|
||||
m_deltaDataset["node"].RemoveMember("int");
|
||||
GenerateAndVerifyDelta();
|
||||
}
|
||||
|
||||
TEST_F(DomPatchTests, TestPatch_RenameNode)
|
||||
{
|
||||
m_deltaDataset["node"].SetNodeName("RenamedNode");
|
||||
GenerateAndVerifyDelta();
|
||||
}
|
||||
|
||||
TEST_F(DomPatchTests, TestPatch_ReplaceRoot)
|
||||
{
|
||||
m_deltaDataset = Value(Type::Array);
|
||||
m_deltaDataset.ArrayPushBack(Value(2));
|
||||
m_deltaDataset.ArrayPushBack(Value(4));
|
||||
m_deltaDataset.ArrayPushBack(Value(6));
|
||||
GenerateAndVerifyDelta();
|
||||
}
|
||||
} // namespace AZ::Dom::Tests
|
||||
Reference in New Issue
Block a user