data/IdentityStore.cpp
| Line | Branch | Exec | Source |
|---|---|---|---|
| 1 | #include "IdentityStore.h" | ||
| 2 | |||
| 3 | #include "AccountConfig.h" | ||
| 4 | |||
| 5 | #include <QDir> | ||
| 6 | #include <QFile> | ||
| 7 | #include <QFileInfo> | ||
| 8 | #include <QJsonArray> | ||
| 9 | #include <QJsonDocument> | ||
| 10 | #include <QSaveFile> | ||
| 11 | #include <QUuid> | ||
| 12 | |||
| 13 | namespace { | ||
| 14 | |||
| 15 | 228 | QString bounded(const QJsonObject &object, const char *key, qsizetype limit) { | |
| 16 |
2/2✓ Branch 3 → 4 taken 228 times.
✓ Branch 4 → 5 taken 228 times.
|
228 | const QString value = object.value(QLatin1String(key)).toString(); |
| 17 |
1/2✗ Branch 7 → 8 not taken.
✓ Branch 7 → 9 taken 228 times.
|
456 | return value.size() > limit ? QString() : value; |
| 18 | 228 | } | |
| 19 | |||
| 20 |
2/2✓ Branch 2 → 3 taken 775 times.
✓ Branch 3 → 4 taken 775 times.
|
775 | QString newId() { return QUuid::createUuid().toString(QUuid::WithoutBraces); } |
| 21 | |||
| 22 | } // namespace | ||
| 23 | |||
| 24 | 807 | QString IdentityStore::pathFor(const QString &profileDirectory) { | |
| 25 |
2/2✓ Branch 2 → 3 taken 807 times.
✓ Branch 6 → 7 taken 807 times.
|
1614 | return QDir(profileDirectory).filePath(QStringLiteral("identities.json")); |
| 26 | } | ||
| 27 | |||
| 28 | 800 | QJsonObject IdentityStore::toJson(const Identity &identity) { | |
| 29 |
1/1✓ Branch 2 → 3 taken 800 times.
|
800 | QJsonArray signatures; |
| 30 |
2/2✓ Branch 46 → 5 taken 22 times.
✓ Branch 46 → 47 taken 800 times.
|
822 | for (const Signature &signature : identity.signatures) |
| 31 |
1/1✓ Branch 28 → 29 taken 22 times.
|
66 | signatures.append(QJsonObject{{QStringLiteral("id"), signature.id}, |
| 32 | 44 | {QStringLiteral("name"), signature.name}, | |
| 33 | 44 | {QStringLiteral("html"), signature.html}, | |
| 34 | 44 | {QStringLiteral("text"), signature.text}, | |
| 35 |
2/4✓ Branch 32 → 33 taken 110 times.
✓ Branch 32 → 34 taken 22 times.
✗ Branch 149 → 150 not taken.
✗ Branch 149 → 151 not taken.
|
176 | {QStringLiteral("textOverridden"), signature.textOverridden}}); |
| 36 | 1600 | return {{QStringLiteral("id"), identity.id}, | |
| 37 | 1600 | {QStringLiteral("accountId"), identity.accountId}, | |
| 38 | 1600 | {QStringLiteral("accountAddress"), identity.accountAddress}, | |
| 39 | 1600 | {QStringLiteral("accountServer"), identity.accountServer}, | |
| 40 | 1600 | {QStringLiteral("accountName"), identity.accountName}, | |
| 41 | 1600 | {QStringLiteral("name"), identity.name}, | |
| 42 | 1600 | {QStringLiteral("email"), identity.email}, | |
| 43 | 1600 | {QStringLiteral("replyTo"), identity.replyTo}, | |
| 44 | 1600 | {QStringLiteral("formattedByDefault"), identity.formattedByDefault}, | |
| 45 | 1600 | {QStringLiteral("bccSelf"), identity.bccSelf}, | |
| 46 | 1600 | {QStringLiteral("wrapPlainText"), identity.wrapPlainText}, | |
| 47 | 1600 | {QStringLiteral("signatures"), signatures}, | |
| 48 | 1600 | {QStringLiteral("newMailSignatureId"), identity.newMailSignatureId}, | |
| 49 | 1600 | {QStringLiteral("replySignatureId"), identity.replySignatureId}, | |
| 50 |
2/4✓ Branch 109 → 110 taken 12000 times.
✓ Branch 109 → 111 taken 800 times.
✗ Branch 192 → 193 not taken.
✗ Branch 192 → 194 not taken.
|
14400 | {QStringLiteral("isDefault"), identity.isDefault}}; |
| 51 | 13732 | } | |
| 52 | |||
| 53 | 20 | std::optional<Identity> IdentityStore::fromJson(const QJsonObject &object) { | |
| 54 | 20 | Identity identity; | |
| 55 |
1/1✓ Branch 2 → 3 taken 20 times.
|
20 | identity.id = bounded(object, "id", 64); |
| 56 |
1/1✓ Branch 5 → 6 taken 20 times.
|
20 | identity.accountId = bounded(object, "accountId", 128); |
| 57 |
1/1✓ Branch 8 → 9 taken 20 times.
|
20 | identity.accountAddress = bounded(object, "accountAddress", 320); |
| 58 |
1/1✓ Branch 11 → 12 taken 20 times.
|
20 | identity.accountServer = bounded(object, "accountServer", 255); |
| 59 |
1/1✓ Branch 14 → 15 taken 20 times.
|
20 | identity.accountName = bounded(object, "accountName", 256); |
| 60 |
1/1✓ Branch 17 → 18 taken 20 times.
|
20 | identity.name = bounded(object, "name", 200); |
| 61 |
1/1✓ Branch 20 → 21 taken 20 times.
|
20 | identity.email = bounded(object, "email", 320); |
| 62 |
1/1✓ Branch 23 → 24 taken 20 times.
|
20 | identity.replyTo = bounded(object, "replyTo", 998); |
| 63 |
2/2✓ Branch 29 → 30 taken 20 times.
✓ Branch 30 → 31 taken 20 times.
|
20 | identity.formattedByDefault = object.value(QStringLiteral("formattedByDefault")).toBool(); |
| 64 |
2/2✓ Branch 37 → 38 taken 20 times.
✓ Branch 38 → 39 taken 20 times.
|
20 | identity.bccSelf = object.value(QStringLiteral("bccSelf")).toBool(); |
| 65 |
2/2✓ Branch 45 → 46 taken 20 times.
✓ Branch 46 → 47 taken 20 times.
|
20 | identity.wrapPlainText = object.value(QStringLiteral("wrapPlainText")).toBool(); |
| 66 |
1/1✓ Branch 50 → 51 taken 20 times.
|
20 | identity.newMailSignatureId = bounded(object, "newMailSignatureId", 64); |
| 67 |
1/1✓ Branch 53 → 54 taken 20 times.
|
20 | identity.replySignatureId = bounded(object, "replySignatureId", 64); |
| 68 |
2/2✓ Branch 59 → 60 taken 20 times.
✓ Branch 60 → 61 taken 20 times.
|
20 | identity.isDefault = object.value(QStringLiteral("isDefault")).toBool(); |
| 69 | // Header values: no line breaks, no NUL. | ||
| 70 |
2/2✓ Branch 83 → 66 taken 58 times.
✓ Branch 83 → 84 taken 19 times.
|
77 | for (QString *value : {&identity.name, &identity.email, &identity.replyTo}) |
| 71 |
9/11✓ Branch 68 → 69 taken 58 times.
✓ Branch 69 → 70 taken 58 times.
✗ Branch 69 → 77 not taken.
✓ Branch 72 → 73 taken 58 times.
✓ Branch 73 → 74 taken 57 times.
✓ Branch 73 → 77 taken 1 time.
✓ Branch 75 → 76 taken 57 times.
✗ Branch 76 → 77 not taken.
✓ Branch 76 → 78 taken 57 times.
✓ Branch 79 → 80 taken 1 time.
✓ Branch 79 → 82 taken 57 times.
|
58 | if (value->contains(QLatin1Char('\r')) || value->contains(QLatin1Char('\n')) || value->contains(QChar::Null)) |
| 72 | 1 | return std::nullopt; | |
| 73 |
5/9✓ Branch 85 → 86 taken 19 times.
✗ Branch 85 → 92 not taken.
✓ Branch 87 → 88 taken 19 times.
✗ Branch 87 → 92 not taken.
✓ Branch 90 → 91 taken 19 times.
✗ Branch 91 → 92 not taken.
✓ Branch 91 → 93 taken 19 times.
✗ Branch 94 → 95 not taken.
✓ Branch 94 → 96 taken 19 times.
|
19 | if (identity.id.isEmpty() || identity.email.isEmpty() || !identity.email.contains(QLatin1Char('@'))) |
| 74 | ✗ | return std::nullopt; | |
| 75 |
2/2✓ Branch 99 → 100 taken 19 times.
✓ Branch 100 → 101 taken 19 times.
|
19 | const QJsonArray signatures = object.value(QStringLiteral("signatures")).toArray(); |
| 76 |
2/3✓ Branch 104 → 105 taken 19 times.
✗ Branch 105 → 106 not taken.
✓ Branch 105 → 107 taken 19 times.
|
19 | if (signatures.size() > MaxSignaturesPerIdentity) return std::nullopt; |
| 77 |
3/3✓ Branch 108 → 109 taken 19 times.
✓ Branch 153 → 110 taken 7 times.
✓ Branch 153 → 154 taken 19 times.
|
26 | for (const QJsonValue &value : signatures) { |
| 78 |
1/1✓ Branch 112 → 113 taken 7 times.
|
7 | const QJsonObject entry = value.toObject(); |
| 79 | 7 | Signature signature; | |
| 80 |
1/1✓ Branch 113 → 114 taken 7 times.
|
7 | signature.id = bounded(entry, "id", 64); |
| 81 |
1/1✓ Branch 116 → 117 taken 7 times.
|
7 | signature.name = bounded(entry, "name", 120); |
| 82 |
1/1✓ Branch 119 → 120 taken 7 times.
|
7 | signature.html = bounded(entry, "html", MaxSignatureBytes); |
| 83 |
1/1✓ Branch 122 → 123 taken 7 times.
|
7 | signature.text = bounded(entry, "text", MaxSignatureBytes); |
| 84 |
2/2✓ Branch 128 → 129 taken 7 times.
✓ Branch 129 → 130 taken 7 times.
|
7 | signature.textOverridden = entry.value(QStringLiteral("textOverridden")).toBool(); |
| 85 |
1/2✗ Branch 134 → 135 not taken.
✓ Branch 134 → 137 taken 7 times.
|
7 | if (signature.id.isEmpty()) return std::nullopt; |
| 86 |
1/1✓ Branch 137 → 138 taken 7 times.
|
7 | identity.signatures.append(signature); |
| 87 | 7 | } | |
| 88 | 19 | return identity; | |
| 89 | 20 | } | |
| 90 | |||
| 91 | 804 | bool IdentityStore::load(QString *error) { | |
| 92 |
1/1✓ Branch 2 → 3 taken 804 times.
|
804 | m_identities.clear(); |
| 93 |
1/1✓ Branch 3 → 4 taken 804 times.
|
804 | QFile file(m_path); |
| 94 |
3/3✓ Branch 4 → 5 taken 804 times.
✓ Branch 5 → 6 taken 786 times.
✓ Branch 5 → 7 taken 18 times.
|
804 | if (!file.exists()) return true; |
| 95 |
2/3✓ Branch 7 → 8 taken 18 times.
✗ Branch 8 → 9 not taken.
✓ Branch 8 → 18 taken 18 times.
|
18 | if (file.size() > MaxFileBytes) { |
| 96 | ✗ | if (error) *error = QStringLiteral("identities file too large"); | |
| 97 | ✗ | return false; | |
| 98 | } | ||
| 99 |
2/3✓ Branch 19 → 20 taken 18 times.
✗ Branch 20 → 21 not taken.
✓ Branch 20 → 27 taken 18 times.
|
18 | if (!file.open(QIODevice::ReadOnly)) { |
| 100 | ✗ | if (error) *error = file.errorString(); | |
| 101 | ✗ | return false; | |
| 102 | } | ||
| 103 | 18 | QJsonParseError parseError; | |
| 104 |
2/2✓ Branch 27 → 28 taken 18 times.
✓ Branch 28 → 29 taken 18 times.
|
18 | const QJsonDocument document = QJsonDocument::fromJson(file.read(MaxFileBytes), &parseError); |
| 105 |
4/7✓ Branch 30 → 31 taken 18 times.
✗ Branch 30 → 33 not taken.
✓ Branch 31 → 32 taken 18 times.
✗ Branch 32 → 33 not taken.
✓ Branch 32 → 34 taken 18 times.
✗ Branch 35 → 36 not taken.
✓ Branch 35 → 45 taken 18 times.
|
18 | if (parseError.error != QJsonParseError::NoError || !document.isObject()) { |
| 106 | ✗ | if (error) *error = QStringLiteral("identities file is not valid JSON"); | |
| 107 | ✗ | return false; | |
| 108 | } | ||
| 109 |
3/3✓ Branch 45 → 46 taken 18 times.
✓ Branch 49 → 50 taken 18 times.
✓ Branch 50 → 51 taken 18 times.
|
36 | const QJsonArray entries = document.object().value(QStringLiteral("identities")).toArray(); |
| 110 |
2/3✓ Branch 55 → 56 taken 18 times.
✗ Branch 56 → 57 not taken.
✓ Branch 56 → 66 taken 18 times.
|
18 | if (entries.size() > MaxIdentities) { |
| 111 | ✗ | if (error) *error = QStringLiteral("too many identities"); | |
| 112 | ✗ | return false; | |
| 113 | } | ||
| 114 | 18 | QList<Identity> loaded; | |
| 115 |
3/3✓ Branch 67 → 68 taken 18 times.
✓ Branch 98 → 69 taken 20 times.
✓ Branch 98 → 99 taken 17 times.
|
37 | for (const QJsonValue &value : entries) { |
| 116 |
2/2✓ Branch 71 → 72 taken 20 times.
✓ Branch 72 → 73 taken 20 times.
|
20 | const auto identity = fromJson(value.toObject()); |
| 117 |
2/2✓ Branch 75 → 76 taken 1 time.
✓ Branch 75 → 85 taken 19 times.
|
20 | if (!identity) { |
| 118 |
1/2✓ Branch 76 → 77 taken 1 time.
✗ Branch 76 → 84 not taken.
|
2 | if (error) *error = QStringLiteral("invalid identity entry"); |
| 119 | 1 | return false; | |
| 120 | } | ||
| 121 |
1/1✓ Branch 86 → 87 taken 19 times.
|
19 | loaded.append(*identity); |
| 122 | 21 | } | |
| 123 | 17 | m_identities = loaded; | |
| 124 | 17 | return true; | |
| 125 | 804 | } | |
| 126 | |||
| 127 | 799 | bool IdentityStore::save(QString *error) const { | |
| 128 |
1/1✓ Branch 2 → 3 taken 799 times.
|
799 | QJsonArray entries; |
| 129 |
4/4✓ Branch 6 → 7 taken 800 times.
✓ Branch 8 → 9 taken 800 times.
✓ Branch 13 → 5 taken 800 times.
✓ Branch 13 → 14 taken 799 times.
|
1599 | for (const Identity &identity : m_identities) entries.append(toJson(identity)); |
| 130 | const QByteArray bytes = | ||
| 131 |
3/5✓ Branch 23 → 24 taken 799 times.
✓ Branch 28 → 29 taken 1598 times.
✓ Branch 28 → 30 taken 799 times.
✗ Branch 93 → 94 not taken.
✗ Branch 93 → 95 not taken.
|
4794 | QJsonDocument(QJsonObject{{QStringLiteral("version"), 1}, {QStringLiteral("identities"), entries}}) |
| 132 |
1/1✓ Branch 24 → 25 taken 799 times.
|
799 | .toJson(QJsonDocument::Indented); |
| 133 |
1/2✗ Branch 35 → 36 not taken.
✓ Branch 35 → 45 taken 799 times.
|
799 | if (bytes.size() > MaxFileBytes) { |
| 134 | ✗ | if (error) *error = QStringLiteral("identities too large to save"); | |
| 135 | ✗ | return false; | |
| 136 | } | ||
| 137 |
4/4✓ Branch 46 → 47 taken 799 times.
✓ Branch 47 → 48 taken 799 times.
✓ Branch 48 → 49 taken 799 times.
✓ Branch 49 → 50 taken 799 times.
|
799 | QDir().mkpath(QFileInfo(m_path).absolutePath()); |
| 138 |
1/1✓ Branch 54 → 55 taken 799 times.
|
799 | QSaveFile file(m_path); |
| 139 |
4/6✓ Branch 56 → 57 taken 799 times.
✓ Branch 59 → 60 taken 799 times.
✓ Branch 60 → 61 taken 799 times.
✗ Branch 60 → 66 not taken.
✓ Branch 63 → 64 taken 799 times.
✗ Branch 63 → 66 not taken.
|
2397 | if (!file.open(QIODevice::WriteOnly) || !file.setPermissions(QFile::ReadOwner | QFile::WriteOwner) || |
| 140 |
5/8✓ Branch 57 → 58 taken 799 times.
✗ Branch 57 → 66 not taken.
✓ Branch 61 → 62 taken 799 times.
✓ Branch 64 → 65 taken 799 times.
✗ Branch 65 → 66 not taken.
✓ Branch 65 → 67 taken 799 times.
✗ Branch 68 → 69 not taken.
✓ Branch 68 → 75 taken 799 times.
|
2397 | file.write(bytes) != bytes.size() || !file.commit()) { |
| 141 | ✗ | if (error) *error = file.errorString(); | |
| 142 | ✗ | return false; | |
| 143 | } | ||
| 144 | 799 | return true; | |
| 145 | 3196 | } | |
| 146 | |||
| 147 | 1603 | bool IdentityStore::reconcile(const std::vector<AccountConfig> &accounts) { | |
| 148 | 1603 | bool changed = false; | |
| 149 | 1603 | QStringList known; | |
| 150 |
2/2✓ Branch 69 → 4 taken 827 times.
✓ Branch 69 → 70 taken 1603 times.
|
2430 | for (const AccountConfig &account : accounts) { |
| 151 |
1/1✓ Branch 5 → 6 taken 827 times.
|
827 | known.append(account.id); |
| 152 | 827 | bool has = false; | |
| 153 |
4/4✓ Branch 6 → 7 taken 827 times.
✓ Branch 7 → 8 taken 827 times.
✓ Branch 46 → 9 taken 79 times.
✓ Branch 46 → 47 taken 827 times.
|
906 | for (Identity &identity : m_identities) { |
| 154 |
2/2✓ Branch 11 → 12 taken 27 times.
✓ Branch 11 → 13 taken 52 times.
|
79 | if (identity.accountId != account.id) continue; |
| 155 | 52 | has = true; | |
| 156 | // The account's own identity follows a changed account address. | ||
| 157 |
6/8✓ Branch 13 → 14 taken 52 times.
✗ Branch 13 → 19 not taken.
✓ Branch 15 → 16 taken 1 time.
✓ Branch 15 → 19 taken 51 times.
✓ Branch 17 → 18 taken 1 time.
✗ Branch 17 → 19 not taken.
✓ Branch 20 → 21 taken 1 time.
✓ Branch 20 → 23 taken 51 times.
|
53 | if (identity.isDefault && identity.accountAddress != account.email && |
| 158 | 1 | identity.email.compare(identity.accountAddress, Qt::CaseInsensitive) == 0) { | |
| 159 | 1 | identity.email = account.email; | |
| 160 | 1 | changed = true; | |
| 161 | } | ||
| 162 | // … and a changed "Your name" while its own name was not edited apart. | ||
| 163 |
5/6✓ Branch 23 → 24 taken 52 times.
✗ Branch 23 → 27 not taken.
✓ Branch 25 → 26 taken 6 times.
✓ Branch 25 → 27 taken 46 times.
✓ Branch 28 → 29 taken 6 times.
✓ Branch 28 → 34 taken 46 times.
|
52 | if (identity.isDefault && identity.accountName != account.name) { |
| 164 |
2/2✓ Branch 30 → 31 taken 4 times.
✓ Branch 30 → 32 taken 2 times.
|
6 | if (identity.name == identity.accountName) identity.name = account.name; |
| 165 | 6 | identity.accountName = account.name; | |
| 166 | 6 | changed = true; | |
| 167 | } | ||
| 168 |
6/6✓ Branch 35 → 36 taken 51 times.
✓ Branch 35 → 38 taken 1 time.
✓ Branch 37 → 38 taken 1 time.
✓ Branch 37 → 39 taken 50 times.
✓ Branch 40 → 41 taken 2 times.
✓ Branch 40 → 44 taken 50 times.
|
52 | if (identity.accountAddress != account.email || identity.accountServer != account.imap.host) { |
| 169 | 2 | identity.accountAddress = account.email; | |
| 170 | 2 | identity.accountServer = account.imap.host; | |
| 171 | 2 | changed = true; | |
| 172 | } | ||
| 173 | } | ||
| 174 |
5/6✓ Branch 47 → 48 taken 775 times.
✓ Branch 47 → 50 taken 52 times.
✗ Branch 49 → 50 not taken.
✓ Branch 49 → 51 taken 775 times.
✓ Branch 52 → 53 taken 52 times.
✓ Branch 52 → 54 taken 775 times.
|
827 | if (has || account.email.isEmpty()) continue; |
| 175 | 775 | Identity identity; | |
| 176 |
1/1✓ Branch 54 → 55 taken 775 times.
|
775 | identity.id = newId(); |
| 177 | 775 | identity.accountId = account.id; | |
| 178 | 775 | identity.accountAddress = account.email; | |
| 179 | 775 | identity.accountServer = account.imap.host; | |
| 180 | 775 | identity.name = account.name; | |
| 181 | 775 | identity.accountName = account.name; | |
| 182 | 775 | identity.email = account.email; | |
| 183 | 775 | identity.isDefault = true; | |
| 184 |
1/1✓ Branch 63 → 64 taken 775 times.
|
775 | m_identities.append(identity); |
| 185 | 775 | changed = true; | |
| 186 | 775 | } | |
| 187 | 1603 | const qsizetype before = m_identities.size(); | |
| 188 |
1/1✓ Branch 71 → 72 taken 1603 times.
|
2448 | m_identities.removeIf([&known](const Identity &identity) { return !known.contains(identity.accountId); }); |
| 189 |
4/4✓ Branch 72 → 73 taken 828 times.
✓ Branch 72 → 75 taken 775 times.
✓ Branch 74 → 75 taken 17 times.
✓ Branch 74 → 76 taken 811 times.
|
3206 | return changed || before != m_identities.size(); |
| 190 | 1603 | } | |
| 191 | |||
| 192 | 44 | QList<Identity> IdentityStore::identitiesFor(const QString &accountId) const { | |
| 193 | 44 | QList<Identity> out; | |
| 194 |
2/2✓ Branch 10 → 4 taken 66 times.
✓ Branch 10 → 11 taken 44 times.
|
110 | for (const Identity &identity : m_identities) |
| 195 |
3/3✓ Branch 6 → 7 taken 41 times.
✓ Branch 6 → 8 taken 25 times.
✓ Branch 7 → 8 taken 41 times.
|
66 | if (identity.accountId == accountId) out.append(identity); |
| 196 | 44 | return out; | |
| 197 | ✗ | } | |
| 198 | |||
| 199 | 82 | std::optional<Identity> IdentityStore::find(const QString &identityId) const { | |
| 200 |
2/2✓ Branch 10 → 4 taken 86 times.
✓ Branch 10 → 11 taken 1 time.
|
87 | for (const Identity &identity : m_identities) |
| 201 |
2/2✓ Branch 6 → 7 taken 81 times.
✓ Branch 6 → 8 taken 5 times.
|
86 | if (identity.id == identityId) return identity; |
| 202 | 1 | return std::nullopt; | |
| 203 | } | ||
| 204 | |||
| 205 | 19 | std::optional<Identity> IdentityStore::defaultFor(const QString &accountId) const { | |
| 206 | 19 | std::optional<Identity> first; | |
| 207 |
1/2✓ Branch 15 → 4 taken 20 times.
✗ Branch 15 → 16 not taken.
|
20 | for (const Identity &identity : m_identities) { |
| 208 |
2/2✓ Branch 6 → 7 taken 1 time.
✓ Branch 6 → 8 taken 19 times.
|
20 | if (identity.accountId != accountId) continue; |
| 209 |
1/2✓ Branch 8 → 9 taken 19 times.
✗ Branch 8 → 10 not taken.
|
19 | if (identity.isDefault) return identity; |
| 210 | ✗ | if (!first) first = identity; | |
| 211 | } | ||
| 212 | ✗ | return first; | |
| 213 | 19 | } | |
| 214 | |||
| 215 | 15 | bool IdentityStore::upsert(const Identity &identity) { | |
| 216 |
4/7✓ Branch 3 → 4 taken 15 times.
✗ Branch 3 → 8 not taken.
✓ Branch 6 → 7 taken 15 times.
✗ Branch 7 → 8 not taken.
✓ Branch 7 → 9 taken 15 times.
✗ Branch 10 → 11 not taken.
✓ Branch 10 → 12 taken 15 times.
|
15 | if (identity.id.isEmpty() || !identity.email.contains(QLatin1Char('@'))) return false; |
| 217 |
2/2✓ Branch 12 → 13 taken 8 times.
✓ Branch 12 → 29 taken 7 times.
|
15 | if (identity.isDefault) |
| 218 |
4/4✓ Branch 13 → 14 taken 8 times.
✓ Branch 14 → 15 taken 8 times.
✓ Branch 27 → 16 taken 6 times.
✓ Branch 27 → 28 taken 8 times.
|
14 | for (Identity &other : m_identities) |
| 219 |
3/6✓ Branch 18 → 19 taken 6 times.
✗ Branch 18 → 22 not taken.
✗ Branch 20 → 21 not taken.
✓ Branch 20 → 22 taken 6 times.
✗ Branch 23 → 24 not taken.
✓ Branch 23 → 25 taken 6 times.
|
6 | if (other.accountId == identity.accountId && other.id != identity.id) other.isDefault = false; |
| 220 |
4/4✓ Branch 29 → 30 taken 15 times.
✓ Branch 30 → 31 taken 15 times.
✓ Branch 40 → 32 taken 14 times.
✓ Branch 40 → 41 taken 9 times.
|
23 | for (Identity &existing : m_identities) { |
| 221 |
2/2✓ Branch 34 → 35 taken 8 times.
✓ Branch 34 → 36 taken 6 times.
|
14 | if (existing.id != identity.id) continue; |
| 222 | 6 | existing = identity; | |
| 223 | 6 | return true; | |
| 224 | } | ||
| 225 |
1/2✗ Branch 42 → 43 not taken.
✓ Branch 42 → 44 taken 9 times.
|
9 | if (m_identities.size() >= MaxIdentities) return false; |
| 226 | 9 | m_identities.append(identity); | |
| 227 | 9 | return true; | |
| 228 | } | ||
| 229 | |||
| 230 | 2 | bool IdentityStore::remove(const QString &identityId) { | |
| 231 |
1/1✓ Branch 2 → 3 taken 2 times.
|
2 | const auto found = find(identityId); |
| 232 |
1/2✗ Branch 4 → 5 not taken.
✓ Branch 4 → 6 taken 2 times.
|
2 | if (!found) return false; |
| 233 |
1/1✓ Branch 6 → 7 taken 2 times.
|
7 | m_identities.removeIf([&identityId](const Identity &identity) { return identity.id == identityId; }); |
| 234 | // The account keeps a default identity. | ||
| 235 |
2/2✓ Branch 8 → 9 taken 1 time.
✓ Branch 8 → 21 taken 1 time.
|
2 | if (found->isDefault) |
| 236 |
3/4✓ Branch 9 → 10 taken 1 time.
✓ Branch 10 → 11 taken 1 time.
✓ Branch 19 → 12 taken 2 times.
✗ Branch 19 → 20 not taken.
|
2 | for (Identity &other : m_identities) |
| 237 |
2/2✓ Branch 15 → 16 taken 1 time.
✓ Branch 15 → 17 taken 1 time.
|
2 | if (other.accountId == found->accountId) { |
| 238 | 1 | other.isDefault = true; | |
| 239 | 1 | break; | |
| 240 | } | ||
| 241 | 2 | return true; | |
| 242 | 2 | } | |
| 243 |