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 <fcntl.h>
8 #include <sys/stat.h>
9 #include <sys/types.h>
10 #include <unistd.h>
11 
12 #include "fileerror.hh"
13 #include "fileutils.hh"
14 #include "testpaths.h"
15 #include "yapetfile.hh"
16 
17 constexpr auto TEST_FILE{BUILDDIR "/yapet-yapetfile-test"};
18 
19 class YapetFileMock : public yapet::YapetFile {
20    public:
YapetFileMock(bool create,bool secure)21     YapetFileMock(bool create, bool secure)
22         : YapetFile{TEST_FILE, create, secure} {}
23 
YapetFileMock(YapetFileMock && other)24     YapetFileMock(YapetFileMock&& other) : YapetFile{std::move(other)} {}
25 
operator =(YapetFileMock && other)26     YapetFile& operator=(YapetFileMock&& other) {
27         return yapet::YapetFile::operator=(std::move(other));
28     }
29 
hasValidFormat()30     bool hasValidFormat() { throw std::runtime_error("Not implemented"); }
31 
readIdentifier()32     yapet::SecureArray readIdentifier() {
33         throw std::runtime_error("Not implemented");
34     }
35 
readUnencryptedMetaData()36     yapet::SecureArray readUnencryptedMetaData() {
37         throw std::runtime_error("Not implemented");
38     }
39 
readHeader()40     yapet::SecureArray readHeader() {
41         throw std::runtime_error("Not implemented");
42     }
43 
readPasswordRecords()44     std::list<yapet::SecureArray> readPasswordRecords() {
45         throw std::runtime_error("Not implemented");
46     }
47 
writeIdentifier()48     void writeIdentifier() { throw std::runtime_error("Not implemented"); }
49 
writeUnencryptedMetaData(const yapet::SecureArray &)50     void writeUnencryptedMetaData(const yapet::SecureArray&) {
51         throw std::runtime_error("Not implemented");
52     }
53 
writeHeader(const yapet::SecureArray &)54     void writeHeader(const yapet::SecureArray&) {
55         throw std::runtime_error("Not implemented");
56     }
57 
writePasswordRecords(const std::list<yapet::SecureArray> &)58     void writePasswordRecords(const std::list<yapet::SecureArray>&) {
59         throw std::runtime_error("Not implemented");
60     }
61 
recognitionString() const62     const std::uint8_t* recognitionString() const {
63         throw std::runtime_error("Not implemented");
64     }
65 
recognitionStringSize() const66     int recognitionStringSize() const {
67         throw std::runtime_error("Not implemented");
68     }
69 
open()70     void open() { openRawFile(); }
71 };
72 
73 class YapetFileTest : public CppUnit::TestFixture {
74    public:
suite()75     static CppUnit::TestSuite* suite() {
76         CppUnit::TestSuite* suiteOfTests =
77             new CppUnit::TestSuite("YapetFile test");
78         suiteOfTests->addTest(new CppUnit::TestCaller<YapetFileTest>{
79             "should fail on non existing file",
80             &YapetFileTest::throwOnNonExisting});
81         suiteOfTests->addTest(new CppUnit::TestCaller<YapetFileTest>{
82             "should create new file with secure permissions",
83             &YapetFileTest::createNewFile});
84         suiteOfTests->addTest(new CppUnit::TestCaller<YapetFileTest>{
85             "should refuse to open existing file with insecure permissions",
86             &YapetFileTest::failToOpenExistingFileWithInsecurePermissions});
87         suiteOfTests->addTest(new CppUnit::TestCaller<YapetFileTest>{
88             "should open existing file", &YapetFileTest::openExistingFile});
89         suiteOfTests->addTest(new CppUnit::TestCaller<YapetFileTest>{
90             "should be forced to open file with insecure permissions",
91             &YapetFileTest::forceOpenExistingFileWithInsecurePermissions});
92         suiteOfTests->addTest(new CppUnit::TestCaller<YapetFileTest>{
93             "should get filename", &YapetFileTest::filename});
94 
95         return suiteOfTests;
96     }
97 
setUp()98     void setUp() { ::unlink(TEST_FILE); }
99 
tearDown()100     void tearDown() { ::unlink(TEST_FILE); }
101 
throwOnNonExisting()102     void throwOnNonExisting() {
103         YapetFileMock file{false, false};
104         CPPUNIT_ASSERT_THROW(file.open(), yapet::FileError);
105     }
106 
createNewFile()107     void createNewFile() {
108         YapetFileMock file{true, false};
109         file.open();
110 
111         CPPUNIT_ASSERT(yapet::hasSecurePermissions(TEST_FILE) == true);
112     }
113 
failToOpenExistingFileWithInsecurePermissions()114     void failToOpenExistingFileWithInsecurePermissions() {
115         auto fd = ::open(TEST_FILE, O_CREAT, S_IRWXU | S_IRWXG | S_IRWXO);
116         if (fd == -1) {
117             throw std::runtime_error("Failure to create test file");
118         }
119         ::close(fd);
120 
121         YapetFileMock file{false, true};
122         CPPUNIT_ASSERT_THROW(file.open(), yapet::FileInsecureError);
123     }
124 
openExistingFile()125     void openExistingFile() {
126         auto fd = ::open(TEST_FILE, O_CREAT, S_IRUSR | S_IWUSR);
127         if (fd == -1) {
128             throw std::runtime_error("Failure to create test file");
129         }
130         ::close(fd);
131 
132         YapetFileMock file{false, true};
133         file.open();
134         // Not throwing is the test
135     }
136 
forceOpenExistingFileWithInsecurePermissions()137     void forceOpenExistingFileWithInsecurePermissions() {
138         auto fd = ::open(TEST_FILE, O_CREAT, S_IRWXU | S_IRWXG | S_IRWXO);
139         if (fd == -1) {
140             throw std::runtime_error("Failure to create test file");
141         }
142         ::close(fd);
143 
144         YapetFileMock file{false, false};
145         file.open();
146         // Not throwing is the test
147     }
148 
filename()149     void filename() {
150         YapetFileMock file{false, true};
151 
152         std::string expected{TEST_FILE};
153 
154         CPPUNIT_ASSERT_EQUAL(expected, file.filename());
155     }
156 };
157 
main()158 int main() {
159     CppUnit::TextUi::TestRunner runner;
160     runner.addTest(YapetFileTest::suite());
161     return runner.run() ? 0 : 1;
162 }