LUMIERA.clone/tests/gui/interact/ui-coord-test.cpp

459 lines
17 KiB
C++
Raw Normal View History

/*
UICoord(Test) - properties of topological UI coordinate specifications
Copyright (C) Lumiera.org
2017, Hermann Vosseler <Ichthyostega@web.de>
This program 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.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
* *****************************************************/
/** @file ui-coord-test.cpp
** unit test \ref UICoord_test
*/
#include "lib/test/run.hpp"
#include "lib/test/test-helper.hpp"
#include "gui/interact/ui-coord.hpp"
#include "lib/format-util.hpp"
#include "lib/util.hpp"
#include <string>
using std::string;
using lib::Symbol;
using util::isnil;
using util::join;
namespace gui {
namespace interact {
namespace test {
using lumiera::error::LERR_(INDEX_BOUNDS);
using lumiera::error::LERR_(LOGIC);
/******************************************************************************//**
* @test verify the basic properties of topological UI coordinate specifications.
* - 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
* @see PathArray_test
* @see UICoordResolver_test
* @see ViewSpecDSL_test
*/
class UICoord_test : public Test
{
virtual void
run (Arg)
{
2017-09-23 17:55:40 +02:00
verify_basics();
verify_builder();
verify_stringRepr();
2017-09-23 17:55:40 +02:00
verify_comparisons();
verify_localPredicates();
}
void
2017-09-23 17:55:40 +02:00
verify_basics()
{
UICoord undef;
CHECK (isnil (undef));
UICoord uic{"Γ","Δ","Θ","Ξ","Σ","Ψ","Φ","Ω"};
CHECK (not isnil (uic));
CHECK (8 == uic.size());
// coordinate sequence is iterable
CHECK ("Γ-Δ-Θ-Ξ-Σ-Ψ-Φ-Ω" == join(uic,"-"));
// indexed access
CHECK ("Γ" == uic[UIC_WINDOW]); // window spec to anchor the path
CHECK ("Δ" == uic[UIC_PERSP]); // the perspective used within that window
CHECK ("Θ" == uic[UIC_PANEL]); // the docking panel within the window
CHECK ("Ξ" == uic[UIC_VIEW]); // the view residing in the docking panel
CHECK ("Σ" == uic[UIC_TAB]); // the tab or element group within the view
CHECK ("Ψ" == uic[UIC_PATH]); // a path sequence...
CHECK ("Φ" == uic[UIC_PATH+1]); // ...descending through local widgets
CHECK ("Ω" == uic[UIC_PATH+2]);
// 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);
CHECK (8 == i);
VERIFY_ERROR (INDEX_BOUNDS, uic[8]);
// string representation
CHECK ("UI:Γ[Δ]-Θ.Ξ.Σ/Ψ/Φ/Ω" == string(uic));
CHECK ( "Γ[Δ]-Θ.Ξ.Σ" == uic.getComp());
CHECK ( "Ψ/Φ/Ω" == uic.getPath());
// new value can be assigned, but not altered in place
2017-10-01 01:30:53 +02:00
uic = UICoord{nullptr,nullptr,"Θ",nullptr,"Σ",nullptr,"Φ"};
CHECK (7 == uic.size());
// representation is trimmed and filled
2017-10-01 21:54:35 +02:00
CHECK ("UI:?-Θ.*.Σ/*/Φ" == string(uic));
CHECK (Symbol::EMPTY == uic[UIC_WINDOW]);
CHECK (Symbol::EMPTY == uic[UIC_PERSP]);
CHECK ("Θ" == uic[UIC_PANEL]);
CHECK ("*" == uic[UIC_VIEW]);
2017-10-01 01:30:53 +02:00
CHECK ("Σ" == uic[UIC_TAB]);
CHECK ("*" == uic[UIC_PATH]);
CHECK ("Φ" == uic[UIC_PATH+1]);
VERIFY_ERROR (INDEX_BOUNDS, uic[UIC_PATH+2]);
}
void
2017-09-23 17:55:40 +02:00
verify_builder()
{
2017-10-01 21:54:35 +02:00
UICoord uic1 = UICoord::window("window");
UICoord uic2 = uic1.view("view"); // Note: does not alter uic1
CHECK ("UI:window" == string(uic1));
CHECK ("UI:window[*]-*.view" == string(uic2));
CHECK (1 == uic1.size());
CHECK (4 == uic2.size());
// fault-tolerant accessors for the generic part
CHECK ("window" == uic1.getWindow());
CHECK ("window" == uic2.getWindow());
CHECK ("" == uic1.getPersp());
CHECK ("*" == uic2.getPersp());
CHECK ("" == uic1.getPanel());
CHECK ("*" == uic2.getPanel());
CHECK ("" == uic1.getView());
CHECK ("view" == uic2.getView());
CHECK ("" == uic1.getTab());
CHECK ("" == uic2.getTab());
CHECK ("" == uic1.getPath());
CHECK ("" == uic2.getPath());
CHECK ("window" == uic1.getComp());
CHECK ("window[*]-*.view" == uic2.getComp());
VERIFY_ERROR (INDEX_BOUNDS, uic1[UIC_PERSP]);
VERIFY_ERROR (INDEX_BOUNDS, uic2[UIC_TAB]);
// partial (incomplete) coordinate spec
UICoord uic3 = UICoord().view("view");
CHECK (4 == uic3.size());
CHECK ("UI:?.view" == string(uic3));
CHECK ("" == uic3.getWindow());
CHECK ("" == uic3.getPersp());
CHECK ("" == uic3.getPanel());
CHECK ("view" == uic3.getView());
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));
uic4 = uic3.prepend("panel");
CHECK (4 == uic4.size());
CHECK ("UI:?-panel.view" == string(uic4));
uic4 = uic4.tab(555);
CHECK (5 == uic4.size());
CHECK ("UI:?-panel.view.#555" == string(uic4));
VERIFY_ERROR(LOGIC, uic1.prepend("root"));
// the builder may shorten/truncate the path
uic4 = uic4.append("α/β/γ/δ/ε/λ").truncateTo(9);
CHECK (9 == uic4.size());
CHECK ("UI:?-panel.view.#555/α/β/γ" == string(uic4));
uic4 = uic4.path("ε/ε/ε/ε/ε").truncateTo(3);
CHECK (3 == uic4.size());
CHECK ("UI:?-panel" == string(uic4));
uic4 = uic4.append("something").truncateTo(2);
CHECK (0 == uic4.size()); // NOTE: normalisation detected absence of any remaining content
CHECK ("UI:?" == string(uic4));
2017-09-23 17:55:40 +02:00
}
void
verify_stringRepr()
{
UICoord uic;
CHECK ("UI:?" == string(uic));
CHECK ("" == uic.getComp());
CHECK ("" == uic.getPath());
uic = uic.path("ἁρχή");
CHECK ("UI:?/ἁρχή" == string(uic));
CHECK ("" == uic.getComp());
CHECK ("ἁρχή" == uic.getPath());
uic = uic.path("α/β/γ");
CHECK ("UI:?/α/β/γ" == string(uic));
CHECK ("" == uic.getComp());
CHECK ("α/β/γ" == uic.getPath());
uic = uic.append("δ");
CHECK ("UI:?/α/β/γ" == string(uic));
CHECK ("" == uic.getComp());
CHECK ("α/β/γ" == uic.getPath());
uic = uic.append("");
CHECK ("UI:?/α/β/γ" == string(uic));
CHECK ("" == uic.getComp());
CHECK ("α/β/γ" == uic.getPath());
uic = uic.append("ε/λ/ον");
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());
CHECK (Symbol::EMPTY == uic.getTab());
CHECK (Symbol::EMPTY == uic[UIC_WINDOW]);
CHECK (Symbol::EMPTY == uic[UIC_PERSP]);
CHECK (Symbol::EMPTY == uic[UIC_PANEL]);
CHECK (Symbol::EMPTY == uic[UIC_VIEW]);
CHECK (Symbol::EMPTY == uic[UIC_TAB]);
CHECK ("α" == uic[UIC_PATH]);
CHECK ("β" == uic[UIC_PATH+1]);
CHECK ("γ" == uic[UIC_PATH+2]);
CHECK ("δ" == uic[UIC_PATH+3]);
CHECK ("ε" == uic[UIC_PATH+4]);
CHECK ("λ" == uic[UIC_PATH+5]);
CHECK ("ον" == uic[UIC_PATH+6]);
uic = uic.prepend("ειδος");
CHECK ("UI:?.ειδος/α/β/γ/δ/ε/λ/ον" == string(uic));
CHECK ("?.ειδος" == uic.getComp());
CHECK ("α/β/γ/δ/ε/λ/ον" == uic.getPath());
CHECK (12 == uic.size());
uic = uic.tab("");
CHECK ("UI:?/α/β/γ/δ/ε/λ/ον" == string(uic));
CHECK ("" == uic.getComp());
CHECK ("α/β/γ/δ/ε/λ/ον" == uic.getPath());
uic = uic.view("ειδος");
CHECK ("UI:?.ειδος.*/α/β/γ/δ/ε/λ/ον" == string(uic));
CHECK ("?.ειδος.*" == uic.getComp());
CHECK ("α/β/γ/δ/ε/λ/ον" == uic.getPath());
uic = uic.prepend("panel");
CHECK ("UI:?-panel.ειδος.*/α/β/γ/δ/ε/λ/ον" == string(uic));
CHECK ("?-panel.ειδος.*" == uic.getComp());
CHECK ("α/β/γ/δ/ε/λ/ον" == uic.getPath());
uic = uic.view(nullptr);
CHECK ("UI:?-panel.*.*/α/β/γ/δ/ε/λ/ον" == string(uic));
CHECK ("?-panel.*.*" == uic.getComp());
CHECK ("α/β/γ/δ/ε/λ/ον" == uic.getPath());
uic = uic.tab(8);
CHECK ("UI:?-panel.*.#8/α/β/γ/δ/ε/λ/ον" == string(uic));
CHECK ("?-panel.*.#8" == uic.getComp());
CHECK ("α/β/γ/δ/ε/λ/ον" == uic.getPath());
uic = uic.noTab();
CHECK ("UI:?-panel.*/α/β/γ/δ/ε/λ/ον" == string(uic));
CHECK ("?-panel.*" == uic.getComp());
CHECK ("α/β/γ/δ/ε/λ/ον" == uic.getPath());
uic = uic.tab(" ");
CHECK ("UI:?-panel.*. /α/β/γ/δ/ε/λ/ον" == string(uic));
CHECK ("?-panel.*. " == uic.getComp());
CHECK ("α/β/γ/δ/ε/λ/ον" == uic.getPath());
uic = uic.prepend("perspective");
CHECK ("UI:?[perspective]-panel.*. /α/β/γ/δ/ε/λ/ον" == string(uic));
CHECK ("?[perspective]-panel.*. " == uic.getComp());
CHECK ("α/β/γ/δ/ε/λ/ον" == uic.getPath());
uic = uic.prepend("win");
CHECK ("UI:win[perspective]-panel.*. /α/β/γ/δ/ε/λ/ον" == string(uic));
CHECK ("win[perspective]-panel.*. " == uic.getComp());
CHECK ("α/β/γ/δ/ε/λ/ον" == uic.getPath());
uic = uic.persp("");
CHECK ("UI:win[*]-panel.*. /α/β/γ/δ/ε/λ/ον" == string(uic));
CHECK ("win[*]-panel.*. " == uic.getComp());
CHECK ("α/β/γ/δ/ε/λ/ον" == uic.getPath());
CHECK (12 == uic.size());
uic = uic.path(" ");
CHECK ("UI:win[*]-panel.*. / " == string(uic));
CHECK ("win[*]-panel.*. " == uic.getComp());
CHECK (" " == uic.getPath());
CHECK (6 == uic.size());
CHECK (" " == uic[UIC_PATH]);
VERIFY_ERROR (INDEX_BOUNDS, uic[UIC_PATH+1]);
uic = uic.path(nullptr);
CHECK ("UI:win[*]-panel.*. " == string(uic));
CHECK ("win[*]-panel.*. " == uic.getComp());
CHECK ("" == uic.getPath());
CHECK (5 == uic.size());
VERIFY_ERROR (INDEX_BOUNDS, uic[UIC_PATH]);
uic = uic.append(nullptr);
CHECK ("UI:win[*]-panel.*. " == string(uic));
CHECK ("win[*]-panel.*. " == uic.getComp());
CHECK ("" == uic.getPath());
CHECK (5 == uic.size());
uic = uic.append("*");
CHECK ("UI:win[*]-panel.*. " == string(uic));
CHECK ("win[*]-panel.*. " == uic.getComp());
CHECK ("" == uic.getPath());
CHECK (5 == uic.size());
uic = uic.append("**");
CHECK ("UI:win[*]-panel.*. /**" == string(uic));
CHECK ("win[*]-panel.*. " == uic.getComp());
CHECK ("**" == uic.getPath());
CHECK ("**" == uic[UIC_PATH]);
CHECK (6 == uic.size());
uic = uic.tab("");
CHECK ("UI:win[*]-panel.*.*/**" == string(uic));
CHECK ("win[*]-panel.*.*" == uic.getComp());
CHECK ("**" == uic.getPath());
CHECK (6 == uic.size());
uic = uic.path("");
CHECK ("UI:win[*]-panel" == string(uic));
CHECK ("win[*]-panel" == uic.getComp());
CHECK ("" == uic.getPath());
CHECK (3 == uic.size());
}
2017-09-23 17:55:40 +02:00
void
verify_comparisons()
{
UICoord u1 {"Γ","Δ","Θ","Ξ","Σ","Ψ","Φ" };
UICoord u11{"Γ","Δ","Θ","Ξ","Σ","Ψ","Φ","Ω"};
UICoord u2 {"Γ","Δ","Θ","Σ","Ξ","Ψ","Φ","Ω"};
UICoord u1c{u1};
CHECK (u1 == u1 );
CHECK (u1 != u11);
CHECK (u2 != u1 );
CHECK (u2 != u11);
CHECK (u1 == u1c);
CHECK (u1 == UICoord("Γ","Δ","Θ","Ξ","Σ","Ψ","Φ" ));
CHECK (u1 == UICoord("Γ","Δ","Θ","Ξ","Σ","Ψ","Φ","" ));
CHECK (UICoord("Γ","Δ","Θ","Ξ","Σ","Ψ","Φ",nullptr) == UICoord("Γ","Δ","Θ","Ξ","Σ","Ψ","Φ"));
CHECK (u11 == u1.path("Ψ/Φ/Ω//"));
CHECK (u11 != u1.path("//Ψ/Φ/Ω"));
CHECK (u1 > u11);
CHECK (u11 < u1 );
CHECK (u1 >= u1 );
CHECK (u1 >= u11);
CHECK (not (u1 < u11));
CHECK (not (u1 < u1 ));
CHECK (not (u1 < u2 ));
CHECK (not (u11 < u2 ));
// expansion of jokers from parent path is tolerated
CHECK (u11 < u1.view("*").window(NULL));
2017-09-23 17:55:40 +02:00
}
void
verify_localPredicates()
2017-09-23 17:55:40 +02:00
{
UICoord nil;
UICoord u1 { "", "", "","Ξ","Σ"};
UICoord u2 {"Γ","*","Θ","Ξ","Σ"};
UICoord u3 {"Γ","Δ","Θ","Ξ","Σ"};
CHECK (not u1.isComplete());
CHECK (not u1.isExplicit());
CHECK ( u2.isComplete());
CHECK (not u2.isExplicit());
CHECK ( u3.isComplete());
CHECK ( u3.isExplicit());
CHECK (u1.isIncomplete());
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));
}
};
/** Register this test class... */
LAUNCHER (UICoord_test, "unit gui");
}}} // namespace gui::interact::test