MailJDTourDownloadDocsQualityTestsCoverage

Which source lines and branches the tests execute. Lines 91.5 %, branches 75.0 % (minimum 85 % and 72 %). main @ 399ffe3d · 21 October 2026 · pipeline 7238.

GCC Code Coverage Report


Directory: src/
Coverage: low: ≥ 0% medium: ≥ 75.0% high: ≥ 90.0%
Coverage Exec / Excl / Total
Lines: 100.0% 7 / 0 / 7
Functions: 100.0% 7 / 0 / 7
Branches: 91.7% 11 / 0 / 12

service/MailServerDiscovery.h
Line Branch Exec Source
1 #pragma once
2 #include <QCoreApplication>
3 #include <QList>
4 #include <QObject>
5 #include <QSet>
6 #include <QString>
7 #include <QTimer>
8 #include <QUrl>
9 #include <QVariantMap>
10 #include <functional>
11
12 // Sprint 100 S100.1.8 (D-6, SF-02): finds the incoming and outgoing servers
13 // of an address without the password. Sources run in parallel, each at most
14 // 4 s, all together at most 8 s, TLS/HTTPS only (rule 11):
15 // 1. DNS SRV (RFC 6186/8314): _imaps._tcp, _submissions._tcp, _submission._tcp
16 // 2. Thunderbird autoconfig XML on the address domain (HTTPS, no redirects)
17 // 3. TLS handshake with imap./mail./smtp.<domain> on 993/465
18 // 4. the Thunderbird ISPDB — only after lookupIspdb() (it sends the
19 // domain to a third party, D-6)
20 // A result is *trusted* when it comes from HTTPS autoconfig on the address
21 // domain or names hosts inside the address domain; otherwise the setup
22 // shows the hosts before the password is sent (§6.2.2 step ③).
23 // Network access goes through three seams so the provider matrix replays
24 // recorded answers (tests/fixtures/autoconfig/).
25 class MailServerDiscovery final : public QObject {
26 Q_OBJECT
27 public:
28 struct Server {
29 QString host;
30 quint16 port = 0;
31 QString security; // "ssl" or "starttls"
32 QString username; // resolved from the template (address, local part)
33 bool operator==(const Server &) const = default;
34
4/4
✓ Branch 3 → 4 taken 311 times.
✓ Branch 3 → 6 taken 99 times.
✓ Branch 4 → 5 taken 310 times.
✓ Branch 4 → 6 taken 1 time.
410 bool valid() const { return !host.isEmpty() && port > 0; }
35 };
36 struct Result {
37 Server imap, smtp;
38 QString source; // "autoconfig", "srv", "probe", "ispdb"
39 bool trusted = false;
40
4/4
✓ Branch 3 → 4 taken 75 times.
✓ Branch 3 → 7 taken 33 times.
✓ Branch 5 → 6 taken 62 times.
✓ Branch 5 → 7 taken 13 times.
108 bool complete() const { return imap.valid() && smtp.valid(); }
41 };
42 struct SrvRecord {
43 QString target;
44 quint16 port = 0;
45 int priority = 0;
46 };
47 using SrvLookup = std::function<void(QObject *owner, const QString &name, std::function<void(QList<SrvRecord>)>)>;
48 // status 0 = network/TLS failure; redirects are never followed.
49 using HttpGet = std::function<void(QObject *owner, const QUrl &url, std::function<void(int status, QByteArray body)>)>;
50 using TlsProbe = std::function<void(QObject *owner, const QString &host, quint16 port, std::function<void(bool)>)>;
51
52 explicit MailServerDiscovery(QObject *parent = nullptr);
53 void setSeams(SrvLookup srv, HttpGet http, TlsProbe tls);
54 8 void setTimeouts(int sourceMs, int overallMs) { m_sourceMs = sourceMs; m_overallMs = overallMs; }
55 // Starts the sources for the address' domain. Earlier runs are cancelled.
56 void start(const QString &address);
57 // D-6: the explicit "Look up in the Thunderbird database".
58 void lookupIspdb();
59 void cancel();
60 1 bool running() const { return m_running; }
61 QString domain() const { return m_domain; }
62 // Per source: "pending", "found", "none" (srv, autoconfig, probe, ispdb).
63 12 QVariantMap sources() const { return m_sources; }
64 24 Result best() const { return m_best; }
65
66 // Pure helpers (unit-tested).
67 static QList<Result> parseAutoconfig(const QByteArray &xml, const QString &address, const QString &source,
68 bool trusted);
69 static QString resolveUsername(const QString &pattern, const QString &address);
70 static bool hostInDomain(const QString &host, const QString &domain);
71 static int rank(const Result &result);
72
73 signals:
74 void sourcesChanged();
75 void finished(bool found);
76
77 private:
78 void sourceDone(const QString &source, const QList<Result> &results);
79 void finishIfDone();
80 void runSrv(quint64 run);
81 void runAutoconfig(quint64 run);
82 void runProbe(quint64 run);
83
3/4
✓ Branch 2 → 3 taken 158 times.
✓ Branch 2 → 5 taken 54 times.
✓ Branch 3 → 4 taken 158 times.
✗ Branch 3 → 5 not taken.
212 bool current(quint64 run) const { return m_running && run == m_run; }
84 QString m_address, m_domain;
85 QVariantMap m_sources;
86 QList<Result> m_results;
87 Result m_best;
88 bool m_running = false;
89 quint64 m_run = 0;
90 int m_sourceMs = 4000;
91 int m_overallMs = 8000;
92 QTimer m_overall;
93 QObject *m_owner = nullptr; // parent of the in-flight requests of one run
94 SrvLookup m_srv;
95 HttpGet m_http;
96 TlsProbe m_tls;
97 };
98