API
 
Loading...
Searching...
No Matches
cameraSim_test.cpp
Go to the documentation of this file.
1/** \file cameraSim_test.cpp
2 * \brief Catch2 tests for the cameraSim app.
3 * \author Jared R. Males (jaredmales@gmail.com)
4 *
5 * \ingroup cameraSim_files
6 */
7
8#include "../../../tests/testXWC.hpp"
9#include "../../../tests/testMacrosINDI.hpp"
10
11#include "../cameraSim.hpp"
12
13using namespace MagAOX::app;
14
15namespace libXWCTest
16{
17
18/** \defgroup cameraSim_unit_test cameraSim Unit Tests
19 * \brief Unit tests for the cameraSim application.
20 *
21 * \ingroup application_unit_test
22 */
23
24/// Namespace for `cameraSim` unit tests.
25/** \ingroup cameraSim_unit_test
26 */
27namespace cameraSimTest
28{
29
30/// \cond DOXYGEN_SUPPRESS_TEST_HARNESS
31class cameraSim_test : public cameraSim
32{
33 public:
34 cameraSim_test( const std::string device )
35 {
36 m_configName = device;
37 m_hasFocus = true;
38
39 m_indiP_focus = pcf::IndiProperty( pcf::IndiProperty::Switch );
40 m_indiP_focus.setDevice( m_configName );
41 m_indiP_focus.setName( "focus" );
42 m_indiP_focus.setState( INDI_IDLE );
43 m_indiP_focus.add( pcf::IndiElement( "state", pcf::IndiElement::Off ) );
44
45 XWCTEST_SETUP_INDI_ARB_NEW_PROP( m_indiP_temp, reconfigure )
46 XWCTEST_SETUP_INDI_ARB_NEW_PROP( m_indiP_temp, temp_ccd )
47 XWCTEST_SETUP_INDI_ARB_NEW_PROP( m_indiP_temp, temp_controller )
48 XWCTEST_SETUP_INDI_ARB_NEW_PROP( m_indiP_temp, readout_speed )
49 XWCTEST_SETUP_INDI_ARB_NEW_PROP( m_indiP_temp, vshift_speed )
50 XWCTEST_SETUP_INDI_ARB_NEW_PROP( m_indiP_temp, emgain )
51 XWCTEST_SETUP_INDI_ARB_NEW_PROP( m_indiP_temp, exptime )
52 XWCTEST_SETUP_INDI_ARB_NEW_PROP( m_indiP_temp, fps )
53 XWCTEST_SETUP_INDI_ARB_NEW_PROP( m_indiP_temp, synchro )
54 XWCTEST_SETUP_INDI_ARB_NEW_PROP( m_indiP_temp, mode )
55 XWCTEST_SETUP_INDI_ARB_NEW_PROP( m_indiP_temp, roi_crop_mode )
56 XWCTEST_SETUP_INDI_ARB_NEW_PROP( m_indiP_temp, roi_region_x )
57 XWCTEST_SETUP_INDI_ARB_NEW_PROP( m_indiP_temp, roi_region_y )
58 XWCTEST_SETUP_INDI_ARB_NEW_PROP( m_indiP_temp, roi_region_w )
59 XWCTEST_SETUP_INDI_ARB_NEW_PROP( m_indiP_temp, roi_region_h )
60 XWCTEST_SETUP_INDI_ARB_NEW_PROP( m_indiP_temp, roi_region_bin_x )
61 XWCTEST_SETUP_INDI_ARB_NEW_PROP( m_indiP_temp, roi_region_bin_y )
62 XWCTEST_SETUP_INDI_ARB_NEW_PROP( m_indiP_temp, roi_region_check )
63 XWCTEST_SETUP_INDI_ARB_NEW_PROP( m_indiP_temp, roi_set )
64 XWCTEST_SETUP_INDI_ARB_NEW_PROP( m_indiP_temp, roi_set_full )
65 XWCTEST_SETUP_INDI_ARB_NEW_PROP( m_indiP_temp, roi_set_full_bin )
66 XWCTEST_SETUP_INDI_ARB_NEW_PROP( m_indiP_temp, roi_load_last )
67 XWCTEST_SETUP_INDI_ARB_NEW_PROP( m_indiP_temp, roi_set_last )
68 XWCTEST_SETUP_INDI_ARB_NEW_PROP( m_indiP_temp, roi_set_default )
69 XWCTEST_SETUP_INDI_ARB_NEW_PROP( m_indiP_temp, shutter )
70 XWCTEST_SETUP_INDI_ARB_NEW_PROP( m_indiP_temp, goto_focus )
71 }
72
73 /// Configure the stdCamera focus-state helper for a monitored switch element.
74 void configureFocusHelper( const std::string &device,
75 const std::string &property,
76 const std::string &element,
77 bool onMeansInFocus )
78 {
79 m_focusStateHelperConfigured = true;
80 m_focusStateSource = device + "." + property;
81 m_focusStateElement = element;
82 m_focusStateOnMeansInFocus = onMeansInFocus;
83 m_focusStateSourceIndex = 0;
84 m_focusMonitoredPropertyKeys = { m_focusStateSource };
85 m_indiP_focusMonitoredProperties.resize( 1 );
86 m_indiP_focusMonitoredProperties[0].setDevice( device );
87 m_indiP_focusMonitoredProperties[0].setName( property );
88 }
89
90 int cacheFocusProperty( const pcf::IndiProperty &ipRecv )
91 {
92 return setCallBack_focusMonitored( ipRecv );
93 }
94
95 bool helperFocusState()
96 {
97 return checkFocusSwitchState();
98 }
99
100 pcf::IndiElement::SwitchStateType publishedFocusState()
101 {
102 return m_indiP_focus["state"].getSwitchState();
103 }
104};
105
106class focusHelper_test : public MagAOXApp<>, public dev::stdCamera<focusHelper_test>
107{
108 friend class dev::stdCamera<focusHelper_test>;
109
110 public:
111 static constexpr bool c_stdCamera_hasFocus = true;
112 static constexpr bool c_stdCamera_tempControl = false;
113 static constexpr bool c_stdCamera_readoutSpeed = false;
114 static constexpr bool c_stdCamera_vShiftSpeed = false;
115 static constexpr bool c_stdCamera_emGain = false;
116 static constexpr bool c_stdCamera_usesModes = false;
117 static constexpr bool c_stdCamera_usesROI = false;
118
119 protected:
120 pcf::IndiProperty m_lastSentProperty; ///< Captures the last INDI command sent through the goto-focus helper.
121
122 int m_sendNewPropertyResult{ 0 }; ///< Return value used by the test sendNewProperty override.
123
124 public:
125 focusHelper_test() : MagAOXApp<>( MAGAOX_CURRENT_SHA1, MAGAOX_REPO_MODIFIED )
126 {
127 m_configName = "camtest";
128 m_hasFocus = true;
129
130 m_indiP_focus = pcf::IndiProperty( pcf::IndiProperty::Switch );
131 m_indiP_focus.setDevice( m_configName );
132 m_indiP_focus.setName( "focus" );
133 m_indiP_focus.setState( INDI_IDLE );
134 m_indiP_focus.add( pcf::IndiElement( "state", pcf::IndiElement::Off ) );
135 }
136
137 ~focusHelper_test() noexcept override = default;
138
139 void configureGotoFocusHelper( const std::vector<std::string> &properties,
140 const std::string &format,
141 const std::string &targetProperty )
142 {
143 m_focusGotoHelperConfigured = true;
144 m_focusGotoSourceProperties = properties;
145 m_focusGotoFormat = format;
146 m_focusGotoTargetProperty = targetProperty;
147 m_focusGotoSourceIndices.clear();
148 m_focusMonitoredPropertyKeys.clear();
149 m_indiP_focusMonitoredProperties.clear();
150
151 REQUIRE( indi::parseIndiKey( m_focusGotoTargetDevice, m_focusGotoTargetName, m_focusGotoTargetProperty ) == 0 );
152
153 for( size_t n = 0; n < properties.size(); ++n )
154 {
155 std::string devName;
156 std::string propName;
157
158 REQUIRE( indi::parseIndiKey( devName, propName, properties[n] ) == 0 );
159
160 m_focusGotoSourceIndices.push_back( static_cast<int>( n ) );
161 m_focusMonitoredPropertyKeys.push_back( properties[n] );
162 m_indiP_focusMonitoredProperties.emplace_back();
163 m_indiP_focusMonitoredProperties[n].setDevice( devName );
164 m_indiP_focusMonitoredProperties[n].setName( propName );
165 }
166 }
167
168 void configureFocusHelper( const std::string &device,
169 const std::string &property,
170 const std::string &element,
171 bool onMeansInFocus )
172 {
173 m_focusStateHelperConfigured = true;
174 m_focusStateSource = device + "." + property;
175 m_focusStateElement = element;
176 m_focusStateOnMeansInFocus = onMeansInFocus;
177 m_focusStateSourceIndex = 0;
178 m_focusMonitoredPropertyKeys = { m_focusStateSource };
179 m_indiP_focusMonitoredProperties.resize( 1 );
180 m_indiP_focusMonitoredProperties[0].setDevice( device );
181 m_indiP_focusMonitoredProperties[0].setName( property );
182 }
183
184 /// Cache a monitored INDI property through the stdCamera helper callback.
185 int cacheFocusProperty( const pcf::IndiProperty &ipRecv )
186 {
187 return setCallBack_focusMonitored( ipRecv );
188 }
189
190 /// Evaluate the cached focus-state helper result.
191 bool checkFocus()
192 {
193 return checkFocusSwitchState();
194 }
195
196 /// Satisfy the stdCamera derived-class interface for unit testing.
197 int gotoFocus()
198 {
199 return 0;
200 }
201
202 /// Capture the last helper-issued INDI command instead of sending it.
203 int sendNewProperty( const pcf::IndiProperty &ipSend )
204 {
205 m_lastSentProperty = ipSend;
206 return m_sendNewPropertyResult;
207 }
208
209 /// Set the return code that the sendNewProperty test hook should report.
210 void setSendNewPropertyResult( int result )
211 {
212 m_sendNewPropertyResult = result;
213 }
214
215 int appStartup() override
216 {
217 return 0;
218 }
219
220 int appLogic() override
221 {
222 return 0;
223 }
224
225 int appShutdown() override
226 {
227 return 0;
228 }
229
230 pcf::IndiElement::SwitchStateType publishedFocusState()
231 {
232 return m_indiP_focus["state"].getSwitchState();
233 }
234
235 /// Retrieve the last INDI property captured from sendGotoFocusCommand.
236 const pcf::IndiProperty &lastSentProperty() const
237 {
238 return m_lastSentProperty;
239 }
240
241 /// Retrieve the configured goto-focus format string after config parsing.
242 const std::string &gotoFocusFormat() const
243 {
244 return m_focusGotoFormat;
245 }
246
247 /// Expose stdCamera configuration setup for the config-file unit test.
248 int setupConfig( mx::app::appConfigurator &config )
249 {
251 }
252
253 /// Expose stdCamera configuration loading for the config-file unit test.
254 int loadConfig( mx::app::appConfigurator &config )
255 {
257 }
258};
259/// \endcond
260
261/// Verify the cameraSim stdCamera callback validators accept only the expected properties.
262/**
263 * \ingroup cameraSim_unit_test
264 */
265TEST_CASE( "cameraSim INDI callbacks validate device and property names", "[cameraSim]" )
266{
267 // clang-format off
268 #ifdef CAMERASIM_TEST_DOXYGEN_REF
269 cameraSim::newCallBack_stdCamera( pcf::IndiProperty() );
270 #endif
271 // clang-format on
272
273 XWCTEST_INDI_ARBNEW_CALLBACK( cameraSim, newCallBack_stdCamera, reconfigure );
274 XWCTEST_INDI_ARBNEW_CALLBACK( cameraSim, newCallBack_stdCamera, temp_ccd );
275 XWCTEST_INDI_ARBNEW_CALLBACK( cameraSim, newCallBack_stdCamera, temp_controller );
276 XWCTEST_INDI_ARBNEW_CALLBACK( cameraSim, newCallBack_stdCamera, readout_speed );
277 XWCTEST_INDI_ARBNEW_CALLBACK( cameraSim, newCallBack_stdCamera, vshift_speed );
278 XWCTEST_INDI_ARBNEW_CALLBACK( cameraSim, newCallBack_stdCamera, emgain );
279 XWCTEST_INDI_ARBNEW_CALLBACK( cameraSim, newCallBack_stdCamera, exptime );
280 XWCTEST_INDI_ARBNEW_CALLBACK( cameraSim, newCallBack_stdCamera, fps );
281 XWCTEST_INDI_ARBNEW_CALLBACK( cameraSim, newCallBack_stdCamera, synchro );
282 XWCTEST_INDI_ARBNEW_CALLBACK( cameraSim, newCallBack_stdCamera, roi_crop_mode );
283 XWCTEST_INDI_ARBNEW_CALLBACK( cameraSim, newCallBack_stdCamera, roi_region_x );
284 XWCTEST_INDI_ARBNEW_CALLBACK( cameraSim, newCallBack_stdCamera, roi_region_y );
285 XWCTEST_INDI_ARBNEW_CALLBACK( cameraSim, newCallBack_stdCamera, roi_region_w );
286 XWCTEST_INDI_ARBNEW_CALLBACK( cameraSim, newCallBack_stdCamera, roi_region_h );
287 XWCTEST_INDI_ARBNEW_CALLBACK( cameraSim, newCallBack_stdCamera, roi_region_bin_x );
288 XWCTEST_INDI_ARBNEW_CALLBACK( cameraSim, newCallBack_stdCamera, roi_region_bin_y );
289 XWCTEST_INDI_ARBNEW_CALLBACK( cameraSim, newCallBack_stdCamera, roi_region_check );
290 XWCTEST_INDI_ARBNEW_CALLBACK( cameraSim, newCallBack_stdCamera, roi_set );
291 XWCTEST_INDI_ARBNEW_CALLBACK( cameraSim, newCallBack_stdCamera, roi_set_full );
292 XWCTEST_INDI_ARBNEW_CALLBACK( cameraSim, newCallBack_stdCamera, roi_set_full_bin );
293 XWCTEST_INDI_ARBNEW_CALLBACK( cameraSim, newCallBack_stdCamera, roi_load_last );
294 XWCTEST_INDI_ARBNEW_CALLBACK( cameraSim, newCallBack_stdCamera, roi_set_last );
295 XWCTEST_INDI_ARBNEW_CALLBACK( cameraSim, newCallBack_stdCamera, roi_set_default );
296 XWCTEST_INDI_ARBNEW_CALLBACK( cameraSim, newCallBack_stdCamera, shutter );
297 XWCTEST_INDI_ARBNEW_CALLBACK( cameraSim, newCallBack_stdCamera, goto_focus );
298}
299
300/// Verify the stdCamera focus helper supports configurable polarity and tracks monitored property updates.
301/**
302 * \ingroup cameraSim_unit_test
303 */
304TEST_CASE( "cameraSim stdCamera focus helper tracks monitored switch properties", "[cameraSim]" )
305{
306 SECTION( "configured element On means out of focus" )
307 {
308 focusHelper_test app;
309 app.configureFocusHelper( "sre", "caution", "focus-mismatch", false );
310
311 pcf::IndiProperty focusProp( pcf::IndiProperty::Switch );
312 focusProp.setDevice( "sre" );
313 focusProp.setName( "caution" );
314 focusProp.add( pcf::IndiElement( "focus-mismatch", pcf::IndiElement::On ) );
315
316 REQUIRE( app.cacheFocusProperty( focusProp ) == 0 );
317 REQUIRE( app.publishedFocusState() == pcf::IndiElement::Off );
318
319 focusProp["focus-mismatch"].setSwitchState( pcf::IndiElement::Off );
320
321 REQUIRE( app.cacheFocusProperty( focusProp ) == 0 );
322 REQUIRE( app.publishedFocusState() == pcf::IndiElement::On );
323 }
324
325 SECTION( "configured element On means in focus" )
326 {
327 focusHelper_test app;
328 app.configureFocusHelper( "sre", "caution", "focus-ok", true );
329
330 pcf::IndiProperty focusProp( pcf::IndiProperty::Switch );
331 focusProp.setDevice( "sre" );
332 focusProp.setName( "caution" );
333 focusProp.add( pcf::IndiElement( "focus-ok", pcf::IndiElement::On ) );
334
335 REQUIRE( app.cacheFocusProperty( focusProp ) == 0 );
336 REQUIRE( app.publishedFocusState() == pcf::IndiElement::On );
337
338 focusProp["focus-ok"].setSwitchState( pcf::IndiElement::Off );
339
340 REQUIRE( app.cacheFocusProperty( focusProp ) == 0 );
341 REQUIRE( app.publishedFocusState() == pcf::IndiElement::Off );
342 }
343}
344
345/// Verify the stdCamera goto-focus helper formats and dispatches the expected preset command.
346/**
347 * \ingroup cameraSim_unit_test
348 */
349TEST_CASE( "cameraSim stdCamera goto-focus helper dispatches preset commands", "[cameraSim]" )
350{
351 focusHelper_test app;
352 app.configureGotoFocusHelper(
353 { "stagebs.presetName", "fwfpm.filterName", "stagescibs.presetName" }, "{}-{}-{}", "stagesci1.presetName" );
354
355 pcf::IndiProperty prop1( pcf::IndiProperty::Switch );
356 prop1.setDevice( "stagebs" );
357 prop1.setName( "presetName" );
358 prop1.add( pcf::IndiElement( "65-35", pcf::IndiElement::On ) );
359 prop1.add( pcf::IndiElement( "ha-ir", pcf::IndiElement::Off ) );
360
361 pcf::IndiProperty prop2( pcf::IndiProperty::Switch );
362 prop2.setDevice( "fwfpm" );
363 prop2.setName( "filterName" );
364 prop2.add( pcf::IndiElement( "open", pcf::IndiElement::On ) );
365 prop2.add( pcf::IndiElement( "lyotsm", pcf::IndiElement::Off ) );
366
367 pcf::IndiProperty prop3( pcf::IndiProperty::Switch );
368 prop3.setDevice( "stagescibs" );
369 prop3.setName( "presetName" );
370 prop3.add( pcf::IndiElement( "ri", pcf::IndiElement::On ) );
371 prop3.add( pcf::IndiElement( "out", pcf::IndiElement::Off ) );
372
373 REQUIRE( app.cacheFocusProperty( prop1 ) == 0 );
374 REQUIRE( app.cacheFocusProperty( prop2 ) == 0 );
375 REQUIRE( app.cacheFocusProperty( prop3 ) == 0 );
376
377 SECTION( "successful dispatch sends the formatted preset selection" )
378 {
379 REQUIRE( app.sendGotoFocusCommand() == 0 );
380 REQUIRE( app.lastSentProperty().getDevice() == "stagesci1" );
381 REQUIRE( app.lastSentProperty().getName() == "presetName" );
382 REQUIRE( app.lastSentProperty().find( "65-35-open-ri" ) );
383 REQUIRE( app.lastSentProperty()["65-35-open-ri"].getSwitchState() == pcf::IndiElement::On );
384 }
385
386 SECTION( "dispatch failures are propagated to the caller" )
387 {
388 app.setSendNewPropertyResult( -1 );
389 REQUIRE( app.sendGotoFocusCommand() == -1 );
390 }
391}
392
393/// Verify the stdCamera goto-focus helper strips wrapping quotes from configured format strings.
394/**
395 * \ingroup cameraSim_unit_test
396 */
397TEST_CASE( "cameraSim stdCamera goto-focus helper strips quoted format strings", "[cameraSim]" )
398{
399 mx::app::writeConfigFile( "/tmp/cameraSim_focusHelper.conf",
400 { "focus.gotoFocus",
401 "focus.gotoFocus",
402 "focus.gotoFocus",
403 "focus.gotoFocus",
404 "focus.gotoFocus",
405 "focus.gotoFocus" },
406 { "numSwitches", "property1", "property2", "property3", "format", "targetProperty" },
407 { "3",
408 "stagebs.presetName",
409 "fwfpm.filterName",
410 "stagescibs.presetName",
411 "\"{}-{}-{}\"",
412 "stagesci1.presetName" } );
413
414 mx::app::appConfigurator config;
415 focusHelper_test app;
416
417 REQUIRE( app.setupConfig( config ) == 0 );
418 config.readConfig( "/tmp/cameraSim_focusHelper.conf" );
419 REQUIRE( app.loadConfig( config ) == 0 );
420 REQUIRE( app.gotoFocusFormat() == "{}-{}-{}" );
421 REQUIRE_FALSE( app.gotoFocusFormat().find( '\"' ) != std::string::npos );
422}
423
424} // namespace cameraSimTest
425
426} // namespace libXWCTest
The base-class for XWCTk applications.
MagAO-X standard camera interface.
int setupConfig(mx::app::appConfigurator &config)
Setup the configuration system.
int loadConfig(mx::app::appConfigurator &config)
load the configuration system results
TEST_CASE("cameraSim INDI callbacks validate device and property names", "[cameraSim]")
Verify the cameraSim stdCamera callback validators accept only the expected properties.
#define XWCTEST_INDI_ARBNEW_CALLBACK(testclass, callback, propname)
Catch-2 tests for whether an arbitrary callback properly validates the input property properly.
#define INDI_IDLE
Definition indiUtils.hpp:27
int parseIndiKey(std::string &devName, std::string &propName, const std::string &key)
Parse an INDI key into the device and property names.
const pcf::IndiProperty & ipRecv
Namespace for all libXWC tests.
#define XWCTEST_SETUP_INDI_ARB_NEW_PROP(varname, propname)