1 /*
2     SPDX-FileCopyrightText: 2017 Csaba Kertesz <csaba.kertesz@gmail.com>
3     SPDX-FileCopyrightText: 2020 Eric Dejouhanet <eric.dejouhanet@gmail.com>
4 
5     SPDX-License-Identifier: GPL-2.0-or-later
6 */
7 
8 #include "config-kstars.h"
9 
10 #include <QObject>
11 #include <QtTest>
12 #include <QDialogButtonBox>
13 #include <QtConcurrent>
14 
15 #include "Options.h"
16 #include "kstars.h"
17 #include "kspaths.h"
18 #include "kswizard.h"
19 #include <KTipDialog>
20 
21 #include "kstars_ui_tests.h"
22 #include "test_kstars_startup.h"
23 
24 
25 struct TestKStarsStartup::_InitialConditions const TestKStarsStartup::m_InitialConditions;
26 
TestKStarsStartup(QObject * parent)27 TestKStarsStartup::TestKStarsStartup(QObject *parent) : QObject(parent)
28 {
29 }
30 
initTestCase()31 void TestKStarsStartup::initTestCase()
32 {
33     if (KStars::Instance() != nullptr)
34         KTRY_SHOW_KSTARS();
35 }
36 
cleanupTestCase()37 void TestKStarsStartup::cleanupTestCase()
38 {
39     foreach (QDialog * d, KStars::Instance()->findChildren<QDialog*>())
40         if (d->isVisible())
41             d->hide();
42 }
43 
init()44 void TestKStarsStartup::init()
45 {
46 }
47 
cleanup()48 void TestKStarsStartup::cleanup()
49 {
50 }
51 
createInstanceTest()52 void TestKStarsStartup::createInstanceTest()
53 {
54 #if defined(HAVE_INDI)
55     QWARN("INDI driver registry is unexpectedly required before we start the KStars wizard");
56 
57     // Locate INDI drivers like drivermanager.cpp does
58     Options::setIndiDriversDir(
59         QStandardPaths::locate(QStandardPaths::GenericDataLocation, "indi", QStandardPaths::LocateDirectory));
60     QVERIFY(QDir(Options::indiDriversDir()).exists());
61 
62     // Look for the second usual place - developer install - OSX should be there too?
63     if (QFile("/usr/local/bin/indiserver").exists())
64         Options::setIndiServer("/usr/local/bin/indiserver");
65     QVERIFY(QFile(Options::indiServer()).exists());
66 #endif
67 
68     // Prepare to close the wizard pages when the KStars instance will start - we could just use the following to bypass
69     // Options::setRunStartupWizard(false);
70     // Remaining in the timer signal waiting for the app to load actually prevents the app from
71     // loading, so retrigger the timer until the app is ready
72     volatile bool installWizardDone = false;
73     if (Options::runStartupWizard() == true) {
74         std::function <void()> closeWizard = [&]
75         {
76             QTRY_VERIFY_WITH_TIMEOUT(KStars::Instance() != nullptr, 5000);
77             KStars * const k = KStars::Instance();
78             QVERIFY(k != nullptr);
79 
80             // Wait for the KStars Wizard to appear, or retrigger the signal
81             if(k->findChild <KSWizard*>() == nullptr)
82             {
83                 QTimer::singleShot(500, KStars::Instance(), closeWizard);
84                 return;
85             }
86 
87             // Verify it is a KSWizard that appeared
88             KSWizard * const w = k->findChild <KSWizard*>();
89             QVERIFY(w != nullptr);
90             QTRY_VERIFY_WITH_TIMEOUT(w->isVisible(), 1000);
91 
92             // Wait for the New Installation Wizard inside that KSWizard
93             QTRY_VERIFY_WITH_TIMEOUT(w->findChild <QWidget*>("WizWelcome") != nullptr, 1000);
94             QWidget * ww = KStars::Instance()->findChild <QWidget*>("WizWelcome");
95             QTRY_VERIFY_WITH_TIMEOUT(ww->isVisible(), 1000);
96 
97             // We could shift to all pages one after the other, but the Next button is difficult to locate, so just dismiss the wizard lazily
98             QDialogButtonBox* buttons = w->findChild<QDialogButtonBox*>();
99             QVERIFY(nullptr != buttons);
100 
101             // search the "Done" button
102             QAbstractButton *doneButton;
103             for (QAbstractButton *button: buttons->buttons())
104             {
105                 if (button->text().toStdString() == "Done")
106                     doneButton = button;
107             }
108             QVERIFY(nullptr != doneButton);
109             QTest::mouseClick(doneButton, Qt::LeftButton);
110 
111             installWizardDone = true;
112         };
113         QTimer::singleShot(500, KStars::Instance(), closeWizard);
114     }
115     else {
116         installWizardDone = true;
117     }
118     // Initialize our instance and wait for the test to finish
119     KTipDialog::setShowOnStart(false);
120     KStars::createInstance(true, m_InitialConditions.clockRunning, m_InitialConditions.dateTime.toString());
121     QVERIFY(KStars::Instance() != nullptr);
122     QTRY_VERIFY_WITH_TIMEOUT(installWizardDone, 10000);
123 
124     // With our instance created, initialize our location
125     // FIXME: do this via UI in the Startup Wizard
126     KStarsData * const d = KStars::Instance()->data();
127     QVERIFY(d != nullptr);
128     GeoLocation * const g = d->locationNamed("Greenwich");
129     QVERIFY(g != nullptr);
130     d->setLocation(*g);
131 
132     // Verify our location is properly selected
133     QCOMPARE(d->geo()->lat()->Degrees(), g->lat()->Degrees());
134     QCOMPARE(d->geo()->lng()->Degrees(), g->lng()->Degrees());
135 }
136 
testInitialConditions()137 void TestKStarsStartup::testInitialConditions()
138 {
139     QVERIFY(KStars::Instance() != nullptr);
140     QVERIFY(KStars::Instance()->data() != nullptr);
141     QVERIFY(KStars::Instance()->data()->clock() != nullptr);
142 
143     QCOMPARE(KStars::Instance()->data()->clock()->isActive(), m_InitialConditions.clockRunning);
144 
145     QEXPECT_FAIL("", "Initial KStars clock is set from system local time, not geolocation, and is untestable for now.",
146                  Continue);
147     QCOMPARE(KStars::Instance()->data()->clock()->utc().toString(), m_InitialConditions.dateTime.toString());
148 
149     QEXPECT_FAIL("", "Precision of KStars local time conversion to local time does not allow strict millisecond comparison.",
150                  Continue);
151     QCOMPARE(KStars::Instance()->data()->clock()->utc().toLocalTime(), m_InitialConditions.dateTime);
152 
153 #if QT_VERSION >= 0x050800
154     // However comparison down to nearest second is expected to be OK
155     QCOMPARE(llround(KStars::Instance()->data()->clock()->utc().toLocalTime().toMSecsSinceEpoch() / 1000.0),
156              m_InitialConditions.dateTime.toSecsSinceEpoch());
157 
158     // Test setting time
159     KStars::Instance()->data()->clock()->setUTC(KStarsDateTime(m_InitialConditions.dateTime));
160     QCOMPARE(llround(KStars::Instance()->data()->clock()->utc().toLocalTime().toMSecsSinceEpoch() / 1000.0),
161              m_InitialConditions.dateTime.toSecsSinceEpoch());
162 #endif
163 }
164