void FileTests::TestWriteFileDisableNewlineAutoReturn() { bool fDisableAutoReturn; VERIFY_SUCCEEDED(TestData::TryGetValue(L"fDisableAutoReturn", fDisableAutoReturn)); bool fProcessedOn; VERIFY_SUCCEEDED(TestData::TryGetValue(L"fProcessedOn", fProcessedOn)); HANDLE const hOut = GetStdOutputHandle(); VERIFY_IS_NOT_NULL(hOut, L"Verify we have the standard output handle."); CONSOLE_SCREEN_BUFFER_INFOEX csbiexOriginal = { 0 }; csbiexOriginal.cbSize = sizeof(csbiexOriginal); VERIFY_WIN32_BOOL_SUCCEEDED(GetConsoleScreenBufferInfoEx(hOut, &csbiexOriginal), L"Retrieve screen buffer properties at beginning of test."); DWORD dwMode = 0; WI_SetFlagIf(dwMode, DISABLE_NEWLINE_AUTO_RETURN, fDisableAutoReturn); WI_SetFlagIf(dwMode, ENABLE_PROCESSED_OUTPUT, fProcessedOn); VERIFY_WIN32_BOOL_SUCCEEDED(SetConsoleMode(hOut, dwMode), L"Set console mode for test."); COORD const coordZero = { 0 }; VERIFY_ARE_EQUAL(coordZero, csbiexOriginal.dwCursorPosition, L"Cursor should be at 0,0 in fresh buffer."); CONSOLE_SCREEN_BUFFER_INFOEX csbiexBefore = { 0 }; csbiexBefore.cbSize = sizeof(csbiexBefore); CONSOLE_SCREEN_BUFFER_INFOEX csbiexAfter = { 0 }; csbiexAfter.cbSize = sizeof(csbiexAfter); COORD coordExpected = { 0 }; WriteFileHelper(hOut, csbiexBefore, csbiexAfter, "abc", 3); coordExpected = csbiexBefore.dwCursorPosition; coordExpected.X += 3; VERIFY_ARE_EQUAL(coordExpected, csbiexAfter.dwCursorPosition, L"Cursor should have moved right to the end of the text written."); WriteFileHelper(hOut, csbiexBefore, csbiexAfter, "\n", 1); if (fProcessedOn) { if (fDisableAutoReturn) { coordExpected = csbiexBefore.dwCursorPosition; coordExpected.Y += 1; } else { coordExpected = csbiexBefore.dwCursorPosition; coordExpected.Y += 1; coordExpected.X = 0; } } else { coordExpected = csbiexBefore.dwCursorPosition; coordExpected.X += 1; } VERIFY_ARE_EQUAL(coordExpected, csbiexAfter.dwCursorPosition, L"Cursor should move to expected position."); }
void FileTests::TestWriteFileVTProcessing() { bool fVtOn; VERIFY_SUCCEEDED(TestData::TryGetValue(L"fVtOn", fVtOn)); bool fProcessedOn; VERIFY_SUCCEEDED(TestData::TryGetValue(L"fProcessedOn", fProcessedOn)); HANDLE const hOut = GetStdOutputHandle(); VERIFY_IS_NOT_NULL(hOut, L"Verify we have the standard output handle."); CONSOLE_SCREEN_BUFFER_INFOEX csbiexOriginal = { 0 }; csbiexOriginal.cbSize = sizeof(csbiexOriginal); VERIFY_WIN32_BOOL_SUCCEEDED(GetConsoleScreenBufferInfoEx(hOut, &csbiexOriginal), L"Retrieve screen buffer properties at beginning of test."); DWORD dwFlags = 0; WI_SetFlagIf(dwFlags, ENABLE_VIRTUAL_TERMINAL_PROCESSING, fVtOn); WI_SetFlagIf(dwFlags, ENABLE_PROCESSED_OUTPUT, fProcessedOn); VERIFY_WIN32_BOOL_SUCCEEDED(SetConsoleMode(hOut, dwFlags), L"Turn on relevant flags for test."); COORD const coordZero = { 0 }; VERIFY_ARE_EQUAL(coordZero, csbiexOriginal.dwCursorPosition, L"Cursor should be at 0,0 in fresh buffer."); PCSTR pszTestString = "\x1b" "[14m"; DWORD const cchTest = (DWORD)strlen(pszTestString); CONSOLE_SCREEN_BUFFER_INFOEX csbiexBefore = { 0 }; csbiexBefore.cbSize = sizeof(csbiexBefore); CONSOLE_SCREEN_BUFFER_INFOEX csbiexAfter = { 0 }; csbiexAfter.cbSize = sizeof(csbiexAfter); WriteFileHelper(hOut, csbiexBefore, csbiexAfter, pszTestString, cchTest); // We only expect characters to be processed and not printed if both processed mode and VT mode are on. bool const fProcessedNotPrinted = fProcessedOn && fVtOn; if (fProcessedNotPrinted) { PCSTR pszReadBackExpected = " "; DWORD const cchReadBackExpected = (DWORD)strlen(pszReadBackExpected); VERIFY_ARE_EQUAL(csbiexBefore.dwCursorPosition, csbiexAfter.dwCursorPosition, L"Verify cursor didn't move because the VT sequence was processed instead of printed."); wistd::unique_ptr<char[]> pszReadBack; ReadBackHelper(hOut, coordZero, cchReadBackExpected, pszReadBack); VERIFY_ARE_EQUAL(String(pszReadBackExpected), String(pszReadBack.get()), L"Verify that nothing was printed into the buffer."); } else { COORD coordExpected = csbiexBefore.dwCursorPosition; coordExpected.X += (SHORT)cchTest; VERIFY_ARE_EQUAL(coordExpected, csbiexAfter.dwCursorPosition, L"Verify cursor moved as characters should have been emitted, not consumed."); wistd::unique_ptr<char[]> pszReadBack; ReadBackHelper(hOut, coordZero, cchTest, pszReadBack); VERIFY_ARE_EQUAL(String(pszTestString), String(pszReadBack.get()), L"Verify that original test string was printed into the buffer."); } }
bool FileStorage::SaveFile(FileEntry& fileEntry, const IStream& sourceStream) { IStream* stream = WriteFileHelper(fileEntry, FileOpenMode::DestoryWriteOrCreate, FileDataType::Binary); RETURN_FALSE_IF_NULL(stream); sourceStream.CopyTo(*stream); SAFE_RELEASE(stream); return true; }
FileEntry* FileStorage::SaveFile(const IStream& sourceStream, const StringRef& path /*= StringRef::Empty*/, DirectoryEntry* parent /*= nullptr*/) { FileEntry* fileEntry = FindOrCreateFileEntry(path, parent); IStream* stream = WriteFileHelper(*fileEntry, FileOpenMode::DestoryWriteOrCreate, FileDataType::Binary); if (stream == nullptr) { RemoveFile(fileEntry); //remove back file return nullptr; } sourceStream.CopyTo(*stream); SAFE_RELEASE(stream); return fileEntry; }
FileEntry* FileStorage::SaveFile(const MemoryByteData& data, const StringRef& path /*= StringRef::Empty*/, DirectoryEntry* parent /*= nullptr*/, DataReadingMode mode /*= DataReadingMode::AlwaysCopy*/) { FileEntry* fileEntry = FindOrCreateFileEntry(path, parent); IStream* stream = WriteFileHelper(*fileEntry, FileOpenMode::DestoryWriteOrCreate, FileDataType::Binary); if (stream == nullptr) { RemoveFile(fileEntry); //remove new created file entry return nullptr; } stream->WriteData(data, mode); SAFE_RELEASE(stream); return fileEntry; }
IStream* FileStorage::WriteFile(const StringRef& path, DirectoryEntry* parent /*= nullptr*/, FileOpenMode openMode /*= FileOpenMode::DestoryWriteOrCreate*/, FileDataType dataType /*= FileDataType::Binary*/) { RETURN_NULL_IF_TRUE(IsReadOnly()); FileEntry* fileEntry = FindFile(path, parent); CoderList coders = GetFileCoders(*fileEntry); if (fileEntry == nullptr) { //not exists switch (openMode) { case FileOpenMode::ReadOnly: case FileOpenMode::ReadWrite: return nullptr; case FileOpenMode::DestoryWriteOrCreate: //create file to only write break; case FileOpenMode::DestoryReadWriteOrCreate: case FileOpenMode::AppendReadWriteClearEOFOrCreate: case FileOpenMode::AppendWriteKeepEOFOrCreate: if (coders != 0) { Log::AssertFailedFormat("Not support read & write file with coder:{}", coders); return nullptr; } ////create file to read write break; default: break; } fileEntry = FindOrCreateFileEntry(path, parent); IStream* stream = WriteFileHelper(*fileEntry, openMode, dataType); if (stream == nullptr) { RemoveFile(fileEntry); //remove back file } return stream; } else { //exists switch (openMode) { case FileOpenMode::ReadOnly: break; case FileOpenMode::ReadWrite: if (fileEntry->IsReadonly()) { Log::AssertFailedFormat("Cannot read & write readonly file:{}", path); return nullptr; } if (coders != 0) { Log::AssertFailedFormat("Not support read & write file with coder:{}", coders); return nullptr; } break; case FileOpenMode::DestoryWriteOrCreate: //use new attribute break; case FileOpenMode::AppendWriteKeepEOFOrCreate: if (coders != 0) { Log::AssertFailedFormat("Cannot append & write readonly file:{}", path); return nullptr; } break; case FileOpenMode::DestoryReadWriteOrCreate: RETURN_NULL_IF_TRUE(IsReadOnly()); if (coders != 0) { Log::AssertFailedFormat("Not support read & write file with coder:{}", coders); return nullptr; } break; case FileOpenMode::AppendReadWriteClearEOFOrCreate: if (fileEntry->IsReadonly()) { Log::AssertFailedFormat("Cannot read & write readonly file:{}", path); return nullptr; } if (GetFileCoders(*fileEntry)) { Log::AssertFailedFormat("Not support read & write file with coder:{}", coders); return nullptr; } break; default: break; } IStream* stream = WriteFileHelper(*fileEntry, openMode, dataType); RETURN_NULL_IF_NULL(stream); return stream; } }
void FileTests::TestWriteFileProcessed() { // \x7 is bell // \x8 is backspace // \x9 is tab // \xa is linefeed // \xd is carriage return // All should cause activity in processed mode. HANDLE const hOut = GetStdOutputHandle(); VERIFY_IS_NOT_NULL(hOut, L"Verify we have the standard output handle."); CONSOLE_SCREEN_BUFFER_INFOEX csbiexOriginal = { 0 }; csbiexOriginal.cbSize = sizeof(csbiexOriginal); VERIFY_WIN32_BOOL_SUCCEEDED(GetConsoleScreenBufferInfoEx(hOut, &csbiexOriginal), L"Retrieve screen buffer properties at beginning of test."); VERIFY_WIN32_BOOL_SUCCEEDED(SetConsoleMode(hOut, ENABLE_PROCESSED_OUTPUT), L"Set processed write mode."); COORD const coordZero = { 0 }; VERIFY_ARE_EQUAL(coordZero, csbiexOriginal.dwCursorPosition, L"Cursor should be at 0,0 in fresh buffer."); // Declare variables needed for each character test. CONSOLE_SCREEN_BUFFER_INFOEX csbiexBefore = { 0 }; CONSOLE_SCREEN_BUFFER_INFOEX csbiexAfter = { 0 }; COORD coordExpected = { 0 }; PCSTR pszTest; DWORD cchTest; PCSTR pszReadBackExpected; DWORD cchReadBack; wistd::unique_ptr<char[]> pszReadBack; // 1. Test bell (\x7) { pszTest = "z\x7"; cchTest = (DWORD)strlen(pszTest); pszReadBackExpected = "z "; cchReadBack = (DWORD)strlen(pszReadBackExpected); // Write z and a bell. Cursor should move once as bell should have made audible noise (can't really test) and not moved or printed anything. WriteFileHelper(hOut, csbiexBefore, csbiexAfter, pszTest, cchTest); coordExpected = csbiexBefore.dwCursorPosition; coordExpected.X += 1; VERIFY_ARE_EQUAL(coordExpected, csbiexAfter.dwCursorPosition, L"Verify cursor moved once for printable character and not for bell."); // Read back written data. ReadBackHelper(hOut, csbiexBefore.dwCursorPosition, cchReadBack, pszReadBack); VERIFY_ARE_EQUAL(String(pszReadBackExpected), String(pszReadBack.get()), L"Verify text matches what we expected to be written into the buffer."); } // 2. Test backspace (\x8) { pszTest = "yx\x8"; cchTest = (DWORD)strlen(pszTest); pszReadBackExpected = "yx "; cchReadBack = (DWORD)strlen(pszReadBackExpected); // Write two characters and a backspace. Cursor should move only one forward as the backspace should have moved the cursor back one after printing the second character. // The backspace character itself is typically non-destructive so it should only affect the cursor, not the buffer contents. WriteFileHelper(hOut, csbiexBefore, csbiexAfter, pszTest, cchTest); coordExpected = csbiexBefore.dwCursorPosition; coordExpected.X += 1; VERIFY_ARE_EQUAL(coordExpected, csbiexAfter.dwCursorPosition, L"Verify cursor moved twice forward for printable characters and once backward for backspace."); // Read back written data. ReadBackHelper(hOut, csbiexBefore.dwCursorPosition, cchReadBack, pszReadBack); VERIFY_ARE_EQUAL(String(pszReadBackExpected), String(pszReadBack.get()), L"Verify text matches what we expected to be written into the buffer."); } // 3. Test tab (\x9) { // The tab character will space pad out the buffer to the next multiple-of-8 boundary. // NOTE: This is dependent on the previous tests running first. pszTest = "\x9"; cchTest = (DWORD)strlen(pszTest); pszReadBackExpected = " "; cchReadBack = (DWORD)strlen(pszReadBackExpected); // Write tab character. Cursor should move out to the next multiple-of-8 and leave space characters in its wake. WriteFileHelper(hOut, csbiexBefore, csbiexAfter, pszTest, cchTest); coordExpected = csbiexBefore.dwCursorPosition; coordExpected.X = 8; VERIFY_ARE_EQUAL(coordExpected, csbiexAfter.dwCursorPosition, L"Verify cursor moved forward to position 8 for tab."); // Read back written data. ReadBackHelper(hOut, csbiexBefore.dwCursorPosition, cchReadBack, pszReadBack); VERIFY_ARE_EQUAL(String(pszReadBackExpected), String(pszReadBack.get()), L"Verify text matches what we expected to be written into the buffer."); } // 4. Test linefeed (\xa) { // The line feed character should move us down to the next line. pszTest = "\xaQ"; cchTest = (DWORD)strlen(pszTest); pszReadBackExpected = "Q "; cchReadBack = (DWORD)strlen(pszReadBackExpected); // Write line feed character. Cursor should move down a line and then the Q from our string should be printed. WriteFileHelper(hOut, csbiexBefore, csbiexAfter, pszTest, cchTest); coordExpected.X = 1; coordExpected.Y = 1; VERIFY_ARE_EQUAL(coordExpected, csbiexAfter.dwCursorPosition, L"Verify cursor moved down a line and then one character over for linefeed + Q."); // Read back written data from the 2nd line. COORD coordRead; coordRead.Y = 1; coordRead.X = 0; ReadBackHelper(hOut, coordRead, cchReadBack, pszReadBack); VERIFY_ARE_EQUAL(String(pszReadBackExpected), String(pszReadBack.get()), L"Verify text matches what we expected to be written into the buffer."); } // 5. Test carriage return (\xd) { // The carriage return character should move us to the front of the line. pszTest = "J\xd"; cchTest = (DWORD)strlen(pszTest); pszReadBackExpected = "QJ "; // J written, then move to beginning of line. cchReadBack = (DWORD)strlen(pszReadBackExpected); // Write text and carriage return character. Cursor should end up at the beginning of this line. The J should have been printed in the line before we moved. WriteFileHelper(hOut, csbiexBefore, csbiexAfter, pszTest, cchTest); coordExpected = csbiexBefore.dwCursorPosition; coordExpected.X = 0; VERIFY_ARE_EQUAL(coordExpected, csbiexAfter.dwCursorPosition, L"Verify cursor moved to beginning of line for carriage return character."); // Read back text written from the 2nd line. ReadBackHelper(hOut, csbiexAfter.dwCursorPosition, cchReadBack, pszReadBack); VERIFY_ARE_EQUAL(String(pszReadBackExpected), String(pszReadBack.get()), L"Verify text matches what we expected to be written into the buffer."); } // 6. Print a character over the top of the existing { // After the carriage return, try typing on top of the Q with a K pszTest = "K"; cchTest = (DWORD)strlen(pszTest); pszReadBackExpected = "KJ "; // NOTE: This is based on the previous test(s). cchReadBack = (DWORD)strlen(pszReadBackExpected); // Write text. Cursor should end up on top of the J. WriteFileHelper(hOut, csbiexBefore, csbiexAfter, pszTest, cchTest); coordExpected = csbiexBefore.dwCursorPosition; coordExpected.X += 1; VERIFY_ARE_EQUAL(coordExpected, csbiexAfter.dwCursorPosition, L"Verify cursor moved over one for printing character."); // Read back text written from the 2nd line. ReadBackHelper(hOut, csbiexBefore.dwCursorPosition, cchReadBack, pszReadBack); VERIFY_ARE_EQUAL(String(pszReadBackExpected), String(pszReadBack.get()), L"Verify text matches what we expected to be written into the buffer."); } }