terminal/src/host/ft_host/API_FillOutputTests.cpp
Carlos Zamora 4dd9f9c180 make filling chars (and, thus, erase line/char) unset wrap (#2831)
EraseInLine calls `FillConsoleOutputCharacterW()`. In filling the row with
chars, we were setting the wrap flag. We need to specifically not do this on
ANY _FILL_ operation. Now a fill operation UNSETS the wrap flag if we fill to
the end of the line.

Originally, we had a boolean `setWrap` that would mean...
- **true**: if writing to the end of the row, SET the wrap value to true
- **false**: if writing to the end of the row, DON'T CHANGE the wrap value

Now we're making this bool a std::optional to allow for a ternary state. This
allows for us to handle the following cases completely. Refer to the table
below:

,- current wrap value
|     ,- are we filling the last cell in the row?
|     |     ,- new wrap value
|     |     |     ,- comments
|--   |--   |--   |
| 0   | 0   | 0   |
| 0   | 1   | 0   |
| 0   | 1   | 1   | THIS CASE WAS HANDLED CORRECTLY
| 1   | 0   | 0   | THIS CASE WAS UNHANDLED
| 1   | 0   | 1   |
| 1   | 1   | 1   |

To handle that special case (1-0-0), we need to UNSET the wrap. So now, we have
~setWrap~ `wrap` mean the following:
- **true**: if writing to the end of the row, SET the wrap value to TRUE
- **false**: if writing to the end of the row, SET the wrap value to FALSE
- **nullopt**: leave the wrap value as it is

Closes #1126
2019-09-30 18:16:31 -07:00

183 lines
8.7 KiB
C++

// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
#include "precomp.h"
#define CP_USA 437
class FillOutputTests
{
BEGIN_TEST_CLASS(FillOutputTests)
END_TEST_CLASS()
TEST_METHOD(WriteNarrowGlyphAscii)
{
HANDLE hConsole = GetStdOutputHandle();
DWORD charsWritten = 0;
VERIFY_WIN32_BOOL_SUCCEEDED(FillConsoleOutputCharacterA(hConsole,
'a',
1,
{ 0, 0 },
&charsWritten));
VERIFY_ARE_EQUAL(1u, charsWritten);
// test a box drawing character
const UINT previousCodepage = GetConsoleOutputCP();
VERIFY_WIN32_BOOL_SUCCEEDED(SetConsoleOutputCP(CP_USA));
charsWritten = 0;
VERIFY_WIN32_BOOL_SUCCEEDED(FillConsoleOutputCharacterA(hConsole,
'\xCE', // U+256C box drawing double vertical and horizontal
1,
{ 0, 0 },
&charsWritten));
VERIFY_ARE_EQUAL(1u, charsWritten);
VERIFY_SUCCEEDED(SetConsoleOutputCP(previousCodepage));
}
TEST_METHOD(WriteNarrowGlyphUnicode)
{
HANDLE hConsole = GetStdOutputHandle();
DWORD charsWritten = 0;
VERIFY_WIN32_BOOL_SUCCEEDED(FillConsoleOutputCharacterW(hConsole,
L'a',
1,
{ 0, 0 },
&charsWritten));
VERIFY_ARE_EQUAL(1u, charsWritten);
}
TEST_METHOD(WriteWideGlyphUnicode)
{
HANDLE hConsole = GetStdOutputHandle();
DWORD charsWritten = 0;
VERIFY_WIN32_BOOL_SUCCEEDED(FillConsoleOutputCharacterW(hConsole,
L'\x304F',
1,
{ 0, 0 },
&charsWritten));
VERIFY_ARE_EQUAL(1u, charsWritten);
}
TEST_METHOD(UnsetWrap)
{
// WARNING: If this test suddenly decides to start failing,
// this is because the wrap registry key is not set.
// TODO GH #2859: Get/Set Registry Key for Wrap
HANDLE hConsole = GetStdOutputHandle();
DWORD charsWritten = 0;
CONSOLE_SCREEN_BUFFER_INFOEX sbiex = { 0 };
sbiex.cbSize = sizeof(sbiex);
VERIFY_WIN32_BOOL_SUCCEEDED(GetConsoleScreenBufferInfoEx(hConsole, &sbiex));
const auto consoleWidth = sbiex.dwSize.X;
std::wstring input(consoleWidth + 2, L'a');
std::wstring filled(consoleWidth, L'b');
// Write until a wrap occurs
VERIFY_WIN32_BOOL_SUCCEEDED(WriteConsoleW(hConsole,
input.data(),
gsl::narrow_cast<DWORD>(input.size()),
&charsWritten,
nullptr));
// Verify wrap occurred
std::unique_ptr<wchar_t[]> bufferText = std::make_unique<wchar_t[]>(consoleWidth);
DWORD readSize = 0;
VERIFY_WIN32_BOOL_SUCCEEDED(ReadConsoleOutputCharacterW(hConsole,
bufferText.get(),
consoleWidth,
{ 0, 0 },
&readSize));
WEX::Common::String expected(input.c_str(), readSize);
WEX::Common::String actual(bufferText.get(), readSize);
VERIFY_ARE_EQUAL(expected, actual);
bufferText = std::make_unique<wchar_t[]>(2);
VERIFY_WIN32_BOOL_SUCCEEDED(ReadConsoleOutputCharacterW(hConsole,
bufferText.get(),
2,
{ 0, 1 },
&readSize));
VERIFY_ARE_EQUAL(2u, readSize);
expected = WEX::Common::String(input.c_str(), readSize);
actual = WEX::Common::String(bufferText.get(), readSize);
VERIFY_ARE_EQUAL(expected, actual);
// Fill Console Line with 'b's
VERIFY_WIN32_BOOL_SUCCEEDED(FillConsoleOutputCharacterW(hConsole,
L'b',
consoleWidth,
{ 2, 0 },
&charsWritten));
// Verify first line is full of 'a's then 'b's
bufferText = std::make_unique<wchar_t[]>(consoleWidth);
VERIFY_WIN32_BOOL_SUCCEEDED(ReadConsoleOutputCharacterW(hConsole,
bufferText.get(),
consoleWidth,
{ 0, 0 },
&readSize));
expected = WEX::Common::String(input.c_str(), 2);
actual = WEX::Common::String(bufferText.get(), 2);
VERIFY_ARE_EQUAL(expected, actual);
expected = WEX::Common::String(filled.c_str(), consoleWidth - 2);
actual = WEX::Common::String(&bufferText[2], readSize - 2);
VERIFY_ARE_EQUAL(expected, actual);
// Verify second line is still has 'a's that wrapped over
bufferText = std::make_unique<wchar_t[]>(2);
VERIFY_WIN32_BOOL_SUCCEEDED(ReadConsoleOutputCharacterW(hConsole,
bufferText.get(),
static_cast<SHORT>(2),
{ 0, 0 },
&readSize));
VERIFY_ARE_EQUAL(2u, readSize);
expected = WEX::Common::String(input.c_str(), 2);
actual = WEX::Common::String(bufferText.get(), readSize);
VERIFY_ARE_EQUAL(expected, actual);
// Resize to be smaller by 2
sbiex.srWindow.Right -= 2;
sbiex.dwSize.X -= 2;
VERIFY_WIN32_BOOL_SUCCEEDED(SetConsoleScreenBufferInfoEx(hConsole, &sbiex));
// Verify first line is full of 'a's then 'b's
bufferText = std::make_unique<wchar_t[]>(consoleWidth - 2);
VERIFY_WIN32_BOOL_SUCCEEDED(ReadConsoleOutputCharacterW(hConsole,
bufferText.get(),
consoleWidth - static_cast<SHORT>(2),
{ 0, 0 },
&readSize));
expected = WEX::Common::String(input.c_str(), 2);
actual = WEX::Common::String(bufferText.get(), 2);
VERIFY_ARE_EQUAL(expected, actual);
expected = WEX::Common::String(filled.c_str(), consoleWidth - 4);
actual = WEX::Common::String(&bufferText[2], readSize - 2);
VERIFY_ARE_EQUAL(expected, actual);
// Verify second line is still has 'a's ('b's didn't wrap over)
bufferText = std::make_unique<wchar_t[]>(static_cast<SHORT>(2));
VERIFY_WIN32_BOOL_SUCCEEDED(ReadConsoleOutputCharacterW(hConsole,
bufferText.get(),
static_cast<SHORT>(2),
{ 0, 0 },
&readSize));
VERIFY_ARE_EQUAL(2u, readSize);
expected = WEX::Common::String(input.c_str(), 2);
actual = WEX::Common::String(bufferText.get(), readSize);
VERIFY_ARE_EQUAL(expected, actual);
}
};