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

458 lines
17 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
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)
{
verify_basics();
verify_builder();
verify_stringRepr();
verify_comparisons();
verify_localPredicates();
}
void
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
uic = UICoord{nullptr,nullptr,"Θ",nullptr,"Σ",nullptr,"Φ"};
CHECK (7 == uic.size());
// representation is trimmed and filled
CHECK ("UI:?-Θ.*.Σ/*/Φ" == string(uic));
CHECK (Symbol::EMPTY == uic[UIC_WINDOW]);
CHECK (Symbol::EMPTY == uic[UIC_PERSP]);
CHECK ("Θ" == uic[UIC_PANEL]);
CHECK ("*" == uic[UIC_VIEW]);
CHECK ("Σ" == uic[UIC_TAB]);
CHECK ("*" == uic[UIC_PATH]);
CHECK ("Φ" == uic[UIC_PATH+1]);
VERIFY_ERROR (INDEX_BOUNDS, uic[UIC_PATH+2]);
}
void
verify_builder()
{
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));
}
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());
}
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));
}
void
verify_localPredicates()
{
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