UI-Coordinates: value representation finished and unit test PASS (#1106)

This commit is contained in:
Fischlurch 2017-10-03 00:57:23 +02:00
parent f23b02b841
commit ed76151d14
3 changed files with 143 additions and 64 deletions

View file

@ -60,7 +60,6 @@
#include <string>
#include <vector>
#include <utility>
//#include <memory>
namespace gui {
@ -68,7 +67,6 @@ namespace interact {
namespace error = lumiera::error;
// using std::unique_ptr;
using std::string;
using lib::Literal;
using lib::Symbol;
@ -95,28 +93,26 @@ namespace interact {
extern Symbol UIC_CURRENT_WINDOW; ///< window spec to refer to the _current window_ @see view-locator.cpp
extern Symbol UIC_ELIDED; ///< indicate that a component is elided or irrelevant here
/**
* Describe a location within the UI through structural/topological coordinates.
* A UICoord specification is a sequence of Literal tokens, elaborating a path descending
* through the hierarchy of UI elements down to the specific UI element to refer.
*
* @todo initial draft as of 9/2017
* @see UICoord_test
*/
class UICoord
: public lib::PathArray<UIC_INLINE_SIZE>
{
using PathAry = lib::PathArray<UIC_INLINE_SIZE>;
public:
/**
* UI-Coordinates can be created explicitly by specifying a sequence of Literal tokens,
* which will be used to initialise and then normalise the underlying PathArray.
* @warning Literal means _"literal"_ with guaranteed storage during the whole execution.
* @remarks - in case you need to construct some part, then use Symbol to _intern_ the
* resulting string into the global static SymbolTable.
* @remarks - in case you need to construct some part, then use \ref Symbol to _intern_
* the resulting string into the global static SymbolTable.
* - usually the Builder API leads to more readable definitions,
* explicitly indicating the meaning of the coordinate's parts.
*/
@ -124,8 +120,8 @@ namespace interact {
explicit
UICoord (ARGS&& ...args) : PathArray(std::forward<ARGS> (args)...) { }
UICoord (UICoord&&) = default;
UICoord (UICoord const&) = default;
UICoord (UICoord&&) = default;
UICoord (UICoord const&) = default;
UICoord (UICoord& o) : UICoord((UICoord const&)o) { }
UICoord& operator= (UICoord const&) = default;
@ -146,16 +142,14 @@ namespace interact {
/** Builder: start definition of UI-Coordinates rooted in given window */
static Builder window (Literal windowID);
// convenience shortcuts to start a copy-builder....
//----- convenience shortcuts to start a copy-builder....
Builder persp (Literal perspectiveID) const;
Builder view (Literal viewID) const;
Builder tab (Literal tabID) const;
Builder tab (uint tabIdx) const;
Builder noTab () const;
// convenience shortcuts to start mutation on a copy...
//----- convenience shortcuts to start mutation on a copy...
Builder path (Literal pathDefinition) const;
Builder append (Literal elmID) const;
Builder prepend (Literal elmID) const;
@ -206,6 +200,24 @@ namespace interact {
}
bool
isPresent (size_t idx) const
{
Literal* elm = unConst(this)->getPosition(idx);
return not isnil(elm)
and *elm != Symbol::ANY;
}
bool
isWildcard (size_t idx) const
{
Literal* elm = unConst(this)->getPosition(idx);
return elm
and *elm == Symbol::ANY;
}
/**
* Check if this coordinate spec can be seen as an extension
* of the given parent coordinates and thus reaches further down
@ -231,7 +243,7 @@ namespace interact {
and ( (*this)[idx]== parent[idx]
or Symbol::ANY == parent[idx]
or isnil (parent[idx])))
++idx;
++idx;
ENSURE (idx < subSiz);
return idx == parSiz;
@ -264,7 +276,7 @@ namespace interact {
if (empty()) return "";
size_t end = min (size(), UIC_PATH);
size_t pos = indexOf(*begin());
size_t pos = indexOf (*begin());
if (pos >= end)
return ""; // empty or path information only
@ -275,7 +287,7 @@ namespace interact {
if (0 < pos) // incomplete UI-Coordinates (not anchored)
buff += "?";
for ( ; pos<end; ++pos)
for ( ; pos<end; ++pos )
switch (pos) {
case UIC_WINDOW:
buff += getWindow();
@ -309,14 +321,14 @@ namespace interact {
string buff; // heuristic pre-allocation
buff.reserve (10 * (siz - UIC_PATH));
iterator elm{this, unConst(this)->getPosition(UIC_PATH)};
iterator elm = pathSeq();
if (isnil (*elm))
{ // irregular case : only a path fragment
{ // irregular case : only a path fragment
elm = this->begin();
buff += "?/";
}
for ( ; elm; ++elm)
for ( ; elm; ++elm )
buff += *elm + "/";
// chop off last delimiter
@ -326,6 +338,14 @@ namespace interact {
return buff;
}
/** iterative access to the path sequence section */
iterator
pathSeq() const
{
return size()<= UIC_PATH? end()
: iterator{this, unConst(this)->getPosition(UIC_PATH)};
}
private:
/** @note Builder allowed to manipulate stored data */
@ -382,7 +402,7 @@ namespace interact {
while (string::npos != (last = sequence.find ('/', pos)))
{
elms.emplace_back (Symbol{sequence.substr(pos, last - pos)});
pos = last + 1;
pos = last + 1; // delimiter stripped
}
sequence = sequence.substr(pos);
if (not isnil (sequence))
@ -391,7 +411,7 @@ namespace interact {
setTailSequence (idx, elms);
}
/** replace the existing path information with the given elements
* @note - storage will possibly be expanded to accommodate
* - the individual path elements will be _interned_ as Symbol
@ -404,7 +424,7 @@ namespace interact {
setTailSequence (size_t idx, std::vector<Literal>& pathElms)
{
size_t cnt = pathElms.size();
expandPosition (idx + cnt);
expandPosition (idx + cnt); // preallocate
for (size_t i=0 ; i < cnt; ++i)
setContent (expandPosition(idx + i), pathElms[i]);
size_t end = size();
@ -413,12 +433,14 @@ namespace interact {
}
public:
public: /* ===== relational operators : equality and partial order ===== */
friend bool
operator== (UICoord const& l, UICoord const& r)
{
return static_cast<PathAry const&> (l) == static_cast<PathAry const&> (r);
return static_cast<PathArray const&> (l) == static_cast<PathArray const&> (r);
}
friend bool
operator< (UICoord const& l, UICoord const& r)
{
@ -433,6 +455,8 @@ namespace interact {
/* === Builder API === */
class UICoord::Builder
@ -453,12 +477,14 @@ namespace interact {
Builder& operator= (Builder &&) = delete;
public:
/** @remark moving a builder instance is allowed */
/** @remark moving a builder instance is acceptable */
Builder (Builder &&) = default;
/* == Builder functions == */
/** change UI coordinate spec to define it to be rooted within the given window
* @note this function allows to _undefine_ the window, thus creating an incomplete spec */
Builder
window (Literal windowID)
{
@ -555,18 +581,21 @@ namespace interact {
UICoord::UICoord (Builder&& builder)
: UICoord{std::move (builder.uic_)}
{
PathAry::normalise();
PathArray::normalise();
}
/** Builder: start definition of UI-Coordinates rooted in the `currentWindow` */
/** @return an empty Builder allowing to define further parts;
* to finish the definition, cast / store it into
* UICoord, which itself is immutable.
*/
inline UICoord::Builder
UICoord::currentWindow()
{
return window (UIC_CURRENT_WINDOW);
}
/** Builder: start definition of UI-Coordinates rooted in given window */
/** @return aBuilder with just the windowID defined */
inline UICoord::Builder
UICoord::window (Literal windowID)
{
@ -574,6 +603,12 @@ namespace interact {
}
/** @return a Builder holding a clone copy of the original UICoord,
* with the perspective information set to a new value.
* @remarks This Builder can then be used do set further parts
* independently of the original. When done, store it
* as new UICoord object. To achieve real mutation,
* assign it to the original variable. */
inline UICoord::Builder
UICoord::persp (Literal perspectiveID) const
{

View file

@ -28,19 +28,13 @@
#include "lib/test/run.hpp"
#include "lib/test/test-helper.hpp"
#include "gui/interact/ui-coord.hpp"
#include "lib/format-cout.hpp"/////////////////////////TODO RLY?
#include "lib/format-util.hpp"
//#include "lib/idi/entry-id.hpp"
//#include "lib/diff/gen-node.hpp"
#include "lib/util.hpp"
#include <string>
using std::string;
//using lib::idi::EntryID;
//using lib::diff::GenNode;
//using util::isSameObject;
using lib::Symbol;
using util::isnil;
using util::join;
@ -51,23 +45,21 @@ namespace gui {
namespace interact {
namespace test {
// using lumiera::error::LUMIERA_ERROR_WRONG_TYPE;
using lumiera::error::LUMIERA_ERROR_INDEX_BOUNDS;
using lumiera::error::LUMIERA_ERROR_LOGIC;
namespace { //Test fixture...
}//(End)Test fixture
/******************************************************************************//**
* @test verify the basic properties of topological UI coordinate specifications.
* - created as path-like sequence of components
* - created as path-like sequence of \ref Literal components
* - provides a builder API for definition and mutation
* - Normalisation and handling of missing parts
* - access to UI coordinate components
* - string representation
* - comparisons
* - predicates
*
* @see ui-coord.hpp
* @see path-array.hpp
@ -98,7 +90,7 @@ namespace test {
UICoord uic{"Γ","Δ","Θ","Ξ","Σ","Ψ","Φ","Ω"};
CHECK (not isnil (uic));
CHECK (8 == uic.size());
// path is iterable
// coordinate sequence is iterable
CHECK ("Γ-Δ-Θ-Ξ-Σ-Ψ-Φ-Ω" == join(uic,"-"));
// indexed access
@ -111,7 +103,11 @@ namespace test {
CHECK ("Φ" == uic[UIC_PATH+1]); // ...descending through local widgets
CHECK ("Ω" == uic[UIC_PATH+2]);
// iteration of complete path matches index order
// sequential access to the path part
CHECK ("Ψ-Φ-Ω" == join(uic.pathSeq(),"-"));
CHECK ("Ψ/Φ/Ω" == uic.getPath());
// iteration of complete coordinates matches index order
uint i=0;
for (UICoord::iterator ii = uic.begin(); ii; ++ii, ++i)
CHECK (uic[i] == *ii);
@ -182,7 +178,7 @@ namespace test {
UICoord uic4 = uic3.persp("perspective");
CHECK (4 == uic4.size());
CHECK ("UI:?[perspective]-*.view" == string(uic4));
uic4 = uic3.append("tab");
CHECK (5 == uic4.size());
CHECK ("UI:?.view.tab" == string(uic4));
@ -228,7 +224,7 @@ namespace test {
CHECK ("UI:?/α/β/γ/δ/ε/λ/ον" == string(uic));
CHECK ("" == uic.getComp());
CHECK ("α/β/γ/δ/ε/λ/ον" == uic.getPath());
// note: we built a partially empty path array...
CHECK (12 == uic.size());
CHECK (Symbol::EMPTY == uic.getView());
@ -371,6 +367,7 @@ namespace test {
CHECK (UICoord("Γ","Δ","Θ","Ξ","Σ","Ψ","Φ",nullptr) == UICoord("Γ","Δ","Θ","Ξ","Σ","Ψ","Φ"));
CHECK (u11 == u1.path("Ψ/Φ/Ω//"));
CHECK (u11 != u1.path("//Ψ/Φ/Ω"));
CHECK (u1 > u11);
CHECK (u11 < u1 );
@ -407,6 +404,38 @@ namespace test {
CHECK (not nil.isExplicit());
CHECK (not nil.isComplete());
CHECK (not nil.isIncomplete()); // note fine point
CHECK (not u1.isPresent(UIC_WINDOW));
CHECK (not u1.isPresent(UIC_PERSP));
CHECK (not u1.isPresent(UIC_PANEL));
CHECK ( u1.isPresent(UIC_VIEW));
CHECK ( u1.isPresent(UIC_TAB));
CHECK (not u1.isPresent(UIC_PATH));
CHECK (not u1.isPresent(UIC_PATH+1));
CHECK ( u2.isPresent(UIC_WINDOW));
CHECK (not u2.isPresent(UIC_PERSP));
CHECK ( u2.isPresent(UIC_PANEL));
CHECK ( u2.isPresent(UIC_VIEW));
CHECK ( u2.isPresent(UIC_TAB));
CHECK (not u2.isPresent(UIC_PATH));
CHECK (not u2.isPresent(UIC_PATH+1));
CHECK ( u3.isPresent(UIC_WINDOW));
CHECK ( u3.isPresent(UIC_PERSP));
CHECK ( u3.isPresent(UIC_PANEL));
CHECK ( u3.isPresent(UIC_VIEW));
CHECK ( u3.isPresent(UIC_TAB));
CHECK (not u3.isPresent(UIC_PATH));
CHECK (not u3.isPresent(UIC_PATH+1));
CHECK (not u2.isWildcard(UIC_WINDOW));
CHECK ( u2.isWildcard(UIC_PERSP));
CHECK (not u2.isWildcard(UIC_PANEL));
CHECK (not u2.isWildcard(UIC_VIEW));
CHECK (not u2.isWildcard(UIC_TAB));
CHECK (not u2.isWildcard(UIC_PATH));
CHECK (not u2.isWildcard(UIC_PATH+1));
}
};

View file

@ -3825,8 +3825,8 @@
</node>
</node>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1506181068556" ID="ID_749871444" MODIFIED="1506181084051" TEXT="UICoord">
<icon BUILTIN="flag-yellow"/>
<node COLOR="#338800" CREATED="1506181068556" ID="ID_749871444" MODIFIED="1506984544618" TEXT="UICoord">
<icon BUILTIN="button_ok"/>
<node COLOR="#338800" CREATED="1506181721910" FOLDED="true" ID="ID_1680105436" MODIFIED="1506956411552" TEXT="Folge von Symbolen">
<icon BUILTIN="button_ok"/>
<node CREATED="1506263953722" ID="ID_1293486815" MODIFIED="1506831482410" TEXT="Basis-Abstraktion">
@ -3924,19 +3924,22 @@
<icon BUILTIN="button_ok"/>
</node>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1506181727069" ID="ID_467120404" MODIFIED="1506181737140" TEXT="lokale Pr&#xe4;dikate">
<icon BUILTIN="flag-yellow"/>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1506181744939" ID="ID_1731446951" MODIFIED="1506181820513" TEXT="present">
<icon BUILTIN="flag-yellow"/>
<node COLOR="#338800" CREATED="1506181727069" ID="ID_467120404" MODIFIED="1506984539619" TEXT="lokale Pr&#xe4;dikate">
<icon BUILTIN="button_ok"/>
<node COLOR="#338800" CREATED="1506181744939" ID="ID_1731446951" MODIFIED="1506984286100" TEXT="present">
<icon BUILTIN="button_ok"/>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1506181747466" ID="ID_1522805946" MODIFIED="1506181821273" TEXT="wildcard">
<icon BUILTIN="flag-yellow"/>
<node COLOR="#338800" CREATED="1506181747466" ID="ID_1522805946" MODIFIED="1506984288444" TEXT="wildcard">
<icon BUILTIN="button_ok"/>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1506181783173" ID="ID_306479120" MODIFIED="1506181821985" TEXT="explicit">
<icon BUILTIN="flag-yellow"/>
<node COLOR="#338800" CREATED="1506181783173" ID="ID_306479120" MODIFIED="1506984294555" TEXT="explicit">
<icon BUILTIN="button_ok"/>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1506181770783" ID="ID_295392903" MODIFIED="1506181822673" TEXT="incomplete">
<icon BUILTIN="flag-yellow"/>
<node COLOR="#338800" CREATED="1506984533458" ID="ID_373226509" MODIFIED="1506984536986" TEXT="complete">
<icon BUILTIN="button_ok"/>
</node>
<node COLOR="#338800" CREATED="1506181770783" ID="ID_295392903" MODIFIED="1506984530019" TEXT="incomplete">
<icon BUILTIN="button_ok"/>
</node>
</node>
</node>
@ -3992,32 +3995,44 @@
</node>
<node CREATED="1506181908037" HGAP="-29" ID="ID_1925951134" MODIFIED="1506956365444" TEXT="Test" VSHIFT="21">
<icon BUILTIN="prepare"/>
<node CREATED="1506181922767" ID="ID_1642380411" MODIFIED="1506181922767" TEXT="UICoord_test">
<node CREATED="1506181922767" ID="ID_1642380411" MODIFIED="1506984675523" TEXT="UICoord_test">
<icon BUILTIN="button_ok"/>
<node COLOR="#338800" CREATED="1506182009518" ID="ID_138248232" MODIFIED="1506906630089" TEXT="verify_basics">
<icon BUILTIN="button_ok"/>
</node>
<node COLOR="#338800" CREATED="1506182009519" ID="ID_1637725534" MODIFIED="1506919626951" TEXT="verify_builder">
<icon BUILTIN="button_ok"/>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1506182009519" ID="ID_542761230" MODIFIED="1506182101802" TEXT="verify_comparisons">
<node COLOR="#338800" CREATED="1506182009519" ID="ID_542761230" MODIFIED="1506984562762" TEXT="verify_comparisons">
<icon BUILTIN="button_ok"/>
</node>
<node COLOR="#338800" CREATED="1506984579372" ID="ID_1752757359" MODIFIED="1506984582125" TEXT="verify_localPredicates">
<icon BUILTIN="button_ok"/>
</node>
</node>
<node CREATED="1506984614487" ID="ID_380908645" MODIFIED="1506984616051" TEXT="UICoordResolver_test">
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1506984645745" ID="ID_244163155" MODIFIED="1506984665826" TEXT="verify_simpleUsage">
<icon BUILTIN="flag-yellow"/>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1506182009519" ID="ID_231137127" MODIFIED="1506182101801" TEXT="verify_queryAnchor">
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1506984645747" ID="ID_517262443" MODIFIED="1506984665001" TEXT="verify_backingQuery">
<icon BUILTIN="flag-yellow"/>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1506182009519" ID="ID_1203731740" MODIFIED="1506182101800" TEXT="verify_queryCoverage">
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1506984645748" ID="ID_1254044275" MODIFIED="1506984664457" TEXT="verify_queryAnchor">
<icon BUILTIN="flag-yellow"/>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1506182009520" ID="ID_1462245568" MODIFIED="1506182101799" TEXT="verify_mutateAnchor">
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1506984645748" ID="ID_670536416" MODIFIED="1506984663914" TEXT="verify_queryCoverage">
<icon BUILTIN="flag-yellow"/>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1506182009520" ID="ID_1785831243" MODIFIED="1506182101798" TEXT="verify_mutateCover">
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1506984645748" ID="ID_1171284706" MODIFIED="1506984663361" TEXT="verify_mutateAnchor">
<icon BUILTIN="flag-yellow"/>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1506182009520" ID="ID_1146069424" MODIFIED="1506182101797" TEXT="verify_mutateExtend">
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1506984645748" ID="ID_1688800613" MODIFIED="1506984662841" TEXT="verify_mutateCovered">
<icon BUILTIN="flag-yellow"/>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1506182009520" ID="ID_1254487071" MODIFIED="1506182101796" TEXT="verify_mutateCreate">
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1506984645748" ID="ID_768385613" MODIFIED="1506984662154" TEXT="verify_mutateExtend">
<icon BUILTIN="flag-yellow"/>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1506984645748" ID="ID_900185933" MODIFIED="1506984661514" TEXT="verify_mutateCreate">
<icon BUILTIN="flag-yellow"/>
</node>
</node>