File indexing completed on 2024-04-21 14:47:21

0001 /*
0002     KStars UI tests for verifying correct counting of the capture module
0003 
0004     SPDX-FileCopyrightText: 2020 Wolfgang Reissenberger <sterne-jaeger@openfuture.de>
0005 
0006     SPDX-License-Identifier: GPL-2.0-or-later
0007 */
0008 
0009 #include "test_ekos_capture_count.h"
0010 
0011 #include "kstars_ui_tests.h"
0012 #include "test_ekos.h"
0013 #include "Options.h"
0014 #include "ekos/auxiliary/opticaltrainmanager.h"
0015 #include "ekos/capture/capture.h"
0016 #include "test_ekos_capture_helper.h"
0017 
0018 /* *****************************************************************************
0019  * Determining the correct number of frames being already captured and need to be
0020  * captured in future is surprisingly complex - which comes from the variety of
0021  * options how capturing can be configured and is being processed.
0022  *
0023  * The simplest way is when the Capture module is used standalone. The only thing
0024  * that needs to be considered is the option setting a captured frames map before
0025  * starting. This map needs to be considered and the Capture module should capture
0026  * only the difference between the numbers defined by the capture sequence and
0027  * these already existing frames.
0028  *
0029  * In combination with the Scheduler module, things get complicated, since the
0030  * Scheduler module
0031  * - has several options how a capture sequence will be repeated
0032  *   (single run, fixed number of iterations, infinite looping, termination by date)
0033  * - has the option "Remember job progress", where if selected existing frames
0034  *   need to be considered and counted.
0035  * ***************************************************************************** */
0036 
0037 TestEkosCaptureCount::TestEkosCaptureCount(QObject *parent) : QObject(parent)
0038 {
0039     m_CaptureHelper = new TestEkosCaptureHelper();
0040 }
0041 
0042 
0043 void TestEkosCaptureCount::testCaptureWithCaptureFramesMap()
0044 {
0045     // clean up capture module
0046     Ekos::Manager::Instance()->captureModule()->clearSequenceQueue();
0047     KTRY_GADGET(Ekos::Manager::Instance()->captureModule(), QTableWidget, queueTable);
0048     QTRY_VERIFY_WITH_TIMEOUT(queueTable->rowCount() == 0, 2000);
0049 
0050     // setup capture sequence, fill captured frames map and set expectations
0051     QVERIFY(prepareCapture());
0052 
0053     // verify if at least one capture is expected
0054     QVERIFY(executeCapturing());
0055 }
0056 
0057 void TestEkosCaptureCount::testSchedulerCapture()
0058 {
0059     KTELL("Expect captures and an idle signal at the end");
0060     m_CaptureHelper->expectedCaptureStates.enqueue(Ekos::CAPTURE_CAPTURING);
0061     expectedSchedulerStates.enqueue(Ekos::SCHEDULER_IDLE);
0062 
0063     KTELL("Prepare scheduler captures");
0064     QVERIFY(prepareScheduledCapture(Ekos::FINISH_REPEAT));
0065 
0066     KTELL("Start scheduler job");
0067     KTRY_CLICK(Ekos::Manager::Instance()->schedulerModule(), startB);
0068 
0069     KTELL("Ensure that the scheduler has started capturing");
0070     QTRY_VERIFY_WITH_TIMEOUT(m_CaptureHelper->expectedCaptureStates.size() == 0, 600000);
0071 
0072     KTELL("Wait for Scheduler to finish capturing");
0073     KVERIFY_EMPTY_QUEUE_WITH_TIMEOUT(expectedSchedulerStates, 600000);
0074 
0075     KTELL("Verify whether all frames are captured as expected");
0076     QVERIFY2(checkCapturedFrames(), "Capturing did not produce the expected amount of frames.");
0077 }
0078 
0079 void TestEkosCaptureCount::testSchedulerCaptureInfiteLooping()
0080 {
0081     // prepare captured frames
0082     QVERIFY(prepareScheduledCapture(Ekos::FINISH_LOOP));
0083 }
0084 
0085 /* *********************************************************************************
0086  *
0087  * Test data
0088  *
0089  * ********************************************************************************* */
0090 
0091 void TestEkosCaptureCount::testSchedulerCapture_data()
0092 {
0093 #ifdef LONG_TEST
0094     prepareTestData(0.1, "Red:2,Green:2,Blue:2", "Red:2,Green:1,Blue:2", "Green:1");
0095     prepareTestData(0.1, "Red:2,Green:2,Blue:2", "Red:3,Green:1,Blue:2", "Green:1");
0096     prepareTestData(0.1, "Red:1,Red:1,Green:1,Green:1,Blue:1,Blue:1", "Red:2,Green:1,Blue:2", "Green:1");
0097     prepareTestData(0.1, "Red:1,Green:1,Blue:1,Red:1,Green:1,Blue:1", "Red:2,Green:1,Blue:2", "Green:1");
0098     prepareTestData(0.1, "Red:1,Green:1,Blue:1", "Red:3,Green:1,Blue:3", "Green:2", 3);
0099     prepareTestData(0.1, "Luminance:3,Red:1,Green:1,Blue:1,Luminance:2", "Luminance:4,Green:1,Blue:1", "Luminance:1,Red:1");
0100     prepareTestData(0.1, "Luminance:3,Red:1,Green:1,Blue:1,Luminance:2", "", "Luminance:10,Red:2,Green:2,Blue:2", 2);
0101     prepareTestData(0.1, "Luminance:3,Red:1,Green:1,Blue:1,Luminance:2", "Luminance:15,Red:1,Green:2,Blue:2", "Red:1", 2);
0102     prepareTestData(0.1, "Luminance:3,Red:1,Green:1,Blue:1,Luminance:2", "Luminance:15,Red:2,Green:3,Blue:3", "Red:1", 3);
0103     prepareTestData(0.1, "Luminance:3,Red:1,Green:1,Blue:1,Luminance:2", "Luminance:15,Red:3,Green:3,Blue:2", "Blue:1", 3);
0104     prepareTestData(0.1, "Luminance:3,Red:1,Green:1,Blue:1,Luminance:2", "Luminance:5,Red:1,Green:1,Blue:1",
0105                     "Luminance:10,Red:2,Green:2,Blue:2", 3);
0106     prepareTestData(0.1, "Luminance:3,Red:1,Green:1,Blue:1,Luminance:2", "Luminance:2,Red:1,Green:1,Blue:1",
0107                     "Luminance:13,Red:2,Green:2,Blue:2", 3);
0108 #else
0109     prepareTestData(1.0, "Red:2,Green:2,Blue:2", "Red:2,Green:1,Blue:2", "Green:1");
0110     prepareTestData(1.0, "Red:1,Green:1,Blue:1,Red:1,Green:1,Blue:1", "Red:2,Green:1,Blue:2", "Green:1");
0111     prepareTestData(1.0, "Luminance:3,Red:1,Green:1,Blue:1,Luminance:2", "Luminance:4,Green:1,Blue:1", "Luminance:1,Red:1");
0112     prepareTestData(1.0, "Luminance:3,Red:1,Green:1,Blue:1,Luminance:2", "Luminance:5,Red:1,Green:1,Blue:1",
0113                     "Luminance:10,Red:2,Green:2,Blue:2", 3);
0114 #endif
0115 }
0116 
0117 void TestEkosCaptureCount::testCaptureWithCaptureFramesMap_data()
0118 {
0119     // use the same test set
0120     testSchedulerCapture_data();
0121 }
0122 
0123 void TestEkosCaptureCount::testSchedulerCaptureInfiteLooping_data()
0124 {
0125     prepareTestData(0.1, "Luminance:2", "Luminance:2", "");
0126     prepareTestData(0.1, "Luminance:3,Red:1,Green:1,Blue:1,Luminance:2", "Luminance:5,Green:1,Blue:1", "");
0127 }
0128 
0129 /* *********************************************************************************
0130  *
0131  * Test infrastructure
0132  *
0133  * ********************************************************************************* */
0134 
0135 void TestEkosCaptureCount::initTestCase()
0136 {
0137     KVERIFY_EKOS_IS_HIDDEN();
0138     KTRY_OPEN_EKOS();
0139     KVERIFY_EKOS_IS_OPENED();
0140     // start the profile
0141     QVERIFY(m_CaptureHelper->startEkosProfile());
0142     m_CaptureHelper->init();
0143     // do not show images
0144     Options::setUseFITSViewer(false);
0145     // disable twilight warning
0146     KMessageBox::saveDontShowAgainYesNo("astronomical_twilight_warning", KMessageBox::ButtonCode::No);
0147     // close the optical trains manager
0148     Ekos::OpticalTrainManager::Instance()->close();
0149     // wait for protile to settle
0150     QTest::qWait(1000);
0151 }
0152 
0153 void TestEkosCaptureCount::cleanupTestCase()
0154 {
0155     m_CaptureHelper->cleanup();
0156     QVERIFY(m_CaptureHelper->shutdownEkosProfile());
0157     KTRY_CLOSE_EKOS();
0158     KVERIFY_EKOS_IS_HIDDEN();
0159 }
0160 
0161 void TestEkosCaptureCount::init()
0162 {
0163     connect(Ekos::Manager::Instance()->captureModule(), &Ekos::Capture::captureComplete, this,
0164             &TestEkosCaptureCount::captureComplete);
0165     connect(Ekos::Manager::Instance()->schedulerModule(), &Ekos::Scheduler::newStatus, this,
0166             &TestEkosCaptureCount::schedulerStateChanged);
0167     QStandardPaths::setTestModeEnabled(true);
0168     // clear image directory
0169     QVERIFY(m_CaptureHelper->getImageLocation()->removeRecursively());
0170 }
0171 
0172 void TestEkosCaptureCount::cleanup()
0173 {
0174     QVERIFY(m_CaptureHelper->stopCapturing());
0175 
0176     disconnect(Ekos::Manager::Instance()->schedulerModule(), &Ekos::Scheduler::newStatus, this,
0177                &TestEkosCaptureCount::schedulerStateChanged);
0178     disconnect(Ekos::Manager::Instance()->captureModule(), &Ekos::Capture::captureComplete, this,
0179                &TestEkosCaptureCount::captureComplete);
0180 
0181     // clean up capture page
0182     Ekos::Manager::Instance()->captureModule()->clearSequenceQueue();
0183 
0184     // clean up expected images
0185     m_expectedImages.clear();
0186 
0187     // cleanup scheduler
0188     m_CaptureHelper->cleanupScheduler();
0189 }
0190 
0191 
0192 /* *********************************************************************************
0193  *
0194  * Helper functions
0195  *
0196  * ********************************************************************************* */
0197 
0198 bool TestEkosCaptureCount::checkCapturedFrames()
0199 {
0200     bool success = true;
0201     for (QMap<QString, int>::iterator it = m_expectedImages.begin(); it != m_expectedImages.end(); ++it)
0202         if (it.value() != 0)
0203         {
0204             QWARN(QString("Capture count for signature %1 does not match: %2 frames too %3 captured.").arg(it.key()).arg(abs(
0205                         it.value())).arg(it.value() < 0 ? "much" : "few").toStdString().c_str());
0206             success = false;
0207         }
0208 
0209     return success;
0210 }
0211 
0212 bool TestEkosCaptureCount::executeCapturing()
0213 {
0214 
0215     // calculate frame counts
0216     int framesCount = 0;
0217     for(int value : m_expectedImages.values())
0218         framesCount += value;
0219 
0220     // capture
0221     KWRAP_SUB(QVERIFY(m_CaptureHelper->startCapturing(framesCount > 0)));
0222 
0223     // expect receiving a new CAPTURE_COMPLETE signal
0224     if (framesCount > 0)
0225         m_CaptureHelper->expectedCaptureStates.enqueue(Ekos::CAPTURE_COMPLETE);
0226 
0227     // wait for finish capturing
0228     // ensure that the scheduler has started capturing
0229     KTRY_VERIFY_WITH_TIMEOUT_SUB(m_CaptureHelper->expectedCaptureStates.size() == 0, 600000);
0230 
0231     // verify whether all frames are captured as expected
0232     KWRAP_SUB(QVERIFY2(checkCapturedFrames(), "Capturing did not produce the expected amount of frames."));
0233 
0234     // wait for shutdown
0235     QTest::qWait(500);
0236     return true;
0237 }
0238 
0239 bool TestEkosCaptureCount::prepareCapture()
0240 {
0241     QFETCH(double, exptime);
0242     QFETCH(QString, sequence);
0243     QFETCH(QString, capturedFramesMap);
0244     QFETCH(QString, expectedFrames);
0245     QFETCH(int, iterations);
0246 
0247     // switch to capture module
0248     Ekos::Capture *capture = Ekos::Manager::Instance()->captureModule();
0249     KWRAP_SUB(KTRY_SWITCH_TO_MODULE_WITH_TIMEOUT(capture, 1000));
0250 
0251     // add target to path to emulate the behavior of the scheduler
0252     QString imagepath = m_CaptureHelper->getImageLocation()->path() + "/" + target;
0253 
0254     // create the destination for images
0255     qCInfo(KSTARS_EKOS_TEST) << "FITS path: " << imagepath;
0256 
0257     // clear the refocus check
0258     KTRY_SET_CHECKBOX_SUB(Ekos::Manager::Instance()->captureModule(), limitRefocusS, false);
0259 
0260     // create capture sequences
0261     for (int i = 0; i < iterations; i++)
0262         KVERIFY_SUB(m_CaptureHelper->fillCaptureSequences(target, sequence, exptime, imagepath));
0263 
0264     // fill the captured frames map that hold the numbers of already taken frames
0265     KVERIFY_SUB(fillCapturedFramesMap(capturedFramesMap, imagepath));
0266 
0267     // fill the map of expected frames
0268     KVERIFY_SUB(setExpectedFrames(expectedFrames));
0269 
0270     // everything successfully completed
0271     return true;
0272 }
0273 
0274 bool TestEkosCaptureCount::prepareScheduledCapture(Ekos::CompletionCondition completionCondition)
0275 {
0276     QFETCH(double, exptime);
0277     QFETCH(QString, sequence);
0278     QFETCH(QString, capturedFramesMap);
0279     QFETCH(QString, expectedFrames);
0280     QFETCH(int, iterations);
0281     QFETCH(bool, rememberJobProgress);
0282 
0283     // switch to capture module
0284     Ekos::Capture *capture = Ekos::Manager::Instance()->captureModule();
0285     KWRAP_SUB(KTRY_SWITCH_TO_MODULE_WITH_TIMEOUT(capture, 1000));
0286 
0287     // create the destination for images
0288     qCInfo(KSTARS_EKOS_TEST) << "FITS path: " << m_CaptureHelper->getImageLocation()->path();
0289 
0290     // step 1: create the frames due to the captured frames map
0291     if (capturedFramesMap != "")
0292     {
0293         KVERIFY_SUB(m_CaptureHelper->fillCaptureSequences(target, capturedFramesMap, exptime,
0294                     m_CaptureHelper->getImageLocation()->filePath(target)));
0295         KVERIFY_SUB(fillCapturedFramesMap("", m_CaptureHelper->getImageLocation()->filePath(target)));
0296         KVERIFY_SUB(setExpectedFrames(capturedFramesMap));
0297 
0298         // create the expected frames
0299         KVERIFY_SUB(executeCapturing());
0300 
0301         // clean up
0302         capture->clearSequenceQueue();
0303     }
0304 
0305     // step 2: create the sequence for the test
0306 
0307     // add target to path to emulate the behavior of the scheduler
0308     QString imagepath = m_CaptureHelper->getImageLocation()->path() + "/" + target;
0309 
0310     KVERIFY_SUB(m_CaptureHelper->fillCaptureSequences(target, sequence, exptime, imagepath));
0311     KVERIFY_SUB(fillCapturedFramesMap("", imagepath));
0312     if (rememberJobProgress)
0313         KVERIFY_SUB(setExpectedFrames(expectedFrames));
0314     else
0315         for (int i = 0; i < iterations; i++)
0316             KVERIFY_SUB(setExpectedFrames(sequence));
0317 
0318     // save current capture sequence to Ekos sequence file
0319     QString sequenceFile = m_CaptureHelper->destination->filePath("test.esq");
0320     qCInfo(KSTARS_EKOS_TEST) << "Sequence file" << sequenceFile << "created.";
0321     KVERIFY_SUB(Ekos::Manager::Instance()->captureModule()->saveSequenceQueue(sequenceFile));
0322 
0323     // setup scheduler
0324     setupScheduler(sequenceFile, sequence, capturedFramesMap, completionCondition, iterations, rememberJobProgress, exptime);
0325 
0326     // everything successfully completed
0327     return true;
0328 }
0329 
0330 bool TestEkosCaptureCount::setupScheduler(QString sequenceFile, QString sequence, QString capturedFramesMap,
0331         Ekos::CompletionCondition completionCondition,
0332         int iterations, bool rememberJobProgress, double exptime)
0333 {
0334     Ekos::Scheduler *scheduler = Ekos::Manager::Instance()->schedulerModule();
0335     KWRAP_SUB(KTRY_SWITCH_TO_MODULE_WITH_TIMEOUT(scheduler, 1000));
0336     // set sequence file
0337     scheduler->setSequence(sequenceFile);
0338     // set Kocab as target
0339     KTRY_SET_LINEEDIT_SUB(scheduler, nameEdit, target);
0340     KTRY_SET_LINEEDIT_SUB(scheduler, raBox, "14 50 42");
0341     KTRY_SET_LINEEDIT_SUB(scheduler, decBox, "74 09 20");
0342     // disable all step checks
0343     KTRY_SET_CHECKBOX_SUB(scheduler, schedulerTrackStep, false);
0344     KTRY_SET_CHECKBOX_SUB(scheduler, schedulerFocusStep, false);
0345     KTRY_SET_CHECKBOX_SUB(scheduler, schedulerAlignStep, false);
0346     KTRY_SET_CHECKBOX_SUB(scheduler, schedulerGuideStep, false);
0347     // ignore twilight
0348     KTRY_SET_CHECKBOX_SUB(scheduler, schedulerTwilight, false);
0349     // set remember job progress
0350     Options::setRememberJobProgress(rememberJobProgress);
0351     // disable INDI stopping after scheduler finished
0352     Options::setStopEkosAfterShutdown(false);
0353 
0354     // set the completion condition
0355     switch (completionCondition)
0356     {
0357         case Ekos::FINISH_REPEAT:
0358             // repeat the job for a fixed amount
0359             KTRY_SET_RADIOBUTTON_SUB(scheduler, schedulerRepeatSequences, true);
0360             KTRY_SET_SPINBOX_SUB(scheduler, schedulerExecutionSequencesLimit, iterations);
0361             break;
0362         case Ekos::FINISH_LOOP:
0363             KTRY_SET_RADIOBUTTON_SUB(scheduler, schedulerUntilTerminated, true);
0364             break;
0365         default:
0366             QWARN(QString("Unsupported completion condition %1!").arg(completionCondition).toStdString().c_str());
0367             return false;
0368             break;
0369     }
0370     // add scheduler job
0371     KTRY_CLICK_SUB(scheduler, addToQueueB);
0372 
0373     // verify the displayed capture counts
0374     KVERIFY_SUB(verifySchedulerCounting(sequence, capturedFramesMap, completionCondition, iterations, rememberJobProgress,
0375                                         exptime));
0376 
0377     // everything worked as expected
0378     return true;
0379 }
0380 
0381 bool TestEkosCaptureCount::verifySchedulerCounting(QString sequence, QString capturedFramesMap,
0382         Ekos::CompletionCondition completionCondition,
0383         int iterations, bool rememberJobProgress, double exptime)
0384 {
0385     Ekos::Scheduler *scheduler = Ekos::Manager::Instance()->schedulerModule();
0386     KTRY_GADGET_SUB(scheduler, QTableWidget, queueTable);
0387     KVERIFY_SUB(queueTable->rowCount() == 1);
0388     KVERIFY_SUB(queueTable->columnCount() > 3);
0389     QString displayedCounts = queueTable->item(0, 2)->text();
0390     KVERIFY2_SUB(displayedCounts.indexOf("/") > 0, "Scheduler job table does not display in style captured/total.");
0391 
0392     int total = -1, captured = -1, total_repeat_expected = 0;
0393 
0394     // check display of expected frames
0395     if (completionCondition == Ekos::FINISH_REPEAT)
0396     {
0397         total = displayedCounts.right(displayedCounts.length() - displayedCounts.indexOf("/") - 1).toInt();
0398         total_repeat_expected = totalCount(sequence) * iterations;
0399         KVERIFY2_SUB(total == total_repeat_expected,
0400                      QString("Scheduler job table shows %1 expected frames instead of %2.").arg(total).arg(
0401                          total_repeat_expected).toStdString().c_str());
0402     }
0403 
0404     // check display of already captured
0405     captured = displayedCounts.left(displayedCounts.indexOf("/")).toInt();
0406     // determine expected captures
0407     int captured_expected = 0;
0408     // the captured frames map is only relevant if the "Remember job progress" option is selected
0409     if (rememberJobProgress)
0410     {
0411         QMap<QString, uint16_t> capturedMap = framesMap(capturedFramesMap);
0412         QMap<QString, uint16_t> sequenceMap = framesMap(sequence);
0413         // for each filter, the displayed total is limited by the capture sequence multiplied by the number of iterations
0414         for (QString key : sequenceMap.keys())
0415             captured_expected += std::min(capturedMap[key], static_cast<uint16_t>(sequenceMap[key] * iterations));
0416     }
0417     // execute the check
0418     KVERIFY2_SUB(captured == captured_expected,
0419                  QString("Scheduler job table shows %1 captured frames instead of %2.").arg(captured).arg(
0420                      captured_expected).toStdString().c_str());
0421 
0422     // check estimated duration time (only relevant for repeats)
0423     if (completionCondition == Ekos::FINISH_REPEAT)
0424     {
0425         QTime startTime = QTime::fromString(queueTable->item(0, 4)->text(), "HH:mm");
0426         QTime endTime = QTime::fromString(queueTable->item(0, 5)->text().right(5), "HH:mm");
0427 
0428         int duration = startTime.secsTo(endTime);
0429         KVERIFY2_SUB(std::fabs((total_repeat_expected - captured_expected)*exptime - duration) <= 60,
0430                      QString("Scheduler job table shows %1 seconds expected instead of %2.").arg(duration).arg((
0431                                  total_repeat_expected - captured_expected)*exptime).toStdString().c_str());
0432     }
0433     // everything worked as expected
0434     return true;
0435 }
0436 
0437 void TestEkosCaptureCount::prepareTestData(double exptime, QString sequence, QString capturedFramesMap,
0438         QString expectedFrames, int iterations)
0439 {
0440 
0441     QTest::addColumn<double>("exptime");             /*!< exposure time */
0442     QTest::addColumn<QString>("sequence");           /*!< list of filters */
0443     QTest::addColumn<QString>("capturedFramesMap");  /*!< list of frame counts */
0444     QTest::addColumn<QString>("expectedFrames");     /*!< list of frames per filter that are expected */
0445     QTest::addColumn<int>("iterations");             /*!< how often should the sequence be repeated */
0446     QTest::addColumn<bool>("rememberJobProgress");   /*!< "Remember job progress" option selected */
0447 
0448     for (bool remember :
0449             {
0450                 false, true
0451             })
0452         QTest::newRow(QString("seq=%1, captured=%2, it=%3, remember=%4").arg(sequence).arg(capturedFramesMap).arg(iterations).arg(
0453                           remember ? "true" : "false").toStdString().c_str())
0454                 << exptime << sequence << capturedFramesMap << expectedFrames << iterations << remember;
0455 }
0456 
0457 bool TestEkosCaptureCount::fillCapturedFramesMap(QString capturedFramesMap, QString imagepath)
0458 {
0459     if (capturedFramesMap != "")
0460     {
0461         for (QString value : capturedFramesMap.split(","))
0462         {
0463             KVERIFY_SUB(value.indexOf(":") > -1);
0464             QString filter = value.left(value.indexOf(":"));
0465             int count      = value.right(value.length() - value.indexOf(":") - 1).toInt();
0466             Ekos::Manager::Instance()->captureModule()->setCapturedFramesMap(m_CaptureHelper->calculateSignature(target, filter,
0467                     imagepath),
0468                     count);
0469         }
0470     }
0471 
0472     return true;
0473 }
0474 
0475 bool TestEkosCaptureCount::setExpectedFrames(QString expectedFrames)
0476 {
0477     if (expectedFrames != "")
0478     {
0479         for (QString value : expectedFrames.split(","))
0480         {
0481             KVERIFY_SUB(value.indexOf(":") > -1);
0482             QString filter = value.left(value.indexOf(":"));
0483             int count      = value.right(value.length() - value.indexOf(":") - 1).toInt();
0484             if (m_expectedImages.contains(filter))
0485                 m_expectedImages[filter] += count;
0486             else
0487                 m_expectedImages.insert(filter, count);
0488         }
0489     }
0490     else
0491         m_expectedImages.clear();
0492 
0493     return true;
0494 }
0495 
0496 int TestEkosCaptureCount::totalCount(QString sequence)
0497 {
0498     if (sequence == "")
0499         return 0;
0500 
0501     int total = 0;
0502     for (QString value : sequence.split(","))
0503         total += value.right(value.length() - value.indexOf(":") - 1).toInt();
0504 
0505     return total;
0506 }
0507 
0508 
0509 QMap<QString, uint16_t> TestEkosCaptureCount::framesMap(QString sequence)
0510 {
0511     QMap<QString, uint16_t> result;
0512 
0513     if (sequence == "")
0514         return result;
0515 
0516     for (QString value : sequence.split(","))
0517     {
0518         QString filter = value.left(value.indexOf(":"));
0519         int count      = value.right(value.length() - value.indexOf(":") - 1).toInt();
0520         if (result.contains(filter))
0521             result[filter] += count;
0522         else
0523             result[filter] = count;
0524     }
0525 
0526     return result;
0527 }
0528 /* *********************************************************************************
0529  *
0530  * Slots
0531  *
0532  * ********************************************************************************* */
0533 
0534 void TestEkosCaptureCount::captureComplete(const QVariantMap &metadata)
0535 {
0536     auto filter = metadata["filter"].toString();
0537     // reduce the for the job's signature the number of expected images
0538     m_expectedImages.insert(filter, m_expectedImages.value(filter, 0) - 1);
0539 }
0540 
0541 void TestEkosCaptureCount::schedulerStateChanged(Ekos::SchedulerState status)
0542 {
0543     m_SchedulerStatus = status;
0544     // check if the new state is the next one expected, then remove it from the stack
0545     if (!expectedSchedulerStates.isEmpty() && expectedSchedulerStates.head() == status)
0546         expectedSchedulerStates.dequeue();
0547 
0548 }
0549 
0550 /* *********************************************************************************
0551  *
0552  * Main function
0553  *
0554  * ********************************************************************************* */
0555 
0556 QTEST_KSTARS_MAIN(TestEkosCaptureCount)