Lumiera  0.pre.03
»edit your freedom«
ui-coord-test.cpp
Go to the documentation of this file.
1 /*
2  UICoord(Test) - properties of topological UI coordinate specifications
3 
4  Copyright (C)
5  2017, Hermann Vosseler <Ichthyostega@web.de>
6 
7   **Lumiera** is free software; you can redistribute it and/or modify it
8   under the terms of the GNU General Public License as published by the
9   Free Software Foundation; either version 2 of the License, or (at your
10   option) any later version. See the file COPYING for further details.
11 
12 * *****************************************************************/
13 
19 #include "lib/test/run.hpp"
20 #include "lib/test/test-helper.hpp"
22 #include "lib/format-util.hpp"
23 #include "lib/util.hpp"
24 
25 #include <string>
26 
27 
28 using std::string;
29 using lib::Symbol;
30 using util::isnil;
31 using util::join;
32 
33 
34 
35 namespace stage {
36 namespace interact {
37 namespace test {
38 
39  using LERR_(INDEX_BOUNDS);
40  using LERR_(LOGIC);
41 
42 
43 
44 
45  /******************************************************************************/
61  class UICoord_test : public Test
62  {
63 
64  virtual void
65  run (Arg)
66  {
67  verify_basics();
68  verify_builder();
69  verify_stringRepr();
70  verify_comparisons();
71  verify_localPredicates();
72  }
73 
74 
75  void
76  verify_basics()
77  {
78  UICoord undef;
79  CHECK (isnil (undef));
80 
81  UICoord uic{"Γ","Δ","Θ","Ξ","Σ","Ψ","Φ","Ω"};
82  CHECK (not isnil (uic));
83  CHECK (8 == uic.size());
84  // coordinate sequence is iterable
85  CHECK ("Γ-Δ-Θ-Ξ-Σ-Ψ-Φ-Ω" == join(uic,"-"));
86 
87  // indexed access
88  CHECK ("Γ" == uic[UIC_WINDOW]); // window spec to anchor the path
89  CHECK ("Δ" == uic[UIC_PERSP]); // the perspective used within that window
90  CHECK ("Θ" == uic[UIC_PANEL]); // the docking panel within the window
91  CHECK ("Ξ" == uic[UIC_VIEW]); // the view residing in the docking panel
92  CHECK ("Σ" == uic[UIC_TAB]); // the tab or element group within the view
93  CHECK ("Ψ" == uic[UIC_PATH]); // a path sequence...
94  CHECK ("Φ" == uic[UIC_PATH+1]); // ...descending through local widgets
95  CHECK ("Ω" == uic[UIC_PATH+2]);
96 
97  // sequential access to the path part
98  CHECK ("Ψ-Φ-Ω" == join(uic.pathSeq(),"-"));
99  CHECK ("Ψ/Φ/Ω" == uic.getPath());
100 
101  // iteration of complete coordinates matches index order
102  uint i=0;
103  for (UICoord::iterator ii = uic.begin(); ii; ++ii, ++i)
104  CHECK (uic[i] == *ii);
105  CHECK (8 == i);
106 
107  VERIFY_ERROR (INDEX_BOUNDS, uic[8]);
108 
109  // string representation
110  CHECK ("UI:Γ[Δ]-Θ.Ξ.Σ/Ψ/Φ/Ω" == string(uic));
111  CHECK ( "Γ[Δ]-Θ.Ξ.Σ" == uic.getComp());
112  CHECK ( "Ψ/Φ/Ω" == uic.getPath());
113 
114  // new value can be assigned, but not altered in place
115  uic = UICoord{nullptr,nullptr,"Θ",nullptr,"Σ",nullptr,"Φ"};
116  CHECK (7 == uic.size());
117 
118  // representation is trimmed and filled
119  CHECK ("UI:?-Θ.*.Σ/*/Φ" == string(uic));
120  CHECK (Symbol::EMPTY == uic[UIC_WINDOW]);
121  CHECK (Symbol::EMPTY == uic[UIC_PERSP]);
122  CHECK ("Θ" == uic[UIC_PANEL]);
123  CHECK ("*" == uic[UIC_VIEW]);
124  CHECK ("Σ" == uic[UIC_TAB]);
125  CHECK ("*" == uic[UIC_PATH]);
126  CHECK ("Φ" == uic[UIC_PATH+1]);
127  VERIFY_ERROR (INDEX_BOUNDS, uic[UIC_PATH+2]);
128  }
129 
130 
131  void
132  verify_builder()
133  {
134  UICoord uic1 = UICoord::window("window");
135  UICoord uic2 = uic1.view("view"); // Note: does not alter uic1
136  CHECK ("UI:window" == string(uic1));
137  CHECK ("UI:window[*]-*.view" == string(uic2));
138  CHECK (1 == uic1.size());
139  CHECK (4 == uic2.size());
140 
141  // fault-tolerant accessors for the generic part
142  CHECK ("window" == uic1.getWindow());
143  CHECK ("window" == uic2.getWindow());
144  CHECK ("" == uic1.getPersp());
145  CHECK ("*" == uic2.getPersp());
146  CHECK ("" == uic1.getPanel());
147  CHECK ("*" == uic2.getPanel());
148  CHECK ("" == uic1.getView());
149  CHECK ("view" == uic2.getView());
150  CHECK ("" == uic1.getTab());
151  CHECK ("" == uic2.getTab());
152  CHECK ("" == uic1.getPath());
153  CHECK ("" == uic2.getPath());
154  CHECK ("window" == uic1.getComp());
155  CHECK ("window[*]-*.view" == uic2.getComp());
156 
157  VERIFY_ERROR (INDEX_BOUNDS, uic1[UIC_PERSP]);
158  VERIFY_ERROR (INDEX_BOUNDS, uic2[UIC_TAB]);
159 
160  // partial (incomplete) coordinate spec
161  UICoord uic3 = UICoord().view("view");
162  CHECK (4 == uic3.size());
163  CHECK ("UI:?.view" == string(uic3));
164  CHECK ("" == uic3.getWindow());
165  CHECK ("" == uic3.getPersp());
166  CHECK ("" == uic3.getPanel());
167  CHECK ("view" == uic3.getView());
168 
169  UICoord uic4 = uic3.persp("perspective");
170  CHECK (4 == uic4.size());
171  CHECK ("UI:?[perspective]-*.view" == string(uic4));
172 
173  uic4 = uic3.append("tab");
174  CHECK (5 == uic4.size());
175  CHECK ("UI:?.view.tab" == string(uic4));
176  uic4 = uic3.prepend("panel");
177  CHECK (4 == uic4.size());
178  CHECK ("UI:?-panel.view" == string(uic4));
179  uic4 = uic4.tab(555);
180  CHECK (5 == uic4.size());
181  CHECK ("UI:?-panel.view.#555" == string(uic4));
182  VERIFY_ERROR(LOGIC, uic1.prepend("root"));
183 
184  // the builder may shorten/truncate the path
185  uic4 = uic4.append("α/β/γ/δ/ε/λ").truncateTo(9);
186  CHECK (9 == uic4.size());
187  CHECK ("UI:?-panel.view.#555/α/β/γ/δ" == string(uic4));
188  uic4 = uic4.path("ε/ε/ε/ε/ε").truncateTo(3);
189  CHECK (3 == uic4.size());
190  CHECK ("UI:?-panel" == string(uic4));
191  uic4 = uic4.append("something").truncateTo(2);
192  CHECK (0 == uic4.size()); // NOTE: normalisation detected absence of any remaining content
193  CHECK ("UI:?" == string(uic4));
194  }
195 
196 
197  void
198  verify_stringRepr()
199  {
200  UICoord uic;
201  CHECK ("UI:?" == string(uic));
202  CHECK ("" == uic.getComp());
203  CHECK ("" == uic.getPath());
204 
205  uic = uic.path("ἁρχή");
206  CHECK ("UI:?/ἁρχή" == string(uic));
207  CHECK ("" == uic.getComp());
208  CHECK ("ἁρχή" == uic.getPath());
209 
210  uic = uic.path("α/β/γ");
211  CHECK ("UI:?/α/β/γ" == string(uic));
212  CHECK ("" == uic.getComp());
213  CHECK ("α/β/γ" == uic.getPath());
214 
215  uic = uic.append("δ");
216  CHECK ("UI:?/α/β/γ/δ" == string(uic));
217  CHECK ("" == uic.getComp());
218  CHECK ("α/β/γ/δ" == uic.getPath());
219 
220  uic = uic.append("");
221  CHECK ("UI:?/α/β/γ/δ" == string(uic));
222  CHECK ("" == uic.getComp());
223  CHECK ("α/β/γ/δ" == uic.getPath());
224 
225  uic = uic.append("ε/λ/ον");
226  CHECK ("UI:?/α/β/γ/δ/ε/λ/ον" == string(uic));
227  CHECK ("" == uic.getComp());
228  CHECK ("α/β/γ/δ/ε/λ/ον" == uic.getPath());
229 
230  // note: we built a partially empty path array...
231  CHECK (12 == uic.size());
232  CHECK (Symbol::EMPTY == uic.getView());
233  CHECK (Symbol::EMPTY == uic.getTab());
234  CHECK (Symbol::EMPTY == uic[UIC_WINDOW]);
235  CHECK (Symbol::EMPTY == uic[UIC_PERSP]);
236  CHECK (Symbol::EMPTY == uic[UIC_PANEL]);
237  CHECK (Symbol::EMPTY == uic[UIC_VIEW]);
238  CHECK (Symbol::EMPTY == uic[UIC_TAB]);
239  CHECK ("α" == uic[UIC_PATH]);
240  CHECK ("β" == uic[UIC_PATH+1]);
241  CHECK ("γ" == uic[UIC_PATH+2]);
242  CHECK ("δ" == uic[UIC_PATH+3]);
243  CHECK ("ε" == uic[UIC_PATH+4]);
244  CHECK ("λ" == uic[UIC_PATH+5]);
245  CHECK ("ον" == uic[UIC_PATH+6]);
246 
247  uic = uic.prepend("ειδος");
248  CHECK ("UI:?.ειδος/α/β/γ/δ/ε/λ/ον" == string(uic));
249  CHECK ("?.ειδος" == uic.getComp());
250  CHECK ("α/β/γ/δ/ε/λ/ον" == uic.getPath());
251  CHECK (12 == uic.size());
252 
253  uic = uic.tab("");
254  CHECK ("UI:?/α/β/γ/δ/ε/λ/ον" == string(uic));
255  CHECK ("" == uic.getComp());
256  CHECK ("α/β/γ/δ/ε/λ/ον" == uic.getPath());
257 
258  uic = uic.view("ειδος");
259  CHECK ("UI:?.ειδος.*/α/β/γ/δ/ε/λ/ον" == string(uic));
260  CHECK ("?.ειδος.*" == uic.getComp());
261  CHECK ("α/β/γ/δ/ε/λ/ον" == uic.getPath());
262 
263  uic = uic.prepend("panel");
264  CHECK ("UI:?-panel.ειδος.*/α/β/γ/δ/ε/λ/ον" == string(uic));
265  CHECK ("?-panel.ειδος.*" == uic.getComp());
266  CHECK ("α/β/γ/δ/ε/λ/ον" == uic.getPath());
267 
268  uic = uic.view(nullptr);
269  CHECK ("UI:?-panel.*.*/α/β/γ/δ/ε/λ/ον" == string(uic));
270  CHECK ("?-panel.*.*" == uic.getComp());
271  CHECK ("α/β/γ/δ/ε/λ/ον" == uic.getPath());
272 
273  uic = uic.tab(8);
274  CHECK ("UI:?-panel.*.#8/α/β/γ/δ/ε/λ/ον" == string(uic));
275  CHECK ("?-panel.*.#8" == uic.getComp());
276  CHECK ("α/β/γ/δ/ε/λ/ον" == uic.getPath());
277 
278  uic = uic.noTab();
279  CHECK ("UI:?-panel.*/α/β/γ/δ/ε/λ/ον" == string(uic));
280  CHECK ("?-panel.*" == uic.getComp());
281  CHECK ("α/β/γ/δ/ε/λ/ον" == uic.getPath());
282 
283  uic = uic.tab(" ");
284  CHECK ("UI:?-panel.*. /α/β/γ/δ/ε/λ/ον" == string(uic));
285  CHECK ("?-panel.*. " == uic.getComp());
286  CHECK ("α/β/γ/δ/ε/λ/ον" == uic.getPath());
287 
288  uic = uic.prepend("perspective");
289  CHECK ("UI:?[perspective]-panel.*. /α/β/γ/δ/ε/λ/ον" == string(uic));
290  CHECK ("?[perspective]-panel.*. " == uic.getComp());
291  CHECK ("α/β/γ/δ/ε/λ/ον" == uic.getPath());
292 
293  uic = uic.prepend("win");
294  CHECK ("UI:win[perspective]-panel.*. /α/β/γ/δ/ε/λ/ον" == string(uic));
295  CHECK ("win[perspective]-panel.*. " == uic.getComp());
296  CHECK ("α/β/γ/δ/ε/λ/ον" == uic.getPath());
297 
298  uic = uic.persp("");
299  CHECK ("UI:win[*]-panel.*. /α/β/γ/δ/ε/λ/ον" == string(uic));
300  CHECK ("win[*]-panel.*. " == uic.getComp());
301  CHECK ("α/β/γ/δ/ε/λ/ον" == uic.getPath());
302  CHECK (12 == uic.size());
303 
304  uic = uic.path(" ");
305  CHECK ("UI:win[*]-panel.*. / " == string(uic));
306  CHECK ("win[*]-panel.*. " == uic.getComp());
307  CHECK (" " == uic.getPath());
308  CHECK (6 == uic.size());
309  CHECK (" " == uic[UIC_PATH]);
310  VERIFY_ERROR (INDEX_BOUNDS, uic[UIC_PATH+1]);
311 
312  uic = uic.path(nullptr);
313  CHECK ("UI:win[*]-panel.*. " == string(uic));
314  CHECK ("win[*]-panel.*. " == uic.getComp());
315  CHECK ("" == uic.getPath());
316  CHECK (5 == uic.size());
317  VERIFY_ERROR (INDEX_BOUNDS, uic[UIC_PATH]);
318 
319  uic = uic.append(nullptr);
320  CHECK ("UI:win[*]-panel.*. " == string(uic));
321  CHECK ("win[*]-panel.*. " == uic.getComp());
322  CHECK ("" == uic.getPath());
323  CHECK (5 == uic.size());
324 
325  uic = uic.append("*");
326  CHECK ("UI:win[*]-panel.*. " == string(uic));
327  CHECK ("win[*]-panel.*. " == uic.getComp());
328  CHECK ("" == uic.getPath());
329  CHECK (5 == uic.size());
330 
331  uic = uic.append("**");
332  CHECK ("UI:win[*]-panel.*. /**" == string(uic));
333  CHECK ("win[*]-panel.*. " == uic.getComp());
334  CHECK ("**" == uic.getPath());
335  CHECK ("**" == uic[UIC_PATH]);
336  CHECK (6 == uic.size());
337 
338  uic = uic.tab("");
339  CHECK ("UI:win[*]-panel.*.*/**" == string(uic));
340  CHECK ("win[*]-panel.*.*" == uic.getComp());
341  CHECK ("**" == uic.getPath());
342  CHECK (6 == uic.size());
343 
344  uic = uic.path("");
345  CHECK ("UI:win[*]-panel" == string(uic));
346  CHECK ("win[*]-panel" == uic.getComp());
347  CHECK ("" == uic.getPath());
348  CHECK (3 == uic.size());
349  }
350 
351 
352  void
353  verify_comparisons()
354  {
355  UICoord u1 {"Γ","Δ","Θ","Ξ","Σ","Ψ","Φ" };
356  UICoord u11{"Γ","Δ","Θ","Ξ","Σ","Ψ","Φ","Ω"};
357  UICoord u2 {"Γ","Δ","Θ","Σ","Ξ","Ψ","Φ","Ω"};
358 
359  UICoord u1c{u1};
360 
361  CHECK (u1 == u1 );
362  CHECK (u1 != u11);
363  CHECK (u2 != u1 );
364  CHECK (u2 != u11);
365 
366  CHECK (u1 == u1c);
367  CHECK (u1 == UICoord("Γ","Δ","Θ","Ξ","Σ","Ψ","Φ" ));
368  CHECK (u1 == UICoord("Γ","Δ","Θ","Ξ","Σ","Ψ","Φ","" ));
369  CHECK (UICoord("Γ","Δ","Θ","Ξ","Σ","Ψ","Φ",nullptr) == UICoord("Γ","Δ","Θ","Ξ","Σ","Ψ","Φ"));
370 
371  CHECK (u11 == u1.path("Ψ/Φ/Ω//"));
372  CHECK (u11 != u1.path("//Ψ/Φ/Ω"));
373 
374  CHECK (u1 > u11);
375  CHECK (u11 < u1 );
376  CHECK (u1 >= u1 );
377  CHECK (u1 >= u11);
378  CHECK (not (u1 < u11));
379  CHECK (not (u1 < u1 ));
380  CHECK (not (u1 < u2 ));
381  CHECK (not (u11 < u2 ));
382 
383  // expansion of jokers from parent path is tolerated
384  CHECK (u11 < u1.view("*").window(NULL));
385  }
386 
387 
388  void
389  verify_localPredicates()
390  {
391  UICoord nil;
392  UICoord u1 { "", "", "","Ξ","Σ"};
393  UICoord u2 {"Γ","*","Θ","Ξ","Σ"};
394  UICoord u3 {"Γ","Δ","Θ","Ξ","Σ"};
395 
396  CHECK (not u1.isComplete());
397  CHECK (not u1.isExplicit());
398 
399  CHECK ( u2.isComplete());
400  CHECK (not u2.isExplicit());
401 
402  CHECK ( u3.isComplete());
403  CHECK ( u3.isExplicit());
404 
405  CHECK (u1.isIncomplete());
406  CHECK (not nil.isExplicit());
407  CHECK (not nil.isComplete());
408  CHECK (not nil.isIncomplete()); // note fine point
409 
410  CHECK (not u1.isPresent(UIC_WINDOW));
411  CHECK (not u1.isPresent(UIC_PERSP));
412  CHECK (not u1.isPresent(UIC_PANEL));
413  CHECK ( u1.isPresent(UIC_VIEW));
414  CHECK ( u1.isPresent(UIC_TAB));
415  CHECK (not u1.isPresent(UIC_PATH));
416  CHECK (not u1.isPresent(UIC_PATH+1));
417 
418  CHECK ( u2.isPresent(UIC_WINDOW));
419  CHECK (not u2.isPresent(UIC_PERSP));
420  CHECK ( u2.isPresent(UIC_PANEL));
421  CHECK ( u2.isPresent(UIC_VIEW));
422  CHECK ( u2.isPresent(UIC_TAB));
423  CHECK (not u2.isPresent(UIC_PATH));
424  CHECK (not u2.isPresent(UIC_PATH+1));
425 
426  CHECK ( u3.isPresent(UIC_WINDOW));
427  CHECK ( u3.isPresent(UIC_PERSP));
428  CHECK ( u3.isPresent(UIC_PANEL));
429  CHECK ( u3.isPresent(UIC_VIEW));
430  CHECK ( u3.isPresent(UIC_TAB));
431  CHECK (not u3.isPresent(UIC_PATH));
432  CHECK (not u3.isPresent(UIC_PATH+1));
433 
434  CHECK (not u2.isWildcard(UIC_WINDOW));
435  CHECK ( u2.isWildcard(UIC_PERSP));
436  CHECK (not u2.isWildcard(UIC_PANEL));
437  CHECK (not u2.isWildcard(UIC_VIEW));
438  CHECK (not u2.isWildcard(UIC_TAB));
439  CHECK (not u2.isWildcard(UIC_PATH));
440  CHECK (not u2.isWildcard(UIC_PATH+1));
441  }
442  };
443 
444 
446  LAUNCHER (UICoord_test, "unit stage");
447 
448 
449 }}} // namespace stage::interact::test
bool isExplicit() const
Definition: ui-coord.hpp:225
Describe a location within the UI through structural/topological coordinates.
Definition: ui-coord.hpp:129
Builder persp(Literal perspectiveID) const
Definition: ui-coord.hpp:695
Definition: run.hpp:40
Builder path(Literal pathDefinition) const
convenience builder function so set a full path definition
Definition: ui-coord.hpp:736
#define VERIFY_ERROR(ERROR_ID, ERRONEOUS_STATEMENT)
Macro to verify that a statement indeed raises an exception.
Token or Atom with distinct identity.
Definition: symbol.hpp:117
Simplistic test class runner.
Lumiera GTK UI implementation root.
Definition: guifacade.cpp:37
Tiny helper functions and shortcuts to be used everywhere Consider this header to be effectively incl...
A topological addressing scheme to designate structural locations within the UI.
A collection of frequently used helper functions to support unit testing.
static Builder window(Literal windowID)
Builder: start definition of UI-Coordinates rooted in given window.
Definition: ui-coord.hpp:682
bool isIncomplete() const
Definition: ui-coord.hpp:206
Collection of small helpers and convenience shortcuts for diagnostics & formatting.
Adapter for building an implementation of the »Lumiera Forward Iterator« concept. ...