QtPass 1.6.0
Multi-platform GUI for pass, the standard unix password manager.
Loading...
Searching...
No Matches
tst_filecontent.cpp
Go to the documentation of this file.
1// SPDX-FileCopyrightText: 2026 Anne Jan Brouwer
2// SPDX-License-Identifier: GPL-3.0-or-later
3#include <QtTest>
4
6
7class tst_filecontent : public QObject {
8 Q_OBJECT
9
10private Q_SLOTS:
11 void parsePlainPassword();
12 void parsePasswordWithNamedFields();
13 void parseWithTemplateFields();
14 void parseWithAllFields();
15 void getRemainingData();
16 void getRemainingDataForDisplay();
17 void namedValuesTakeValue();
18 void namedValuesTakeValueNotFound();
19 void parseEmptyContent();
20 void parsePasswordOnly();
21 void parseMultipleNamedFields();
22 void parseMatchingTemplateFields();
23 void parseOtpauthHiddenLine();
24 void parseColonInValue();
25 void parseTemplateFieldsCaseSensitive();
26};
27
28void tst_filecontent::parsePlainPassword() {
29 QString content = "my_secret_password";
30 FileContent fc = FileContent::parse(content, QStringList(), false);
31 QVERIFY2(fc.getPassword() == "my_secret_password", "Password should match");
32 QVERIFY(fc.getNamedValues().isEmpty());
33}
34
35void tst_filecontent::parsePasswordWithNamedFields() {
36 QString content = "secret123\nusername: john\npassword: doe";
37 QStringList templateFields;
38 FileContent fc = FileContent::parse(content, templateFields, false);
39 QVERIFY2(fc.getPassword() == "secret123", "Password should be secret123");
40 QVERIFY(fc.getNamedValues().isEmpty());
41}
42
43void tst_filecontent::parseWithTemplateFields() {
44 QString content =
45 "mypassword\nusername: john@example.com\nurl: https://example.com";
46 QStringList templateFields = {"username", "url"};
47 FileContent fc = FileContent::parse(content, templateFields, false);
48 QVERIFY2(fc.getPassword() == "mypassword", "Password should be mypassword");
49
50 NamedValues nv = fc.getNamedValues();
51 QVERIFY(nv.size() == 2);
52 QVERIFY(nv[0].name == "username");
53 QVERIFY(nv[0].value == "john@example.com");
54 QVERIFY(nv[1].name == "url");
55 QVERIFY(nv[1].value == "https://example.com");
56}
57
58void tst_filecontent::parseWithAllFields() {
59 QString content =
60 "pass123\nusername: admin\nnotes: some notes\ncustom: value";
61 QStringList templateFields;
62 FileContent fc = FileContent::parse(content, templateFields, true);
63
64 QVERIFY2(fc.getPassword() == "pass123", "Password should be pass123");
65
66 NamedValues nv = fc.getNamedValues();
67 QVERIFY(nv.size() == 3);
68 QVERIFY(nv[0].name == "username");
69 QVERIFY(nv[0].value == "admin");
70 QVERIFY(nv[1].name == "notes");
71 QVERIFY(nv[1].value == "some notes");
72 QVERIFY(nv[2].name == "custom");
73 QVERIFY(nv[2].value == "value");
74}
75
76void tst_filecontent::getRemainingData() {
77 QString content = "secret\nfield1: value1\nfield2: value2\nextra: data";
78 QStringList templateFields = {"field1"};
79 FileContent fc = FileContent::parse(content, templateFields, false);
80
81 QString remaining = fc.getRemainingData();
82 QVERIFY(remaining.contains("field2"));
83 QVERIFY(remaining.contains("extra"));
84}
85
86void tst_filecontent::getRemainingDataForDisplay() {
87 QString content =
88 "secret\nnotes: some notes\notpauth://totp/Secret: SKI123456";
89 QStringList templateFields;
90 FileContent fc = FileContent::parse(content, templateFields, false);
91
92 QString display = fc.getRemainingDataForDisplay();
93 QVERIFY(display.contains("notes"));
94 QVERIFY(!display.contains("otpauth"));
95}
96
97void tst_filecontent::namedValuesTakeValue() {
98 NamedValues nv = {{"username", "john"}, {"password", "secret"}};
99
100 QString val = nv.takeValue("username");
101 QVERIFY2(val == "john", "Should return 'john'");
102
103 val = nv.takeValue("username");
104 QVERIFY2(val.isEmpty(), "Should return empty after taking");
105}
106
107void tst_filecontent::namedValuesTakeValueNotFound() {
108 NamedValues nv = {{"username", "john"}};
109
110 QString val = nv.takeValue("nonexistent");
111 QVERIFY2(val.isEmpty(), "Should return empty for nonexistent key");
112}
113
114void tst_filecontent::parseEmptyContent() {
115 FileContent fc = FileContent::parse("", QStringList(), false);
116 QVERIFY(fc.getPassword().isEmpty());
117}
118
119void tst_filecontent::parsePasswordOnly() {
120 FileContent fc = FileContent::parse("single_line", QStringList(), false);
121 QVERIFY(fc.getPassword() == "single_line");
122}
123
124void tst_filecontent::parseMultipleNamedFields() {
125 QString content = "pass\nuser: u1\nuser: u2\nuser: u3";
126 QStringList templateFields = {"user"};
127 FileContent fc = FileContent::parse(content, templateFields, false);
128 QVERIFY(fc.getPassword() == "pass");
129 NamedValues nv = fc.getNamedValues();
130 QVERIFY2(nv.size() == 3, "Expected exactly three parsed user fields");
131 QVERIFY2(nv[0].name == "user" && nv[0].value == "u1",
132 "First user field should be parsed as user: u1");
133 QVERIFY2(nv[1].name == "user" && nv[1].value == "u2",
134 "Second user field should be parsed as user: u2");
135 QVERIFY2(nv[2].name == "user" && nv[2].value == "u3",
136 "Third user field should be parsed as user: u3");
137}
138
139void tst_filecontent::parseOtpauthHiddenLine() {
140 QString content = "secret\notpauth://totp/Example:alice@email?secret=key";
141 FileContent fc = FileContent::parse(content, QStringList(), false);
142 QString expected = "otpauth://totp/Example:alice@email?secret=key";
143 QVERIFY2(fc.getRemainingData() == expected,
144 "otpauth line should be preserved in remaining data");
145 QVERIFY(fc.getRemainingDataForDisplay().isEmpty());
146}
147
148void tst_filecontent::parseMatchingTemplateFields() {
149 QString content = "secret123\nusername: john\npassword: doe";
150 QStringList templateFields = {"username", "password"};
151 FileContent fc = FileContent::parse(content, templateFields, false);
152 QVERIFY2(fc.getPassword() == "secret123", "Password should be secret123");
153 NamedValues nv = fc.getNamedValues();
154 QVERIFY(nv.size() == 2);
155 QVERIFY(nv[0].name == "username");
156 QVERIFY(nv[0].value == "john");
157 QVERIFY(nv[1].name == "password");
158 QVERIFY(nv[1].value == "doe");
159}
160
161void tst_filecontent::parseColonInValue() {
162 QString content = "pass\nurl: https://example.com:8080/path";
163 QStringList templateFields = {"url"};
164 FileContent fc = FileContent::parse(content, templateFields, false);
165 NamedValues nv = fc.getNamedValues();
166 QVERIFY(nv.size() == 1);
167 QString urlValue = nv.takeValue("url");
168 QVERIFY2(urlValue == "https://example.com:8080/path",
169 "url value should match full URL with port");
170}
171
172void tst_filecontent::parseTemplateFieldsCaseSensitive() {
173 QString content = "pass\nUser: value";
174 QStringList templateFields = {"user"};
175 FileContent fc = FileContent::parse(content, templateFields, false);
176 NamedValues nv = fc.getNamedValues();
177 QVERIFY(nv.isEmpty());
178 QVERIFY2(fc.getRemainingData().contains("User: value"),
179 "unmatched case should be in remaining data");
180}
181
182QTEST_MAIN(tst_filecontent)
183#include "tst_filecontent.moc"
auto getRemainingData() const -> QString
Gets remaining data not in named values.
auto getNamedValues() const -> NamedValues
Gets named value pairs from the parsed file.
auto getRemainingDataForDisplay() const -> QString
Gets remaining data for display (excludes hidden fields like OTP).
auto getPassword() const -> QString
Gets the password from the parsed file.
static auto parse(const QString &fileContent, const QStringList &templateFields, bool allFields) -> FileContent
parse parses the given fileContent in a FileContent object. The password is accessible through getPas...
auto takeValue(const QString &name) -> QString
Finds and removes a named value by name.