keyresolvercoretest.cpp 42.8 KB
Newer Older
1
/*
2
    autotests/keyresolvercoretest.cpp
3
4
5
6
7
8
9
10

    This file is part of libkleopatra's test suite.
    SPDX-FileCopyrightText: 2021 g10 Code GmbH
    SPDX-FileContributor: Ingo Klöcker <dev@ingo-kloecker.de>

    SPDX-License-Identifier: GPL-2.0-or-later
*/

11
#include <Libkleo/Formatting>
12
#include <Libkleo/KeyCache>
13
#include <Libkleo/KeyGroup>
14
#include <Libkleo/KeyResolverCore>
15
16

#include <QObject>
Ingo Klöcker's avatar
Ingo Klöcker committed
17
#include <QProcess>
18
19
20
21
22
23
24
25
26
#include <QTest>

#include <gpgme++/key.h>

#include <memory>

using namespace Kleo;
using namespace GpgME;

27
28
29
30
31
32
33
34
namespace QTest
{
template <>
inline bool qCompare(GpgME::UserID::Validity const &t1, GpgME::UserID::Validity const &t2, const char *actual, const char *expected,
                    const char *file, int line)
{
    return qCompare(int(t1), int(t2), actual, expected, file, line);
}
35
36
37
38
39
40
41

template <>
inline bool qCompare(int const &t1, KeyResolverCore::SolutionFlags const &t2, const char *actual, const char *expected,
                    const char *file, int line)
{
    return qCompare(int(t1), int(t2), actual, expected, file, line);
}
42
43
44
45
46
47
48
49
50
51
52
53
54
55

template <>
inline char *toString(const GpgME::Protocol &t)
{
    return qstrdup(Formatting::displayName(t).toLocal8Bit().constData());
}

template <>
inline bool qCompare(GpgME::Protocol const &t1, GpgME::Protocol const &t2, const char *actual, const char *expected,
                    const char *file, int line)
{
    return compare_helper(t1 == t2, "Compared values are not the same",
                          toString(t1), toString(t2), actual, expected, file, line);
}
56
57
}

58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
namespace
{
KeyGroup createGroup(const QString &name,
                     const std::vector<Key> &keys = std::vector<Key>(),
                     KeyGroup::Source source = KeyGroup::ApplicationConfig,
                     const QString &configName = QString())
{
    const KeyGroup::Id groupId = (source == KeyGroup::ApplicationConfig) ?
                                 (configName.isEmpty() ? name : configName) :
                                 name;
    KeyGroup g(groupId, name, keys, source);
    return g;
}
}

