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