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 }