LUMIERA.clone/tests/library/diff/diff-ignore-changes-test.cpp
Ichthyostega 806db414dd Copyright: clarify and simplify the file headers
* Lumiera source code always was copyrighted by individual contributors
 * there is no entity "Lumiera.org" which holds any copyrights
 * Lumiera source code is provided under the GPL Version 2+

== Explanations ==
Lumiera as a whole is distributed under Copyleft, GNU General Public License Version 2 or above.
For this to become legally effective, the ''File COPYING in the root directory is sufficient.''

The licensing header in each file is not strictly necessary, yet considered good practice;
attaching a licence notice increases the likeliness that this information is retained
in case someone extracts individual code files. However, it is not by the presence of some
text, that legally binding licensing terms become effective; rather the fact matters that a
given piece of code was provably copyrighted and published under a license. Even reformatting
the code, renaming some variables or deleting parts of the code will not alter this legal
situation, but rather creates a derivative work, which is likewise covered by the GPL!

The most relevant information in the file header is the notice regarding the
time of the first individual copyright claim. By virtue of this initial copyright,
the first author is entitled to choose the terms of licensing. All further
modifications are permitted and covered by the License. The specific wording
or format of the copyright header is not legally relevant, as long as the
intention to publish under the GPL remains clear. The extended wording was
based on a recommendation by the FSF. It can be shortened, because the full terms
of the license are provided alongside the distribution, in the file COPYING.
2024-11-17 23:42:55 +01:00

244 lines
8.6 KiB
C++
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
DiffIgnoreChanges(Test) - apply diff to black hole
Copyright (C)
2018, Hermann Vosseler <Ichthyostega@web.de>
  **Lumiera** is free software; you can redistribute it and/or modify it
  under the terms of the GNU General Public License as published by the
  Free Software Foundation; either version 2 of the License, or (at your
  option) any later version. See the file COPYING for further details.
