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