switch implementation of TestMutationTarget to storing full GenNodes
when implementing the assignment and mutation primitives it became clear that the original approach of just storing a log or string rendered elements does not work: for assignment, we need to locate an element by ID
This commit is contained in:
parent
1016d792b9
commit
b0c6ba0777
2 changed files with 67 additions and 48 deletions
|
|
@ -51,7 +51,7 @@
|
|||
#include "lib/diff/record.hpp"
|
||||
#include "lib/diff/tree-mutator.hpp"
|
||||
#include "lib/idi/genfunc.hpp"
|
||||
#include "lib/format-obj.hpp"
|
||||
#include "lib/format-util.hpp"
|
||||
#include "lib/test/event-log.hpp"
|
||||
#include "lib/util.hpp"
|
||||
//#include "lib/format-string.hpp"
|
||||
|
|
@ -73,15 +73,15 @@ namespace diff{
|
|||
using lib::test::EventLog;
|
||||
using lib::test::EventMatch;
|
||||
using lib::Literal;
|
||||
using iter_stl::eachElm;
|
||||
using util::unConst;
|
||||
using util::isnil;
|
||||
using util::join;
|
||||
// using std::function;
|
||||
using std::string;
|
||||
using std::forward;
|
||||
using std::move;
|
||||
|
||||
using VecS = std::vector<string>;
|
||||
|
||||
|
||||
namespace { // diagnostic helpers: render diff spec....
|
||||
|
||||
|
|
@ -199,20 +199,23 @@ namespace diff{
|
|||
class TestMutationTarget
|
||||
: boost::noncopyable
|
||||
{
|
||||
using VecG = std::vector<GenNode>;
|
||||
|
||||
EventLog log_{identify (this)};
|
||||
|
||||
VecS content_{};
|
||||
VecS prev_content_{};
|
||||
VecG content_{};
|
||||
VecG prev_content_{};
|
||||
|
||||
|
||||
public:
|
||||
using iterator = typename iter_stl::_SeqT<VecS>::Range;
|
||||
using const_iterator = typename iter_stl::_SeqT<const VecS>::Range;
|
||||
using iterator = typename iter_stl::_SeqT<VecG>::Range;
|
||||
using const_iterator = typename iter_stl::_SeqT<const VecG>::Range;
|
||||
|
||||
const_iterator begin() const { return iter_stl::eachElm(content_); }
|
||||
const_iterator begin() const { return eachElm(content_); }
|
||||
const_iterator end() const { return const_iterator(); }
|
||||
|
||||
iterator srcIter() {return iter_stl::eachElm(prev_content_); }
|
||||
iterator srcIter() { return eachElm(prev_content_); }
|
||||
iterator lastElm() { return iterator(VecG::iterator(&content_.back()), content_.end());}
|
||||
|
||||
|
||||
friend const_iterator begin (TestMutationTarget const& target) { return target.begin(); }
|
||||
|
|
@ -231,23 +234,33 @@ namespace diff{
|
|||
}
|
||||
|
||||
void
|
||||
inject (string&& elm, string operationID)
|
||||
inject (GenNode&& elm, string operationID)
|
||||
{
|
||||
content_.emplace_back (forward<string>(elm));
|
||||
log_.event (operationID, content_.back());
|
||||
content_.emplace_back (forward<GenNode>(elm));
|
||||
log_.event (operationID, renderNode (content_.back()));
|
||||
}
|
||||
|
||||
iterator
|
||||
findSrc (string const& spec, iterator pos)
|
||||
static iterator
|
||||
search (GenNode::ID const& targetID, iterator pos)
|
||||
{
|
||||
while (pos and *pos != spec) ++pos;
|
||||
while (pos and not pos->matches(targetID))
|
||||
++pos;
|
||||
return pos;
|
||||
}
|
||||
|
||||
void
|
||||
logSkip (string contentLog)
|
||||
iterator
|
||||
locate (GenNode::ID const& targetID)
|
||||
{
|
||||
log_.event ("skipSrc", isnil(contentLog)? util::BOTTOM_INDICATOR : contentLog);
|
||||
if (!empty() and content_.back().matches(targetID))
|
||||
return lastElm();
|
||||
else
|
||||
return search (targetID, eachElm(content_));
|
||||
}
|
||||
|
||||
void
|
||||
logSkip (GenNode const& content)
|
||||
{
|
||||
log_.event ("skipSrc", isnil(content.idi.getSym())? util::BOTTOM_INDICATOR : renderNode(content));
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -259,12 +272,18 @@ namespace diff{
|
|||
return content_.empty();
|
||||
}
|
||||
|
||||
/** check for recorded element */
|
||||
bool
|
||||
contains (string spec) const
|
||||
/** render payload content for diagnostics */
|
||||
string
|
||||
showContent () const
|
||||
{
|
||||
VecS const& currentValidContent{content_};
|
||||
return util::contains (currentValidContent, spec);
|
||||
return join (transformIterator (begin(), renderNode));
|
||||
}
|
||||
|
||||
/** render elements waiting in source buffer to be accepted */
|
||||
string
|
||||
showSrcBuffer () const
|
||||
{
|
||||
return join (transformIterator (eachElm(prev_content_), renderNode));
|
||||
}
|
||||
|
||||
EventMatch
|
||||
|
|
@ -337,9 +356,9 @@ namespace diff{
|
|||
{
|
||||
if (pos_)
|
||||
{
|
||||
string posSpec = *pos_;
|
||||
GenNode const& skippedElm = *pos_;
|
||||
++pos_;
|
||||
target_.logSkip (posSpec);
|
||||
target_.logSkip (skippedElm);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -350,7 +369,7 @@ namespace diff{
|
|||
virtual void
|
||||
injectNew (GenNode const& n) override
|
||||
{
|
||||
target_.inject (renderNode (n), "injectNew");
|
||||
target_.inject (GenNode{n}, "injectNew");
|
||||
}
|
||||
|
||||
virtual bool
|
||||
|
|
@ -364,10 +383,8 @@ namespace diff{
|
|||
virtual bool
|
||||
matchSrc (GenNode const& n) override
|
||||
{
|
||||
if (!pos_)
|
||||
return false;
|
||||
string spec{renderNode (n)};
|
||||
return spec == *pos_;
|
||||
return pos_? n.matches(*pos_)
|
||||
: false;
|
||||
}
|
||||
|
||||
/** accept existing element, when matching the given spec */
|
||||
|
|
@ -383,11 +400,11 @@ namespace diff{
|
|||
|
||||
/** locate designated element and accept it at current position */
|
||||
virtual bool
|
||||
findSrc (GenNode const& n) override
|
||||
findSrc (GenNode const& ref) override
|
||||
{
|
||||
if (!pos_)
|
||||
return false;
|
||||
Iter found = target_.findSrc (renderNode (n), pos_);
|
||||
Iter found = TestMutationTarget::search (ref.idi, pos_);
|
||||
if (not found) return false;
|
||||
else
|
||||
{
|
||||
|
|
@ -430,8 +447,10 @@ namespace diff{
|
|||
virtual bool
|
||||
assignElm (GenNode const& spec)
|
||||
{
|
||||
UNIMPLEMENTED("locate and assign");
|
||||
return false;
|
||||
Iter targetElm = target_.locate (spec.idi);
|
||||
if (not targetElm) return false;
|
||||
*targetElm = spec;
|
||||
return true;
|
||||
}
|
||||
|
||||
/** locate the designated target element and build a suittable
|
||||
|
|
|
|||
|
|
@ -38,6 +38,7 @@
|
|||
|
||||
using util::join;
|
||||
using util::isnil;
|
||||
using util::contains;
|
||||
using lib::time::Time;
|
||||
using std::string;
|
||||
//using std::vector;
|
||||
|
|
@ -122,7 +123,7 @@ namespace test{
|
|||
|
||||
mutator.injectNew (ATTRIB1);
|
||||
CHECK (!isnil (target));
|
||||
CHECK (target.contains("α = 1"));
|
||||
CHECK (contains(target.showContent(), "α = 1"));
|
||||
CHECK (target.verifyEvent("injectNew","α = 1")
|
||||
.after("attachMutator"));
|
||||
|
||||
|
|
@ -139,9 +140,9 @@ namespace test{
|
|||
.beforeEvent("injectNew","b")
|
||||
.beforeEvent("injectNew","78:56:34.012")
|
||||
);
|
||||
CHECK (join(target) == "α = 1, γ = 3.45, γ = 3.45, b, b, 78:56:34.012");
|
||||
CHECK (target.showContent() == "α = 1, γ = 3.45, γ = 3.45, b, b, 78:56:34.012");
|
||||
cout << "Content after population; "
|
||||
<< join(target) <<endl;
|
||||
<< target.showContent() <<endl;
|
||||
|
||||
|
||||
// now attach new mutator for second round...
|
||||
|
|
@ -155,28 +156,28 @@ namespace test{
|
|||
|
||||
CHECK (isnil (target)); // the "visible" new content is still void
|
||||
CHECK (not mutator2.emptySrc()); // content was moved into hiden "src" buffer
|
||||
CHECK (join(target.srcIter()) == "α = 1, γ = 3.45, γ = 3.45, b, b, 78:56:34.012");
|
||||
CHECK (target.showSrcBuffer() == "α = 1, γ = 3.45, γ = 3.45, b, b, 78:56:34.012");
|
||||
|
||||
CHECK (mutator2.matchSrc (ATTRIB1)); // current head element of src "matches" the given spec
|
||||
CHECK (isnil (target)); // the match didn't change anything
|
||||
|
||||
CHECK (mutator2.findSrc (ATTRIB3)); // serach for an element further down into src... // findSrc
|
||||
CHECK (!isnil (target)); // ...pick and accept it into the "visible" part of target
|
||||
CHECK (join(target) == "γ = 3.45");
|
||||
CHECK (target.showContent() == "γ = 3.45");
|
||||
|
||||
CHECK (mutator2.matchSrc (ATTRIB1)); // element at head of src is still ATTRIB1 (as before)
|
||||
CHECK (mutator2.acceptSrc (ATTRIB1)); // now pick and accept this src element // acceptSrc
|
||||
CHECK (join(target) == "γ = 3.45, α = 1");
|
||||
CHECK (target.showContent() == "γ = 3.45, α = 1");
|
||||
|
||||
CHECK (not mutator2.emptySrc()); // next we have to clean up waste
|
||||
mutator2.skipSrc(); // left behind by the findSrc() operation // skipSrc
|
||||
CHECK (join(target) == "γ = 3.45, α = 1");
|
||||
CHECK (target.showContent() == "γ = 3.45, α = 1");
|
||||
|
||||
mutator2.injectNew (ATTRIB2); // injectNew
|
||||
CHECK (not mutator2.emptySrc());
|
||||
CHECK (mutator2.matchSrc (ATTRIB3));
|
||||
CHECK (mutator2.acceptSrc (ATTRIB3)); // acceptSrc
|
||||
CHECK (join(target) == "γ = 3.45, α = 1, β = 2, γ = 3.45");
|
||||
CHECK (target.showContent() == "γ = 3.45, α = 1, β = 2, γ = 3.45");
|
||||
|
||||
// now proceding with the children.
|
||||
// NOTE: the TestWireTap / TestMutationTarget does not enforce the attribute / children distinction!
|
||||
|
|
@ -208,10 +209,9 @@ namespace test{
|
|||
.beforeEvent("acceptSrc","b")
|
||||
.beforeEvent("acceptSrc","78:56:34.012")
|
||||
);
|
||||
CHECK (join(target.srcIter(), "#") == "###b##"); // we've left back lots of waste, and one abandoned Child "b" (isn't that horrifying?)
|
||||
CHECK (join(target) == "γ = 3.45, α = 1, β = 2, γ = 3.45, Rec(), b, 78:56:34.012");
|
||||
CHECK (target.showContent() == "γ = 3.45, α = 1, β = 2, γ = 3.45, Rec(), b, 78:56:34.012");
|
||||
cout << "Content after reordering; "
|
||||
<< join(target) <<endl;
|
||||
<< target.showContent() <<endl;
|
||||
|
||||
|
||||
|
||||
|
|
@ -226,9 +226,9 @@ namespace test{
|
|||
CHECK (mutator3.acceptSrc (ATTRIB3)); // and accept the second copy of attribute γ
|
||||
CHECK (mutator3.matchSrc (SUB_NODE)); // this /would/ be the next source element, but...
|
||||
|
||||
CHECK (not target.contains("γ = 3.14159265"));
|
||||
CHECK (not contains(target.showContent(), "γ = 3.14159265"));
|
||||
CHECK (mutator3.assignElm(GAMMA_PI)); // ...we assign a new payload to the current element first
|
||||
CHECK ( target.contains("γ = 3.14159265"));
|
||||
CHECK ( contains(target.showContent(), "γ = 3.14159265"));
|
||||
CHECK (mutator3.accept_until (Ref::END)); // fast forward, since we do not want to re-order anything
|
||||
|
||||
// for mutation of an enclosed scope, in real usage the managing TreeDiffInterpreter
|
||||
|
|
@ -252,7 +252,7 @@ namespace test{
|
|||
VERIFY_ERROR (LOGIC, mutator3.assignElm (differentTime));
|
||||
|
||||
cout << "Content after mutation; "
|
||||
<< join(target) <<endl;
|
||||
<< target.showContent() <<endl;
|
||||
|
||||
cout << "____Mutation-Log______________\n"
|
||||
<< join(target.getLog(), "\n")
|
||||
|
|
|
|||
Loading…
Reference in a new issue