API
 
Loading...
Searching...
No Matches
indiPropNode_test.cpp
Go to the documentation of this file.
1/** \file indiPropNode_test.cpp
2 * \brief Catch2 tests for the xInstGraph `indiPropNode` helper.
3 * \author Jared R. Males (jaredmales@gmail.com)
4 *
5 * \ingroup xInstGraph_files
6 */
7
8#include "../../../../tests/testXWC.hpp"
9
10#include <fstream>
11
12#include "../../../../libMagAOX/libMagAOX.hpp"
13
14#define XWC_XIGNODE_TEST
15#include "../indiPropNode.hpp"
16
17namespace libXWCTest
18{
19
20/** \addtogroup xInstGraph_unit_test
21 * \brief Additional unit tests for the xInstGraph application.
22 *
23 * \ingroup application_unit_test
24 */
25
26/// Namespace for `xInstGraph` node unit tests.
27/** \ingroup xInstGraph_unit_test
28 */
29namespace xInstGraphTest
30{
31
32void writeXML()
33{
34 std::ofstream fout( "/tmp/xigNode_test.xml" );
35 fout << "<mxfile host=\"test\">\n";
36 fout << " <diagram id=\"test\" name=\"test\">\n";
37 fout << " <mxGraphModel>\n";
38 fout << " <root>\n";
39 fout << " <mxCell id=\"0\"/>\n";
40 fout << " <mxCell id=\"1\" parent=\"0\"/>\n";
41 fout << " <mxCell id=\"node:telescope\">\n";
42 fout << "</mxCell>\n";
43 fout << " </root>\n";
44 fout << " </mxGraphModel>\n";
45 fout << " </diagram>\n";
46 fout << "</mxfile>\n";
47 fout.close();
48}
49
50SCENARIO( "Creating and configuring an indiPropNode", "[instGraph::indiPropNode]" )
51{
52 // clang-format off
53 #ifdef XINSTGRAPH_TEST_DOXYGEN_REF
54 indiPropNode::loadConfig( *(mx::app::appConfigurator *)nullptr );
56 #endif
57 // clang-format on
58
59 GIVEN( "a valid XML file, a valid config file" )
60 {
61 WHEN( "node is in file, default config" )
62 {
63 ingr::instGraphXML parentGraph;
64 writeXML();
65 mx::app::writeConfigFile( "/tmp/indiPropNode_test.conf",
66 { "telescope", "telescope", "telescope", "telescope" },
67 { "type", "propKey", "propEl", "propVal" },
68 { "indiProp", "tel.dome", "status", "on" } );
69 mx::app::appConfigurator config;
70 config.readConfig( "/tmp/indiPropNode_test.conf" );
71
72 std::string emsg;
73
74 int rv = parentGraph.loadXMLFile( emsg, "/tmp/xigNode_test.xml" );
75
76 REQUIRE( rv == 0 );
77 REQUIRE( emsg == "" );
78
79 indiPropNode *tsn = nullptr;
80 bool pass = false;
81 try
82 {
83 tsn = new indiPropNode( "telescope", &parentGraph );
84 pass = true;
85 }
86 catch( const std::exception &e )
87 {
88 std::cerr << e.what() << "\n";
89 }
90
91 REQUIRE( pass == true );
92 REQUIRE( tsn != nullptr );
93
94 REQUIRE( tsn->name() == "telescope" );
95 REQUIRE( tsn->node()->name() == "telescope" );
96
97 pass = false;
98 try
99 {
100 tsn->loadConfig( config );
101 pass = true;
102 }
103 catch( const std::exception &e )
104 {
105 std::cerr << e.what() << "\n";
106 }
107
108 REQUIRE( pass == true );
109
110 // check config-ed values
111 REQUIRE( tsn->propKey() == "tel.dome" );
112 REQUIRE( tsn->propEl() == "status" );
113 REQUIRE( tsn->propValStr() == "on" );
114 REQUIRE( tsn->propValNum() == std::numeric_limits<double>::lowest() );
115 REQUIRE( tsn->propValSw() == pcf::IndiElement::SwitchStateType::UnknownSwitchState );
116 REQUIRE( tsn->type() == pcf::IndiProperty::Type::Unknown );
117 REQUIRE( tsn->tol() == 1e-7 );
118 REQUIRE( tsn->state() == false );
119 }
120 WHEN( "node is in file, config setting tol" )
121 {
122 ingr::instGraphXML parentGraph;
123 writeXML();
124 mx::app::writeConfigFile( "/tmp/indiPropNode_test.conf",
125 { "telescope", "telescope", "telescope", "telescope", "telescope" },
126 { "type", "propKey", "propEl", "propVal", "tol" },
127 { "indiProp", "tel.dome", "status", "on", "1e-8" } );
128 mx::app::appConfigurator config;
129 config.readConfig( "/tmp/indiPropNode_test.conf" );
130
131 std::string emsg;
132
133 int rv = parentGraph.loadXMLFile( emsg, "/tmp/xigNode_test.xml" );
134
135 REQUIRE( rv == 0 );
136 REQUIRE( emsg == "" );
137
138 indiPropNode *tsn = nullptr;
139 bool pass = false;
140 try
141 {
142 tsn = new indiPropNode( "telescope", &parentGraph );
143 pass = true;
144 }
145 catch( const std::exception &e )
146 {
147 std::cerr << e.what() << "\n";
148 }
149
150 REQUIRE( pass == true );
151 REQUIRE( tsn != nullptr );
152
153 REQUIRE( tsn->name() == "telescope" );
154 REQUIRE( tsn->node()->name() == "telescope" );
155
156 pass = false;
157 try
158 {
159 tsn->loadConfig( config );
160 pass = true;
161 }
162 catch( const std::exception &e )
163 {
164 std::cerr << e.what() << "\n";
165 }
166
167 REQUIRE( pass == true );
168
169 // check config-ed values
170 REQUIRE( tsn->propKey() == "tel.dome" );
171 REQUIRE( tsn->propEl() == "status" );
172 REQUIRE( tsn->propValStr() == "on" );
173 REQUIRE( tsn->propValNum() == std::numeric_limits<double>::lowest() );
174 REQUIRE( tsn->propValSw() == pcf::IndiElement::SwitchStateType::UnknownSwitchState );
175 REQUIRE( tsn->type() == pcf::IndiProperty::Type::Unknown );
176 REQUIRE( tsn->tol() == 1e-8 );
177 REQUIRE( tsn->state() == false );
178 }
179
180 WHEN( "node is in file, handling a text property" )
181 {
182 ingr::instGraphXML parentGraph;
183 writeXML();
184 mx::app::writeConfigFile( "/tmp/indiPropNode_test.conf",
185 { "telescope", "telescope", "telescope", "telescope" },
186 { "type", "propKey", "propEl", "propVal" },
187 { "indiProp", "tel.dome", "status", "on" } );
188 mx::app::appConfigurator config;
189 config.readConfig( "/tmp/indiPropNode_test.conf" );
190
191 std::string emsg;
192
193 parentGraph.loadXMLFile( emsg, "/tmp/xigNode_test.xml" );
194
195 indiPropNode *tsn = new indiPropNode( "telescope", &parentGraph );
196 tsn->loadConfig( config );
197
198 pcf::IndiProperty ip( pcf::IndiProperty::Text );
199 ip.setDevice( "tel" );
200 ip.setName( "dome" );
201 ip.add( pcf::IndiElement( "status" ) );
202 ip["status"] = "on";
203
204 tsn->handleSetProperty( ip );
205 REQUIRE( tsn->type() == pcf::IndiProperty::Text );
206 REQUIRE( tsn->state() == true );
207
208 ip["status"] = "off";
209 tsn->handleSetProperty( ip );
210 REQUIRE( tsn->state() == false );
211 }
212
213 WHEN( "node is in file, handling a number property" )
214 {
215 ingr::instGraphXML parentGraph;
216 writeXML();
217 mx::app::writeConfigFile( "/tmp/indiPropNode_test.conf",
218 { "telescope", "telescope", "telescope", "telescope" },
219 { "type", "propKey", "propEl", "propVal" },
220 { "indiProp", "tel.dome", "status", "1.5" } );
221 mx::app::appConfigurator config;
222 config.readConfig( "/tmp/indiPropNode_test.conf" );
223
224 std::string emsg;
225
226 parentGraph.loadXMLFile( emsg, "/tmp/xigNode_test.xml" );
227
228 indiPropNode *tsn = new indiPropNode( "telescope", &parentGraph );
229 tsn->loadConfig( config );
230
231 pcf::IndiProperty ip( pcf::IndiProperty::Number );
232 ip.setDevice( "tel" );
233 ip.setName( "dome" );
234 ip.add( pcf::IndiElement( "status" ) );
235 ip["status"] = "1.5";
236
237 tsn->handleSetProperty( ip );
238 REQUIRE( tsn->type() == pcf::IndiProperty::Number );
239 REQUIRE( tsn->propValNum() == 1.5 );
240 REQUIRE( tsn->state() == true );
241
242 ip["status"] = "1.6";
243 tsn->handleSetProperty( ip );
244 REQUIRE( tsn->state() == false );
245 }
246
247 WHEN( "node is in file, handling a switch property" )
248 {
249 ingr::instGraphXML parentGraph;
250 writeXML();
251 mx::app::writeConfigFile( "/tmp/indiPropNode_test.conf",
252 { "telescope", "telescope", "telescope", "telescope" },
253 { "type", "propKey", "propEl", "propVal" },
254 { "indiProp", "tel.dome", "status", "on" } );
255 mx::app::appConfigurator config;
256 config.readConfig( "/tmp/indiPropNode_test.conf" );
257
258 std::string emsg;
259
260 parentGraph.loadXMLFile( emsg, "/tmp/xigNode_test.xml" );
261
262 indiPropNode *tsn = new indiPropNode( "telescope", &parentGraph );
263 tsn->loadConfig( config );
264
265 pcf::IndiProperty ip( pcf::IndiProperty::Switch );
266 ip.setDevice( "tel" );
267 ip.setName( "dome" );
268 ip.add( pcf::IndiElement( "status" ) );
269 ip["status"].setSwitchState( pcf::IndiElement::SwitchStateType::On );
270
271 tsn->handleSetProperty( ip );
272 REQUIRE( tsn->type() == pcf::IndiProperty::Switch );
273 REQUIRE( tsn->propValSw() == pcf::IndiElement::SwitchStateType::On );
274 REQUIRE( tsn->state() == true );
275
276 ip["status"].setSwitchState( pcf::IndiElement::SwitchStateType::Off );
277 tsn->handleSetProperty( ip );
278 REQUIRE( tsn->state() == false );
279 }
280 }
281
282 GIVEN( "invalid configs" )
283 {
284 WHEN( "parent graph is null, default config" )
285 {
286 indiPropNode *tsn = nullptr;
287 bool pass = false;
288 try
289 {
290 tsn = new indiPropNode( "telescope", nullptr );
291 pass = true;
292 }
293 catch( const std::exception &e )
294 {
295 std::cerr << e.what() << "\n";
296 }
297
298 REQUIRE( pass == false );
299 REQUIRE( tsn == nullptr );
300 }
301 WHEN( "node not in file, default config" )
302 {
303 ingr::instGraphXML parentGraph;
304 writeXML();
305 mx::app::writeConfigFile( "/tmp/indiPropNode_test.conf",
306 { "telescope", "telescope", "telescope", "telescope" },
307 { "type", "propKey", "propEl", "propVal" },
308 { "indiProp", "tel.dome", "status", "on" } );
309 mx::app::appConfigurator config;
310 config.readConfig( "/tmp/indiPropNode_test.conf" );
311
312 std::string emsg;
313
314 int rv = parentGraph.loadXMLFile( emsg, "/tmp/xigNode_test.xml" );
315
316 REQUIRE( rv == 0 );
317 REQUIRE( emsg == "" );
318
319 indiPropNode *tsn = nullptr;
320 bool pass = false;
321 try
322 {
323 tsn = new indiPropNode( "telescope2", &parentGraph );
324 pass = true;
325 }
326 catch( const std::exception &e )
327 {
328 std::cerr << e.what() << "\n";
329 }
330
331 REQUIRE( pass == false );
332 REQUIRE( tsn == nullptr );
333 }
334
335 WHEN( "node is in file, default config, wrong node type" )
336 {
337 ingr::instGraphXML parentGraph;
338 writeXML();
339 mx::app::writeConfigFile( "/tmp/indiPropNode_test.conf",
340 { "telescope", "telescope", "telescope", "telescope" },
341 { "type", "propKey", "propEl", "propVal" },
342 { "fakeProp", "tel.dome", "status", "on" } );
343 mx::app::appConfigurator config;
344 config.readConfig( "/tmp/indiPropNode_test.conf" );
345
346 std::string emsg;
347
348 int rv = parentGraph.loadXMLFile( emsg, "/tmp/xigNode_test.xml" );
349
350 REQUIRE( rv == 0 );
351 REQUIRE( emsg == "" );
352
353 indiPropNode *tsn = nullptr;
354 bool pass = false;
355 try
356 {
357 tsn = new indiPropNode( "telescope", &parentGraph );
358 pass = true;
359 }
360 catch( const std::exception &e )
361 {
362 std::cerr << e.what() << "\n";
363 }
364
365 REQUIRE( pass == true );
366 REQUIRE( tsn != nullptr );
367
368 REQUIRE( tsn->name() == "telescope" );
369 REQUIRE( tsn->node()->name() == "telescope" );
370
371 pass = false;
372 try
373 {
374 tsn->loadConfig( config );
375 pass = true;
376 }
377 catch( const std::exception &e )
378 {
379 std::cerr << e.what() << "\n";
380 }
381
382 REQUIRE( pass == false );
383 }
384 WHEN( "node is in file, default config, propKey empty" )
385 {
386 ingr::instGraphXML parentGraph;
387 writeXML();
388 mx::app::writeConfigFile( "/tmp/indiPropNode_test.conf",
389 { "telescope", "telescope", "telescope", "telescope" },
390 { "type", "propKey", "propEl", "propVal" },
391 { "indiProp", "", "status", "on" } );
392 mx::app::appConfigurator config;
393 config.readConfig( "/tmp/indiPropNode_test.conf" );
394
395 std::string emsg;
396
397 int rv = parentGraph.loadXMLFile( emsg, "/tmp/xigNode_test.xml" );
398
399 REQUIRE( rv == 0 );
400 REQUIRE( emsg == "" );
401
402 indiPropNode *tsn = nullptr;
403 bool pass = false;
404 try
405 {
406 tsn = new indiPropNode( "telescope", &parentGraph );
407 pass = true;
408 }
409 catch( const std::exception &e )
410 {
411 std::cerr << e.what() << "\n";
412 }
413
414 REQUIRE( pass == true );
415 REQUIRE( tsn != nullptr );
416
417 REQUIRE( tsn->name() == "telescope" );
418 REQUIRE( tsn->node()->name() == "telescope" );
419
420 pass = false;
421 try
422 {
423 tsn->loadConfig( config );
424 pass = true;
425 }
426 catch( const std::exception &e )
427 {
428 std::cerr << e.what() << "\n";
429 }
430
431 REQUIRE( pass == false );
432 }
433 WHEN( "node is in file, default config, propEl empty" )
434 {
435 ingr::instGraphXML parentGraph;
436 writeXML();
437 mx::app::writeConfigFile( "/tmp/indiPropNode_test.conf",
438 { "telescope", "telescope", "telescope", "telescope" },
439 { "type", "propKey", "propEl", "propVal" },
440 { "indiProp", "tel.dome", "", "on" } );
441 mx::app::appConfigurator config;
442 config.readConfig( "/tmp/indiPropNode_test.conf" );
443
444 std::string emsg;
445
446 int rv = parentGraph.loadXMLFile( emsg, "/tmp/xigNode_test.xml" );
447
448 REQUIRE( rv == 0 );
449 REQUIRE( emsg == "" );
450
451 indiPropNode *tsn = nullptr;
452 bool pass = false;
453 try
454 {
455 tsn = new indiPropNode( "telescope", &parentGraph );
456 pass = true;
457 }
458 catch( const std::exception &e )
459 {
460 std::cerr << e.what() << "\n";
461 }
462
463 REQUIRE( pass == true );
464 REQUIRE( tsn != nullptr );
465
466 REQUIRE( tsn->name() == "telescope" );
467 REQUIRE( tsn->node()->name() == "telescope" );
468
469 pass = false;
470 try
471 {
472 tsn->loadConfig( config );
473 pass = true;
474 }
475 catch( const std::exception &e )
476 {
477 std::cerr << e.what() << "\n";
478 }
479
480 REQUIRE( pass == false );
481 }
482 WHEN( "node is in file, default config, propVal empty" )
483 {
484 ingr::instGraphXML parentGraph;
485 writeXML();
486 mx::app::writeConfigFile( "/tmp/indiPropNode_test.conf",
487 { "telescope", "telescope", "telescope", "telescope" },
488 { "type", "propKey", "propEl", "propVal" },
489 { "indiProp", "tel.come", "status", "" } );
490 mx::app::appConfigurator config;
491 config.readConfig( "/tmp/indiPropNode_test.conf" );
492
493 std::string emsg;
494
495 int rv = parentGraph.loadXMLFile( emsg, "/tmp/xigNode_test.xml" );
496
497 REQUIRE( rv == 0 );
498 REQUIRE( emsg == "" );
499
500 indiPropNode *tsn = nullptr;
501 bool pass = false;
502 try
503 {
504 tsn = new indiPropNode( "telescope", &parentGraph );
505 pass = true;
506 }
507 catch( const std::exception &e )
508 {
509 std::cerr << e.what() << "\n";
510 }
511
512 REQUIRE( pass == true );
513 REQUIRE( tsn != nullptr );
514
515 REQUIRE( tsn->name() == "telescope" );
516 REQUIRE( tsn->node()->name() == "telescope" );
517
518 pass = false;
519 try
520 {
521 tsn->loadConfig( config );
522 pass = true;
523 }
524 catch( const std::exception &e )
525 {
526 std::cerr << e.what() << "\n";
527 }
528
529 REQUIRE( pass == false );
530 }
531 WHEN( "a number property with invalid propVal" )
532 {
533 ingr::instGraphXML parentGraph;
534 writeXML();
535 mx::app::writeConfigFile( "/tmp/indiPropNode_test.conf",
536 { "telescope", "telescope", "telescope", "telescope" },
537 { "type", "propKey", "propEl", "propVal" },
538 { "indiProp", "tel.dome", "status", "abcde" } );
539 mx::app::appConfigurator config;
540 config.readConfig( "/tmp/indiPropNode_test.conf" );
541
542 std::string emsg;
543
544 parentGraph.loadXMLFile( emsg, "/tmp/xigNode_test.xml" );
545
546 indiPropNode *tsn = new indiPropNode( "telescope", &parentGraph );
547 tsn->loadConfig( config );
548
549 pcf::IndiProperty ip( pcf::IndiProperty::Number );
550 ip.setDevice( "tel" );
551 ip.setName( "dome" );
552 ip.add( pcf::IndiElement( "status" ) );
553 ip["status"] = "1.5";
554
555 bool pass = false;
556 try
557 {
558 tsn->handleSetProperty( ip );
559 pass = true;
560 }
561 catch( const std::exception &e )
562 {
563 std::cerr << e.what() << '\n';
564 }
565
566 REQUIRE( pass == false );
567 }
568 WHEN( "invalid switch property" )
569 {
570 ingr::instGraphXML parentGraph;
571 writeXML();
572 mx::app::writeConfigFile( "/tmp/indiPropNode_test.conf",
573 { "telescope", "telescope", "telescope", "telescope" },
574 { "type", "propKey", "propEl", "propVal" },
575 { "indiProp", "tel.dome", "status", "qq" } );
576 mx::app::appConfigurator config;
577 config.readConfig( "/tmp/indiPropNode_test.conf" );
578
579 std::string emsg;
580
581 parentGraph.loadXMLFile( emsg, "/tmp/xigNode_test.xml" );
582
583 indiPropNode *tsn = new indiPropNode( "telescope", &parentGraph );
584 tsn->loadConfig( config );
585
586 pcf::IndiProperty ip( pcf::IndiProperty::Switch );
587 ip.setDevice( "tel" );
588 ip.setName( "dome" );
589 ip.add( pcf::IndiElement( "status" ) );
590 ip["status"].setSwitchState( pcf::IndiElement::SwitchStateType::On );
591
592 bool pass = false;
593 try
594 {
595 tsn->handleSetProperty( ip );
596 pass = true;
597 }
598 catch( const std::exception &e )
599 {
600 std::cerr << e.what() << '\n';
601 }
602
603 REQUIRE( pass == false );
604 }
605 }
606}
607
608} // namespace xInstGraphTest
609
610} // namespace libXWCTest
An instGraph node which tracks a specific INDI property and element of that property.
void propEl(const std::string &pe)
Set the element of the INDI property to track.
const pcf::IndiProperty::Type & type() const
Get the type of the INDI property being tracked.
const pcf::IndiElement::SwitchStateType & propValSw()
Get the target value of the INDI element if it's a switch.
void loadConfig(mx::app::appConfigurator &config)
Configure this node form an appConfigurator.
virtual int handleSetProperty(const pcf::IndiProperty &ipRecv)
INDI SetProperty callback.
const bool & state() const
Get the current value of the comparison.
void propKey(const std::string &pk)
Set the unique key of the INDI property to track.
const std::string & propKey() const
Get the unique key of the INDI property to track.
void propValStr(const std::string &pv)
Set the target value of the INDI element.
const double & tol() const
Get the tolerance used for numeric comparison.
const double & propValNum() const
Get the target value of the INDI element if it's a number.
ingr::instNode * node()
Get the pointer to the underlying node.
Definition xigNode.hpp:121
std::string name()
Get the name of this node.
Definition xigNode.hpp:106
SCENARIO("Creating and configuring an fsmNode", "[instGraph::fsmNode]")
void writeXML()
Write a minimal draw.io graph containing one of each supported node type.
Namespace for all libXWC tests.