1//========================================================================
2//
3// check_distinguished_name_parser.h
4//
5// This file is licensed under the GPLv2 or later
6//
7// Copyright 2023 g10 Code GmbH, Author: Sune Stolborg Vuorela <sune@vuorela.dk>
8//========================================================================
9#include "DistinguishedNameParser.h"
10
11#include <QtTest/QTest>
12#include <iostream>
13
14class TestDistinguishedNameParser : public QObject
15{
16 Q_OBJECT
17public:
18 explicit TestDistinguishedNameParser(QObject *parent = nullptr) : QObject(parent) { }
19private slots:
20 // The big set of input/output. Several of the helper functions can be tested independently
21 void testParser();
22 void testParser_data();
23
24 void testRemoveLeadingSpaces();
25 void testRemoveLeadingSpaces_data();
26
27 void testRemoveTrailingSpaces();
28 void testRemoveTrailingSpaces_data();
29
30 void testParseHexString();
31 void testParseHexString_data();
32};
33
34void TestDistinguishedNameParser::testParser()
35{
36 QFETCH(std::string, inputData);
37 QFETCH(DN::Result, expectedResult);
38
39 auto result = DN::parseString(string: inputData);
40 QCOMPARE(result, expectedResult);
41}
42
43void TestDistinguishedNameParser::testParser_data()
44{
45 QTest::addColumn<std::string>(name: "inputData");
46 QTest::addColumn<DN::Result>(name: "expectedResult");
47
48 QTest::newRow(dataTag: "empty") << std::string {} << DN::Result {};
49 QTest::newRow(dataTag: "CN=Simple") << std::string { "CN=Simple" } << DN::Result { { "CN", "Simple" } };
50 QTest::newRow(dataTag: "CN=Name with spaces") << std::string { "CN=Name with spaces" } << DN::Result { { "CN", "Name with spaces" } };
51 QTest::newRow(dataTag: "CN=Simple,O=Silly") << std::string { "CN=Simple,O=Silly" } << DN::Result { { "CN", "Simple" }, { "O", "Silly" } };
52 QTest::newRow(dataTag: "CN=Steve Kille,O=Isode Limited,C=GB") << std::string { "CN=Steve Kille,O=Isode Limited,C=GB" } << DN::Result { { "CN", "Steve Kille" }, { "O", "Isode Limited" }, { "C", "GB" } };
53 QTest::newRow(dataTag: "CN=some.user@example.com, O=MyCompany, L=San Diego,ST=California, C=US")
54 << std::string { "CN=some.user@example.com, O=MyCompany, L=San Diego,ST=California, C=US" } << DN::Result { { "CN", "some.user@example.com" }, { "O", "MyCompany" }, { "L", "San Diego" }, { "ST", "California" }, { "C", "US" } };
55 QTest::newRow(dataTag: "Multi valued") << std::string { "OU=Sales+CN=J. Smith,O=Widget Inc.,C=US" }
56 << DN::Result { { "OU", "Sales" }, { "CN", "J. Smith" }, { "O", "Widget Inc." }, { "C", "US" } }; // This is technically wrong, but probably good enough for now
57 QTest::newRow(dataTag: "Escaping comma") << std::string { "CN=L. Eagle,O=Sue\\, Grabbit and Runn,C=GB" } << DN::Result { { "CN", "L. Eagle" }, { "O", "Sue, Grabbit and Runn" }, { "C", "GB" } };
58 QTest::newRow(dataTag: "Escaped trailing space") << std::string { "CN=Trailing space\\ " } << DN::Result { { "CN", "Trailing space " } };
59 QTest::newRow(dataTag: "Escaped quote") << std::string { "CN=Quotation \\\" Mark" } << DN::Result { { "CN", "Quotation \" Mark" } };
60
61 QTest::newRow(dataTag: "CN=Simple with escaping") << std::string { "CN=S\\69mpl\\65\\7A" } << DN::Result { { "CN", "Simplez" } };
62 QTest::newRow(dataTag: "SN=Lu\\C4\\8Di\\C4\\87") << std::string { "SN=Lu\\C4\\8Di\\C4\\87" } << DN::Result { { "SN", "Lučić" } };
63 QTest::newRow(dataTag: "CN=\"Quoted name\"") << std::string { "CN=\"Quoted name\"" } << DN::Result { { "CN", "Quoted name" } };
64 QTest::newRow(dataTag: "CN=\" Leading and trailing spacees \"") << std::string { "CN=\" Leading and trailing spaces \"" } << DN::Result { { "CN", " Leading and trailing spaces " } };
65 QTest::newRow(dataTag: "Comma in quotes") << std::string { "CN=\"Comma, inside\"" } << DN::Result { { "CN", "Comma, inside" } };
66 QTest::newRow(dataTag: "forbidden chars in quotes") << std::string { "CN=\"Forbidden !@#$%&*()<>[]{},.?/\\| chars\"" } << DN::Result { { "CN", "Forbidden !@#$%&*()<>[]{},.?/\\| chars" } };
67 QTest::newRow(dataTag: "Quoted quotation") << std::string { "CN=\"Quotation \\\" Mark\"" } << DN::Result { { "CN", "Quotation \" Mark" } };
68 QTest::newRow(dataTag: "Quoted quotation") << std::string { "CN=\"Quotation \\\" Mark\\\" Multiples\"" } << DN::Result { { "CN", "Quotation \" Mark\" Multiples" } };
69
70 QTest::newRow(dataTag: "frompdf1") << std::string { "2.5.4.97=#5553742D49644E722E20444520313233343735323233,CN=TeleSec PKS eIDAS QES CA 5,O=Deutsche Telekom AG,C=DE" }
71 << DN::Result { { "2.5.4.97", "USt-IdNr. DE 123475223" }, { "CN", "TeleSec PKS eIDAS QES CA 5" }, { "O", "Deutsche Telekom AG" }, { "C", "DE" } };
72 QTest::newRow(dataTag: "frompdf2") << std::string { "2.5.4.5=#34,CN=Koch\\, Werner,2.5.4.42=#5765726E6572,2.5.4.4=#4B6F6368,C=DE" }
73 << DN::Result { { "SerialNumber", "4" }, { "CN", "Koch, Werner" }, { "GN", "Werner" }, { "SN", "Koch" }, { "C", "DE" } };
74 QTest::newRow(dataTag: "frompdf2a") << std::string { "2.5.4.5=#34,CN=Koch\\, Werner,oid.2.5.4.42=#5765726E6572,OID.2.5.4.4=#4B6F6368,C=DE" }
75 << DN::Result { { "SerialNumber", "4" }, { "CN", "Koch, Werner" }, { "GN", "Werner" }, { "SN", "Koch" }, { "C", "DE" } };
76
77 // weird spacing
78 QTest::newRow(dataTag: "CN =Simple") << std::string { "CN =Simple" } << DN::Result { { "CN", "Simple" } };
79 QTest::newRow(dataTag: "CN= Simple") << std::string { "CN= Simple" } << DN::Result { { "CN", "Simple" } };
80 QTest::newRow(dataTag: "CN=Simple ") << std::string { "CN=Simple " } << DN::Result { { "CN", "Simple" } };
81 QTest::newRow(dataTag: "CN=Simple,") << std::string { "CN=Simple," } << DN::Result { { "CN", "Simple" } };
82 QTest::newRow(dataTag: "CN=Simple, O=Silly") << std::string { "CN=Simple, O=Silly" } << DN::Result { { "CN", "Simple" }, { "O", "Silly" } };
83
84 // various malformed
85 QTest::newRow(dataTag: "CN=Simple\\") << std::string { "CN=Simple\\" } << DN::Result {};
86 QTest::newRow(dataTag: "CN=") << std::string { "CN=" } << DN::Result {};
87 QTest::newRow(dataTag: "CN=Simple\\X") << std::string { "CN=Simple\\X" } << DN::Result {};
88 QTest::newRow(dataTag: "CN=Simple, O") << std::string { "CN=Simple, O" } << DN::Result {};
89 QTest::newRow(dataTag: "CN=Sim\"ple") << std::string { "CN=Sim\"ple, O" } << DN::Result {};
90 QTest::newRow(dataTag: "CN=Simple\\a") << std::string { "CN=Simple\\a" } << DN::Result {};
91 QTest::newRow(dataTag: "=Simple") << std::string { "=Simple" } << DN::Result {};
92 QTest::newRow(dataTag: "CN=\"Simple") << std::string { "CN=\"Simple" } << DN::Result {};
93 QTest::newRow(dataTag: "CN=\"Simple") << std::string { "CN=\"Simple\\" } << DN::Result {};
94 QTest::newRow(dataTag: "unquoted quotation in quotation") << std::string { "CN=\"Quotation \" Mark\"" } << DN::Result {};
95}
96
97void TestDistinguishedNameParser::testRemoveLeadingSpaces()
98{
99 QFETCH(std::string, input);
100 QFETCH(std::string, expectedOutput);
101
102 auto result = DN::detail::removeLeadingSpaces(view: input);
103 QCOMPARE(result, expectedOutput);
104}
105void TestDistinguishedNameParser::testRemoveLeadingSpaces_data()
106{
107 QTest::addColumn<std::string>(name: "input");
108 QTest::addColumn<std::string>(name: "expectedOutput");
109
110 QTest::newRow(dataTag: "Empty") << std::string {} << std::string {};
111 QTest::newRow(dataTag: "No leading spaces") << std::string { "horse" } << std::string { "horse" };
112 QTest::newRow(dataTag: "Some spaces") << std::string { " horse" } << std::string { "horse" };
113 QTest::newRow(dataTag: "Some leading and trailing") << std::string { " horse " } << std::string { "horse " };
114}
115
116void TestDistinguishedNameParser::testRemoveTrailingSpaces()
117{
118 QFETCH(std::string, input);
119 QFETCH(std::string, expectedOutput);
120
121 auto result = DN::detail::removeTrailingSpaces(view: input);
122 QCOMPARE(result, expectedOutput);
123}
124void TestDistinguishedNameParser::testRemoveTrailingSpaces_data()
125{
126 QTest::addColumn<std::string>(name: "input");
127 QTest::addColumn<std::string>(name: "expectedOutput");
128
129 QTest::newRow(dataTag: "Empty") << std::string {} << std::string {};
130 QTest::newRow(dataTag: "No leading spaces") << std::string { "horse" } << std::string { "horse" };
131 QTest::newRow(dataTag: "Some spaces") << std::string { "horse " } << std::string { "horse" };
132 QTest::newRow(dataTag: "Some leading and trailing") << std::string { " horse " } << std::string { " horse" };
133}
134
135void TestDistinguishedNameParser::testParseHexString()
136{
137 QFETCH(std::string, input);
138 QFETCH(std::optional<std::string>, expectedOutput);
139
140 auto result = DN::detail::parseHexString(view: input);
141 QCOMPARE(result, expectedOutput);
142}
143
144void TestDistinguishedNameParser::testParseHexString_data()
145{
146 QTest::addColumn<std::string>(name: "input");
147 QTest::addColumn<std::optional<std::string>>(name: "expectedOutput");
148
149 QTest::newRow(dataTag: "4") << std::string { "34" } << std::optional<std::string>("4");
150 QTest::newRow(dataTag: "Koch") << std::string { "4B6F6368" } << std::optional<std::string>("Koch");
151 QTest::newRow(dataTag: "USt-IdNr. DE 123475223") << std::string { "5553742D49644E722E20444520313233343735323233" } << std::optional<std::string>("USt-IdNr. DE 123475223");
152
153 // various baddies
154 QTest::newRow(dataTag: "empty") << std::string {} << std::optional<std::string> {};
155 QTest::newRow(dataTag: "FFF") << std::string { "FFF" } << std::optional<std::string> {};
156 QTest::newRow(dataTag: "F") << std::string { "F" } << std::optional<std::string> {};
157 QTest::newRow(dataTag: "XX") << std::string { "XX" } << std::optional<std::string> {};
158}
159
160QTEST_GUILESS_MAIN(TestDistinguishedNameParser);
161#include "check_distinguished_name_parser.moc"
162

source code of poppler/qt6/tests/check_distinguished_name_parser.cpp