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:
Fischlurch 2016-03-11 17:39:25 +01:00
parent 1016d792b9
commit b0c6ba0777
2 changed files with 67 additions and 48 deletions

View file

@ -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

View file

@ -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")