API
 
Loading...
Searching...
No Matches
userGainCtrl_test.cpp
Go to the documentation of this file.
1/** \file userGainCtrl_test.cpp
2 * \brief Catch2 tests for the userGainCtrl app.
3 * \author Jared R. Males (jaredmales@gmail.com)
4 *
5 * \ingroup userGainCtrl_files
6 */
7
8#include "../../../tests/testXWC.hpp"
9#include "../../../tests/testMacrosINDI.hpp"
10
11#include "../userGainCtrl.hpp"
12
13using namespace MagAOX::app;
14
15namespace libXWCTest
16{
17
18/** \defgroup userGainCtrl_unit_test userGainCtrl Unit Tests
19 * \brief Unit tests for the userGainCtrl application.
20 *
21 * \ingroup application_unit_test
22 */
23
24/// Namespace for `userGainCtrl` unit tests.
25/** \ingroup userGainCtrl_unit_test
26 */
27namespace userGainCtrlTest
28{
29
30/// \cond DOXYGEN_SUPPRESS_TEST_HARNESS
31class userGainCtrl_test : public userGainCtrl
32{
33
34 public:
35 userGainCtrl_test( const std::string device )
36 {
37 m_configName = device;
38
40 XWCTEST_SETUP_INDI_NEW_PROP( singleModeNo );
41 XWCTEST_SETUP_INDI_NEW_PROP( singleGain );
43 }
44};
45/// \endcond
46
47/// Verify the userGainCtrl callback validators accept only the expected properties.
48/**
49 * \ingroup userGainCtrl_unit_test
50 */
51SCENARIO( "INDI Callbacks", "[userGainCtrl]" )
52{
53 // clang-format off
54 #ifdef USERGAINCTRL_TEST_DOXYGEN_REF
55 userGainCtrl::newCallBack_m_indiP_zeroAll( pcf::IndiProperty() );
56 userGainCtrl::newCallBack_m_indiP_singleModeNo( pcf::IndiProperty() );
57 userGainCtrl::newCallBack_m_indiP_singleGain( pcf::IndiProperty() );
58 userGainCtrl::newCallBack_m_indiP_singleMC( pcf::IndiProperty() );
59 userGainCtrl::newCallBack_blockGains( pcf::IndiProperty() );
60 userGainCtrl::newCallBack_blockMCs( pcf::IndiProperty() );
61 userGainCtrl::newCallBack_blockLimits( pcf::IndiProperty() );
62 blockModes( *(std::vector<uint16_t> *)nullptr, *(std::vector<std::string> *)nullptr, 0, 0, false );
63 #endif
64 // clang-format on
65
70 XWCTEST_INDI_ARBNEW_CALLBACK( userGainCtrl, newCallBack_blockGains, block00_gain );
71 XWCTEST_INDI_ARBNEW_CALLBACK( userGainCtrl, newCallBack_blockMCs, block70_multcoeff );
72 XWCTEST_INDI_ARBNEW_CALLBACK( userGainCtrl, newCallBack_blockLimits, block32_limit );
73}
74
75/// Verify `blockModes()` partitions the requested modes into controller-sized blocks.
76/**
77 * \ingroup userGainCtrl_unit_test
78 */
79SCENARIO( "Calculating Blocks", "[userGainCtrl]" )
80{
81 GIVEN( "No Zernikes" )
82 {
83 int rv;
84 std::vector<uint16_t> blocks;
85 std::vector<std::string> names;
86 // A full block means that all the modes in the last block are present
87 WHEN( "Full blocks" )
88 {
89 rv = blockModes( blocks, names, 24, 0, false );
90
91 REQUIRE( rv == 0 );
92 REQUIRE( blocks.size() == 1 );
93 REQUIRE( blocks[0] == 24 );
94
95 rv = blockModes( blocks, names, 80, 0, false );
96
97 REQUIRE( rv == 0 );
98 REQUIRE( blocks.size() == 2 );
99 REQUIRE( blocks[0] == 24 );
100 REQUIRE( blocks[1] == 56 );
101
102 rv = blockModes( blocks, names, 168, 0, false );
103
104 REQUIRE( rv == 0 );
105 REQUIRE( blocks.size() == 3 );
106 REQUIRE( blocks[0] == 24 );
107 REQUIRE( blocks[1] == 56 );
108 REQUIRE( blocks[2] == 88 );
109 }
110
111 // A partial block means that not all modes in last block are present
112 WHEN( "Partial blocks" )
113 {
114 rv = blockModes( blocks, names, 25, 0, false );
115
116 REQUIRE( rv == 0 );
117 REQUIRE( blocks.size() == 2 );
118 REQUIRE( blocks[0] == 24 );
119 REQUIRE( blocks[1] == 1 );
120
121 rv = blockModes( blocks, names, 85, 0, false );
122
123 REQUIRE( rv == 0 );
124 REQUIRE( blocks.size() == 3 );
125 REQUIRE( blocks[0] == 24 );
126 REQUIRE( blocks[1] == 56 );
127 REQUIRE( blocks[2] == 5 );
128
129 rv = blockModes( blocks, names, 287, 0, false );
130
131 REQUIRE( rv == 0 );
132 REQUIRE( blocks.size() == 4 );
133 REQUIRE( blocks[0] == 24 );
134 REQUIRE( blocks[1] == 56 );
135 REQUIRE( blocks[2] == 88 );
136 REQUIRE( blocks[3] == 119 );
137 }
138
139 // Test when Zernikes cover various numbers of blocks
140 WHEN( "Full blocks, Zernikes in 1 block, no split" )
141 {
142 rv = blockModes( blocks, names, 24, 10, false );
143 REQUIRE( rv == 0 );
144 REQUIRE( blocks.size() == 4 );
145 REQUIRE( blocks[0] == 2 );
146 REQUIRE( blocks[1] == 1 );
147 REQUIRE( blocks[2] == 7 );
148 REQUIRE( blocks[3] == 14 );
149
150 rv = blockModes( blocks, names, 80, 5, false );
151
152 REQUIRE( rv == 0 );
153 REQUIRE( blocks.size() == 5 );
154 REQUIRE( blocks[0] == 2 );
155 REQUIRE( blocks[1] == 1 );
156 REQUIRE( blocks[2] == 2 );
157 REQUIRE( blocks[3] == 19 );
158 REQUIRE( blocks[4] == 56 );
159
160 rv = blockModes( blocks, names, 168, 23, false );
161
162 REQUIRE( rv == 0 );
163 REQUIRE( blocks.size() == 6 );
164 REQUIRE( blocks[0] == 2 );
165 REQUIRE( blocks[1] == 1 );
166 REQUIRE( blocks[2] == 20 );
167 REQUIRE( blocks[3] == 1 );
168 REQUIRE( blocks[4] == 56 );
169 REQUIRE( blocks[5] == 88 );
170 }
171
172 WHEN( "Full blocks, Zernikes in 2 blocks, no split" )
173 {
174 rv = blockModes( blocks, names, 24, 25, false );
175
176 REQUIRE( rv == 0 );
177 REQUIRE( blocks.size() == 3 );
178 REQUIRE( blocks[0] == 2 );
179 REQUIRE( blocks[1] == 1 );
180 REQUIRE( blocks[2] == 22 );
181
182 rv = blockModes( blocks, names, 80, 25, false );
183
184 REQUIRE( rv == 0 );
185 REQUIRE( blocks.size() == 4 );
186 REQUIRE( blocks[0] == 2 );
187 REQUIRE( blocks[1] == 1 );
188 REQUIRE( blocks[2] == 22 );
189 REQUIRE( blocks[3] == 55 );
190
191 rv = blockModes( blocks, names, 168, 79, false );
192 REQUIRE( rv == 0 );
193 REQUIRE( blocks.size() == 5 );
194 REQUIRE( blocks[0] == 2 );
195 REQUIRE( blocks[1] == 1 );
196 REQUIRE( blocks[2] == 76 );
197 REQUIRE( blocks[3] == 1 );
198 REQUIRE( blocks[4] == 88 );
199 }
200
201 WHEN( "Partial blocks, Zernikes in 1 block, no split" )
202 {
203 rv = blockModes( blocks, names, 25, 10, false );
204
205 REQUIRE( rv == 0 );
206 REQUIRE( blocks.size() == 5 );
207 REQUIRE( blocks[0] == 2 );
208 REQUIRE( blocks[1] == 1 );
209 REQUIRE( blocks[2] == 7 );
210 REQUIRE( blocks[3] == 14 );
211 REQUIRE( blocks[4] == 1 );
212
213 rv = blockModes( blocks, names, 85, 5, false );
214
215 REQUIRE( rv == 0 );
216 REQUIRE( blocks.size() == 6 );
217 REQUIRE( blocks[0] == 2 );
218 REQUIRE( blocks[1] == 1 );
219 REQUIRE( blocks[2] == 2 );
220 REQUIRE( blocks[3] == 19 );
221 REQUIRE( blocks[4] == 56 );
222 REQUIRE( blocks[5] == 5 );
223
224 rv = blockModes( blocks, names, 287, 23, false );
225
226 REQUIRE( rv == 0 );
227 REQUIRE( blocks.size() == 7 );
228 REQUIRE( blocks[0] == 2 );
229 REQUIRE( blocks[1] == 1 );
230 REQUIRE( blocks[2] == 20 );
231 REQUIRE( blocks[3] == 1 );
232 REQUIRE( blocks[4] == 56 );
233 REQUIRE( blocks[5] == 88 );
234 REQUIRE( blocks[6] == 119 );
235 }
236
237 WHEN( "Partial blocks, Zernikes in 2 blocks, no split" )
238 {
239 rv = blockModes( blocks, names, 26, 25, false );
240
241 REQUIRE( rv == 0 );
242 REQUIRE( blocks.size() == 4 );
243 REQUIRE( blocks[0] == 2 );
244 REQUIRE( blocks[1] == 1 );
245 REQUIRE( blocks[2] == 22 );
246 REQUIRE( blocks[3] == 1 );
247
248 rv = blockModes( blocks, names, 85, 25, false );
249
250 REQUIRE( rv == 0 );
251 REQUIRE( blocks.size() == 5 );
252 REQUIRE( blocks[0] == 2 );
253 REQUIRE( blocks[1] == 1 );
254 REQUIRE( blocks[2] == 22 );
255 REQUIRE( blocks[3] == 55 );
256 REQUIRE( blocks[4] == 5 );
257
258 rv = blockModes( blocks, names, 287, 79, false );
259
260 REQUIRE( rv == 0 );
261 REQUIRE( blocks.size() == 6 );
262 REQUIRE( blocks[0] == 2 );
263 REQUIRE( blocks[1] == 1 );
264 REQUIRE( blocks[2] == 76 );
265 REQUIRE( blocks[3] == 1 ); // b = 1, 80
266 REQUIRE( blocks[4] == 88 ); // b = 2, 168
267 REQUIRE( blocks[5] == 119 );
268 }
269
270 WHEN( "Full blocks, Zernikes in 1 block, with split" )
271 {
272 rv = blockModes( blocks, names, 24, 10, true );
273 REQUIRE( rv == 0 );
274 REQUIRE( blocks.size() == 5 );
275 REQUIRE( blocks[0] == 1 );
276 REQUIRE( blocks[1] == 1 );
277 REQUIRE( blocks[2] == 1 );
278 REQUIRE( blocks[3] == 7 );
279 REQUIRE( blocks[4] == 14 );
280
281 rv = blockModes( blocks, names, 80, 5, true );
282
283 REQUIRE( rv == 0 );
284 REQUIRE( blocks.size() == 6 );
285 REQUIRE( blocks[0] == 1 );
286 REQUIRE( blocks[1] == 1 );
287 REQUIRE( blocks[2] == 1 );
288 REQUIRE( blocks[3] == 2 );
289 REQUIRE( blocks[4] == 19 );
290 REQUIRE( blocks[5] == 56 );
291
292 rv = blockModes( blocks, names, 168, 23, true );
293
294 REQUIRE( rv == 0 );
295 REQUIRE( blocks.size() == 7 );
296 REQUIRE( blocks[0] == 1 );
297 REQUIRE( blocks[1] == 1 );
298 REQUIRE( blocks[2] == 1 );
299 REQUIRE( blocks[3] == 20 );
300 REQUIRE( blocks[4] == 1 );
301 REQUIRE( blocks[5] == 56 );
302 REQUIRE( blocks[6] == 88 );
303 }
304
305 WHEN( "Full blocks, Zernikes in 2 blocks, with split" )
306 {
307 rv = blockModes( blocks, names, 24, 25, true );
308
309 REQUIRE( rv == 0 );
310 REQUIRE( blocks.size() == 4 );
311 REQUIRE( blocks[0] == 1 );
312 REQUIRE( blocks[1] == 1 );
313 REQUIRE( blocks[2] == 1 );
314 REQUIRE( blocks[3] == 22 );
315
316 rv = blockModes( blocks, names, 80, 25, true );
317
318 REQUIRE( rv == 0 );
319 REQUIRE( blocks.size() == 5 );
320 REQUIRE( blocks[0] == 1 );
321 REQUIRE( blocks[1] == 1 );
322 REQUIRE( blocks[2] == 1 );
323 REQUIRE( blocks[3] == 22 );
324 REQUIRE( blocks[4] == 55 );
325
326 rv = blockModes( blocks, names, 168, 79, true );
327 REQUIRE( rv == 0 );
328 REQUIRE( blocks.size() == 6 );
329 REQUIRE( blocks[0] == 1 );
330 REQUIRE( blocks[1] == 1 );
331 REQUIRE( blocks[2] == 1 );
332 REQUIRE( blocks[3] == 76 );
333 REQUIRE( blocks[4] == 1 );
334 REQUIRE( blocks[5] == 88 );
335 }
336
337 WHEN( "Partial blocks, Zernikes in 1 block, with split" )
338 {
339 rv = blockModes( blocks, names, 25, 10, true );
340
341 REQUIRE( rv == 0 );
342 REQUIRE( blocks.size() == 6 );
343 REQUIRE( blocks[0] == 1 );
344 REQUIRE( blocks[1] == 1 );
345 REQUIRE( blocks[2] == 1 );
346 REQUIRE( blocks[3] == 7 );
347 REQUIRE( blocks[4] == 14 );
348 REQUIRE( blocks[5] == 1 );
349
350 rv = blockModes( blocks, names, 85, 5, true );
351
352 REQUIRE( rv == 0 );
353 REQUIRE( blocks.size() == 7 );
354 REQUIRE( blocks[0] == 1 );
355 REQUIRE( blocks[1] == 1 );
356 REQUIRE( blocks[2] == 1 );
357 REQUIRE( blocks[3] == 2 );
358 REQUIRE( blocks[4] == 19 );
359 REQUIRE( blocks[5] == 56 );
360 REQUIRE( blocks[6] == 5 );
361
362 rv = blockModes( blocks, names, 287, 23, true );
363
364 REQUIRE( rv == 0 );
365 REQUIRE( blocks.size() == 8 );
366 REQUIRE( blocks[0] == 1 );
367 REQUIRE( blocks[1] == 1 );
368 REQUIRE( blocks[2] == 1 );
369 REQUIRE( blocks[3] == 20 );
370 REQUIRE( blocks[4] == 1 );
371 REQUIRE( blocks[5] == 56 );
372 REQUIRE( blocks[6] == 88 );
373 REQUIRE( blocks[7] == 119 );
374 }
375
376 WHEN( "Partial blocks, Zernikes in 2 blocks, with split" )
377 {
378 rv = blockModes( blocks, names, 26, 25, true );
379
380 REQUIRE( rv == 0 );
381 REQUIRE( blocks.size() == 5 );
382 REQUIRE( blocks[0] == 1 );
383 REQUIRE( blocks[1] == 1 );
384 REQUIRE( blocks[2] == 1 );
385 REQUIRE( blocks[3] == 22 );
386 REQUIRE( blocks[4] == 1 );
387
388 rv = blockModes( blocks, names, 85, 25, true );
389
390 REQUIRE( rv == 0 );
391 REQUIRE( blocks.size() == 6 );
392 REQUIRE( blocks[0] == 1 );
393 REQUIRE( blocks[1] == 1 );
394 REQUIRE( blocks[2] == 1 );
395 REQUIRE( blocks[3] == 22 );
396 REQUIRE( blocks[4] == 55 );
397 REQUIRE( blocks[5] == 5 );
398
399 rv = blockModes( blocks, names, 287, 79, true );
400
401 REQUIRE( rv == 0 );
402 REQUIRE( blocks.size() == 7 );
403 REQUIRE( blocks[0] == 1 );
404 REQUIRE( blocks[1] == 1 );
405 REQUIRE( blocks[2] == 1 );
406 REQUIRE( blocks[3] == 76 );
407 REQUIRE( blocks[4] == 1 ); // b = 1, 80
408 REQUIRE( blocks[5] == 88 ); // b = 2, 168
409 REQUIRE( blocks[6] == 119 );
410 }
411
412 // Test if it all generalizes to even more zernikes
413 WHEN( "Partial blocks, Zernikes in 3 blocks, with split" )
414 {
415 rv = blockModes( blocks, names, 26, 81, true ); // this should give 81 modes and quit
416
417 REQUIRE( rv == 0 );
418 REQUIRE( blocks.size() == 4 );
419 REQUIRE( blocks[0] == 1 );
420 REQUIRE( blocks[1] == 1 );
421 REQUIRE( blocks[2] == 1 );
422 REQUIRE( blocks[3] == 78 );
423
424 rv = blockModes( blocks, names, 85, 81, true );
425
426 REQUIRE( rv == 0 );
427 REQUIRE( blocks.size() == 5 );
428 REQUIRE( blocks[0] == 1 );
429 REQUIRE( blocks[1] == 1 );
430 REQUIRE( blocks[2] == 1 );
431 REQUIRE( blocks[3] == 78 );
432 REQUIRE( blocks[4] == 4 );
433
434 rv = blockModes( blocks, names, 287, 100, true );
435
436 REQUIRE( rv == 0 );
437 REQUIRE( blocks.size() == 6 );
438 REQUIRE( blocks[0] == 1 );
439 REQUIRE( blocks[1] == 1 );
440 REQUIRE( blocks[2] == 1 );
441 REQUIRE( blocks[3] == 97 );
442 REQUIRE( blocks[4] == 68 ); // b = 2, 168
443 REQUIRE( blocks[5] == 119 );
444 }
445
446 WHEN( "The Full MagAO-X" )
447 {
448 rv = blockModes( blocks, names, 2400, 10, true ); // this should give 81 modes and quite
449
450 REQUIRE( rv == 0 );
451 REQUIRE( blocks.size() == 16 );
452 REQUIRE( blocks[0] == 1 );
453 REQUIRE( blocks[1] == 1 );
454 REQUIRE( blocks[2] == 1 );
455 REQUIRE( blocks[3] == 7 );
456 REQUIRE( blocks[4] == 14 ); // b=0 remainder
457 REQUIRE( blocks[5] == 56 ); // b=1
458 REQUIRE( blocks[6] == 88 );
459 REQUIRE( blocks[7] == 120 );
460 REQUIRE( blocks[8] == 152 );
461 REQUIRE( blocks[9] == 184 );
462 REQUIRE( blocks[10] == 216 );
463 REQUIRE( blocks[11] == 248 );
464 REQUIRE( blocks[12] == 280 );
465 REQUIRE( blocks[13] == 312 );
466 REQUIRE( blocks[14] == 344 );
467 REQUIRE( blocks[15] == 376 );
468 }
469 }
470}
471
472} // namespace userGainCtrlTest
473
474} // namespace libXWCTest
int newCallBack_blockLimits(const pcf::IndiProperty &ipRecv)
Callback to process a NEW block limits.
int newCallBack_blockMCs(const pcf::IndiProperty &ipRecv)
Callback to process a NEW block mult. coeff.s.
int newCallBack_blockGains(const pcf::IndiProperty &ipRecv)
Callback to process a NEW block gain request.
#define XWCTEST_INDI_NEW_CALLBACK(testclass, propname)
Catch-2 tests for whether a NEW callback properly validates the input property properly.
#define XWCTEST_INDI_ARBNEW_CALLBACK(testclass, callback, propname)
Catch-2 tests for whether an arbitrary callback properly validates the input property properly.
SCENARIO("INDI Callbacks", "[userGainCtrl]")
Verify the userGainCtrl callback validators accept only the expected properties.
int blockModes(std::vector< uint16_t > &blocks, std::vector< std::string > &names, uint16_t Nmodes, uint16_t Nzern, bool splitTT)
Calculate the number of blocks and the number of modes per block.
Namespace for all libXWC tests.
#define XWCTEST_SETUP_INDI_NEW_PROP(propname)