* *****************************************************************/
/** @file diff-ignore-changes-test.cpp
** unit test \ref DiffIgnoreChanges_test.
** Covers the special case of a TreeMutator configured to accept
** any diff without actually doing anything.
*/
#include "lib/test/run.hpp"
#include "lib/test/test-helper.hpp"
#include "lib/format-util.hpp"
#include "lib/diff/tree-diff-application.hpp"
#include "lib/diff/test-mutation-target.hpp"
#include "lib/format-string.hpp"
#include "lib/format-cout.hpp"
#include "lib/util.hpp"
#include <string>
using lib::iter_stl::snapshot;
using lib::time::Time;
using std::string;
namespace lib {
namespace diff{
namespace test{
namespace {//Test fixture....
// define some GenNode elements
// to act as templates within the concrete diff
// NOTE: everything in this diff language is by-value
const GenNode ATTRIB1("α", 1), // attribute α = 1
ATTRIB2("β", int64_t(2)), // attribute α = 2L (int64_t)
ATTRIB3("γ", 3.45), // attribute γ = 3.45 (double)
TYPE_X("type", "ξ"), // a "magic" type attribute "Xi"
TYPE_Z("type", "ζ"), //
CHILD_A("a"), // unnamed string child node
CHILD_B('b'), // unnamed char child node
CHILD_T(Time(12,34,56,78)), // unnamed time value child
SUB_NODE = MakeRec().genNode(), // empty anonymous node used to open a sub scope
ATTRIB_NODE = MakeRec().genNode("δ"), // empty named node to be attached as attribute δ
GAMMA_PI("γ", 3.14159265); // happens to have the same identity (ID) as ATTRIB3
}//(End)Test fixture
using LERR_(DIFF_CONFLICT);
/**************************************************************************//**
* @test Special case: build a TreeMutator to accept any change and do nothing.
*
* @note for sake of symmetry, this test uses the same verb sequence used in
* all the other tree diff tests, assuming this sequence covers pretty
* much all features supported by the tree diff language.
*
* @see DiffComplexApplication_test test case which _indeed does a lot..._
* @see TreeMutator_test base operations of the adapter
* @see diff-tree-application.hpp
* @see tree-diff.hpp
*/
class DiffIgnoreChanges_test
: public Test
, TreeDiffLanguage
{
using DiffSeq = iter_stl::IterSnapshot<DiffStep>;
DiffSeq
populationDiff()
{
return snapshot({ins(ATTRIB1)
, ins(ATTRIB3)
, ins(ATTRIB3)
, ins(CHILD_B)
, ins(CHILD_B)
, ins(CHILD_T)
});
} // ==> ATTRIB1, ATTRIB3, (ATTRIB3), CHILD_B, CHILD_B, CHILD_T
DiffSeq
reorderingDiff()
{
return snapshot({after(Ref::ATTRIBS)
, ins(ATTRIB2)
, del(CHILD_B)
, ins(SUB_NODE)
, find(CHILD_T)
, pick(CHILD_B)
, skip(CHILD_T)
});
} // ==> ATTRIB1, ATTRIB3, (ATTRIB3), ATTRIB2, SUB_NODE, CHILD_T, CHILD_B
DiffSeq
mutationDiff()
{
return snapshot({after(CHILD_B)
, after(Ref::END)
, set(GAMMA_PI)
, mut(SUB_NODE)
, ins(TYPE_X)
, ins(ATTRIB2)
, ins(CHILD_B)
, ins(CHILD_A)
, emu(SUB_NODE)
, ins(ATTRIB_NODE)
, mut(ATTRIB_NODE)
, ins(TYPE_Z)
, ins(CHILD_A)
, ins(CHILD_A)
, ins(CHILD_A)
, emu(ATTRIB_NODE)
});
} // ==> ATTRIB1, ATTRIB3 := π, (ATTRIB3), ATTRIB2,
// ATTRIB_NODE{ type ζ, CHILD_A, CHILD_A, CHILD_A }
// SUB_NODE{ type ξ, ATTRIB2, CHILD_B, CHILD_A },
// CHILD_T, CHILD_B
virtual void
run (Arg)
{
fail_or_ignore();
fish_for_content();
}
/** @test fail or ignore, depending on toggle.
* - the TreeMutator default implementation produces a failure,
* when it actually has to handle some diff verb
* - yet a custom TreeMutator can be configured to `ignoreAllChanges()`,
* in which case it will consume any diff without effect.
* This test also demonstrates that the actual TreeMutator is built anew
* for each diff application (TreeMutator is meant to be disposable).
* Thus we may alter the behaviour of the diff binding dynamically.
* @remark the actual use case for this is the TimelineGui, which
* either forwards changes to a TimelineWidget, or silently
* ignores them when the corresponding timeline is not opened.
*/
void
fail_or_ignore()
{
struct HappyBlackHole
{
bool diligent = true;
void
buildMutator (TreeMutator::Handle buff)
{
if (diligent)
buff.emplace(
TreeMutator());
else
buff.emplace(
TreeMutator::build()
.ignoreAllChanges());
}
};
HappyBlackHole subject;
DiffApplicator<HappyBlackHole> application(subject);
VERIFY_ERROR(DIFF_CONFLICT, application.consume(populationDiff()) );
VERIFY_ERROR(DIFF_CONFLICT, application.consume(reorderingDiff()) );
VERIFY_ERROR(DIFF_CONFLICT, application.consume(mutationDiff()) );
subject.diligent = false;
application.consume(populationDiff());
application.consume(reorderingDiff());
application.consume(mutationDiff());
}
/** @test fish some content and ignore everything else.
* While the BlackHoleMutation binding generated by `ignoreAllChanges()`
* must be used as bottom layer of a custom TreeMutator, it is possible
* to layer a partial diff binding on top. This test demonstrates this
* with a single attribute binding, which just "fishes" any value
* mentioned in the diff for that specific attribute. Any other
* changes are silently ignored non the less...
*/
void
fish_for_content()
{
struct Scrounger
{
double loot = 0.0;
void
buildMutator (TreeMutator::Handle buff)
{
buff.emplace (
TreeMutator::build()
.ignoreAllChanges()
.change("γ", [&](double val) { loot = val; }));
}
};
Scrounger subject;
DiffApplicator<Scrounger> application(subject);
const auto NOTHING = 0.0;
const auto VAL_1 = ATTRIB3.data.get<double>();
const auto VAL_2 = GAMMA_PI.data.get<double>();
CHECK (subject.loot == NOTHING);
application.consume(populationDiff());
CHECK (subject.loot == VAL_1);
application.consume(reorderingDiff());
CHECK (subject.loot == VAL_1);
application.consume(mutationDiff());
CHECK (subject.loot == VAL_2);
}
};
/** Register this test class... */
LAUNCHER (DiffIgnoreChanges_test, "unit common");
}}} // namespace lib::diff::test