73
class KeyResolverCoreTest: public QObject
74
75
76
77
78
{
    Q_OBJECT
private Q_SLOTS:
    void init()
    {
79
        mGnupgHome = QTest::qExtractTestData("/fixtures/keyresolvercoretest");
80
81
82
83
        qputenv("GNUPGHOME", mGnupgHome->path().toLocal8Bit());

        // hold a reference to the key cache to avoid rebuilding while the test is running
        mKeyCache = KeyCache::instance();
84
85
        // make sure that the key cache has been populated
        (void)mKeyCache->keys();
86
87
88
89
90
91
92
93
    }

    void cleanup()
    {
        // verify that nobody else holds a reference to the key cache
        QVERIFY(mKeyCache.use_count() == 1);
        mKeyCache.reset();

Ingo Klöcker's avatar
Ingo Klöcker committed
94
95
96
        // kill all running gpg daemons
        (void)QProcess::execute("gpgconf", {"--kill", "all"});

97
        mGnupgHome.reset();
Ingo Klöcker's avatar
Ingo Klöcker committed
98
        qunsetenv("GNUPGHOME");
99
100
101
102
103
    }

    void test_verify_test_keys()
    {
        {
104
105
106
107
108
            const Key openpgp = testKey("sender-mixed@example.net", OpenPGP);
            QVERIFY(openpgp.hasSecret() && openpgp.canEncrypt() && openpgp.canSign());
            QCOMPARE(openpgp.userID(0).validity(), UserID::Ultimate);
            const Key smime = testKey("sender-mixed@example.net", CMS);
            QVERIFY(smime.hasSecret() && smime.canEncrypt() && smime.canSign());
109
            QCOMPARE(smime.userID(0).validity(), UserID::Full);
110
111
        }
        {
112
113
114
            const Key openpgp = testKey("sender-openpgp@example.net", OpenPGP);
            QVERIFY(openpgp.hasSecret() && openpgp.canEncrypt() && openpgp.canSign());
            QCOMPARE(openpgp.userID(0).validity(), UserID::Ultimate);
115
        }
116
117
118
119
120
        {
            const Key smime = testKey("sender-smime@example.net", CMS);
            QVERIFY(smime.hasSecret() && smime.canEncrypt() && smime.canSign());
            QCOMPARE(smime.userID(0).validity(), UserID::Full);
        }
121
        {
122
123
            const Key openpgp = testKey("prefer-openpgp@example.net", OpenPGP);
            QVERIFY(openpgp.canEncrypt());
124
125
126
127
128
129
130
131
            QCOMPARE(openpgp.userID(0).validity(), UserID::Ultimate);
            const Key smime = testKey("prefer-openpgp@example.net", CMS);
            QVERIFY(smime.canEncrypt());
            QCOMPARE(smime.userID(0).validity(), UserID::Full);
        }
        {
            const Key openpgp = testKey("full-validity@example.net", OpenPGP);
            QVERIFY(openpgp.canEncrypt());
132
            QCOMPARE(openpgp.userID(0).validity(), UserID::Full);
133
134
135
            const Key smime = testKey("full-validity@example.net", CMS);
            QVERIFY(smime.canEncrypt());
            QCOMPARE(smime.userID(0).validity(), UserID::Full);
136
137
        }
        {
138
            const Key openpgp = testKey("prefer-smime@example.net", OpenPGP);
139
140
            QVERIFY(openpgp.canEncrypt());
            QCOMPARE(openpgp.userID(0).validity(), UserID::Marginal);
141
            const Key smime = testKey("prefer-smime@example.net", CMS);
142
            QVERIFY(smime.canEncrypt());
143
            QCOMPARE(smime.userID(0).validity(), UserID::Full);
144
145
146
        }
    }

147
    void test_openpgp_is_used_if_openpgp_only_and_smime_only_are_both_possible()
148
    {
149
        KeyResolverCore resolver(/*encrypt=*/ true, /*sign=*/ true);
150
        resolver.setAllowMixedProtocols(false);
151
152
        resolver.setSender(QStringLiteral("sender-mixed@example.net"));

153
        const auto result = resolver.resolve();
154

155
156
157
158
159
        QCOMPARE(result.flags & KeyResolverCore::ResolvedMask, KeyResolverCore::AllResolved);
        QCOMPARE(result.flags & KeyResolverCore::ProtocolsMask, KeyResolverCore::OpenPGPOnly);
        QCOMPARE(result.solution.protocol, OpenPGP);
        QCOMPARE(result.solution.signingKeys.size(), 1);
        QCOMPARE(result.solution.signingKeys[0].primaryFingerprint(),
160
                 testKey("sender-mixed@example.net", OpenPGP).primaryFingerprint());
161
162
163
        QCOMPARE(result.solution.encryptionKeys.size(), 1);
        QCOMPARE(result.solution.encryptionKeys.value("sender-mixed@example.net").size(), 1);
        QCOMPARE(result.solution.encryptionKeys.value("sender-mixed@example.net")[0].primaryFingerprint(),
164
                 testKey("sender-mixed@example.net", OpenPGP).primaryFingerprint());
165
166
167
168
169
170
171
172
        QCOMPARE(result.alternative.protocol, CMS);
        QCOMPARE(result.alternative.signingKeys.size(), 1);
        QCOMPARE(result.alternative.signingKeys[0].primaryFingerprint(),
                 testKey("sender-mixed@example.net", CMS).primaryFingerprint());
        QCOMPARE(result.alternative.encryptionKeys.size(), 1);
        QCOMPARE(result.alternative.encryptionKeys.value("sender-mixed@example.net").size(), 1);
        QCOMPARE(result.alternative.encryptionKeys.value("sender-mixed@example.net")[0].primaryFingerprint(),
                 testKey("sender-mixed@example.net", CMS).primaryFingerprint());
173
174
    }

175
176
    void test_openpgp_is_used_if_openpgp_only_and_smime_only_are_both_possible_with_preference_for_openpgp()
    {
177
        KeyResolverCore resolver(/*encrypt=*/ true, /*sign=*/ true);
178
        resolver.setAllowMixedProtocols(false);
179
180
181
        resolver.setPreferredProtocol(OpenPGP);
        resolver.setSender(QStringLiteral("sender-mixed@example.net"));

182
        const auto result = resolver.resolve();
183

184
185
186
187
188
        QCOMPARE(result.flags & KeyResolverCore::ResolvedMask, KeyResolverCore::AllResolved);
        QCOMPARE(result.flags & KeyResolverCore::ProtocolsMask, KeyResolverCore::OpenPGPOnly);
        QCOMPARE(result.solution.protocol, OpenPGP);
        QCOMPARE(result.solution.signingKeys.size(), 1);
        QCOMPARE(result.solution.signingKeys[0].primaryFingerprint(),
189
                 testKey("sender-mixed@example.net", OpenPGP).primaryFingerprint());
190
191
192
        QCOMPARE(result.solution.encryptionKeys.size(), 1);
        QCOMPARE(result.solution.encryptionKeys.value("sender-mixed@example.net").size(), 1);
        QCOMPARE(result.solution.encryptionKeys.value("sender-mixed@example.net")[0].primaryFingerprint(),
193
                 testKey("sender-mixed@example.net", OpenPGP).primaryFingerprint());
194
195
196
197
198
199
200
201
        QCOMPARE(result.alternative.protocol, CMS);
        QCOMPARE(result.alternative.signingKeys.size(), 1);
        QCOMPARE(result.alternative.signingKeys[0].primaryFingerprint(),
                 testKey("sender-mixed@example.net", CMS).primaryFingerprint());
        QCOMPARE(result.alternative.encryptionKeys.size(), 1);
        QCOMPARE(result.alternative.encryptionKeys.value("sender-mixed@example.net").size(), 1);
        QCOMPARE(result.alternative.encryptionKeys.value("sender-mixed@example.net")[0].primaryFingerprint(),
                 testKey("sender-mixed@example.net", CMS).primaryFingerprint());
202
203
204
205
    }

    void test_smime_is_used_if_openpgp_only_and_smime_only_are_both_possible_with_preference_for_smime()
    {
206
        KeyResolverCore resolver(/*encrypt=*/ true, /*sign=*/ true);
207
        resolver.setAllowMixedProtocols(false);
208
209
210
        resolver.setPreferredProtocol(CMS);
        resolver.setSender(QStringLiteral("sender-mixed@example.net"));

211
        const auto result = resolver.resolve();
212

213
214
215
216
217
        QCOMPARE(result.flags & KeyResolverCore::ResolvedMask, KeyResolverCore::AllResolved);
        QCOMPARE(result.flags & KeyResolverCore::ProtocolsMask, KeyResolverCore::CMSOnly);
        QCOMPARE(result.solution.protocol, CMS);
        QCOMPARE(result.solution.signingKeys.size(), 1);
        QCOMPARE(result.solution.signingKeys[0].primaryFingerprint(),
218
                 testKey("sender-mixed@example.net", CMS).primaryFingerprint());
219
220
221
        QCOMPARE(result.solution.encryptionKeys.size(), 1);
        QCOMPARE(result.solution.encryptionKeys.value("sender-mixed@example.net").size(), 1);
        QCOMPARE(result.solution.encryptionKeys.value("sender-mixed@example.net")[0].primaryFingerprint(),
222
                 testKey("sender-mixed@example.net", CMS).primaryFingerprint());
223
224
225
226
227
228
229
230
        QCOMPARE(result.alternative.protocol, OpenPGP);
        QCOMPARE(result.alternative.signingKeys.size(), 1);
        QCOMPARE(result.alternative.signingKeys[0].primaryFingerprint(),
                 testKey("sender-mixed@example.net", OpenPGP).primaryFingerprint());
        QCOMPARE(result.alternative.encryptionKeys.size(), 1);
        QCOMPARE(result.alternative.encryptionKeys.value("sender-mixed@example.net").size(), 1);
        QCOMPARE(result.alternative.encryptionKeys.value("sender-mixed@example.net")[0].primaryFingerprint(),
                 testKey("sender-mixed@example.net", OpenPGP).primaryFingerprint());
231
232
    }

233
234
235
236
237
238
239
240
241
    void test_in_mixed_mode_openpgp_is_used_if_openpgp_only_and_smime_only_are_both_possible()
    {
        KeyResolverCore resolver(/*encrypt=*/ true, /*sign=*/ true);
        resolver.setSender(QStringLiteral("sender-mixed@example.net"));

        const auto result = resolver.resolve();

        QCOMPARE(result.flags & KeyResolverCore::ResolvedMask, KeyResolverCore::AllResolved);
        QCOMPARE(result.flags & KeyResolverCore::ProtocolsMask, KeyResolverCore::OpenPGPOnly);
242
        QCOMPARE(result.solution.protocol, OpenPGP);
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
        QCOMPARE(result.solution.signingKeys.size(), 1);
        QCOMPARE(result.solution.signingKeys[0].primaryFingerprint(),
                 testKey("sender-mixed@example.net", OpenPGP).primaryFingerprint());
        QCOMPARE(result.solution.encryptionKeys.size(), 1);
        QCOMPARE(result.solution.encryptionKeys.value("sender-mixed@example.net").size(), 1);
        QCOMPARE(result.solution.encryptionKeys.value("sender-mixed@example.net")[0].primaryFingerprint(),
                 testKey("sender-mixed@example.net", OpenPGP).primaryFingerprint());
        // no alternative solution is proposed
        QCOMPARE(result.alternative.protocol, UnknownProtocol);
        QCOMPARE(result.alternative.encryptionKeys.size(), 0);
    }

    void test_in_mixed_mode_openpgp_is_used_if_openpgp_only_and_smime_only_are_both_possible_with_preference_for_openpgp()
    {
        KeyResolverCore resolver(/*encrypt=*/ true, /*sign=*/ true);
        resolver.setPreferredProtocol(OpenPGP);
        resolver.setSender(QStringLiteral("sender-mixed@example.net"));

        const auto result = resolver.resolve();

        QCOMPARE(result.flags & KeyResolverCore::ResolvedMask, KeyResolverCore::AllResolved);
        QCOMPARE(result.flags & KeyResolverCore::ProtocolsMask, KeyResolverCore::OpenPGPOnly);
265
        QCOMPARE(result.solution.protocol, OpenPGP);
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
        QCOMPARE(result.solution.signingKeys.size(), 1);
        QCOMPARE(result.solution.signingKeys[0].primaryFingerprint(),
                 testKey("sender-mixed@example.net", OpenPGP).primaryFingerprint());
        QCOMPARE(result.solution.encryptionKeys.size(), 1);
        QCOMPARE(result.solution.encryptionKeys.value("sender-mixed@example.net").size(), 1);
        QCOMPARE(result.solution.encryptionKeys.value("sender-mixed@example.net")[0].primaryFingerprint(),
                 testKey("sender-mixed@example.net", OpenPGP).primaryFingerprint());
        // no alternative solution is proposed
        QCOMPARE(result.alternative.protocol, UnknownProtocol);
        QCOMPARE(result.alternative.encryptionKeys.size(), 0);
    }

    void test_in_mixed_mode_smime_is_used_if_openpgp_only_and_smime_only_are_both_possible_with_preference_for_smime()
    {
        KeyResolverCore resolver(/*encrypt=*/ true, /*sign=*/ true);
        resolver.setPreferredProtocol(CMS);
        resolver.setSender(QStringLiteral("sender-mixed@example.net"));

        const auto result = resolver.resolve();

        QCOMPARE(result.flags & KeyResolverCore::ResolvedMask, KeyResolverCore::AllResolved);
        QCOMPARE(result.flags & KeyResolverCore::ProtocolsMask, KeyResolverCore::CMSOnly);
288
        QCOMPARE(result.solution.protocol, CMS);
289
290
291
292
293
294
295
296
297
298
299
300
301
        QCOMPARE(result.solution.signingKeys.size(), 1);
        QCOMPARE(result.solution.signingKeys[0].primaryFingerprint(),
                 testKey("sender-mixed@example.net", CMS).primaryFingerprint());
        QCOMPARE(result.solution.encryptionKeys.size(), 1);
        QCOMPARE(result.solution.encryptionKeys.value("sender-mixed@example.net").size(), 1);
        QCOMPARE(result.solution.encryptionKeys.value("sender-mixed@example.net")[0].primaryFingerprint(),
                 testKey("sender-mixed@example.net", CMS).primaryFingerprint());
        // no alternative solution is proposed
        QCOMPARE(result.alternative.protocol, UnknownProtocol);
        QCOMPARE(result.alternative.encryptionKeys.size(), 0);
    }

    void test_in_mixed_mode_keys_with_higher_validity_are_preferred_if_both_protocols_are_needed()
302
303
    {
        KeyResolverCore resolver(/*encrypt=*/ true, /*sign=*/ false);
304
        resolver.setRecipients({"sender-openpgp@example.net", "sender-smime@example.net", "prefer-openpgp@example.net", "prefer-smime@example.net"});
305

306
        const auto result = resolver.resolve();
307

308
309
310
311
312
313
314
315
        QCOMPARE(result.flags & KeyResolverCore::ResolvedMask, KeyResolverCore::AllResolved);
        QCOMPARE(result.flags & KeyResolverCore::ProtocolsMask, KeyResolverCore::MixedProtocols);
        QCOMPARE(result.solution.protocol, UnknownProtocol);
        QCOMPARE(result.solution.encryptionKeys.size(), 4);
        QVERIFY(result.solution.encryptionKeys.contains("sender-openpgp@example.net"));
        QVERIFY(result.solution.encryptionKeys.contains("sender-smime@example.net"));
        QCOMPARE(result.solution.encryptionKeys.value("prefer-openpgp@example.net").size(), 1);
        QCOMPARE(result.solution.encryptionKeys.value("prefer-openpgp@example.net")[0].primaryFingerprint(),
316
                 testKey("prefer-openpgp@example.net", OpenPGP).primaryFingerprint());
317
318
        QCOMPARE(result.solution.encryptionKeys.value("prefer-smime@example.net").size(), 1);
        QCOMPARE(result.solution.encryptionKeys.value("prefer-smime@example.net")[0].primaryFingerprint(),
319
                 testKey("prefer-smime@example.net", CMS).primaryFingerprint());
320
321
322
        // no alternative solution is proposed
        QCOMPARE(result.alternative.protocol, UnknownProtocol);
        QCOMPARE(result.alternative.encryptionKeys.size(), 0);
323
324
    }

325
    void test_reports_unresolved_addresses_if_both_protocols_are_allowed_but_no_keys_are_found_for_an_address()
326
327
    {
        KeyResolverCore resolver(/*encrypt=*/ true, /*sign=*/ false);
328
        resolver.setRecipients({"unknown@example.net"});
329

330
        const auto result = resolver.resolve();
331

332
333
        QCOMPARE(result.flags & KeyResolverCore::ResolvedMask, KeyResolverCore::SomeUnresolved);
        QCOMPARE(result.flags & KeyResolverCore::ProtocolsMask, KeyResolverCore::OpenPGPOnly);
334
        QCOMPARE(result.solution.protocol, OpenPGP);
335
        QCOMPARE(result.solution.encryptionKeys.value("unknown@example.net").size(), 0);
336
337
    }

338
    void test_reports_unresolved_addresses_if_openpgp_is_requested_and_no_openpgp_keys_are_found_for_an_address()
339
340
341
342
    {
        KeyResolverCore resolver(/*encrypt=*/ true, /*sign=*/ false, OpenPGP);
        resolver.setRecipients({"sender-openpgp@example.net", "sender-smime@example.net"});

343
344
345
346
        const auto result = resolver.resolve();

        QCOMPARE(result.flags & KeyResolverCore::ResolvedMask, KeyResolverCore::SomeUnresolved);
        QCOMPARE(result.flags & KeyResolverCore::ProtocolsMask, KeyResolverCore::OpenPGPOnly);
347
        QCOMPARE(result.solution.protocol, OpenPGP);
348
349
350
351
        QCOMPARE(result.solution.encryptionKeys.size(), 2);
        QCOMPARE(result.solution.encryptionKeys.value("sender-openpgp@example.net").size(), 1);
        QCOMPARE(result.solution.encryptionKeys.value("sender-smime@example.net").size(), 0);
        QCOMPARE(result.alternative.encryptionKeys.size(), 0);
352
353
    }

354
    void test_reports_unresolved_addresses_if_smime_is_requested_and_no_smime_keys_are_found_for_an_address()
355
356
357
358
    {
        KeyResolverCore resolver(/*encrypt=*/ true, /*sign=*/ false, CMS);
        resolver.setRecipients({"sender-openpgp@example.net", "sender-smime@example.net"});

359
360
361
362
        const auto result = resolver.resolve();

        QCOMPARE(result.flags & KeyResolverCore::ResolvedMask, KeyResolverCore::SomeUnresolved);
        QCOMPARE(result.flags & KeyResolverCore::ProtocolsMask, KeyResolverCore::CMSOnly);
363
        QCOMPARE(result.solution.protocol, CMS);
364
365
366
367
        QCOMPARE(result.solution.encryptionKeys.size(), 2);
        QCOMPARE(result.solution.encryptionKeys.value("sender-openpgp@example.net").size(), 0);
        QCOMPARE(result.solution.encryptionKeys.value("sender-smime@example.net").size(), 1);
        QCOMPARE(result.alternative.encryptionKeys.size(), 0);
368
369
    }

370
    void test_reports_unresolved_addresses_if_mixed_protocols_are_not_allowed_but_needed()
371
372
373
374
375
    {
        KeyResolverCore resolver(/*encrypt=*/ true, /*sign=*/ false);
        resolver.setAllowMixedProtocols(false);
        resolver.setRecipients({"sender-openpgp@example.net", "sender-smime@example.net"});

376
377
378
379
        const auto result = resolver.resolve();

        QCOMPARE(result.flags & KeyResolverCore::ResolvedMask, KeyResolverCore::SomeUnresolved);
        QCOMPARE(result.flags & KeyResolverCore::ProtocolsMask, KeyResolverCore::OpenPGPOnly);
380
        QCOMPARE(result.solution.protocol, OpenPGP);
381
382
383
384
385
386
        QCOMPARE(result.solution.encryptionKeys.size(), 2);
        QCOMPARE(result.solution.encryptionKeys.value("sender-openpgp@example.net").size(), 1);
        QCOMPARE(result.solution.encryptionKeys.value("sender-smime@example.net").size(), 0);
        QCOMPARE(result.alternative.encryptionKeys.size(), 2);
        QCOMPARE(result.alternative.encryptionKeys.value("sender-openpgp@example.net").size(), 0);
        QCOMPARE(result.alternative.encryptionKeys.value("sender-smime@example.net").size(), 1);
387
388
    }

389
    void test_openpgp_overrides_are_used_if_both_protocols_are_allowed()
390
391
    {
        const QString override = testKey("prefer-openpgp@example.net", OpenPGP).primaryFingerprint();
392
        KeyResolverCore resolver(/*encrypt=*/ true, /*sign=*/ true);
393
        resolver.setAllowMixedProtocols(false);
394
        resolver.setSender(QStringLiteral("sender-mixed@example.net"));
395
396
        resolver.setRecipients({"full-validity@example.net"});
        resolver.setOverrideKeys({{OpenPGP, {{QStringLiteral("Needs to be normalized <full-validity@example.net>"), {override}}}}});
397

398
        const auto result = resolver.resolve();
399

400
401
402
403
404
405
406
        QCOMPARE(result.flags & KeyResolverCore::ResolvedMask, KeyResolverCore::AllResolved);
        QCOMPARE(result.flags & KeyResolverCore::ProtocolsMask, KeyResolverCore::OpenPGPOnly);
        QCOMPARE(result.solution.encryptionKeys.value("full-validity@example.net").size(), 1);
        QCOMPARE(result.solution.encryptionKeys.value("full-validity@example.net")[0].primaryFingerprint(), override);
        QCOMPARE(result.alternative.encryptionKeys.value("full-validity@example.net").size(), 1);
        QCOMPARE(result.alternative.encryptionKeys.value("full-validity@example.net")[0].primaryFingerprint(),
                 testKey("full-validity@example.net", CMS).primaryFingerprint());
407
408
409
410
411
412
413
414
415
416
    }

    void test_openpgp_overrides_are_used_if_openpgp_only_is_requested()
    {
        const QString override = testKey("prefer-openpgp@example.net", OpenPGP).primaryFingerprint();
        KeyResolverCore resolver(/*encrypt=*/ true, /*sign=*/ true, OpenPGP);
        resolver.setSender(QStringLiteral("sender-mixed@example.net"));
        resolver.setRecipients({"full-validity@example.net"});
        resolver.setOverrideKeys({{OpenPGP, {{QStringLiteral("Needs to be normalized <full-validity@example.net>"), {override}}}}});

417
        const auto result = resolver.resolve();
418

419
420
421
422
423
        QCOMPARE(result.flags & KeyResolverCore::ResolvedMask, KeyResolverCore::AllResolved);
        QCOMPARE(result.flags & KeyResolverCore::ProtocolsMask, KeyResolverCore::OpenPGPOnly);
        QCOMPARE(result.solution.encryptionKeys.value("full-validity@example.net").size(), 1);
        QCOMPARE(result.solution.encryptionKeys.value("full-validity@example.net")[0].primaryFingerprint(), override);
        QCOMPARE(result.alternative.encryptionKeys.size(), 0);
424
425
426
427
428
429
430
431
432
433
    }

    void test_openpgp_overrides_are_ignored_if_smime_only_is_requested()
    {
        const QString override = testKey("prefer-openpgp@example.net", OpenPGP).primaryFingerprint();
        KeyResolverCore resolver(/*encrypt=*/ true, /*sign=*/ true, CMS);
        resolver.setSender(QStringLiteral("sender-mixed@example.net"));
        resolver.setRecipients({"full-validity@example.net"});
        resolver.setOverrideKeys({{OpenPGP, {{QStringLiteral("Needs to be normalized <full-validity@example.net>"), {override}}}}});

434
        const auto result = resolver.resolve();
435

436
437
438
439
        QCOMPARE(result.flags & KeyResolverCore::ResolvedMask, KeyResolverCore::AllResolved);
        QCOMPARE(result.flags & KeyResolverCore::ProtocolsMask, KeyResolverCore::CMSOnly);
        QCOMPARE(result.solution.encryptionKeys.value("full-validity@example.net").size(), 1);
        QCOMPARE(result.solution.encryptionKeys.value("full-validity@example.net")[0].primaryFingerprint(),
440
                 testKey("full-validity@example.net", CMS).primaryFingerprint());
441
        QCOMPARE(result.alternative.encryptionKeys.size(), 0);
442
443
    }

444
    void test_smime_overrides_are_used_if_both_protocols_are_allowed_and_smime_is_preferred()
445
446
    {
        const QString override = testKey("prefer-smime@example.net", CMS).primaryFingerprint();
447
        KeyResolverCore resolver(/*encrypt=*/ true, /*sign=*/ true);
448
        resolver.setAllowMixedProtocols(false);
449
450
        resolver.setPreferredProtocol(CMS);
        resolver.setSender(QStringLiteral("sender-mixed@example.net"));
451
452
        resolver.setRecipients({"full-validity@example.net"});
        resolver.setOverrideKeys({{CMS, {{QStringLiteral("Needs to be normalized <full-validity@example.net>"), {override}}}}});
453

454
        const auto result = resolver.resolve();
455

456
457
458
459
460
461
462
        QCOMPARE(result.flags & KeyResolverCore::ResolvedMask, KeyResolverCore::AllResolved);
        QCOMPARE(result.flags & KeyResolverCore::ProtocolsMask, KeyResolverCore::CMSOnly);
        QCOMPARE(result.solution.encryptionKeys.value("full-validity@example.net").size(), 1);
        QCOMPARE(result.solution.encryptionKeys.value("full-validity@example.net")[0].primaryFingerprint(), override);
        QCOMPARE(result.alternative.encryptionKeys.value("full-validity@example.net").size(), 1);
        QCOMPARE(result.alternative.encryptionKeys.value("full-validity@example.net")[0].primaryFingerprint(),
                 testKey("full-validity@example.net", OpenPGP).primaryFingerprint());
463
464
465
466
467
468
469
470
471
472
    }

    void test_smime_overrides_are_used_if_smime_only_is_requested()
    {
        const QString override = testKey("prefer-smime@example.net", CMS).primaryFingerprint();
        KeyResolverCore resolver(/*encrypt=*/ true, /*sign=*/ true, CMS);
        resolver.setSender(QStringLiteral("sender-mixed@example.net"));
        resolver.setRecipients({"full-validity@example.net"});
        resolver.setOverrideKeys({{CMS, {{QStringLiteral("Needs to be normalized <full-validity@example.net>"), {override}}}}});

473
        const auto result = resolver.resolve();
474

475
476
477
478
479
        QCOMPARE(result.flags & KeyResolverCore::ResolvedMask, KeyResolverCore::AllResolved);
        QCOMPARE(result.flags & KeyResolverCore::ProtocolsMask, KeyResolverCore::CMSOnly);
        QCOMPARE(result.solution.encryptionKeys.value("full-validity@example.net").size(), 1);
        QCOMPARE(result.solution.encryptionKeys.value("full-validity@example.net")[0].primaryFingerprint(), override);
        QCOMPARE(result.alternative.encryptionKeys.size(), 0);
480
481
482
483
484
485
486
487
488
489
    }

    void test_smime_overrides_are_ignored_if_openpgp_only_is_requested()
    {
        const QString override = testKey("prefer-smime@example.net", CMS).primaryFingerprint();
        KeyResolverCore resolver(/*encrypt=*/ true, /*sign=*/ true, OpenPGP);
        resolver.setSender(QStringLiteral("sender-mixed@example.net"));
        resolver.setRecipients({"full-validity@example.net"});
        resolver.setOverrideKeys({{CMS, {{QStringLiteral("Needs to be normalized <full-validity@example.net>"), {override}}}}});

490
        const auto result = resolver.resolve();
491

492
493
494
495
        QCOMPARE(result.flags & KeyResolverCore::ResolvedMask, KeyResolverCore::AllResolved);
        QCOMPARE(result.flags & KeyResolverCore::ProtocolsMask, KeyResolverCore::OpenPGPOnly);
        QCOMPARE(result.solution.encryptionKeys.value("full-validity@example.net").size(), 1);
        QCOMPARE(result.solution.encryptionKeys.value("full-validity@example.net")[0].primaryFingerprint(),
496
                 testKey("full-validity@example.net", OpenPGP).primaryFingerprint());
497
        QCOMPARE(result.alternative.encryptionKeys.size(), 0);
498
499
    }

500
501
502
503
504
505
506
507
508
509
    void test_overrides_for_wrong_protocol_are_ignored()
    {
        const QString override1 = testKey("full-validity@example.net", CMS).primaryFingerprint();
        const QString override2 = testKey("full-validity@example.net", OpenPGP).primaryFingerprint();
        KeyResolverCore resolver(/*encrypt=*/ true, /*sign=*/ true);
        resolver.setSender(QStringLiteral("sender-mixed@example.net"));
        resolver.setRecipients({"sender-openpgp@example.net", "sender-smime@example.net"});
        resolver.setOverrideKeys({{OpenPGP, {{QStringLiteral("Needs to be normalized <sender-openpgp@example.net>"), {override1}}}}});
        resolver.setOverrideKeys({{CMS, {{QStringLiteral("Needs to be normalized <sender-smime@example.net>"), {override2}}}}});

510
        const auto result = resolver.resolve();
511

512
513
514
515
        QCOMPARE(result.flags & KeyResolverCore::ResolvedMask, KeyResolverCore::AllResolved);
        QCOMPARE(result.flags & KeyResolverCore::ProtocolsMask, KeyResolverCore::MixedProtocols);
        QCOMPARE(result.solution.encryptionKeys.value("sender-openpgp@example.net").size(), 1);
        QCOMPARE(result.solution.encryptionKeys.value("sender-openpgp@example.net")[0].primaryFingerprint(),
516
                 testKey("sender-openpgp@example.net", OpenPGP).primaryFingerprint());
517
518
        QCOMPARE(result.solution.encryptionKeys.value("sender-smime@example.net").size(), 1);
        QCOMPARE(result.solution.encryptionKeys.value("sender-smime@example.net")[0].primaryFingerprint(),
519
520
521
                 testKey("sender-smime@example.net", CMS).primaryFingerprint());
    }

522
523
524
525
526
527
528
529
    void test_openpgp_only_common_overrides_are_used_for_openpgp()
    {
        const QString override = testKey("prefer-openpgp@example.net", OpenPGP).primaryFingerprint();
        KeyResolverCore resolver(/*encrypt=*/ true, /*sign=*/ true);
        resolver.setSender(QStringLiteral("sender-mixed@example.net"));
        resolver.setRecipients({"sender-openpgp@example.net"});
        resolver.setOverrideKeys({{UnknownProtocol, {{QStringLiteral("Needs to be normalized <sender-openpgp@example.net>"), {override}}}}});

530
        const auto result = resolver.resolve();
531

532
533
534
535
        QCOMPARE(result.flags & KeyResolverCore::ResolvedMask, KeyResolverCore::AllResolved);
        QCOMPARE(result.flags & KeyResolverCore::ProtocolsMask, KeyResolverCore::OpenPGPOnly);
        QCOMPARE(result.solution.encryptionKeys.value("sender-openpgp@example.net").size(), 1);
        QCOMPARE(result.solution.encryptionKeys.value("sender-openpgp@example.net")[0].primaryFingerprint(), override);
536
537
538
539
540
541
542
543
544
545
    }

    void test_smime_only_common_overrides_are_used_for_smime()
    {
        const QString override = testKey("prefer-smime@example.net", CMS).primaryFingerprint();
        KeyResolverCore resolver(/*encrypt=*/ true, /*sign=*/ true);
        resolver.setSender(QStringLiteral("sender-mixed@example.net"));
        resolver.setRecipients({"sender-smime@example.net"});
        resolver.setOverrideKeys({{UnknownProtocol, {{QStringLiteral("Needs to be normalized <sender-smime@example.net>"), {override}}}}});

546
        const auto result = resolver.resolve();
547

548
549
550
551
        QCOMPARE(result.flags & KeyResolverCore::ResolvedMask, KeyResolverCore::AllResolved);
        QCOMPARE(result.flags & KeyResolverCore::ProtocolsMask, KeyResolverCore::CMSOnly);
        QCOMPARE(result.solution.encryptionKeys.value("sender-smime@example.net").size(), 1);
        QCOMPARE(result.solution.encryptionKeys.value("sender-smime@example.net")[0].primaryFingerprint(), override);
552
553
    }

554
555
556
557
558
559
560
561
    void test_mixed_protocol_common_overrides_override_protocol_specific_resolution()
    {
        const QString override1 = testKey("prefer-openpgp@example.net", OpenPGP).primaryFingerprint();
        const QString override2 = testKey("prefer-smime@example.net", CMS).primaryFingerprint();
        KeyResolverCore resolver(/*encrypt=*/ true, /*sign=*/ true);
        resolver.setSender(QStringLiteral("sender-mixed@example.net"));
        resolver.setOverrideKeys({{UnknownProtocol, {{QStringLiteral("sender-mixed@example.net"), {override1, override2}}}}});

562
        const auto result = resolver.resolve();
563

564
565
566
567
568
        QCOMPARE(result.flags & KeyResolverCore::ResolvedMask, KeyResolverCore::AllResolved);
        QCOMPARE(result.flags & KeyResolverCore::ProtocolsMask, KeyResolverCore::MixedProtocols);
        QCOMPARE(result.solution.encryptionKeys.value("sender-mixed@example.net").size(), 2);
        QCOMPARE(result.solution.encryptionKeys.value("sender-mixed@example.net")[0].primaryFingerprint(), override1);
        QCOMPARE(result.solution.encryptionKeys.value("sender-mixed@example.net")[1].primaryFingerprint(), override2);
569
570
    }

571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
    void test_common_overrides_override_protocol_specific_overrides()
    {
        const QString override1 = testKey("full-validity@example.net", OpenPGP).primaryFingerprint();
        const QString override2 = testKey("full-validity@example.net", CMS).primaryFingerprint();
        KeyResolverCore resolver(/*encrypt=*/ true, /*sign=*/ true);
        resolver.setSender(QStringLiteral("sender-mixed@example.net"));
        resolver.setRecipients({"sender-openpgp@example.net", "sender-smime@example.net"});
        resolver.setOverrideKeys({
            {OpenPGP, {
                {QStringLiteral("sender-openpgp@example.net"), {testKey("prefer-openpgp@example.net", OpenPGP).primaryFingerprint()}}
            }},
            {CMS, {
                {QStringLiteral("sender-smime@example.net"), {testKey("prefer-smime@example.net", CMS).primaryFingerprint()}}
            }},
            {UnknownProtocol, {
                {QStringLiteral("sender-openpgp@example.net"), {override1}},
                {QStringLiteral("sender-smime@example.net"), {override2}}
            }}
        });

591
592
593
594
595
596
597
598
        const auto result = resolver.resolve();

        QCOMPARE(result.flags & KeyResolverCore::ResolvedMask, KeyResolverCore::AllResolved);
        QCOMPARE(result.flags & KeyResolverCore::ProtocolsMask, KeyResolverCore::MixedProtocols);
        QCOMPARE(result.solution.encryptionKeys.value("sender-openpgp@example.net").size(), 1);
        QCOMPARE(result.solution.encryptionKeys.value("sender-openpgp@example.net")[0].primaryFingerprint(), override1);
        QCOMPARE(result.solution.encryptionKeys.value("sender-smime@example.net").size(), 1);
        QCOMPARE(result.solution.encryptionKeys.value("sender-smime@example.net")[0].primaryFingerprint(), override2);
599
600
    }

601
602
603
604
605
606
607
608
    void test_reports_failure_if_openpgp_is_requested_but_common_overrides_require_smime()
    {
        KeyResolverCore resolver(/*encrypt=*/ true, /*sign=*/ false, OpenPGP);
        resolver.setRecipients({"sender-mixed@example.net"});
        resolver.setOverrideKeys({{UnknownProtocol, {
            {QStringLiteral("sender-mixed@example.net"), {testKey("prefer-smime@example.net", CMS).primaryFingerprint()}}
        }}});

609
610
611
        const auto result = resolver.resolve();

        QVERIFY(result.flags & KeyResolverCore::Error);
612
613
614
615
616
617
618
619
620
621
    }

    void test_reports_failure_if_smime_is_requested_but_common_overrides_require_openpgp()
    {
        KeyResolverCore resolver(/*encrypt=*/ true, /*sign=*/ false, CMS);
        resolver.setRecipients({"sender-mixed@example.net"});
        resolver.setOverrideKeys({{UnknownProtocol, {
            {QStringLiteral("sender-mixed@example.net"), {testKey("prefer-openpgp@example.net", OpenPGP).primaryFingerprint()}}
        }}});

622
623
624
        const auto result = resolver.resolve();

        QVERIFY(result.flags & KeyResolverCore::Error);
625
626
627
628
629
630
631
632
633
634
635
636
637
638
    }

    void test_reports_failure_if_mixed_protocols_are_not_allowed_but_required_by_common_overrides()
    {
        KeyResolverCore resolver(/*encrypt=*/ true, /*sign=*/ false);
        resolver.setAllowMixedProtocols(false);
        resolver.setRecipients({"sender-mixed@example.net"});
        resolver.setOverrideKeys({{UnknownProtocol, {
            {QStringLiteral("sender-mixed@example.net"), {
                testKey("prefer-openpgp@example.net", OpenPGP).primaryFingerprint(),
                testKey("prefer-smime@example.net", CMS).primaryFingerprint()
            }}
        }}});

639
640
641
        const auto result = resolver.resolve();

        QVERIFY(result.flags & KeyResolverCore::Error);
642
643
    }

644
    void test_groups__openpgp_only_mode__ignores_non_openpgp_only_groups()
645
646
    {
        const std::vector<KeyGroup> groups = {
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
            createGroup("group@example.net", {
                testKey("sender-openpgp@example.net", OpenPGP),
                testKey("sender-smime@example.net", CMS)
            }),
            createGroup("group@example.net", {
                testKey("prefer-smime@example.net", CMS)
            }),
            createGroup("group@example.net", {
                testKey("prefer-openpgp@example.net", OpenPGP),
            }),
        };
        KeyCache::mutableInstance()->setGroups(groups);
        KeyResolverCore resolver(/*encrypt=*/ true, /*sign=*/ false, OpenPGP);
        resolver.setRecipients({"group@example.net"});

        const auto result = resolver.resolve();

        QCOMPARE(result.flags & KeyResolverCore::ResolvedMask, KeyResolverCore::AllResolved);
        QCOMPARE(result.flags & KeyResolverCore::ProtocolsMask, KeyResolverCore::OpenPGPOnly);
        QCOMPARE(result.solution.protocol, OpenPGP);
        QCOMPARE(result.solution.encryptionKeys.value("group@example.net").size(), 1);
        QCOMPARE(result.solution.encryptionKeys.value("group@example.net")[0].primaryFingerprint(),
                 testKey("prefer-openpgp@example.net", OpenPGP).primaryFingerprint());
    }

    void test_groups__smime_only_mode__ignores_non_smime_only_groups()
    {
        const std::vector<KeyGroup> groups = {
            createGroup("group@example.net", {
                testKey("sender-openpgp@example.net", OpenPGP),
                testKey("sender-smime@example.net", CMS)
            }),
            createGroup("group@example.net", {
                testKey("prefer-smime@example.net", CMS)
            }),
            createGroup("group@example.net", {
                testKey("prefer-openpgp@example.net", OpenPGP),
            }),
        };
        KeyCache::mutableInstance()->setGroups(groups);
        KeyResolverCore resolver(/*encrypt=*/ true, /*sign=*/ false, CMS);
        resolver.setRecipients({"group@example.net"});

        const auto result = resolver.resolve();

        QCOMPARE(result.flags & KeyResolverCore::ResolvedMask, KeyResolverCore::AllResolved);
        QCOMPARE(result.flags & KeyResolverCore::ProtocolsMask, KeyResolverCore::CMSOnly);
        QCOMPARE(result.solution.protocol, CMS);
        QCOMPARE(result.solution.encryptionKeys.value("group@example.net").size(), 1);
        QCOMPARE(result.solution.encryptionKeys.value("group@example.net")[0].primaryFingerprint(),
                 testKey("prefer-smime@example.net", CMS).primaryFingerprint());
    }

    void test_groups__single_protocol_mode__ignores_mixed_protocol_groups()
    {
        const std::vector<KeyGroup> groups = {
            createGroup("sender-mixed@example.net", {
                testKey("sender-openpgp@example.net", OpenPGP),
                testKey("sender-smime@example.net", CMS)
            }),
        };
        KeyCache::mutableInstance()->setGroups(groups);
        KeyResolverCore resolver(/*encrypt=*/ true, /*sign=*/ false);
        resolver.setAllowMixedProtocols(false);
        resolver.setRecipients({"sender-mixed@example.net"});

        const auto result = resolver.resolve();

        QCOMPARE(result.flags & KeyResolverCore::ResolvedMask, KeyResolverCore::AllResolved);
        QCOMPARE(result.flags & KeyResolverCore::ProtocolsMask, KeyResolverCore::OpenPGPOnly);
        QCOMPARE(result.solution.protocol, OpenPGP);
        QCOMPARE(result.solution.encryptionKeys.value("sender-mixed@example.net").size(), 1);
        QCOMPARE(result.solution.encryptionKeys.value("sender-mixed@example.net")[0].primaryFingerprint(),
                 testKey("sender-mixed@example.net", OpenPGP).primaryFingerprint());
    }

    void test_groups__mixed_mode__single_protocol_groups_are_preferred_over_mixed_protocol_groups()
    {
        const std::vector<KeyGroup> groups = {
            createGroup("group@example.net", {
                testKey("sender-openpgp@example.net", OpenPGP),
                testKey("sender-smime@example.net", CMS)
            }),
            createGroup("group@example.net", {
                testKey("prefer-smime@example.net", CMS)
            }),
            createGroup("group@example.net", {
                testKey("prefer-openpgp@example.net", OpenPGP),
            }),
        };
        KeyCache::mutableInstance()->setGroups(groups);
        KeyResolverCore resolver(/*encrypt=*/ true, /*sign=*/ false);
        resolver.setRecipients({"group@example.net"});

        const auto result = resolver.resolve();

        QCOMPARE(result.flags & KeyResolverCore::ResolvedMask, KeyResolverCore::AllResolved);
        QCOMPARE(result.flags & KeyResolverCore::ProtocolsMask, KeyResolverCore::OpenPGPOnly);
        QCOMPARE(result.solution.protocol, OpenPGP);
        QCOMPARE(result.solution.encryptionKeys.value("group@example.net").size(), 1);
        QCOMPARE(result.solution.encryptionKeys.value("group@example.net")[0].primaryFingerprint(),
                 testKey("prefer-openpgp@example.net", OpenPGP).primaryFingerprint());
    }

    void test_groups__mixed_mode__openpgp_only_group_preferred_over_mixed_protocol_group()
    {
        const std::vector<KeyGroup> groups = {
            createGroup("group@example.net", {
                testKey("sender-openpgp@example.net", OpenPGP),
                testKey("sender-smime@example.net", CMS)
            }),
758
759
            createGroup("group@example.net", {
                testKey("sender-openpgp@example.net", OpenPGP)
760
            }),
761
762
763
764
765
766
767
768
769
770
771
772
773
774
        };
        KeyCache::mutableInstance()->setGroups(groups);
        KeyResolverCore resolver(/*encrypt=*/ true, /*sign=*/ false);
        resolver.setRecipients({"group@example.net"});

        const auto result = resolver.resolve();

        QCOMPARE(result.flags & KeyResolverCore::ResolvedMask, KeyResolverCore::AllResolved);
        QCOMPARE(result.flags & KeyResolverCore::ProtocolsMask, KeyResolverCore::OpenPGPOnly);
        QCOMPARE(result.solution.encryptionKeys.value("group@example.net").size(), 1);
        QCOMPARE(result.solution.encryptionKeys.value("group@example.net")[0].primaryFingerprint(),
                 testKey("sender-openpgp@example.net", OpenPGP).primaryFingerprint());
    }

775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
    void test_groups__mixed_mode__smime_only_group_preferred_over_mixed_protocol_group()
    {
        const std::vector<KeyGroup> groups = {
            createGroup("group@example.net", {
                testKey("sender-openpgp@example.net", OpenPGP),
                testKey("sender-smime@example.net", CMS)
            }),
            createGroup("group@example.net", {
                testKey("sender-smime@example.net", CMS)
            }),
        };
        KeyCache::mutableInstance()->setGroups(groups);
        KeyResolverCore resolver(/*encrypt=*/ true, /*sign=*/ false);
        resolver.setRecipients({"group@example.net"});

        const auto result = resolver.resolve();

        QCOMPARE(result.flags & KeyResolverCore::ResolvedMask, KeyResolverCore::AllResolved);
        QCOMPARE(result.flags & KeyResolverCore::ProtocolsMask, KeyResolverCore::CMSOnly);
        QCOMPARE(result.solution.encryptionKeys.value("group@example.net").size(), 1);
        QCOMPARE(result.solution.encryptionKeys.value("group@example.net")[0].primaryFingerprint(),
                 testKey("sender-smime@example.net", CMS).primaryFingerprint());
    }

    void test_groups__mixed_mode__mixed_protocol_groups_are_used()
    {
        const std::vector<KeyGroup> groups = {
            createGroup("sender-mixed@example.net", {
                testKey("sender-openpgp@example.net", OpenPGP),
                testKey("sender-smime@example.net", CMS)
            }),
        };
        KeyCache::mutableInstance()->setGroups(groups);
        KeyResolverCore resolver(/*encrypt=*/ true, /*sign=*/ false);
        resolver.setRecipients({"sender-mixed@example.net"});

        const auto result = resolver.resolve();

        QCOMPARE(result.flags & KeyResolverCore::ResolvedMask, KeyResolverCore::AllResolved);
        QCOMPARE(result.flags & KeyResolverCore::ProtocolsMask, KeyResolverCore::MixedProtocols);
        QCOMPARE(result.solution.protocol, UnknownProtocol);
        QCOMPARE(result.solution.encryptionKeys.value("sender-mixed@example.net").size(), 2);
    }

819
private:
820
821
822
823
824
825
826
827
    Key testKey(const char *email, Protocol protocol = UnknownProtocol)
    {
        const std::vector<Key> keys = KeyCache::instance()->findByEMailAddress(email);
        for (const auto &key: keys) {
            if (protocol == UnknownProtocol || key.protocol() == protocol) {
                return key;
            }
        }
828
829
        qWarning() << "No" << Formatting::displayName(protocol) << "test key found for" << email;
        return {};
830
831
    }

832
833
834
835
836
private:
    QSharedPointer<QTemporaryDir> mGnupgHome;
    std::shared_ptr<const KeyCache> mKeyCache;
};

837
838
QTEST_MAIN(KeyResolverCoreTest)
#include "keyresolvercoretest.moc"