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: 97.7% 169 / 0 / 173
Functions: 92.3% 12 / 0 / 13
Branches: 75.4% 267 / 0 / 354

service/NativeImageResources.cpp
Line Branch Exec Source
1 #include "NativeImageResources.h"
2
3 #include <QBuffer>
4 #include <QFile>
5 #include <QFileInfo>
6 #include <QImageReader>
7 #include <QScopeGuard>
8 #include <QSet>
9 #include <QSqlDatabase>
10 #include <QSqlDriver>
11 #include <QSqlQuery>
12 #include <QUuid>
13 #include <QVariant>
14 #include <sqlite3.h>
15 #ifdef Q_OS_UNIX
16 #include <sys/stat.h>
17 #endif
18
19 namespace {
20 84 bool validRequest(const NativeImageContext &context, const QStringList &ids,
21 const std::atomic_bool *cancelled) {
22
2/2
✓ Branch 4 → 5 taken 64 times.
✓ Branch 4 → 20 taken 1 time.
65 return (!cancelled || !cancelled->load(std::memory_order_relaxed)) &&
23
8/8
✓ Branch 5 → 6 taken 67 times.
✓ Branch 5 → 20 taken 16 times.
✓ Branch 6 → 7 taken 66 times.
✓ Branch 6 → 20 taken 1 time.
✓ Branch 8 → 9 taken 22 times.
✓ Branch 8 → 20 taken 44 times.
✓ Branch 10 → 11 taken 21 times.
✓ Branch 10 → 20 taken 1 time.
105 context.folderId > 0 && context.uid > 0 && !ids.isEmpty() &&
24
1/2
✓ Branch 12 → 13 taken 21 times.
✗ Branch 12 → 20 not taken.
43 ids.size() <= 128 && context.expectedHtml.size() <= 1024 * 1024 &&
25
4/5
✓ Branch 2 → 3 taken 65 times.
✓ Branch 2 → 5 taken 19 times.
✓ Branch 14 → 15 taken 21 times.
✓ Branch 15 → 16 taken 21 times.
✗ Branch 15 → 20 not taken.
189 !context.databasePath.contains(QChar::Null) &&
26
6/8
✓ Branch 16 → 17 taken 21 times.
✓ Branch 17 → 18 taken 21 times.
✓ Branch 18 → 19 taken 20 times.
✓ Branch 18 → 20 taken 1 time.
✓ Branch 21 → 22 taken 21 times.
✓ Branch 21 → 23 taken 63 times.
✗ Branch 25 → 26 not taken.
✗ Branch 25 → 27 not taken.
105 QFileInfo(context.databasePath).isFile();
27 }
28
29 18 bool usesUtf8(QSqlDatabase &db, bool *utf8) {
30
1/1
✓ Branch 2 → 3 taken 18 times.
18 QSqlQuery encoding(db);
31
9/16
✓ Branch 6 → 7 taken 18 times.
✓ Branch 7 → 8 taken 17 times.
✓ Branch 7 → 10 taken 1 time.
✓ Branch 8 → 9 taken 17 times.
✗ Branch 9 → 10 not taken.
✓ Branch 9 → 11 taken 17 times.
✓ Branch 12 → 13 taken 18 times.
✗ Branch 12 → 14 not taken.
✓ Branch 14 → 15 taken 18 times.
✗ Branch 14 → 16 not taken.
✓ Branch 16 → 17 taken 1 time.
✓ Branch 16 → 18 taken 17 times.
✗ Branch 32 → 33 not taken.
✗ Branch 32 → 34 not taken.
✗ Branch 36 → 37 not taken.
✗ Branch 36 → 38 not taken.
36 if (!encoding.exec(QStringLiteral("PRAGMA encoding")) || !encoding.next()) return false;
32
2/2
✓ Branch 18 → 19 taken 17 times.
✓ Branch 19 → 20 taken 17 times.
51 *utf8 = encoding.value(0).toString().compare(
33 34 QStringLiteral("UTF-8"), Qt::CaseInsensitive) == 0;
34 17 return true;
35 18 }
36
37 19 QHash<QString, QImage> readSnapshot(QSqlDatabase &db, bool utf8,
38 const NativeImageContext &context,
39 const QStringList &canonicalIds,
40 const std::atomic_bool *cancelled,
41 bool *healthy) {
42 1086 const auto interrupted = [cancelled] {
43
3/4
✓ Branch 2 → 3 taken 28 times.
✓ Branch 2 → 6 taken 1058 times.
✗ Branch 4 → 5 not taken.
✓ Branch 4 → 6 taken 28 times.
1086 return cancelled && cancelled->load(std::memory_order_relaxed);
44 19 };
45
1/2
✗ Branch 3 → 4 not taken.
✓ Branch 3 → 5 taken 19 times.
19 if (interrupted()) return {};
46
2/3
✓ Branch 5 → 6 taken 19 times.
✗ Branch 6 → 7 not taken.
✓ Branch 6 → 8 taken 19 times.
19 if (!db.transaction()) { *healthy = false; return {}; }
47 // A retained connection must never carry a read snapshot into the next
48 // mail. Query objects below die before these guards unwind.
49 57 const auto rollback = qScopeGuard([&] {
50
1/2
✗ Branch 3 → 4 not taken.
✓ Branch 3 → 5 taken 19 times.
19 if (!db.rollback()) *healthy = false;
51 19 });
52 19 sqlite3 *sqlite = nullptr;
53
6/7
✓ Branch 9 → 10 taken 6 times.
✓ Branch 9 → 13 taken 13 times.
✓ Branch 10 → 11 taken 6 times.
✓ Branch 11 → 12 taken 6 times.
✗ Branch 11 → 13 not taken.
✓ Branch 14 → 15 taken 6 times.
✓ Branch 14 → 32 taken 13 times.
19 if (cancelled && db.driver()) {
54
2/2
✓ Branch 15 → 16 taken 6 times.
✓ Branch 16 → 17 taken 6 times.
6 if (auto handle = db.driver()->handle();
55
7/13
✓ Branch 17 → 18 taken 6 times.
✓ Branch 18 → 19 taken 6 times.
✗ Branch 18 → 24 not taken.
✓ Branch 19 → 20 taken 6 times.
✓ Branch 20 → 21 taken 6 times.
✓ Branch 22 → 23 taken 6 times.
✗ Branch 22 → 24 not taken.
✓ Branch 25 → 26 taken 6 times.
✗ Branch 25 → 27 not taken.
✓ Branch 27 → 28 taken 6 times.
✗ Branch 27 → 30 not taken.
✗ Branch 258 → 259 not taken.
✗ Branch 258 → 260 not taken.
6 handle.isValid() && QByteArray(handle.typeName()) == "sqlite3*")
56
1/1
✓ Branch 28 → 29 taken 6 times.
6 sqlite = *static_cast<sqlite3 **>(handle.data());
57 }
58
3/3
✓ Branch 32 → 33 taken 6 times.
✓ Branch 32 → 36 taken 13 times.
✓ Branch 34 → 35 taken 6 times.
19 if (sqlite) sqlite3_progress_handler(sqlite, 1000, [](void *context) {
59 ✗ return static_cast<const std::atomic_bool *>(context)->load(
60 ✗ std::memory_order_relaxed) ? 1 : 0;
61 }, const_cast<std::atomic_bool *>(cancelled));
62 57 const auto clearProgress = qScopeGuard([sqlite] {
63
2/2
✓ Branch 2 → 3 taken 6 times.
✓ Branch 2 → 4 taken 13 times.
19 if (sqlite) sqlite3_progress_handler(sqlite, 0, nullptr, nullptr);
64 19 });
65
66
1/1
✓ Branch 37 → 38 taken 19 times.
19 QSqlQuery header(db);
67 // SQLite's UTF-8 TEXT storage can compare exact source bytes without
68 // returning the whole document. Keep decoded comparison for older caches
69 // with a different database encoding.
70
1/1
✓ Branch 57 → 58 taken 19 times.
57 header.prepare(QStringLiteral("SELECT h.id") +
71
3/7
✓ Branch 46 → 47 taken 19 times.
✗ Branch 46 → 48 not taken.
✓ Branch 54 → 55 taken 19 times.
✗ Branch 64 → 65 not taken.
✓ Branch 64 → 66 taken 19 times.
✗ Branch 281 → 282 not taken.
✗ Branch 281 → 283 not taken.
76 (utf8 ? QString{} : QStringLiteral(", b.text_html")) +
72
1/1
✓ Branch 55 → 56 taken 19 times.
57 QStringLiteral(" FROM headers h JOIN folders f ON f.id=h.folder_id "
73 "JOIN bodies b ON b.header_id=h.id WHERE h.folder_id=? AND h.uid=? AND f.uidvalidity=? "
74 19 "AND length(CAST(b.text_html AS BLOB))<=1048576") +
75
3/7
✓ Branch 38 → 39 taken 19 times.
✗ Branch 38 → 42 not taken.
✓ Branch 56 → 57 taken 19 times.
✓ Branch 69 → 70 taken 19 times.
✗ Branch 69 → 71 not taken.
✗ Branch 296 → 297 not taken.
✗ Branch 296 → 298 not taken.
76 (utf8 ? QStringLiteral(" AND CAST(b.text_html AS BLOB)=?") : QString{}));
76
1/1
✓ Branch 73 → 74 taken 19 times.
19 header.addBindValue(context.folderId);
77
1/1
✓ Branch 77 → 78 taken 19 times.
19 header.addBindValue(context.uid);
78
1/1
✓ Branch 81 → 82 taken 19 times.
19 header.addBindValue(context.uidValidity);
79
2/3
✓ Branch 83 → 84 taken 19 times.
✗ Branch 83 → 89 not taken.
✓ Branch 86 → 87 taken 19 times.
38 if (utf8) header.addBindValue(context.expectedHtml);
80
6/6
✓ Branch 89 → 90 taken 19 times.
✓ Branch 90 → 91 taken 18 times.
✓ Branch 90 → 99 taken 1 time.
✓ Branch 91 → 92 taken 18 times.
✓ Branch 92 → 93 taken 14 times.
✓ Branch 92 → 99 taken 4 times.
33 if (!header.exec() || !header.next() ||
81
6/21
✗ Branch 93 → 94 not taken.
✓ Branch 93 → 100 taken 14 times.
✗ Branch 94 → 95 not taken.
✗ Branch 95 → 96 not taken.
✗ Branch 96 → 97 not taken.
✗ Branch 98 → 99 not taken.
✗ Branch 98 → 100 not taken.
✗ Branch 101 → 102 not taken.
✓ Branch 101 → 103 taken 19 times.
✗ Branch 103 → 104 not taken.
✓ Branch 103 → 105 taken 19 times.
✗ Branch 105 → 106 not taken.
✓ Branch 105 → 107 taken 19 times.
✓ Branch 107 → 108 taken 5 times.
✓ Branch 107 → 109 taken 14 times.
✗ Branch 318 → 319 not taken.
✗ Branch 318 → 320 not taken.
✗ Branch 322 → 323 not taken.
✗ Branch 322 → 324 not taken.
✗ Branch 326 → 327 not taken.
✗ Branch 326 → 328 not taken.
33 (!utf8 && header.value(1).toString().toUtf8() != context.expectedHtml)) return {};
82
2/2
✓ Branch 109 → 110 taken 14 times.
✓ Branch 110 → 111 taken 14 times.
14 const qint64 headerId = header.value(0).toLongLong();
83
1/1
✓ Branch 112 → 113 taken 14 times.
14 header.finish();
84 struct Metadata { qint64 id = 0; qint64 bytes = 0; QString type; int count = 0; };
85 14 QHash<QString, Metadata> metadata;
86
1/1
✓ Branch 115 → 116 taken 14 times.
14 const QSet<QString> requested(canonicalIds.begin(), canonicalIds.end());
87
1/1
✓ Branch 116 → 117 taken 14 times.
14 QSqlQuery rows(db);
88
1/1
✓ Branch 120 → 121 taken 14 times.
14 rows.prepare(QStringLiteral(
89 "SELECT id,content_id,content_type,length(data) FROM attachments "
90 "WHERE header_id=? AND presentation=1 LIMIT 1001"));
91
1/1
✓ Branch 125 → 126 taken 14 times.
14 rows.addBindValue(headerId);
92
3/3
✓ Branch 127 → 128 taken 14 times.
✓ Branch 128 → 129 taken 1 time.
✓ Branch 128 → 130 taken 13 times.
14 if (!rows.exec()) return {};
93 13 int count = 0;
94
3/3
✓ Branch 163 → 164 taken 1041 times.
✓ Branch 164 → 131 taken 1029 times.
✓ Branch 164 → 165 taken 12 times.
1041 while (rows.next()) {
95
5/6
✓ Branch 131 → 132 taken 1028 times.
✓ Branch 131 → 134 taken 1 time.
✗ Branch 133 → 134 not taken.
✓ Branch 133 → 135 taken 1028 times.
✓ Branch 136 → 137 taken 1 time.
✓ Branch 136 → 138 taken 1028 times.
1029 if (++count > 1000 || interrupted()) return {};
96
2/2
✓ Branch 138 → 139 taken 1028 times.
✓ Branch 139 → 140 taken 1028 times.
1028 const QString cid = rows.value(1).toString();
97
2/2
✓ Branch 142 → 143 taken 999 times.
✓ Branch 142 → 144 taken 29 times.
1028 if (!requested.contains(cid)) continue;
98
1/1
✓ Branch 144 → 145 taken 29 times.
29 auto &item = metadata[cid];
99 29 ++item.count;
100
2/2
✓ Branch 145 → 146 taken 29 times.
✓ Branch 146 → 147 taken 29 times.
29 item.id = rows.value(0).toLongLong();
101
2/2
✓ Branch 148 → 149 taken 29 times.
✓ Branch 149 → 150 taken 29 times.
29 item.type = rows.value(2).toString();
102
2/2
✓ Branch 153 → 154 taken 29 times.
✓ Branch 154 → 155 taken 29 times.
29 item.bytes = rows.value(3).toLongLong();
103 1028 }
104
1/1
✓ Branch 165 → 166 taken 12 times.
12 rows.finish();
105 12 QHash<QString, QImage> images;
106 12 qint64 decodedBytes = 0;
107 12 qint64 encodedBytes = 0;
108
1/1
✓ Branch 166 → 167 taken 12 times.
12 QSqlQuery data(db);
109
1/1
✓ Branch 167 → 168 taken 12 times.
12 data.setForwardOnly(true);
110
1/1
✓ Branch 171 → 172 taken 12 times.
12 data.prepare(QStringLiteral("SELECT data FROM attachments WHERE id=? AND header_id=?"));
111
2/2
✓ Branch 242 → 176 taken 27 times.
✓ Branch 242 → 243 taken 11 times.
38 for (const QString &cid : canonicalIds) {
112
1/2
✗ Branch 178 → 179 not taken.
✓ Branch 178 → 180 taken 27 times.
27 if (interrupted()) return {};
113
2/2
✓ Branch 180 → 181 taken 1 time.
✓ Branch 180 → 182 taken 26 times.
27 if (decodedBytes >= NativeImageResources::MaxAggregateBytes) break;
114
2/2
✓ Branch 183 → 184 taken 1 time.
✓ Branch 183 → 185 taken 25 times.
33 if (images.contains(cid)) continue;
115 25 const auto item = metadata.value(cid);
116
4/4
✓ Branch 186 → 187 taken 22 times.
✓ Branch 186 → 190 taken 3 times.
✓ Branch 187 → 188 taken 21 times.
✓ Branch 187 → 190 taken 1 time.
25 if (item.count != 1 || item.bytes <= 0 ||
117
2/2
✓ Branch 188 → 189 taken 20 times.
✓ Branch 188 → 190 taken 1 time.
21 item.bytes > NativeImageResources::MaxEncodedBytes ||
118
2/2
✓ Branch 189 → 190 taken 1 time.
✓ Branch 189 → 191 taken 19 times.
25 item.bytes > 20 * 1024 * 1024 - encodedBytes) continue;
119
1/1
✓ Branch 193 → 194 taken 19 times.
19 data.bindValue(0, item.id);
120
1/1
✓ Branch 197 → 198 taken 19 times.
19 data.bindValue(1, headerId);
121
5/9
✓ Branch 199 → 200 taken 19 times.
✓ Branch 200 → 201 taken 19 times.
✗ Branch 200 → 203 not taken.
✓ Branch 201 → 202 taken 19 times.
✗ Branch 202 → 203 not taken.
✓ Branch 202 → 204 taken 19 times.
✗ Branch 205 → 206 not taken.
✓ Branch 205 → 208 taken 19 times.
✗ Branch 206 → 207 not taken.
19 if (!data.exec() || !data.next()) { data.finish(); continue; }
122
2/2
✓ Branch 208 → 209 taken 19 times.
✓ Branch 209 → 210 taken 19 times.
19 const QByteArray bytes = data.value(0).toByteArray();
123
1/1
✓ Branch 211 → 212 taken 19 times.
19 data.finish();
124 19 encodedBytes += bytes.size();
125
1/1
✓ Branch 213 → 214 taken 19 times.
19 QImage image = NativeImageResources::decode(bytes, item.type);
126
5/5
✓ Branch 214 → 215 taken 19 times.
✓ Branch 215 → 216 taken 18 times.
✓ Branch 215 → 218 taken 1 time.
✓ Branch 220 → 221 taken 1 time.
✓ Branch 220 → 222 taken 18 times.
37 if (image.isNull() ||
127
2/3
✓ Branch 216 → 217 taken 18 times.
✗ Branch 217 → 218 not taken.
✓ Branch 217 → 219 taken 18 times.
19 image.sizeInBytes() > NativeImageResources::MaxAggregateBytes - decodedBytes) continue;
128
1/1
✓ Branch 222 → 223 taken 18 times.
18 decodedBytes += image.sizeInBytes();
129
1/1
✓ Branch 224 → 225 taken 18 times.
18 images.insert(cid, std::move(image));
130 27 }
131
1/2
✗ Branch 244 → 245 not taken.
✓ Branch 244 → 246 taken 12 times.
12 return interrupted() ? QHash<QString, QImage>{} : images;
132 19 }
133
134 #ifdef Q_OS_UNIX
135 struct ResidentReadConnection {
136 QString path;
137 QString name;
138 QSqlDatabase db;
139 quint64 device = 0;
140 quint64 inode = 0;
141 bool utf8 = false;
142
143 2 ~ResidentReadConnection() { reset(); }
144 5 void reset() {
145
4/4
✓ Branch 3 → 4 taken 3 times.
✓ Branch 3 → 9 taken 2 times.
✓ Branch 5 → 6 taken 3 times.
✓ Branch 6 → 7 taken 3 times.
5 if (db.isValid()) { db.close(); db = QSqlDatabase(); }
146
2/2
✓ Branch 10 → 11 taken 3 times.
✓ Branch 10 → 12 taken 2 times.
5 if (!name.isEmpty()) QSqlDatabase::removeDatabase(name);
147 5 path.clear(); name.clear(); device = inode = 0; utf8 = false;
148 5 }
149 5 bool ensure(const QString &databasePath) {
150 5 struct stat file{};
151
1/1
✓ Branch 2 → 3 taken 5 times.
5 const QByteArray nativePath = QFile::encodeName(databasePath);
152
3/6
✓ Branch 5 → 6 taken 5 times.
✗ Branch 5 → 7 not taken.
✗ Branch 6 → 7 not taken.
✓ Branch 6 → 8 taken 5 times.
✗ Branch 9 → 10 not taken.
✓ Branch 9 → 12 taken 5 times.
5 if (::stat(nativePath.constData(), &file) != 0 || !S_ISREG(file.st_mode)) {
153 ✗ reset();
154 ✗ return false;
155 }
156 5 const auto currentDevice = quint64(file.st_dev);
157 5 const auto currentInode = quint64(file.st_ino);
158
8/9
✓ Branch 12 → 13 taken 5 times.
✓ Branch 13 → 14 taken 3 times.
✓ Branch 13 → 19 taken 2 times.
✓ Branch 15 → 16 taken 2 times.
✓ Branch 15 → 19 taken 1 time.
✓ Branch 16 → 17 taken 2 times.
✗ Branch 16 → 19 not taken.
✓ Branch 20 → 21 taken 2 times.
✓ Branch 20 → 22 taken 3 times.
7 if (db.isOpen() && path == databasePath && device == currentDevice &&
159
1/2
✓ Branch 17 → 18 taken 2 times.
✗ Branch 17 → 19 not taken.
4 inode == currentInode) return true;
160
1/1
✓ Branch 22 → 23 taken 3 times.
3 reset();
161
3/3
✓ Branch 23 → 24 taken 3 times.
✓ Branch 24 → 25 taken 3 times.
✓ Branch 28 → 29 taken 3 times.
6 name = QStringLiteral("native-images-resident-") + QUuid::createUuid().toString();
162
2/2
✓ Branch 37 → 38 taken 3 times.
✓ Branch 38 → 39 taken 3 times.
6 db = QSqlDatabase::addDatabase(QStringLiteral("QSQLITE"), name);
163
1/1
✓ Branch 42 → 43 taken 3 times.
3 db.setDatabaseName(databasePath);
164
1/1
✓ Branch 46 → 47 taken 3 times.
6 db.setConnectOptions(QStringLiteral("QSQLITE_OPEN_READONLY;QSQLITE_BUSY_TIMEOUT=50"));
165
5/9
✓ Branch 49 → 50 taken 3 times.
✓ Branch 50 → 51 taken 3 times.
✗ Branch 50 → 53 not taken.
✓ Branch 51 → 52 taken 3 times.
✗ Branch 52 → 53 not taken.
✓ Branch 52 → 54 taken 3 times.
✗ Branch 55 → 56 not taken.
✓ Branch 55 → 58 taken 3 times.
✗ Branch 56 → 57 not taken.
3 if (!db.open() || !usesUtf8(db, &utf8)) { reset(); return false; }
166 3 struct stat opened{};
167 3 if (::stat(nativePath.constData(), &opened) != 0 ||
168
3/6
✓ Branch 60 → 61 taken 3 times.
✗ Branch 60 → 63 not taken.
✓ Branch 61 → 62 taken 3 times.
✗ Branch 61 → 63 not taken.
✗ Branch 65 → 66 not taken.
✓ Branch 65 → 68 taken 3 times.
6 quint64(opened.st_dev) != currentDevice ||
169
1/3
✗ Branch 62 → 63 not taken.
✓ Branch 62 → 64 taken 3 times.
✗ Branch 66 → 67 not taken.
3 quint64(opened.st_ino) != currentInode) { reset(); return false; }
170 3 path = databasePath;
171 3 device = currentDevice;
172 3 inode = currentInode;
173 3 return true;
174 5 }
175 };
176 #endif
177 } // namespace
178
179 28 QImage NativeImageResources::decode(const QByteArray &bytes, const QString &contentType) {
180
6/6
✓ Branch 3 → 4 taken 27 times.
✓ Branch 3 → 6 taken 1 time.
✓ Branch 5 → 6 taken 1 time.
✓ Branch 5 → 7 taken 26 times.
✓ Branch 8 → 9 taken 2 times.
✓ Branch 8 → 10 taken 26 times.
28 if (bytes.isEmpty() || bytes.size() > MaxEncodedBytes) return {};
181
3/3
✓ Branch 12 → 13 taken 26 times.
✓ Branch 13 → 14 taken 26 times.
✓ Branch 14 → 15 taken 26 times.
26 const QString type = contentType.section(';', 0, 0).trimmed().toLower();
182 const QHash<QString, QByteArray> formats{{"image/png", "png"}, {"image/jpeg", "jpeg"},
183
2/4
✓ Branch 24 → 25 taken 130 times.
✓ Branch 24 → 26 taken 26 times.
✗ Branch 93 → 94 not taken.
✗ Branch 93 → 95 not taken.
156 {"image/gif", "gif"}, {"image/webp", "webp"}, {"image/bmp", "bmp"}};
184
2/2
✓ Branch 27 → 28 taken 1 time.
✓ Branch 27 → 29 taken 25 times.
26 if (!formats.contains(type)) return {};
185
1/1
✓ Branch 29 → 30 taken 25 times.
25 QBuffer buffer;
186
1/1
✓ Branch 30 → 31 taken 25 times.
25 buffer.setData(bytes);
187
2/3
✓ Branch 32 → 33 taken 25 times.
✗ Branch 33 → 34 not taken.
✓ Branch 33 → 35 taken 25 times.
25 if (!buffer.open(QIODevice::ReadOnly)) return {};
188
1/1
✓ Branch 36 → 37 taken 25 times.
25 QImageReader reader(&buffer);
189
1/1
✓ Branch 38 → 39 taken 25 times.
25 reader.setDecideFormatFromContent(true);
190
4/4
✓ Branch 40 → 41 taken 25 times.
✓ Branch 41 → 42 taken 25 times.
✓ Branch 46 → 47 taken 3 times.
✓ Branch 46 → 48 taken 22 times.
25 if (reader.format().toLower() != formats.value(type)) return {};
191
1/1
✓ Branch 48 → 49 taken 22 times.
22 const QSize size = reader.size();
192
8/10
✓ Branch 50 → 51 taken 22 times.
✗ Branch 50 → 60 not taken.
✓ Branch 52 → 53 taken 22 times.
✗ Branch 52 → 60 not taken.
✓ Branch 54 → 55 taken 21 times.
✓ Branch 54 → 60 taken 1 time.
✓ Branch 56 → 57 taken 20 times.
✓ Branch 56 → 60 taken 1 time.
✓ Branch 62 → 63 taken 3 times.
✓ Branch 62 → 64 taken 19 times.
42 if (size.width() <= 0 || size.height() <= 0 || size.width() > 8192 || size.height() > 8192 ||
193
2/2
✓ Branch 59 → 60 taken 1 time.
✓ Branch 59 → 61 taken 19 times.
23 qint64(size.width()) * size.height() > MaxDecodedPixels) return {};
194
1/1
✓ Branch 64 → 65 taken 19 times.
19 reader.setAutoTransform(true);
195
1/1
✓ Branch 65 → 66 taken 19 times.
19 QImage image = reader.read(); // First frame only; never iterate an animation.
196
5/8
✓ Branch 66 → 67 taken 19 times.
✓ Branch 67 → 68 taken 19 times.
✗ Branch 67 → 70 not taken.
✓ Branch 68 → 69 taken 19 times.
✗ Branch 69 → 70 not taken.
✓ Branch 69 → 71 taken 19 times.
✗ Branch 72 → 73 not taken.
✓ Branch 72 → 74 taken 19 times.
19 if (image.isNull() || image.sizeInBytes() > MaxDecodedPixels * 4) return {};
197
1/1
✓ Branch 75 → 76 taken 19 times.
19 return image.convertToFormat(QImage::Format_ARGB32_Premultiplied);
198 52 }
199
200 21 QHash<QString, QImage> NativeImageResources::load(
201 const NativeImageContext &context, const QStringList &canonicalIds,
202 const std::atomic_bool *cancelled) {
203
3/3
✓ Branch 2 → 3 taken 21 times.
✓ Branch 3 → 4 taken 6 times.
✓ Branch 3 → 5 taken 15 times.
21 if (!validRequest(context, canonicalIds, cancelled)) return {};
204
3/3
✓ Branch 5 → 6 taken 15 times.
✓ Branch 6 → 7 taken 15 times.
✓ Branch 10 → 11 taken 15 times.
30 const QString name = QStringLiteral("native-images-") + QUuid::createUuid().toString();
205 15 QHash<QString, QImage> result;
206 {
207
1/1
✓ Branch 17 → 18 taken 15 times.
15 auto db = QSqlDatabase::addDatabase(QStringLiteral("QSQLITE"), name);
208
1/1
✓ Branch 20 → 21 taken 15 times.
15 db.setDatabaseName(context.databasePath);
209
1/1
✓ Branch 24 → 25 taken 15 times.
15 db.setConnectOptions(QStringLiteral("QSQLITE_OPEN_READONLY;QSQLITE_BUSY_TIMEOUT=50"));
210
2/3
✓ Branch 27 → 28 taken 15 times.
✓ Branch 28 → 29 taken 15 times.
✗ Branch 28 → 39 not taken.
15 if (db.open()) {
211 15 bool utf8 = false;
212
3/3
✓ Branch 29 → 30 taken 15 times.
✓ Branch 30 → 31 taken 14 times.
✓ Branch 30 → 37 taken 1 time.
15 if (usesUtf8(db, &utf8)) {
213 14 bool healthy = true;
214
1/1
✓ Branch 31 → 32 taken 14 times.
14 result = readSnapshot(db, utf8, context, canonicalIds, cancelled, &healthy);
215
1/2
✗ Branch 34 → 35 not taken.
✓ Branch 34 → 36 taken 14 times.
14 if (!healthy) result.clear();
216 }
217
1/1
✓ Branch 37 → 38 taken 15 times.
15 db.close();
218 }
219 15 }
220
1/1
✓ Branch 40 → 41 taken 15 times.
15 QSqlDatabase::removeDatabase(name);
221
1/2
✗ Branch 43 → 44 not taken.
✓ Branch 43 → 45 taken 1 time.
1 return cancelled && cancelled->load(std::memory_order_relaxed)
222
2/2
✓ Branch 41 → 42 taken 1 time.
✓ Branch 41 → 45 taken 14 times.
16 ? QHash<QString, QImage>{} : result;
223 15 }
224
225 63 QHash<QString, QImage> NativeImageResources::loadResident(
226 const NativeImageContext &context, const QStringList &canonicalIds,
227 const std::atomic_bool *cancelled) {
228 #ifndef Q_OS_UNIX
229 return load(context, canonicalIds, cancelled);
230 #else
231
3/3
✓ Branch 2 → 3 taken 63 times.
✓ Branch 3 → 4 taken 58 times.
✓ Branch 3 → 5 taken 5 times.
63 if (!validRequest(context, canonicalIds, cancelled)) return {};
232 // NativeDocumentService has one retained preparation thread. A file
233 // replacement at the same path changes its inode and closes this handle
234 // before another message can read from the obsolete cache.
235
3/3
✓ Branch 5 → 6 taken 2 times.
✓ Branch 5 → 8 taken 3 times.
✓ Branch 6 → 7 taken 2 times.
5 static thread_local ResidentReadConnection connection;
236
2/3
✓ Branch 8 → 9 taken 5 times.
✗ Branch 9 → 10 not taken.
✓ Branch 9 → 11 taken 5 times.
5 if (!connection.ensure(context.databasePath)) return {};
237 5 bool healthy = true;
238 5 auto result = readSnapshot(connection.db, connection.utf8, context,
239
1/1
✓ Branch 11 → 12 taken 5 times.
5 canonicalIds, cancelled, &healthy);
240
1/3
✗ Branch 12 → 13 not taken.
✓ Branch 12 → 15 taken 5 times.
✗ Branch 14 → 15 not taken.
5 if (!healthy) { result.clear(); connection.reset(); }
241
1/2
✗ Branch 17 → 18 not taken.
✓ Branch 17 → 19 taken 5 times.
5 return cancelled && cancelled->load(std::memory_order_relaxed)
242
1/2
✓ Branch 15 → 16 taken 5 times.
✗ Branch 15 → 19 not taken.
10 ? QHash<QString, QImage>{} : result;
243 #endif
244 5 }
245