858 lines
35 KiB
C++
858 lines
35 KiB
C++
// Copyright (c) Microsoft Corporation.
|
|
// Licensed under the MIT license.
|
|
|
|
#include "precomp.h"
|
|
|
|
#include "Common.hpp"
|
|
|
|
#include <future>
|
|
|
|
using namespace WEX::Logging;
|
|
using WEX::TestExecution::TestData;
|
|
using namespace WEX::Common;
|
|
|
|
// This class is intended to test:
|
|
// WriteFile
|
|
|
|
class FileTests
|
|
{
|
|
// Method isolation level will completely close and re-open the OpenConsole session for every
|
|
// TEST_METHOD below. This saves us the time of cleaning up the mode state and the contents of
|
|
// the buffer and cursor position for each test. Launching a new OpenConsole is much quicker.
|
|
BEGIN_TEST_CLASS(FileTests)
|
|
TEST_CLASS_PROPERTY(L"IsolationLevel", L"Method")
|
|
END_TEST_CLASS();
|
|
|
|
TEST_METHOD(TestUtf8WriteFileInvalid);
|
|
|
|
TEST_METHOD(TestWriteFileRaw);
|
|
TEST_METHOD(TestWriteFileProcessed);
|
|
|
|
BEGIN_TEST_METHOD(TestWriteFileWrapEOL)
|
|
TEST_METHOD_PROPERTY(L"Data:fFlagOn", L"{true, false}")
|
|
END_TEST_METHOD();
|
|
|
|
BEGIN_TEST_METHOD(TestWriteFileVTProcessing)
|
|
TEST_METHOD_PROPERTY(L"Data:fVtOn", L"{true, false}")
|
|
TEST_METHOD_PROPERTY(L"Data:fProcessedOn", L"{true, false}")
|
|
END_TEST_METHOD();
|
|
|
|
BEGIN_TEST_METHOD(TestWriteFileDisableNewlineAutoReturn)
|
|
TEST_METHOD_PROPERTY(L"Data:fDisableAutoReturn", L"{true, false}")
|
|
TEST_METHOD_PROPERTY(L"Data:fProcessedOn", L"{true, false}")
|
|
END_TEST_METHOD();
|
|
|
|
TEST_METHOD(TestWriteFileSuspended);
|
|
|
|
TEST_METHOD(TestReadFileBasic);
|
|
TEST_METHOD(TestReadFileBasicSync);
|
|
TEST_METHOD(TestReadFileBasicEmpty);
|
|
TEST_METHOD(TestReadFileLine);
|
|
TEST_METHOD(TestReadFileLineSync);
|
|
|
|
TEST_CLASS_SETUP(ClassSetup);
|
|
TEST_CLASS_CLEANUP(ClassCleanup);
|
|
|
|
TEST_METHOD_SETUP(MethodSetup);
|
|
TEST_METHOD_CLEANUP(MethodCleanup);
|
|
|
|
/*BEGIN_TEST_METHOD(TestReadFileEcho)
|
|
TEST_METHOD_PROPERTY(L"Data:fUseBlockedRead", L"{true, false}")
|
|
END_TEST_METHOD();*/
|
|
};
|
|
|
|
static HANDLE _cancellationEvent = nullptr;
|
|
|
|
bool FileTests::ClassSetup()
|
|
{
|
|
_cancellationEvent = CreateEventW(nullptr, TRUE, FALSE, nullptr);
|
|
VERIFY_WIN32_BOOL_SUCCEEDED(!!_cancellationEvent, L"Create cancellation event.");
|
|
return true;
|
|
}
|
|
|
|
bool FileTests::ClassCleanup()
|
|
{
|
|
VERIFY_WIN32_BOOL_SUCCEEDED(CloseHandle(_cancellationEvent), L"Cleanup cancellation event.");
|
|
return true;
|
|
}
|
|
|
|
bool FileTests::MethodSetup()
|
|
{
|
|
VERIFY_WIN32_BOOL_SUCCEEDED(ResetEvent(_cancellationEvent), L"Reset cancellation event.");
|
|
return true;
|
|
}
|
|
|
|
bool FileTests::MethodCleanup()
|
|
{
|
|
VERIFY_WIN32_BOOL_SUCCEEDED(SetEvent(_cancellationEvent), L"Set cancellation event.");
|
|
return true;
|
|
}
|
|
|
|
void FileTests::TestUtf8WriteFileInvalid()
|
|
{
|
|
Log::Comment(L"Backup original console codepage.");
|
|
UINT const uiOriginalCP = GetConsoleOutputCP();
|
|
auto restoreOriginalCP = wil::scope_exit([&] {
|
|
Log::Comment(L"Restore original console codepage.");
|
|
SetConsoleOutputCP(uiOriginalCP);
|
|
});
|
|
|
|
HANDLE const hOut = GetStdOutputHandle();
|
|
VERIFY_IS_NOT_NULL(hOut, L"Verify we have the standard output handle.");
|
|
|
|
VERIFY_WIN32_BOOL_SUCCEEDED(SetConsoleOutputCP(CP_UTF8), L"Set output codepage to UTF8");
|
|
|
|
DWORD dwWritten;
|
|
DWORD dwExpectedWritten;
|
|
const char* str;
|
|
DWORD cbStr;
|
|
|
|
// \x80 is an invalid UTF-8 continuation
|
|
// \x40 is the @ symbol which is valid.
|
|
str = "\x80\x40";
|
|
cbStr = (DWORD)strlen(str);
|
|
dwWritten = 0;
|
|
dwExpectedWritten = cbStr;
|
|
|
|
VERIFY_WIN32_BOOL_SUCCEEDED(WriteFile(hOut, str, cbStr, &dwWritten, nullptr));
|
|
VERIFY_ARE_EQUAL(dwExpectedWritten, dwWritten);
|
|
|
|
// \x80 is an invalid UTF-8 continuation
|
|
// \x40 is the @ symbol which is valid.
|
|
str = "\x80\x40\x40";
|
|
cbStr = (DWORD)strlen(str);
|
|
dwWritten = 0;
|
|
dwExpectedWritten = cbStr;
|
|
|
|
VERIFY_WIN32_BOOL_SUCCEEDED(WriteFile(hOut, str, cbStr, &dwWritten, nullptr));
|
|
VERIFY_ARE_EQUAL(dwExpectedWritten, dwWritten);
|
|
|
|
// \x80 is an invalid UTF-8 continuation
|
|
// \x40 is the @ symbol which is valid.
|
|
str = "\x80\x80\x80\x40";
|
|
cbStr = (DWORD)strlen(str);
|
|
dwWritten = 0;
|
|
dwExpectedWritten = cbStr;
|
|
|
|
VERIFY_WIN32_BOOL_SUCCEEDED(WriteFile(hOut, str, cbStr, &dwWritten, nullptr));
|
|
VERIFY_ARE_EQUAL(dwExpectedWritten, dwWritten);
|
|
}
|
|
|
|
void FileTests::TestWriteFileRaw()
|
|
{
|
|
// \x7 is bell
|
|
// \x8 is backspace
|
|
// \x9 is tab
|
|
// \xa is linefeed
|
|
// \xd is carriage return
|
|
// All should be ignored/printed in raw mode.
|
|
PCSTR strTest = "z\x7y\x8z\x9y\xaz\xdy";
|
|
DWORD const cchTest = (DWORD)strlen(strTest);
|
|
String strReadBackExpected(strTest);
|
|
|
|
HANDLE const hOut = GetStdOutputHandle();
|
|
VERIFY_IS_NOT_NULL(hOut, L"Verify we have the standard output handle.");
|
|
|
|
CONSOLE_SCREEN_BUFFER_INFOEX csbiexBefore = { 0 };
|
|
csbiexBefore.cbSize = sizeof(csbiexBefore);
|
|
VERIFY_WIN32_BOOL_SUCCEEDED(GetConsoleScreenBufferInfoEx(hOut, &csbiexBefore), L"Retrieve screen buffer properties before writing.");
|
|
|
|
VERIFY_WIN32_BOOL_SUCCEEDED(SetConsoleMode(hOut, 0), L"Set raw write mode.");
|
|
|
|
COORD const coordZero = { 0 };
|
|
VERIFY_ARE_EQUAL(coordZero, csbiexBefore.dwCursorPosition, L"Cursor should be at 0,0 in fresh buffer.");
|
|
|
|
DWORD dwWritten = 0;
|
|
VERIFY_WIN32_BOOL_SUCCEEDED(WriteFile(hOut, strTest, cchTest, &dwWritten, nullptr), L"Write text into buffer using WriteFile");
|
|
VERIFY_ARE_EQUAL(cchTest, dwWritten);
|
|
|
|
CONSOLE_SCREEN_BUFFER_INFOEX csbiexAfter = { 0 };
|
|
csbiexAfter.cbSize = sizeof(csbiexAfter);
|
|
VERIFY_WIN32_BOOL_SUCCEEDED(GetConsoleScreenBufferInfoEx(hOut, &csbiexAfter), L"Retrieve screen buffer properties after writing.");
|
|
|
|
csbiexBefore.dwCursorPosition.X += (SHORT)cchTest;
|
|
VERIFY_ARE_EQUAL(csbiexBefore.dwCursorPosition, csbiexAfter.dwCursorPosition, L"Verify cursor moved expected number of squares for the write length.");
|
|
|
|
DWORD const cbReadBackBuffer = cchTest + 2; // +1 so we can read back a "space" that should be after what we wrote. +1 more so this can be null terminated for String class comparison.
|
|
wistd::unique_ptr<char[]> strReadBack = wil::make_unique_failfast<char[]>(cbReadBackBuffer);
|
|
ZeroMemory(strReadBack.get(), cbReadBackBuffer * sizeof(char));
|
|
|
|
DWORD dwRead = 0;
|
|
VERIFY_WIN32_BOOL_SUCCEEDED(ReadConsoleOutputCharacterA(hOut, strReadBack.get(), cchTest + 1, coordZero, &dwRead), L"Read back the data in the buffer.");
|
|
// +1 to read back the space that should be after the text we wrote
|
|
|
|
strReadBackExpected += " "; // add in the space that should appear after the written text (buffer should be space filled when empty)
|
|
|
|
VERIFY_ARE_EQUAL(strReadBackExpected, String(strReadBack.get()), L"Ensure that the buffer contents match what we expected based on what we wrote.");
|
|
}
|
|
|
|
void WriteFileHelper(HANDLE hOut,
|
|
CONSOLE_SCREEN_BUFFER_INFOEX& csbiexBefore,
|
|
CONSOLE_SCREEN_BUFFER_INFOEX& csbiexAfter,
|
|
PCSTR psTest,
|
|
DWORD cchTest)
|
|
{
|
|
csbiexBefore.cbSize = sizeof(csbiexBefore);
|
|
VERIFY_WIN32_BOOL_SUCCEEDED(GetConsoleScreenBufferInfoEx(hOut, &csbiexBefore), L"Retrieve screen buffer properties before writing.");
|
|
|
|
DWORD dwWritten = 0;
|
|
VERIFY_WIN32_BOOL_SUCCEEDED(WriteFile(hOut, psTest, cchTest, &dwWritten, nullptr), L"Write text into buffer using WriteFile");
|
|
VERIFY_ARE_EQUAL(cchTest, dwWritten, L"Verify all characters were written.");
|
|
|
|
csbiexAfter.cbSize = sizeof(csbiexAfter);
|
|
VERIFY_WIN32_BOOL_SUCCEEDED(GetConsoleScreenBufferInfoEx(hOut, &csbiexAfter), L"Retrieve screen buffer properties after writing.");
|
|
}
|
|
|
|
void ReadBackHelper(HANDLE hOut,
|
|
COORD coordReadBackPos,
|
|
DWORD dwReadBackLength,
|
|
wistd::unique_ptr<char[]>& pszReadBack)
|
|
{
|
|
// Add one so it can be zero terminated.
|
|
DWORD cbBuffer = dwReadBackLength + 1;
|
|
wistd::unique_ptr<char[]> pszRead = wil::make_unique_failfast<char[]>(cbBuffer);
|
|
ZeroMemory(pszRead.get(), cbBuffer * sizeof(char));
|
|
|
|
DWORD dwRead = 0;
|
|
VERIFY_WIN32_BOOL_SUCCEEDED(ReadConsoleOutputCharacterA(hOut, pszRead.get(), dwReadBackLength, coordReadBackPos, &dwRead), L"Read back data in the buffer.");
|
|
VERIFY_ARE_EQUAL(dwReadBackLength, dwRead, L"Verify API reports we read back the number of characters we asked for.");
|
|
|
|
pszReadBack.swap(pszRead);
|
|
}
|
|
|
|
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.");
|
|
}
|
|
}
|
|
|
|
void FileTests::TestWriteFileWrapEOL()
|
|
{
|
|
bool fFlagOn;
|
|
VERIFY_SUCCEEDED(TestData::TryGetValue(L"fFlagOn", fFlagOn));
|
|
|
|
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.");
|
|
|
|
if (fFlagOn)
|
|
{
|
|
VERIFY_WIN32_BOOL_SUCCEEDED(SetConsoleMode(hOut, ENABLE_WRAP_AT_EOL_OUTPUT), L"Set wrap at EOL.");
|
|
}
|
|
else
|
|
{
|
|
VERIFY_WIN32_BOOL_SUCCEEDED(SetConsoleMode(hOut, 0), L"Make sure wrap at EOL is off.");
|
|
}
|
|
|
|
COORD const coordZero = { 0 };
|
|
VERIFY_ARE_EQUAL(coordZero, csbiexOriginal.dwCursorPosition, L"Cursor should be at 0,0 in fresh buffer.");
|
|
|
|
// Fill first row of the buffer with Z characters until 1 away from the end.
|
|
for (SHORT i = 0; i < csbiexOriginal.dwSize.X - 1; i++)
|
|
{
|
|
WriteFile(hOut, "Z", 1, nullptr, nullptr);
|
|
}
|
|
|
|
CONSOLE_SCREEN_BUFFER_INFOEX csbiexBefore = { 0 };
|
|
csbiexBefore.cbSize = sizeof(csbiexBefore);
|
|
CONSOLE_SCREEN_BUFFER_INFOEX csbiexAfter = { 0 };
|
|
csbiexAfter.cbSize = sizeof(csbiexAfter);
|
|
COORD coordExpected = { 0 };
|
|
|
|
VERIFY_WIN32_BOOL_SUCCEEDED(GetConsoleScreenBufferInfoEx(hOut, &csbiexBefore), L"Get cursor position information before attempting to wrap at end of line.");
|
|
VERIFY_WIN32_BOOL_SUCCEEDED(WriteFile(hOut, "Y", 1, nullptr, nullptr), L"Write of final character in line succeeded.");
|
|
VERIFY_WIN32_BOOL_SUCCEEDED(GetConsoleScreenBufferInfoEx(hOut, &csbiexAfter), L"Get cursor position information after attempting to wrap at end of line.");
|
|
|
|
if (fFlagOn)
|
|
{
|
|
Log::Comment(L"Cursor should go down a row if we tried to print at end of line.");
|
|
coordExpected = csbiexBefore.dwCursorPosition;
|
|
coordExpected.Y++;
|
|
coordExpected.X = 0;
|
|
}
|
|
else
|
|
{
|
|
Log::Comment(L"Cursor shouldn't move when printing at end of line.");
|
|
coordExpected = csbiexBefore.dwCursorPosition;
|
|
}
|
|
|
|
VERIFY_ARE_EQUAL(coordExpected, csbiexAfter.dwCursorPosition, L"Verify cursor moved as expected based on flag state.");
|
|
}
|
|
|
|
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.");
|
|
}
|
|
}
|
|
|
|
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 SendKeyHelper(HANDLE hIn, WORD vk)
|
|
{
|
|
INPUT_RECORD irPause = { 0 };
|
|
irPause.EventType = KEY_EVENT;
|
|
irPause.Event.KeyEvent.bKeyDown = TRUE;
|
|
irPause.Event.KeyEvent.wVirtualKeyCode = vk;
|
|
|
|
DWORD dwWritten = 0;
|
|
VERIFY_WIN32_BOOL_SUCCEEDED(WriteConsoleInputW(hIn, &irPause, 1u, &dwWritten), L"Key event sent.");
|
|
}
|
|
|
|
void PauseHelper(HANDLE hIn)
|
|
{
|
|
SendKeyHelper(hIn, VK_PAUSE);
|
|
}
|
|
|
|
void UnpauseHelper(HANDLE hIn)
|
|
{
|
|
SendKeyHelper(hIn, VK_ESCAPE);
|
|
}
|
|
|
|
void FileTests::TestWriteFileSuspended()
|
|
{
|
|
HANDLE const hOut = GetStdOutputHandle();
|
|
VERIFY_IS_NOT_NULL(hOut, L"Verify we have the standard output handle.");
|
|
|
|
HANDLE const hIn = GetStdInputHandle();
|
|
VERIFY_IS_NOT_NULL(hIn, L"Verify we have the standard input 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;
|
|
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.");
|
|
|
|
VERIFY_WIN32_BOOL_SUCCEEDED(WriteFile(hOut, "abc", 3, nullptr, nullptr), L"Test first write success.");
|
|
PauseHelper(hIn);
|
|
|
|
auto BlockedWrite = std::async([&] {
|
|
Log::Comment(L"Background WriteFile scheduled.");
|
|
VERIFY_WIN32_BOOL_SUCCEEDED(WriteFile(hOut, "def", 3, nullptr, nullptr), L"Test second write success.");
|
|
});
|
|
|
|
UnpauseHelper(hIn);
|
|
|
|
BlockedWrite.wait();
|
|
}
|
|
|
|
void SendFullKeyStrokeHelper(HANDLE hIn, char ch)
|
|
{
|
|
INPUT_RECORD ir[2];
|
|
ZeroMemory(ir, ARRAYSIZE(ir) * sizeof(INPUT_RECORD));
|
|
ir[0].EventType = KEY_EVENT;
|
|
ir[0].Event.KeyEvent.bKeyDown = TRUE;
|
|
ir[0].Event.KeyEvent.dwControlKeyState = ch < 0x20 ? LEFT_CTRL_PRESSED : 0; // set left_ctrl_pressed for control keys.
|
|
ir[0].Event.KeyEvent.uChar.AsciiChar = ch;
|
|
ir[0].Event.KeyEvent.wVirtualKeyCode = VkKeyScanA(ir[0].Event.KeyEvent.uChar.AsciiChar);
|
|
ir[0].Event.KeyEvent.wVirtualScanCode = (WORD)MapVirtualKeyA(ir[0].Event.KeyEvent.wVirtualKeyCode, MAPVK_VK_TO_VSC);
|
|
ir[0].Event.KeyEvent.wRepeatCount = 1;
|
|
ir[1] = ir[0];
|
|
ir[1].Event.KeyEvent.bKeyDown = FALSE;
|
|
|
|
DWORD dwWritten = 0;
|
|
VERIFY_WIN32_BOOL_SUCCEEDED(WriteConsoleInputA(hIn, ir, (DWORD)ARRAYSIZE(ir), &dwWritten), L"Writing key stroke.");
|
|
VERIFY_ARE_EQUAL((DWORD)ARRAYSIZE(ir), dwWritten, L"Written matches expected.");
|
|
}
|
|
|
|
void FileTests::TestReadFileBasic()
|
|
{
|
|
HANDLE const hIn = GetStdInputHandle();
|
|
VERIFY_IS_NOT_NULL(hIn, L"Verify we have the standard input handle.");
|
|
|
|
DWORD dwMode = 0;
|
|
VERIFY_WIN32_BOOL_SUCCEEDED(SetConsoleMode(hIn, dwMode), L"Set input mode for test.");
|
|
|
|
VERIFY_WIN32_BOOL_SUCCEEDED(FlushConsoleInputBuffer(hIn), L"Flush input buffer in preparation for test.");
|
|
|
|
char ch = '\0';
|
|
Log::Comment(L"Queue background blocking read file operation.");
|
|
auto BackgroundRead = std::async([&] {
|
|
DWORD dwRead = 0;
|
|
VERIFY_WIN32_BOOL_SUCCEEDED(ReadFile(hIn, &ch, 1, &dwRead, nullptr), L"Read file was successful.");
|
|
VERIFY_ARE_EQUAL(1u, dwRead, L"Verify we read 1 character.");
|
|
});
|
|
|
|
char const chExpected = 'a';
|
|
Log::Comment(L"Send a key into the console.");
|
|
SendFullKeyStrokeHelper(hIn, chExpected);
|
|
|
|
Log::Comment(L"Wait for background to unblock.");
|
|
BackgroundRead.wait();
|
|
VERIFY_ARE_EQUAL(chExpected, ch);
|
|
}
|
|
|
|
void FileTests::TestReadFileBasicSync()
|
|
{
|
|
HANDLE const hIn = GetStdInputHandle();
|
|
VERIFY_IS_NOT_NULL(hIn, L"Verify we have the standard input handle.");
|
|
|
|
DWORD dwMode = 0;
|
|
VERIFY_WIN32_BOOL_SUCCEEDED(SetConsoleMode(hIn, dwMode), L"Set input mode for test.");
|
|
|
|
VERIFY_WIN32_BOOL_SUCCEEDED(FlushConsoleInputBuffer(hIn), L"Flush input buffer in preparation for test.");
|
|
|
|
char const chExpected = 'a';
|
|
Log::Comment(L"Send a key into the console.");
|
|
SendFullKeyStrokeHelper(hIn, chExpected);
|
|
|
|
char ch = '\0';
|
|
Log::Comment(L"Read with synchronous blocking read.");
|
|
DWORD dwRead = 0;
|
|
VERIFY_WIN32_BOOL_SUCCEEDED(ReadFile(hIn, &ch, 1, &dwRead, nullptr), L"Read file was successful.");
|
|
VERIFY_ARE_EQUAL(1u, dwRead, L"Verify we read 1 character.");
|
|
|
|
VERIFY_ARE_EQUAL(chExpected, ch);
|
|
}
|
|
|
|
void FileTests::TestReadFileBasicEmpty()
|
|
{
|
|
HANDLE const hIn = GetStdInputHandle();
|
|
VERIFY_IS_NOT_NULL(hIn, L"Verify we have the standard input handle.");
|
|
|
|
DWORD dwMode = 0;
|
|
VERIFY_WIN32_BOOL_SUCCEEDED(SetConsoleMode(hIn, dwMode), L"Set input mode for test.");
|
|
|
|
VERIFY_WIN32_BOOL_SUCCEEDED(FlushConsoleInputBuffer(hIn), L"Flush input buffer in preparation for test.");
|
|
|
|
char ch = '\0';
|
|
Log::Comment(L"Queue background blocking read file operation.");
|
|
auto BackgroundRead = std::async([&] {
|
|
DWORD dwRead = 0;
|
|
VERIFY_WIN32_BOOL_SUCCEEDED(ReadFile(hIn, &ch, 1, &dwRead, nullptr), L"Read file was successful.");
|
|
VERIFY_ARE_EQUAL(0u, dwRead, L"We should have read nothing back. It should just return from Ctrl+Z");
|
|
});
|
|
|
|
char const chExpected = '\x1a'; // ctrl+z character
|
|
Log::Comment(L"Send a key into the console.");
|
|
SendFullKeyStrokeHelper(hIn, chExpected);
|
|
|
|
Log::Comment(L"Wait for background to unblock.");
|
|
BackgroundRead.wait();
|
|
VERIFY_ARE_EQUAL('\0', ch);
|
|
}
|
|
|
|
void FileTests::TestReadFileLine()
|
|
{
|
|
HANDLE const hIn = GetStdInputHandle();
|
|
VERIFY_IS_NOT_NULL(hIn, L"Verify we have the standard input handle.");
|
|
|
|
DWORD dwMode = ENABLE_LINE_INPUT;
|
|
VERIFY_WIN32_BOOL_SUCCEEDED(SetConsoleMode(hIn, dwMode), L"Set input mode for test.");
|
|
|
|
VERIFY_WIN32_BOOL_SUCCEEDED(FlushConsoleInputBuffer(hIn), L"Flush input buffer in preparation for test.");
|
|
|
|
char ch = '\0';
|
|
Log::Comment(L"Queue background blocking read file operation.");
|
|
auto BackgroundRead = std::async([&] {
|
|
DWORD dwRead = 0;
|
|
VERIFY_WIN32_BOOL_SUCCEEDED(ReadFile(hIn, &ch, 1, &dwRead, nullptr), L"Read file was successful.");
|
|
VERIFY_ARE_EQUAL(1u, dwRead, L"Verify we read 1 character.");
|
|
});
|
|
|
|
char const chExpected = 'a';
|
|
Log::Comment(L"Send a key into the console.");
|
|
SendFullKeyStrokeHelper(hIn, chExpected);
|
|
|
|
auto status = BackgroundRead.wait_for(std::chrono::milliseconds(250));
|
|
VERIFY_ARE_EQUAL(std::future_status::timeout, status, L"We should still be waiting for a result.");
|
|
VERIFY_ARE_EQUAL('\0', ch, L"Character shouldn't be filled by background read yet.");
|
|
|
|
Log::Comment(L"Send a line feed character, we should stay blocked.");
|
|
SendFullKeyStrokeHelper(hIn, '\n');
|
|
status = BackgroundRead.wait_for(std::chrono::milliseconds(250));
|
|
VERIFY_ARE_EQUAL(std::future_status::timeout, status, L"We should still be waiting for a result.");
|
|
VERIFY_ARE_EQUAL('\0', ch, L"Character shouldn't be filled by background read yet.");
|
|
|
|
Log::Comment(L"Now send a carriage return into the console to signify the end of the input line.");
|
|
SendFullKeyStrokeHelper(hIn, '\r');
|
|
|
|
Log::Comment(L"Wait for background thread to unblock.");
|
|
BackgroundRead.wait();
|
|
VERIFY_ARE_EQUAL(chExpected, ch);
|
|
}
|
|
|
|
void FileTests::TestReadFileLineSync()
|
|
{
|
|
HANDLE const hIn = GetStdInputHandle();
|
|
VERIFY_IS_NOT_NULL(hIn, L"Verify we have the standard input handle.");
|
|
|
|
DWORD dwMode = ENABLE_LINE_INPUT;
|
|
VERIFY_WIN32_BOOL_SUCCEEDED(SetConsoleMode(hIn, dwMode), L"Set input mode for test.");
|
|
|
|
VERIFY_WIN32_BOOL_SUCCEEDED(FlushConsoleInputBuffer(hIn), L"Flush input buffer in preparation for test.");
|
|
|
|
char const chExpected = 'a';
|
|
Log::Comment(L"Send a key into the console followed by a carriage return.");
|
|
SendFullKeyStrokeHelper(hIn, chExpected);
|
|
SendFullKeyStrokeHelper(hIn, '\r');
|
|
|
|
char ch = '\0';
|
|
Log::Comment(L"Read back the input with a synchronous blocking read.");
|
|
DWORD dwRead = 0;
|
|
VERIFY_WIN32_BOOL_SUCCEEDED(ReadFile(hIn, &ch, 1, nullptr, nullptr), L"Read file was successful.");
|
|
VERIFY_ARE_EQUAL(0u, dwRead, L"Verify we read 0 characters.");
|
|
|
|
VERIFY_ARE_EQUAL(chExpected, ch);
|
|
}
|
|
|
|
//void FileTests::TestReadFileEcho()
|
|
//{
|
|
// bool fUseBlockedRead;
|
|
// VERIFY_SUCCEEDED(TestData::TryGetValue(L"fUseBlockedRead", fUseBlockedRead));
|
|
//
|
|
// HANDLE const hOut = GetStdOutputHandle();
|
|
// VERIFY_IS_NOT_NULL(hOut, L"Verify we have the standard output handle.");
|
|
//
|
|
// HANDLE const hIn = GetStdInputHandle();
|
|
// VERIFY_IS_NOT_NULL(hIn, L"Verify we have the standard input handle.");
|
|
//
|
|
// DWORD dwMode = ENABLE_LINE_INPUT | ENABLE_ECHO_INPUT;
|
|
// VERIFY_WIN32_BOOL_SUCCEEDED(SetConsoleMode(hIn, dwMode), L"Set input mode for test.");
|
|
//
|
|
// VERIFY_WIN32_BOOL_SUCCEEDED(FlushConsoleInputBuffer(hIn), L"Flush input buffer in preparation for test.");
|
|
//
|
|
// CONSOLE_SCREEN_BUFFER_INFOEX csbiexOriginal = { 0 };
|
|
// csbiexOriginal.cbSize = sizeof(csbiexOriginal);
|
|
// VERIFY_WIN32_BOOL_SUCCEEDED(GetConsoleScreenBufferInfoEx(hOut, &csbiexOriginal), L"Retrieve output screen buffer information.");
|
|
//
|
|
// COORD const coordZero = { 0 };
|
|
// VERIFY_ARE_EQUAL(coordZero, csbiexOriginal.dwCursorPosition, L"We expect the cursor to be at 0,0 for the start of this test.");
|
|
//
|
|
// char ch = '\0';
|
|
// std::future<void> BackgroundRead;
|
|
// if (fUseBlockedRead)
|
|
// {
|
|
// Log::Comment(L"Queue background blocking read file operation.");
|
|
// BackgroundRead = std::async([&] {
|
|
// OVERLAPPED overlapped = { 0 };
|
|
// wil::unique_event evt;
|
|
// evt.create();
|
|
// overlapped.hEvent = evt.get();
|
|
//
|
|
// DWORD dwRead = 0;
|
|
// VERIFY_WIN32_BOOL_SUCCEEDED(ReadFile(hIn, &ch, 1, nullptr, &overlapped), L"Read file was dispatched successfully.");
|
|
//
|
|
// std::array<HANDLE, 2> handles;
|
|
// handles[0] = _cancellationEvent;
|
|
// handles[1] = overlapped.hEvent;
|
|
//
|
|
// WaitForMultipleObjects(2, handles.data(), FALSE, INFINITE);
|
|
// Log::Comment(L"Wait complete.");
|
|
//
|
|
// VERIFY_ARE_EQUAL(0u, dwRead, L"Verify we read 0 characters.");
|
|
// });
|
|
// }
|
|
//
|
|
// Log::Comment(L"Read back the first line of the buffer to see that it is empty.");
|
|
// wistd::unique_ptr<char[]> pszBefore;
|
|
// PCSTR pszBeforeExpected = " ";
|
|
// DWORD const cchBeforeExpected = (DWORD)strlen(pszBeforeExpected);
|
|
// ReadBackHelper(hOut, coordZero, cchBeforeExpected, pszBefore);
|
|
// VERIFY_ARE_EQUAL(String(pszBeforeExpected), String(pszBefore.get()), L"Verify the first few characters of the buffer are empty (spaces)");
|
|
//
|
|
// PCSTR pszAfterExpected = "qzmp ";
|
|
// COORD coordCursorAfter = { 0 };
|
|
// DWORD const cchAfterExpected = (DWORD)strlen(pszAfterExpected);
|
|
//
|
|
// Log::Comment(L"Now write in a few input characters to the buffer.");
|
|
// for (DWORD i = 0; i < cchAfterExpected - 1; i++)
|
|
// {
|
|
// SendFullKeyStrokeHelper(hIn, pszAfterExpected[i]);
|
|
// coordCursorAfter.X++;
|
|
// }
|
|
//
|
|
// Log::Comment(L"Read back the first line of the buffer to see if we've echoed characters.");
|
|
// wistd::unique_ptr<char[]> pszAfter;
|
|
// ReadBackHelper(hOut, coordZero, cchAfterExpected, pszAfter);
|
|
//
|
|
// if (fUseBlockedRead)
|
|
// {
|
|
// VERIFY_ARE_EQUAL(String(pszAfterExpected), String(pszAfter.get()), L"Verify the characters written were echoed into the buffer.");
|
|
// }
|
|
// else
|
|
// {
|
|
// VERIFY_ARE_EQUAL(String(pszBeforeExpected), String(pszAfter.get()), L"Verify nothing should have been printed while no one was waiting on a read.");
|
|
// }
|
|
//
|
|
// CONSOLE_SCREEN_BUFFER_INFOEX csbiexAfter = { 0 };
|
|
// csbiexAfter.cbSize = sizeof(csbiexAfter);
|
|
// VERIFY_WIN32_BOOL_SUCCEEDED(GetConsoleScreenBufferInfoEx(hOut, &csbiexAfter), L"Get the cursor position after the writes.");
|
|
//
|
|
// if (fUseBlockedRead)
|
|
// {
|
|
// VERIFY_ARE_EQUAL(coordCursorAfter, csbiexAfter.dwCursorPosition, L"Cursor should have moved with the writes.");
|
|
// }
|
|
// else
|
|
// {
|
|
// VERIFY_ARE_EQUAL(coordZero, csbiexAfter.dwCursorPosition, L"Cursor shouldn't move if no one is waiting with a read.");
|
|
// }
|
|
//
|
|
// if (fUseBlockedRead)
|
|
// {
|
|
// Log::Comment(L"Send newline to unblock the read.");
|
|
// SendFullKeyStrokeHelper(hIn, '\r');
|
|
// BackgroundRead.wait();
|
|
// }
|
|
//}
|