API
 
Loading...
Searching...
No Matches
zaberCtrl_test.cpp
Go to the documentation of this file.
1/** \file zaberCtrl_test.cpp
2 * \brief Catch2 tests for the zaberCtrl app.
3 * \author Jared R. Males (jaredmales@gmail.com)
4 *
5 * \ingroup zaberCtrl_files
6 */
7
8#include "../../../tests/testXWC.hpp"
9#include "../../../tests/testMacrosINDI.hpp"
10
11#include "../zaberCtrl.hpp"
12
13using namespace MagAOX::app;
14
15namespace libXWCTest
16{
17
18/** \defgroup zaberCtrl_unit_test zaberCtrl Unit Tests
19 * \brief Unit tests for the zaberCtrl application.
20 *
21 * \ingroup application_unit_test
22 */
23
24/// Namespace for `zaberCtrl` unit tests.
25/** \ingroup zaberCtrl_unit_test
26 */
27namespace zaberCtrlTest
28{
29
30/// \cond DOXYGEN_SUPPRESS_TEST_HARNESS
31class zaberCtrl_test : public zaberCtrl
32{
33
34 public:
35 /// Construct a testable controller instance.
36 zaberCtrl_test( const std::string &device )
37 {
38 m_configName = device;
39 m_stageName = "stage";
40
43
44 // stdMotionStage:
46 XWCTEST_SETUP_INDI_NEW_PROP( presetName );
49
50 XWCTEST_SETUP_INDI_ARB_PROP( m_indiP_stageState, stest, curr_state );
51 XWCTEST_SETUP_INDI_ARB_PROP( m_indiP_stageMaxRawPos, stest, max_pos );
52 XWCTEST_SETUP_INDI_ARB_PROP( m_indiP_stageRawPos, stest, curr_pos );
53 XWCTEST_SETUP_INDI_ARB_PROP( m_indiP_stageTgtPos, stest, tgt_pos );
54 XWCTEST_SETUP_INDI_ARB_PROP( m_indiP_stageTemp, stest, temp );
55 XWCTEST_SETUP_INDI_ARB_PROP( m_indiP_stageParked, stest, parked );
56 }
57
58 /// Set the current test position state.
59 void setStagePosition( double pos, double countsPerMillimeter )
60 {
61 m_pos = pos;
62 m_countsPerMillimeter = countsPerMillimeter;
63 }
64
65 /// Set the configured preset positions and names for testing.
66 void setPresets( const std::vector<float> &positions, const std::vector<std::string> &names )
67 {
68 m_presetPositions = positions;
69 m_presetNames = names;
70 }
71
72 /// Set the current parked state for testing.
73 void setParked( bool parked )
74 {
75 m_parked = parked;
76 }
77
78 /// Set the current motion and preset telemetry values for testing.
79 void setStageTelemetry( int8_t moving, float preset, float presetTarget )
80 {
81 m_moving = moving;
82 m_preset = preset;
83 m_preset_target = presetTarget;
84 }
85
86 /// Set the current motion-state classification for testing.
87 void setMovingState( int8_t movingState )
88 {
89 m_movingState = movingState;
90 }
91
92 /// Set the configured home-preset index for testing.
93 void setHomePresetIndex( int homePresetIndex )
94 {
95 m_homePreset = homePresetIndex;
96 }
97
98 /// Track a specific preset-name alias for testing.
99 int setPresetAliasIndex( int presetNameIndex )
100 {
101 return setPresetNameTracking( presetNameIndex );
102 }
103
104 /// Clear any tracked preset-name alias for testing.
105 void clearPresetAliasIndex()
106 {
107 clearPresetNameTracking();
108 }
109
110 /// Resolve the active preset-name index for the current position.
111 int activeAliasIndex()
112 {
113 return activePresetNameIndex( presetNumber() );
114 }
115
116 /// Resolve the active preset name for the current position.
117 std::string activeAliasName()
118 {
119 return activePresetName( presetNumber() );
120 }
121
122 /// Resolve the preset name that telemetry should record.
123 std::string telemetryAliasName()
124 {
125 return telemetryPresetName();
126 }
127
128 /// Invoke the base-class power-off handling under test.
129 int stageOnPowerOff()
130 {
132 }
133
134 /// Invoke the powered-off telemetry sync under test.
135 int syncPoweredOffTelemetry()
136 {
137 return syncPowerOffStageTelemetry();
138 }
139
140 /// Apply a stage-state INDI update for the configured test stage.
141 int applyStageState( const std::string &stageState )
142 {
143 pcf::IndiProperty ip;
144 ip.setDevice( "stest" );
145 ip.setName( "curr_state" );
146 ip.add( pcf::IndiElement( m_stageName ) );
147 ip[m_stageName].set( stageState );
148
149 return setCallBack_m_indiP_stageState( ip );
150 }
151
152 /// Get the current FSM state.
153 stateCodes::stateCodeT fsmState()
154 {
155 return state();
156 }
157
158 /// Get the current homing bookkeeping state.
159 int homingState() const
160 {
161 return m_homingState;
162 }
163
164 /// Get the current logged moving state.
165 int8_t movingState() const
166 {
167 return m_moving;
168 }
169
170 /// Get the current logged preset value.
171 float presetValue() const
172 {
173 return m_preset;
174 }
175
176 /// Get the current logged preset target value.
177 float presetTargetValue() const
178 {
179 return m_preset_target;
180 }
181};
182/// \endcond
183
184/// Verify zaberCtrl callback validation and preset-alias helpers behave as expected.
185/**
186 * \ingroup zaberCtrl_unit_test
187 */
188SCENARIO( "INDI Callbacks", "[zaberCtrl]" )
189{
190 // clang-format off
191 #ifdef ZABERCTRL_TEST_DOXYGEN_REF
192 zaberCtrl::newCallBack_m_indiP_pos( pcf::IndiProperty() );
193 zaberCtrl::newCallBack_m_indiP_rawPos( pcf::IndiProperty() );
194 zaberCtrl::setCallBack_m_indiP_stageState( pcf::IndiProperty() );
195 zaberCtrl::activePresetName( 0 );
196 #endif
197 // clang-format on
198
205
206 XWCTEST_INDI_SET_CALLBACK( zaberCtrl, m_indiP_stageState, stest, curr_state );
207 XWCTEST_INDI_SET_CALLBACK( zaberCtrl, m_indiP_stageMaxRawPos, stest, max_pos );
208 XWCTEST_INDI_SET_CALLBACK( zaberCtrl, m_indiP_stageRawPos, stest, curr_pos );
209 XWCTEST_INDI_SET_CALLBACK( zaberCtrl, m_indiP_stageTgtPos, stest, tgt_pos );
210 XWCTEST_INDI_SET_CALLBACK( zaberCtrl, m_indiP_stageTemp, stest, temp );
211 XWCTEST_INDI_SET_CALLBACK( zaberCtrl, m_indiP_stageParked, stest, parked );
212}
213
214SCENARIO( "Power-off stage telemetry", "[zaberCtrl]" )
215{
216 zaberCtrl_test zct( "stest" );
217
218 zct.setPresets( { -1, 1, 2, 3 }, { "none", "one", "two", "three" } );
219 zct.setStagePosition( 2.0, 1000.0 );
220
221 WHEN( "the stage powers off while parked" )
222 {
223 zct.setParked( true );
224 zct.setStageTelemetry( 0, 2, 2 );
225
226 REQUIRE( zct.syncPoweredOffTelemetry() == 0 );
227 REQUIRE( zct.presetValue() == 2 );
228 REQUIRE( zct.presetTargetValue() == 2 );
229 }
230
231 WHEN( "the stage powers off while not parked" )
232 {
233 zct.setParked( false );
234 zct.setStageTelemetry( 0, 2, 2 );
235
236 REQUIRE( zct.syncPoweredOffTelemetry() == 0 );
237 REQUIRE( zct.presetValue() == 0 );
238 REQUIRE( zct.presetTargetValue() == 0 );
239 }
240}
241
242SCENARIO( "Homing READY transitions update the controller FSM promptly", "[zaberCtrl]" )
243{
244 zaberCtrl_test zct( "stest" );
245
246 WHEN( "homing completes without a configured post-home preset move" )
247 {
248 zct.setHomePresetIndex( -1 );
249
250 REQUIRE( zct.applyStageState( "HOMING" ) == 0 );
251 REQUIRE( zct.fsmState() == stateCodes::HOMING );
252 REQUIRE( zct.homingState() == 1 );
253
254 REQUIRE( zct.applyStageState( "READY" ) == 0 );
255 REQUIRE( zct.fsmState() == stateCodes::READY );
256 REQUIRE( zct.homingState() == 0 );
257 }
258
259 WHEN( "homing completes and a post-home preset move is still pending" )
260 {
261 zct.setHomePresetIndex( 1 );
262
263 REQUIRE( zct.applyStageState( "HOMING" ) == 0 );
264 REQUIRE( zct.fsmState() == stateCodes::HOMING );
265 REQUIRE( zct.homingState() == 1 );
266
267 REQUIRE( zct.applyStageState( "READY" ) == 0 );
268 REQUIRE( zct.fsmState() == stateCodes::HOMING );
269 REQUIRE( zct.homingState() == 2 );
270 }
271}
272
273SCENARIO( "Preset-name aliases follow the selected shared-position preset", "[zaberCtrl]" )
274{
275 zaberCtrl_test zct( "stest" );
276
277 zct.setPresets( { -1, 10, 20, 20 }, { "none", "open", "science", "focus" } );
278 zct.setStagePosition( 20.0, 1000.0 );
279 zct.setStageTelemetry( 0, 3, 3 );
280
281 WHEN( "a specific alias was selected for a shared preset position" )
282 {
283 REQUIRE( zct.setPresetAliasIndex( 3 ) == 0 );
284
285 REQUIRE( zct.activeAliasIndex() == 3 );
286 REQUIRE( zct.activeAliasName() == "focus" );
287 }
288
289 WHEN( "the stage is moving toward a selected alias" )
290 {
291 REQUIRE( zct.setPresetAliasIndex( 3 ) == 0 );
292 zct.setMovingState( 1 );
293 zct.setStageTelemetry( 1, 2, 3 );
294
295 REQUIRE( zct.activeAliasIndex() == 3 );
296 REQUIRE( zct.activeAliasName() == "focus" );
297 }
298
299 WHEN( "no alias is being tracked" )
300 {
301 zct.clearPresetAliasIndex();
302
303 REQUIRE( zct.activeAliasIndex() == 2 );
304 REQUIRE( zct.activeAliasName() == "science" );
305 }
306
307 WHEN( "the alias tracking is cleared on power off" )
308 {
309 REQUIRE( zct.setPresetAliasIndex( 3 ) == 0 );
310
311 REQUIRE( zct.stageOnPowerOff() == 0 );
312 REQUIRE( zct.movingState() == -2 );
313 REQUIRE( zct.presetValue() == 3 );
314 REQUIRE( zct.presetTargetValue() == 3 );
315 REQUIRE( zct.activeAliasIndex() == 3 );
316 REQUIRE( zct.activeAliasName() == "focus" );
317 REQUIRE( zct.telemetryAliasName() == "focus" );
318 }
319}
320
321} // namespace zaberCtrlTest
322
323} // namespace libXWCTest
int onPowerOff()
Actions on power off.
The MagAO-X Zaber Stage Controller.
Definition zaberCtrl.hpp:38
#define XWCTEST_INDI_SET_CALLBACK(testclass, varname, device, propname)
Catch-2 tests for whether a SET callback properly validates the input property properly.
#define XWCTEST_INDI_NEW_CALLBACK(testclass, propname)
Catch-2 tests for whether a NEW callback properly validates the input property properly.
SCENARIO("INDI Callbacks", "[zaberCtrl]")
Verify zaberCtrl callback validation and preset-alias helpers behave as expected.
Namespace for all libXWC tests.
@ HOMING
The device is homing.
@ READY
The device is ready for operation, but is not operating.
int16_t stateCodeT
The type of the state code.
#define XWCTEST_SETUP_INDI_ARB_PROP(varname, device, propname)
#define XWCTEST_SETUP_INDI_NEW_PROP(propname)