1 #include <cppunit/CompilerOutputter.h>
2 #include <cppunit/TestCaller.h>
3 #include <cppunit/TestFixture.h>
4 #include <cppunit/extensions/TestFactoryRegistry.h>
5 #include <cppunit/ui/text/TestRunner.h>
6
7 #include <cstring>
8
9 #include <fcntl.h>
10 #include <sys/stat.h>
11 #include <sys/types.h>
12 #include <unistd.h>
13
14 #include "fileerror.hh"
15 #include "fileutils.hh"
16 #include "testpaths.h"
17 #include "yapet20file.hh"
18
19 constexpr auto TEST_FILE{BUILDDIR "/yapet-yapet20file-test"};
20
21 class Yapet20FileTest : public CppUnit::TestFixture {
22 public:
suite()23 static CppUnit::TestSuite* suite() {
24 CppUnit::TestSuite* suiteOfTests =
25 new CppUnit::TestSuite("Yapet 2.0 File test");
26 suiteOfTests->addTest(new CppUnit::TestCaller<Yapet20FileTest>{
27 "should not fail opening a new file",
28 &Yapet20FileTest::openNewFile});
29 suiteOfTests->addTest(new CppUnit::TestCaller<Yapet20FileTest>{
30 "should fail reading empty identifier",
31 &Yapet20FileTest::failOpeningEmptyFile});
32
33 suiteOfTests->addTest(new CppUnit::TestCaller<Yapet20FileTest>{
34 "should fail opening a file with wrong identifier",
35 &Yapet20FileTest::failOpeningFileWithWrongIdentifier});
36 suiteOfTests->addTest(new CppUnit::TestCaller<Yapet20FileTest>{
37 "should read identifier", &Yapet20FileTest::readIdentifier});
38
39 suiteOfTests->addTest(new CppUnit::TestCaller<Yapet20FileTest>{
40 "should fail reading empty meta data",
41 &Yapet20FileTest::failReadingEmptyMetaData});
42 suiteOfTests->addTest(new CppUnit::TestCaller<Yapet20FileTest>{
43 "should read meta data", &Yapet20FileTest::readMetaData});
44
45 suiteOfTests->addTest(new CppUnit::TestCaller<Yapet20FileTest>{
46 "should fail reading empty header",
47 &Yapet20FileTest::failReadingEmptyHeader});
48 suiteOfTests->addTest(new CppUnit::TestCaller<Yapet20FileTest>{
49 "should read header", &Yapet20FileTest::readHeader});
50
51 suiteOfTests->addTest(new CppUnit::TestCaller<Yapet20FileTest>{
52 "should return empty password list",
53 &Yapet20FileTest::readNoPasswords});
54 suiteOfTests->addTest(new CppUnit::TestCaller<Yapet20FileTest>{
55 "should read password records",
56 &Yapet20FileTest::readPasswordRecords});
57 suiteOfTests->addTest(new CppUnit::TestCaller<Yapet20FileTest>{
58 "should move", &Yapet20FileTest::moveConstructor});
59 suiteOfTests->addTest(new CppUnit::TestCaller<Yapet20FileTest>{
60 "should move assign", &Yapet20FileTest::moveAssignment});
61
62 return suiteOfTests;
63 }
64
setUp()65 void setUp() { ::unlink(TEST_FILE); }
66
tearDown()67 void tearDown() { ::unlink(TEST_FILE); }
68
openNewFile()69 void openNewFile() {
70 yapet::Yapet20File newFile{TEST_FILE, true, false};
71 newFile.open();
72 }
73
failOpeningEmptyFile()74 void failOpeningEmptyFile() {
75 int fd = ::open(TEST_FILE, O_CREAT | O_WRONLY, S_IWUSR | S_IRUSR);
76 CPPUNIT_ASSERT(fd > -1);
77 ::close(fd);
78
79 yapet::Yapet20File yapet20File{TEST_FILE, false, false};
80 CPPUNIT_ASSERT_THROW(yapet20File.open(), yapet::FileFormatError);
81 }
82
failOpeningFileWithWrongIdentifier()83 void failOpeningFileWithWrongIdentifier() {
84 yapet::Yapet20File yapet20File{
85 BUILDDIR "/yapet20file-corrupt-identifier.pet", false, false};
86 CPPUNIT_ASSERT_THROW(yapet20File.open(), yapet::FileFormatError);
87 }
88
readIdentifier()89 void readIdentifier() {
90 // try/catch block to close file when yapet20File goes out of scope
91 try {
92 yapet::Yapet20File yapet20File{TEST_FILE, true, false};
93 yapet20File.open();
94 yapet20File.writeIdentifier();
95 } catch (...) {
96 CPPUNIT_FAIL("No exception expected");
97 }
98
99 yapet::Yapet20File yapet20File2{TEST_FILE, false, false};
100 yapet20File2.open();
101 CPPUNIT_ASSERT(
102 std::memcmp(*yapet20File2.readIdentifier(), "YAPET2.0", 8) == 0);
103 }
104
failReadingEmptyMetaData()105 void failReadingEmptyMetaData() {
106 yapet::Yapet20File yapet20File{TEST_FILE, true, false};
107 yapet20File.open();
108 yapet20File.writeIdentifier();
109
110 CPPUNIT_ASSERT_THROW(yapet20File.readHeader(), yapet::FileFormatError);
111 }
112
readMetaData()113 void readMetaData() {
114 yapet::SecureArray metaData{yapet::toSecureArray("metadata")};
115 try {
116 yapet::Yapet20File yapet20File{TEST_FILE, true, false};
117 yapet20File.open();
118 yapet20File.writeIdentifier();
119
120 yapet20File.writeUnencryptedMetaData(metaData);
121 } catch (...) {
122 CPPUNIT_FAIL("No exception expected");
123 }
124
125 yapet::Yapet20File yapet20File{TEST_FILE, false, false};
126 yapet20File.open();
127 auto actual = yapet20File.readUnencryptedMetaData();
128
129 CPPUNIT_ASSERT(metaData == actual);
130 }
131
failReadingEmptyHeader()132 void failReadingEmptyHeader() {
133 yapet::Yapet20File yapet20File{TEST_FILE, true, false};
134 yapet20File.open();
135 yapet20File.writeIdentifier();
136 CPPUNIT_ASSERT_THROW(yapet20File.readHeader(), yapet::FileFormatError);
137
138 yapet::SecureArray metaData{yapet::toSecureArray("metadata")};
139 yapet20File.writeUnencryptedMetaData(metaData);
140 CPPUNIT_ASSERT_THROW(yapet20File.readHeader(), yapet::FileFormatError);
141 }
142
readHeader()143 void readHeader() {
144 yapet::SecureArray headerData(2);
145 (*headerData)[0] = 'A';
146 (*headerData)[1] = 'B';
147 // try/catch block to close file when yapet20File goes out of scope
148 try {
149 yapet::Yapet20File yapet20File{TEST_FILE, true, false};
150 yapet20File.open();
151 yapet20File.writeIdentifier();
152 yapet::SecureArray metaData{yapet::toSecureArray("metadata")};
153 yapet20File.writeUnencryptedMetaData(metaData);
154
155 yapet20File.writeHeader(headerData);
156 } catch (...) {
157 CPPUNIT_FAIL("No exception expected");
158 }
159
160 yapet::Yapet20File yapet20File{TEST_FILE, false, false};
161 yapet20File.open();
162 auto actual = yapet20File.readHeader();
163
164 CPPUNIT_ASSERT(actual == headerData);
165 }
166
readNoPasswords()167 void readNoPasswords() {
168 // try/catch block to close file when yapet20File goes out of scope
169 try {
170 yapet::Yapet20File yapet20File{TEST_FILE, true, false};
171 yapet20File.open();
172 yapet20File.writeIdentifier();
173 yapet::SecureArray metaData{yapet::toSecureArray("metadata")};
174 yapet20File.writeUnencryptedMetaData(metaData);
175
176 yapet::SecureArray headerData(1);
177 (*headerData)[0] = 'M';
178 yapet20File.writeHeader(headerData);
179 } catch (...) {
180 CPPUNIT_FAIL("No exception expected");
181 }
182
183 yapet::Yapet20File yapet20File{TEST_FILE, false, false};
184 yapet20File.open();
185
186 auto passwords = yapet20File.readPasswordRecords();
187 CPPUNIT_ASSERT(passwords.size() == 0);
188 }
189
writeTestPasswords()190 void writeTestPasswords() {
191 yapet::Yapet20File yapet20File{TEST_FILE, true, false};
192 yapet20File.open();
193 yapet20File.writeIdentifier();
194 yapet::SecureArray metaData{yapet::toSecureArray("metadata")};
195 yapet20File.writeUnencryptedMetaData(metaData);
196
197 yapet::SecureArray headerData(1);
198 (*headerData)[0] = 'M';
199 yapet20File.writeHeader(headerData);
200
201 std::list<yapet::SecureArray> passwords;
202 for (auto i = 0; i < 5; i++) {
203 yapet::SecureArray password(1);
204 **password = i;
205 passwords.push_back(password);
206 }
207
208 yapet20File.writePasswordRecords(passwords);
209 }
210
testPasswordRecords(std::list<yapet::SecureArray> passwords)211 void testPasswordRecords(std::list<yapet::SecureArray> passwords) {
212 CPPUNIT_ASSERT(passwords.size() == 5);
213
214 auto expectedValue{0};
215 for (auto password : passwords) {
216 CPPUNIT_ASSERT(password.size() == 1);
217 CPPUNIT_ASSERT(**password == expectedValue++);
218 }
219 }
220
readPasswordRecords()221 void readPasswordRecords() {
222 writeTestPasswords();
223
224 yapet::Yapet20File yapet20File{TEST_FILE, false, false};
225 yapet20File.open();
226 auto passwords = yapet20File.readPasswordRecords();
227
228 testPasswordRecords(passwords);
229 }
230
moveConstructor()231 void moveConstructor() {
232 writeTestPasswords();
233
234 yapet::Yapet20File yapet20File{TEST_FILE, false, false};
235 yapet20File.open();
236
237 yapet::Yapet20File yapet10FileMoved{std::move(yapet20File)};
238
239 CPPUNIT_ASSERT(yapet10FileMoved.isSecure() == false);
240 CPPUNIT_ASSERT(yapet10FileMoved.isCreate() == false);
241
242 auto passwords = yapet10FileMoved.readPasswordRecords();
243 testPasswordRecords(passwords);
244 }
245
moveAssignment()246 void moveAssignment() {
247 writeTestPasswords();
248
249 yapet::Yapet20File yapet20File{TEST_FILE, false, false};
250 yapet20File.open();
251
252 yapet::Yapet20File yapet10FileMoved = std::move(yapet20File);
253
254 CPPUNIT_ASSERT(yapet10FileMoved.isSecure() == false);
255 CPPUNIT_ASSERT(yapet10FileMoved.isCreate() == false);
256
257 auto passwords = yapet10FileMoved.readPasswordRecords();
258 testPasswordRecords(passwords);
259 }
260 };
261
main()262 int main() {
263 CppUnit::TextUi::TestRunner runner;
264 runner.addTest(Yapet20FileTest::suite());
265 return runner.run() ? 0 : 1;
266 }