#include #include #include #include #include #include using Kademlia::CUInt128; using namespace muleunit; namespace muleunit { template <> wxString StringFrom(const CPath& path) { return path.GetPrintable(); } } //! The max file-size of auto-generated files to test. const size_t TEST_LENGTH = 512; namespace muleunit { //! Needed for ASSERT_EQUALS with CMD4Hash values template <> wxString StringFrom(const CMD4Hash& hash) { return hash.Encode(); } //! Needed for ASSERT_EQUALS with CUInt128 values template <> wxString StringFrom(const CUInt128& value) { return value.ToHexString(); } } void writePredefData(CFileDataIO* file) { char data[TEST_LENGTH]; for (size_t j = 0; j < TEST_LENGTH; ++j) { data[j] = j & 0xff; } file->Write(data, TEST_LENGTH); file->Seek(0, wxFromStart); } ///////////////////////////////////////////////////////////////////// // Specialize this template for each implemention // of the CFileDataIO interface you wish to test. // // This struct must be a subclass of Test. // // Two pointers are to be defined: // m_emptyFile, which must be an empty, zero-length file // m_predefFile, which must be TEST_LENGTH in size and // and contain the sequence 0..255 repeated // as needed. // // The following functions should be overridden: // - setUp() // - tearDown() // template struct FileDataIOFixture; template <> class FileDataIOFixture : public Test { public: FileDataIOFixture(const wxString& testName) : Test(wxT("FileDataIO"), wxT("CFile - ") + testName) {} CFile* m_emptyFile; CFile* m_predefFile; void setUp() { m_emptyFile = m_predefFile = NULL; const CPath emptyPath = CPath(wxT("FileDataIOTest.empty")); const CPath datPath = CPath(wxT("FileDataIOTest.dat")); m_emptyFile = new CFile(); m_emptyFile->Create(emptyPath, true); ASSERT_TRUE(m_emptyFile->IsOpened()); m_emptyFile->Close(); m_emptyFile->Open(emptyPath, CFile::read_write); ASSERT_TRUE(m_emptyFile->IsOpened()); m_predefFile = new CFile(); m_predefFile->Create(datPath, true); ASSERT_TRUE(m_predefFile->IsOpened()); m_predefFile->Close(); m_predefFile->Open(datPath, CFile::read_write); ASSERT_TRUE(m_predefFile->IsOpened()); writePredefData(m_predefFile); ASSERT_EQUALS(0u, m_predefFile->GetPosition()); ASSERT_EQUALS(TEST_LENGTH, m_predefFile->GetLength()); } void tearDown() { delete m_emptyFile; delete m_predefFile; wxRemoveFile(wxT("FileDataIOTest.dat")); wxRemoveFile(wxT("FileDataIOTest.empty")); } }; template <> class FileDataIOFixture : public Test { public: FileDataIOFixture(const wxString& testName) : Test(wxT("FileDataIO"), wxT("CMemFile - ") + testName) {} CMemFile* m_emptyFile; CMemFile* m_predefFile; void setUp() { m_emptyFile = m_predefFile = NULL; m_emptyFile = new CMemFile(); m_predefFile = new CMemFile(); writePredefData(m_predefFile); ASSERT_EQUALS(0u, m_predefFile->GetPosition()); ASSERT_EQUALS(TEST_LENGTH, m_predefFile->GetLength()); } void tearDown() { delete m_emptyFile; delete m_predefFile; } }; ///////////////////////////////////////////////////////////////////// // A writeWrite interface should be implemented for each set of // read/write functions that is to be tested. The following 3 // static functions must be implemented in each specialization of the // template: // // - TYPE genValue(size_t j), which returns the expected value at // position j in the files with predefined data. // - TYPE readValue(CFileDataIO*), which returns and returns the // value at the current position in the file. // - void writeValue(CFileDataIO*, TYPE), which writes the given // value at the current position in the file. // - wxString name(), which returns the human-readble name of the type // template struct RWInterface; template <> struct RWInterface { static uint8 genValue(size_t j) { return j & 0xff; } static uint8 readValue(CFileDataIO* file) { return file->ReadUInt8(); } static void writeValue(CFileDataIO* file, uint8 value) { file->WriteUInt8(value); } static wxString name() { return wxT("UInt8"); } }; template <> struct RWInterface { static uint16 genValue(size_t j) { return (((j + 1) & 0xff) << 8) | (j & 0xff); } static uint16 readValue(CFileDataIO* file) { return file->ReadUInt16(); } static void writeValue(CFileDataIO* file, uint16 value) { file->WriteUInt16(value); } static wxString name() { return wxT("UInt16"); } }; template <> struct RWInterface { static uint32 genValue(size_t j) { return (((j + 3) & 0xff) << 24) | (((j + 2) & 0xff) << 16) | (((j + 1) & 0xff) << 8) | (j & 0xff); } static uint32 readValue(CFileDataIO* file) { return file->ReadUInt32(); } static void writeValue(CFileDataIO* file, uint32 value) { file->WriteUInt32(value); } static wxString name() { return wxT("UInt32"); } }; template <> struct RWInterface { static CMD4Hash genValue(size_t j) { CMD4Hash value; for (size_t y = j; y < j + 16; y++) { value[y - j] = y & 0xff; } return value; } static CMD4Hash readValue(CFileDataIO* file) { return file->ReadHash(); } static void writeValue(CFileDataIO* file, CMD4Hash value) { file->WriteHash(value); } static wxString name() { return wxT("CMD4Hash"); } }; template <> struct RWInterface { static CUInt128 genValue(size_t j) { CUInt128 value; for (size_t y = 0; y < 16; y += 4) { value.Set32BitChunk(y >> 2, ((j + y ) & 0xff) | ((j + y + 1) & 0xff) << 8 | ((j + y + 2) & 0xff) << 16 | ((j + y + 3) & 0xff) << 24); } return value; } static CUInt128 readValue(CFileDataIO* file) { return file->ReadUInt128(); } static void writeValue(CFileDataIO* file, CUInt128 value) { file->WriteUInt128(value); } static wxString name() { return wxT("CUInt128"); } }; ///////////////////////////////////////////////////////////////////// // The following tests ensure that the given implementations // of the CFileDataIO interface properly does so. template class ReadTest : public FileDataIOFixture { typedef RWInterface RW; public: ReadTest() : FileDataIOFixture(wxT("Read ") + RW::name()) {} void run() { CFileDataIO* file = this->m_predefFile; for (size_t j = 0; j < TEST_LENGTH + 1 - SIZE; ++j) { ASSERT_EQUALS(j, file->Seek(j, wxFromStart)); ASSERT_EQUALS(j, file->GetPosition()); ASSERT_EQUALS(RW::genValue(j), RW::readValue(file)); ASSERT_EQUALS(j + SIZE, file->GetPosition()); } ASSERT_EQUALS(TEST_LENGTH, file->GetLength()); // Check reads past EOF for (size_t i = 0; i < SIZE; ++i) { ASSERT_EQUALS(TEST_LENGTH - i, file->Seek(-(signed)i, wxFromEnd)); ASSERT_RAISES(CEOFException, RW::readValue(file)); } // Check that only the given length is written to the target buffer char testBuffer[32]; memset(testBuffer, 127, 32); char* buf = testBuffer + 8; for (int i = 0; i < 16; ++i) { ASSERT_EQUALS(0u, file->Seek(0, wxFromStart)); ASSERT_EQUALS(0u, file->GetPosition()); file->Read(buf, i + 1); for (int j = 0; j < 32; ++j) { if (j < 8 || j > i + 8) { ASSERT_EQUALS(127, (int)testBuffer[j]); } else { ASSERT_EQUALS(j - 8, (int)testBuffer[j]); } } } } }; template class WriteTest : public FileDataIOFixture { typedef RWInterface RW; public: WriteTest() : FileDataIOFixture(wxT("Write ") + RW::name()) {} void run() { const unsigned char CanaryData = 170; const char canaryBlock[] = { CanaryData }; CFileDataIO* file = this->m_predefFile; for (size_t j = 0; j < TEST_LENGTH + 1 - SIZE; ++j) { // Clear before, after and at the target byte(s) for (int t = -SIZE; t < (int)(2*SIZE); ++t) { if ((j + t) < TEST_LENGTH && ((int)j + t) >= 0) { file->Seek(j + t, wxFromStart); ASSERT_EQUALS(j + t, file->GetPosition()); file->Write(canaryBlock, 1); ASSERT_EQUALS(j + t + 1, file->GetPosition()); // Check that canary was written file->Seek(j + t, wxFromStart); ASSERT_EQUALS(CanaryData, file->ReadUInt8()); ASSERT_EQUALS(j + t + 1, file->GetPosition()); } } file->Seek(j, wxFromStart); ASSERT_EQUALS(j, file->GetPosition()); RW::writeValue(file, RW::genValue(j)); ASSERT_EQUALS(j + SIZE, file->GetPosition()); // Check before, after and at the target byte for (int t = -SIZE; t < (int)(2*SIZE); ++t) { if ((j + t) < TEST_LENGTH && ((int)j + t) >= 0) { if (t) { if (t < 0 || t >= (int)SIZE) { file->Seek(j + t, wxFromStart); ASSERT_EQUALS(CanaryData, file->ReadUInt8()); ASSERT_EQUALS(j + t + 1, file->GetPosition()); } } else { file->Seek(j + t, wxFromStart); ASSERT_EQUALS(RW::genValue(j), RW::readValue(file)); ASSERT_EQUALS(j + t + SIZE, file->GetPosition()); } } } } ASSERT_EQUALS(TEST_LENGTH, file->GetLength()); } }; template class SeekTest : public FileDataIOFixture { public: SeekTest() : FileDataIOFixture(wxT("Seek")) {} void run() { CFileDataIO* file = this->m_predefFile; ASSERT_EQUALS(0u, file->GetPosition()); for (size_t pos = 0; pos < TEST_LENGTH * 2; pos += pos + 1) { ASSERT_EQUALS(pos, file->Seek(pos, wxFromStart)); ASSERT_EQUALS(pos, file->GetPosition()); } ASSERT_EQUALS(0u, file->Seek(0, wxFromStart)); ASSERT_EQUALS(0u, file->GetPosition()); for (size_t pos = 0, cur = 0; pos < TEST_LENGTH * 2; pos += ++cur) { ASSERT_EQUALS(pos, file->Seek(cur, wxFromCurrent)); ASSERT_EQUALS(pos, file->GetPosition()); } ASSERT_EQUALS(0u, file->Seek(0, wxFromStart)); ASSERT_EQUALS(0u, file->GetPosition()); for (size_t pos = 0; pos < TEST_LENGTH; pos += pos + 1) { ASSERT_EQUALS(TEST_LENGTH - pos, file->Seek(-(signed)pos, wxFromEnd)); ASSERT_EQUALS(TEST_LENGTH - pos, file->GetPosition()); } ASSERT_EQUALS(0u, file->Seek(0, wxFromStart)); ASSERT_EQUALS(0u, file->GetPosition()); // Seek to negative is invalid for (off_t pos = 1; pos < 10; ++pos) { ASSERT_RAISES(CInvalidParamsEx, file->Seek(-1 * pos)); ASSERT_EQUALS(0u, file->GetPosition()); } // Corner-case ASSERT_RAISES(CInvalidParamsEx, file->Seek(std::numeric_limits::min())); ASSERT_EQUALS(0u, file->GetPosition()); } }; template class WritePastEndTest : public FileDataIOFixture { public: WritePastEndTest() : FileDataIOFixture(wxT("Write Past End")) {} void run() { CFileDataIO* file = this->m_emptyFile; ASSERT_EQUALS(0u, file->GetLength()); ASSERT_EQUALS(0u, file->GetPosition()); file->WriteUInt8(0); ASSERT_EQUALS(1u, file->GetLength()); ASSERT_EQUALS(1u, file->GetPosition()); file->WriteUInt16(0); ASSERT_EQUALS(3u, file->GetLength()); ASSERT_EQUALS(3u, file->GetPosition()); file->WriteUInt32(0); ASSERT_EQUALS(7u, file->GetLength()); ASSERT_EQUALS(7u, file->GetPosition()); file->WriteHash(CMD4Hash()); ASSERT_EQUALS(23u, file->GetLength()); ASSERT_EQUALS(23u, file->GetPosition()); // TODO: ReadUInt128 char tmp[42]; memset(tmp, 0, 42); file->Write(tmp, 42); ASSERT_EQUALS(65u, file->GetLength()); ASSERT_EQUALS(65u, file->GetPosition()); // Check that the length is always increased, regardless of starting pos size_t length = file->GetLength(); for (size_t j = 0; j < 16; ++j) { ASSERT_EQUALS(length + j - 15u, file->Seek(-15, wxFromEnd)); ASSERT_EQUALS(length + j - 15u, file->GetPosition()); file->WriteHash(CMD4Hash()); ASSERT_EQUALS(length + j + 1u, file->GetLength()); ASSERT_EQUALS(length + j + 1u, file->GetPosition()); } } }; template class StringTest : public FileDataIOFixture { public: StringTest() : FileDataIOFixture(wxT("String")) {} struct Encoding { const EUtf8Str id; const char* header; const size_t headLen; }; struct TestString { const wxChar* str; // Raw and UTF8 expected lengths ... const size_t lengths[2]; }; void run() { CFileDataIO* file = this->m_emptyFile; // TODO: Need to test non-ascii values when using unicode/etc, zero-length lengthfields Encoding encodings[] = { {utf8strNone, NULL, 0}, {utf8strOptBOM, "\xEF\xBB\xBF", 3}, {utf8strRaw, NULL, 0} }; TestString testData[] = { { wxT("0123456789abcdef"), { 16, 16 } }, { wxT(""), { 0, 0 } }, { wxT("abc ø def æ ghi å"), { 17, 20 } }, { wxT("aáeéuúó"), { 7, 11 } }, { wxT("uüoöÿeëaäyÿ"), { 11, 17 } }, }; for (size_t str = 0; str < ArraySize(testData); ++str) { CONTEXT(wxString(wxT("Testing string: '")) << testData[str].str << wxT("'")); for (size_t enc = 0; enc < ArraySize(encodings); ++enc) { CONTEXT(wxString::Format(wxT("Testing encoding: %i"), encodings[enc])); const wxChar* curStr = testData[str].str; size_t strLen = testData[str].lengths[(encodings[enc].id == utf8strNone) ? 0 : 1]; size_t headLen = encodings[enc].headLen; file->WriteString(curStr, encodings[enc].id, 2); ASSERT_EQUALS(strLen + 2 + headLen, file->GetPosition()); ASSERT_EQUALS(0u, file->Seek(0, wxFromStart)); ASSERT_EQUALS(strLen + headLen, file->ReadUInt16()); // Check header (if any) if (encodings[enc].header) { wxCharBuffer head(headLen); file->Read(head.data(), headLen); ASSERT_EQUALS(0, memcmp(head, encodings[enc].header, headLen)); } ASSERT_EQUALS(0u, file->Seek(0, wxFromStart)); ASSERT_EQUALS(curStr, file->ReadString(encodings[enc].id, 2)); ASSERT_EQUALS(0u, file->Seek(0, wxFromStart)); file->WriteString(curStr, encodings[enc].id, 4); ASSERT_EQUALS(strLen + 4 + headLen, file->GetPosition()); ASSERT_EQUALS(0u, file->Seek(0, wxFromStart)); ASSERT_EQUALS(strLen + headLen, file->ReadUInt32()); // Check header (if any) if (encodings[enc].header) { wxCharBuffer head(headLen); file->Read(head.data(), headLen); ASSERT_EQUALS(0, memcmp(head, encodings[enc].header, headLen)); } ASSERT_EQUALS(0u, file->Seek(0, wxFromStart)); ASSERT_EQUALS(curStr, file->ReadString(encodings[enc].id, 4)); ASSERT_EQUALS(0u, file->Seek(0, wxFromStart)); } } CAssertOff silence; for (size_t enc = 0; enc < ArraySize(encodings); ++enc) { CONTEXT(wxString::Format(wxT("Testing encoding against poisoning: %i"), encodings[enc])); ////////////////////////////////////////////// // Check if we guard against "poisoning". ASSERT_EQUALS(0u, file->Seek(0, wxFromStart)); const size_t rawLen = (((uint16)-1) * 3) / 4; wxString badStr(wxT('\xfe'), rawLen); // This will cause the string to be UTF-8 encoded, // thereby exceeding the max length-field size (16b). file->WriteString(badStr, encodings[enc].id, 2); file->WriteUInt16(0x7913); ASSERT_EQUALS(0u, file->Seek(0, wxFromStart)); file->ReadString(true, 2); ASSERT_EQUALS(0x7913, file->ReadUInt16()); } } }; // Do not attempt to use this test with CMemFile. template class LargeFileTest : public FileDataIOFixture { public: LargeFileTest() : FileDataIOFixture(wxT("LargeFile")) {} void run() { CFile* file = dynamic_cast(this->m_emptyFile); ASSERT_TRUE(file != NULL); ASSERT_EQUALS(2147483647UL, file->Seek(2147483647L, wxFromStart)); ASSERT_EQUALS(2147483648UL, file->Seek(1, wxFromCurrent)); ASSERT_EQUALS(2147483648UL, file->GetPosition()); ASSERT_EQUALS(4294967296ULL, file->Seek(4294967296ULL, wxFromStart)); ASSERT_EQUALS(4294967296ULL, file->GetPosition()); } }; ///////////////////////////////////////////////////////////////////// // Registration of all tests ReadTest CFileReadUInt8Test; ReadTest CFileReadUInt16Test; ReadTest CFileReadUInt32Test; ReadTest CFileReadCMD4HashTest; ReadTest CFileReadCUInt128Test; WriteTest CFileWriteUInt8Test; WriteTest CFileWriteUInt16Test; WriteTest CFileWriteUInt32Test; WriteTest CFileWriteCMD4HashTest; WriteTest CFileWriteCUInt128Test; SeekTest CFileSeekTest; WritePastEndTest CFileWritePastEnd; StringTest CFileStringTest; LargeFileTest CFileLargeFileTest; ReadTest CMemFileReadUInt8Test; ReadTest CMemFileReadUInt16Test; ReadTest CMemFileReadUInt32Test; ReadTest CMemFileReadCMD4HashTest; ReadTest CMemFileReadCUInt128Test; WriteTest CMemFileWriteUInt8Test; WriteTest CMemFileWriteUInt16Test; WriteTest CMemFileWriteUInt32Test; WriteTest CMemFileWriteCMD4HashTest; WriteTest CMemFileWriteCUInt128Test; SeekTest CMemFileSeekTest; WritePastEndTest CMemFileWritePastEnd; StringTest CMemFileStringTest; ///////////////////////////////////////////////////////////////////// // CMemFile specific tests DECLARE_SIMPLE(CMemFile); TEST(CMemFile, AttachedBuffer) { const size_t BufferLength = 1024; byte buffer[BufferLength]; for (size_t i = 0; i < BufferLength; ++i) { buffer[i] = i & 0xFF; } CMemFile file(buffer, BufferLength); for (size_t i = 0; i < BufferLength; ++i) { ASSERT_EQUALS(file.ReadUInt8(), i & 0xFF); } // Resizing upwards should fail ASSERT_RAISES(CRunTimeException, file.SetLength(BufferLength * 2)); ASSERT_EQUALS(BufferLength, file.GetLength()); // Resizing downwards should be ok, as should resizes up (but within bufferlen) file.SetLength(BufferLength / 2); ASSERT_EQUALS(BufferLength / 2, file.GetLength()); file.SetLength(BufferLength); ASSERT_EQUALS(BufferLength, file.GetLength()); // Write past end should fail ASSERT_EQUALS(BufferLength, file.Seek(0, wxFromEnd)); ASSERT_RAISES(CRunTimeException, file.WriteUInt8(0)); // Init with invalid buffer should fail ASSERT_RAISES(CRunTimeException, new CMemFile(static_cast(NULL), 1024)); ASSERT_RAISES(CRunTimeException, new CMemFile(static_cast(NULL), 1024)); } TEST(CMemFile, ConstBuffer) { byte arr[10]; CMemFile file(const_cast(arr), sizeof(arr)); ASSERT_RAISES(CRunTimeException, file.WriteUInt8(0)); ASSERT_RAISES(CRunTimeException, file.WriteUInt16(0)); ASSERT_RAISES(CRunTimeException, file.WriteUInt32(0)); ASSERT_RAISES(CRunTimeException, file.WriteUInt64(0)); char buffer[sizeof(arr)]; ASSERT_RAISES(CRunTimeException, file.Write(buffer, sizeof(arr))); } TEST(CMemFile, SetLength) { CMemFile file; ASSERT_EQUALS(0u, file.GetLength()); file.SetLength(1024); ASSERT_EQUALS(1024u, file.GetLength()); ASSERT_EQUALS(1024u, file.Seek(0, wxFromEnd)); file.SetLength(512u); ASSERT_EQUALS(512u, file.GetLength()); ASSERT_EQUALS(512u, file.Seek(0, wxFromEnd)); } ///////////////////////////////////////////////////////////////////// // CFile specific tests const CPath testFile = CPath(wxT("TestFile.dat")); const unsigned testMode = 0600; DECLARE(CFile); void setUp() { // Ensure that the testfile doesn't exist if (testFile.FileExists()) { if (!CPath::RemoveFile(testFile)) { MULE_VALIDATE_STATE(false, wxT("Failed to remove temporary file.")); } } } void tearDown() { if (testFile.FileExists()) { CPath::RemoveFile(testFile); } } END_DECLARE; TEST(CFile, Constructor) { // Test initial conditions { CFile file; ASSERT_TRUE(!file.IsOpened()); ASSERT_TRUE(file.fd() == CFile::fd_invalid); ASSERT_RAISES(CRunTimeException, file.WriteUInt8(0)); ASSERT_RAISES(CRunTimeException, file.ReadUInt8()); ASSERT_RAISES(CRunTimeException, file.Seek(0, wxFromStart)); ASSERT_RAISES(CRunTimeException, file.GetLength()); ASSERT_RAISES(CRunTimeException, file.GetPosition()); ASSERT_RAISES(CRunTimeException, file.SetLength(13)); ASSERT_RAISES(CRunTimeException, file.Flush()); ASSERT_RAISES(CRunTimeException, file.Close()); ASSERT_TRUE(!file.IsOpened()); ASSERT_TRUE(file.fd() == CFile::fd_invalid); } // Create test file { CFile file; ASSERT_TRUE(file.Create(testFile, false, testMode)); ASSERT_EQUALS(testFile, file.GetFilePath()); file.WriteUInt32(1); } { CFile file(testFile, CFile::read); ASSERT_TRUE(file.IsOpened()); ASSERT_TRUE(file.fd() != CFile::fd_invalid); ASSERT_EQUALS(testFile, file.GetFilePath()); ASSERT_EQUALS(4u, file.GetLength()); ASSERT_EQUALS(1u, file.ReadUInt32()); ASSERT_RAISES(CIOFailureException, file.WriteUInt8(0)); } { CFile file(testFile, CFile::write); ASSERT_TRUE(file.IsOpened()); ASSERT_TRUE(file.fd() != CFile::fd_invalid); ASSERT_EQUALS(testFile, file.GetFilePath()); ASSERT_EQUALS(0u, file.GetPosition()); ASSERT_EQUALS(0u, file.GetLength()); file.WriteUInt32(1); ASSERT_EQUALS(0u, file.Seek(0, wxFromStart)); ASSERT_RAISES(CIOFailureException, file.ReadUInt8()); } { CFile file(testFile, CFile::read_write); ASSERT_TRUE(file.IsOpened()); ASSERT_TRUE(file.fd() != CFile::fd_invalid); ASSERT_EQUALS(testFile, file.GetFilePath()); ASSERT_EQUALS(4u, file.GetLength()); ASSERT_EQUALS(0u, file.GetPosition()); ASSERT_EQUALS(1u, file.ReadUInt32()); ASSERT_EQUALS(0u, file.Seek(0, wxFromStart)); file.WriteUInt32(2); ASSERT_EQUALS(0u, file.Seek(0, wxFromStart)); ASSERT_EQUALS(2u, file.ReadUInt32()); } { CFile file(testFile, CFile::write_append); ASSERT_TRUE(file.IsOpened()); ASSERT_TRUE(file.fd() != CFile::fd_invalid); ASSERT_EQUALS(4u, file.GetLength()); file.WriteUInt32(1); ASSERT_EQUALS(0u, file.Seek(0, wxFromStart)); ASSERT_RAISES(CIOFailureException, file.ReadUInt8()); ASSERT_TRUE(file.Close()); ASSERT_TRUE(file.Open(testFile, CFile::read)); ASSERT_EQUALS(2u, file.ReadUInt32()); ASSERT_EQUALS(1u, file.ReadUInt32()); } } TEST(CFile, Create) { ASSERT_FALSE(testFile.FileExists()); // Check creation of new file, when none exists, with/without overwrite for (size_t i = 0; i < 2; ++i) { bool overwrite = (i == 1); CFile file; ASSERT_TRUE(!file.IsOpened()); ASSERT_TRUE(file.fd() == CFile::fd_invalid); ASSERT_TRUE(file.Create(testFile, overwrite, testMode)); ASSERT_TRUE(file.IsOpened()); ASSERT_TRUE(file.fd() != CFile::fd_invalid); ASSERT_EQUALS(testFile, file.GetFilePath()); ASSERT_TRUE(file.Close()); ASSERT_TRUE(file.fd() == CFile::fd_invalid); ASSERT_TRUE(!file.IsOpened()); ASSERT_TRUE(wxFile::Access(testFile.GetRaw(), wxFile::read)); ASSERT_TRUE(wxFile::Access(testFile.GetRaw(), wxFile::write)); ASSERT_TRUE(wxRemoveFile(testFile.GetRaw())); } // Create testfile, with a bit of contents { CFile file; ASSERT_TRUE(file.Create(testFile, false, testMode)); ASSERT_EQUALS(testFile, file.GetFilePath()); file.WriteUInt32(1); } // Check that owerwrite = false works as expected { CFile file; ASSERT_FALSE(file.Create(testFile, false, testMode)); ASSERT_TRUE(file.fd() == CFile::fd_invalid); ASSERT_TRUE(!file.IsOpened()); // Open and check contents ASSERT_TRUE(file.Open(testFile, CFile::read)); ASSERT_TRUE(file.IsOpened()); ASSERT_TRUE(file.fd() != CFile::fd_invalid); ASSERT_EQUALS(testFile, file.GetFilePath()); ASSERT_EQUALS(4u, file.GetLength()); ASSERT_EQUALS(1u, file.ReadUInt32()); ASSERT_TRUE(file.Close()); ASSERT_TRUE(file.fd() == CFile::fd_invalid); ASSERT_TRUE(!file.IsOpened()); } // Check that owerwrite = true works as expected { CFile file; ASSERT_TRUE(file.Create(testFile, true, testMode)); ASSERT_TRUE(file.IsOpened()); ASSERT_TRUE(file.fd() != CFile::fd_invalid); ASSERT_EQUALS(testFile, file.GetFilePath()); ASSERT_EQUALS(0u, file.GetLength()); ASSERT_TRUE(file.Close()); ASSERT_TRUE(file.fd() == CFile::fd_invalid); ASSERT_TRUE(!file.IsOpened()); } ASSERT_TRUE(wxFile::Access(testFile.GetRaw(), wxFile::read)); ASSERT_TRUE(wxFile::Access(testFile.GetRaw(), wxFile::write)); } TEST(CFile, SetLength) { CFile file(testFile, CFile::write); ASSERT_EQUALS(0u, file.GetLength()); file.SetLength(1024); ASSERT_EQUALS(1024u, file.GetLength()); ASSERT_EQUALS(1024u, file.Seek(0, wxFromEnd)); file.SetLength(512u); ASSERT_EQUALS(512u, file.GetLength()); ASSERT_EQUALS(512u, file.Seek(0, wxFromEnd)); } TEST(CFile, GetAvailable) { { CFile file(testFile, CFile::write); writePredefData(&file); } CFile file(testFile, CFile::read); const uint64 length = file.GetLength(); while (!file.Eof()) { ASSERT_EQUALS(length - file.GetPosition(), file.GetAvailable()); file.ReadUInt32(); ASSERT_EQUALS(length - file.GetPosition(), file.GetAvailable()); } ASSERT_EQUALS(0u, file.GetAvailable()); file.Seek(1024, wxFromCurrent); ASSERT_EQUALS(0u, file.GetAvailable()); }