introduce new mutation primitive as pointed out by preceding analysis

to summarise, it turned out that it is impossible to
provide an airtight 'emptySrc' implementation when binding
to object fields -- so we distinguish into positive and
negative tests, allowing to loosen the sanity check
only for the latter ones when binding to object fields.
This commit is contained in:
Fischlurch 2016-05-24 22:23:06 +02:00
parent b47b4c3f94
commit 4571d3fb0f
4 changed files with 51 additions and 0 deletions

View file

@ -282,6 +282,14 @@ namespace diff{
% render(target.data));
}
void
logScopeCompletion (iterator processingPos)
{
log_.event ("completeScope", _Fmt{"⤴ scope%s completed / %d waste elm(s) dropped"}
% (processingPos? " NOT":"")
% prev_content_.size());
}
/* === Diagnostic / Verification === */
@ -510,6 +518,15 @@ namespace diff{
}
}
/** verify all our pending (old) source elements where mentioned.
* @note allows chained "onion-layers" to clean-up and verify.*/
virtual bool
completeScope()
{
target_.logScopeCompletion (pos_);
return PAR::completeScope()
and isnil(this->pos_);
}
};

View file

@ -310,6 +310,15 @@
return target_found? binding_.openSub (*target_found, spec.idi, targetBuff)
: false;
}
/** verify all our pending (old) source elements where mentioned.
* @note allows chained "onion-layers" to clean-up and verify.*/
virtual bool
completeScope()
{
return PAR::completeScope()
and isnil(this->pos_);
}
};

View file

@ -280,6 +280,17 @@ namespace diff{
return false;
}
/** ensure the scope addressed by this TreeMutator
* was processed and exhausted without mismatch
* @return `true` when all "open ends" are closed
* and no pending work remains to be done. */
virtual bool
completeScope()
{
// nothing to clean-up or verify by default
return true;
}
virtual void setAttribute (ID, Attribute&) { /* do nothing by default */ }
/**

View file

@ -136,6 +136,7 @@ namespace test{
mutator.injectNew (CHILD_B);
mutator.injectNew (CHILD_B);
mutator.injectNew (CHILD_T);
CHECK (mutator.completeScope());
CHECK (target.verify("attachMutator")
.beforeEvent("injectNew","α = 1")
.beforeEvent("injectNew","γ = 3.45")
@ -143,6 +144,7 @@ namespace test{
.beforeEvent("injectNew","b")
.beforeEvent("injectNew","b")
.beforeEvent("injectNew","78:56:34.012")
.beforeEvent("completeScope","scope completed")
);
CHECK (target.showContent() == "α = 1, γ = 3.45, γ = 3.45, b, b, 78:56:34.012");
cout << "Content after population; "
@ -200,6 +202,7 @@ namespace test{
CHECK (mutator2.acceptSrc (CHILD_T)); // acceptSrc
CHECK (not mutator2.hasSrc()); // source contents exhausted
CHECK (not mutator2.acceptSrc (CHILD_T));
CHECK (mutator2.completeScope()); // no pending elements left, everything resolved
CHECK (target.verify("attachMutator")
.beforeEvent("injectNew","78:56:34.012")
.before("attachMutator")
@ -212,6 +215,7 @@ namespace test{
.beforeEvent("injectNew","Rec()")
.beforeEvent("acceptSrc","b")
.beforeEvent("acceptSrc","78:56:34.012")
.beforeEvent("completeScope","scope completed")
);
CHECK (target.showContent() == "γ = 3.45, α = 1, β = 2, γ = 3.45, Rec(), b, 78:56:34.012");
cout << "Content after reordering; "
@ -233,7 +237,9 @@ namespace test{
CHECK (not contains(target.showContent(), "γ = 3.1415927"));
CHECK (mutator3.assignElm(GAMMA_PI)); // ...we assign a new payload to the current element first
CHECK ( contains(target.showContent(), "γ = 3.1415927"));
CHECK (not mutator3.completeScope()); // not done yet...
CHECK (mutator3.accept_until (Ref::END)); // fast forward, since we do not want to re-order anything
CHECK ( mutator3.completeScope()); // now any pending elements where default-resolved
cout << "Content after assignment; "
<< target.showContent() <<endl;
@ -265,9 +271,11 @@ namespace test{
.beforeEvent("accept_until β","β = 2")
.beforeEvent("acceptSrc","γ = 3.45")
.beforeEvent("assignElm","γ: 3.45 ⤅ 3.1415927")
.beforeEvent("completeScope","scope NOT completed")
.beforeEvent("accept_until END","Rec()")
.beforeEvent("accept_until END","b")
.beforeEvent("accept_until END","78:56:34.012")
.beforeEvent("completeScope","scope completed")
.beforeEvent("mutateChild","_CHILD_Record.001: start mutation...Rec()")
);
@ -347,6 +355,7 @@ namespace test{
mutator1.injectNew (CHILD_B);
mutator1.injectNew (CHILD_B);
mutator1.injectNew (CHILD_T);
CHECK (mutator1.completeScope());
auto contents = stringify(eachElm(target));
CHECK ("α1≻" == *contents);
@ -421,6 +430,7 @@ namespace test{
CHECK (mutator2.acceptSrc (CHILD_T)); // acceptSrc
CHECK (not mutator2.hasSrc()); // source contents exhausted
CHECK (not mutator2.acceptSrc (CHILD_T)); // ...anything beyond is NOP
CHECK (mutator2.completeScope()); // no pending elements left, everything resolved
// verify reordered shape
contents = stringify(eachElm(target));
@ -501,7 +511,9 @@ namespace test{
CHECK (not contains(join(target), "γ3.1415927≻"));
CHECK (mutator3.assignElm(GAMMA_PI)); // ...we assign a new payload to the current element first
CHECK ( contains(join(target), "γ3.1415927≻"));
CHECK (not mutator3.completeScope());
CHECK (mutator3.accept_until (Ref::END)); // fast forward, since we do not want to re-order anything
CHECK ( mutator3.completeScope()); // now any pending elements where default-resolved
cout << "Content after assignment; "
<< join(target) <<endl;
@ -558,6 +570,8 @@ namespace test{
subMutatorBuffer->injectNew (CHILD_A);
subMutatorBuffer->injectNew (CHILD_A);
subMutatorBuffer->injectNew (CHILD_A);
CHECK (subMutatorBuffer->completeScope()); // no pending "open ends" left in sub-scope
CHECK (mutator3.completeScope()); // and likewise in the enclosing main scope
// and thus we've gotten a second nested scope, populated with new values
cout << "Sub|" << join(subScopes[ATTRIB_NODE.idi]) <<endl;