## Summary of the Pull Request #4354 is a pretty complicated PR. It's got a bunch of conpty changes, but what it also has was some critical improvements to the roundtrip test suite. I'm working on some other bugfixes in the same area currently, and need these tests enhancements in those branches _now_. The rest of #4354 is complex enough that I don't trust it will get merged soon (if ever). However, these fixes _should_ be in regardless. ## PR Checklist * [x] Taken directly from #4354 * [x] I work here * [x] Tests added/passed * [n/a] Requires documentation to be updated ## Detailed Description of the Pull Request / Additional comments This is four main changes: * Enable conpty to be fully enabled in unittests. Just setting up a VT renderer isn't enough to trick the host into being in conpty mode - it also needs to have some other flags set. * Some minor changes to `CommonState` to better configure the common test state for conpty * Move some of the verify helpers from `ConptyRoundtripTests` into their own helper class, to be shared in multiple tests * Add a `TerminalBufferTests` class, for testing the Terminal buffer directly (without conpty). This change is really easier than ![image](https://user-images.githubusercontent.com/18356694/73278427-2d1b4480-41b1-11ea-9bbe-70671c557f49.png) would suggest, I promise.
This commit is contained in:
parent
e8658cd71e
commit
685720a767
|
@ -30,7 +30,11 @@ namespace Microsoft::Terminal::Core
|
|||
|
||||
// fwdecl unittest classes
|
||||
#ifdef UNIT_TESTING
|
||||
class ConptyRoundtripTests;
|
||||
namespace TerminalCoreUnitTests
|
||||
{
|
||||
class TerminalBufferTests;
|
||||
class ConptyRoundtripTests;
|
||||
};
|
||||
#endif
|
||||
|
||||
class Microsoft::Terminal::Core::Terminal final :
|
||||
|
@ -252,6 +256,7 @@ private:
|
|||
#pragma endregion
|
||||
|
||||
#ifdef UNIT_TESTING
|
||||
friend class ::ConptyRoundtripTests;
|
||||
friend class TerminalCoreUnitTests::TerminalBufferTests;
|
||||
friend class TerminalCoreUnitTests::ConptyRoundtripTests;
|
||||
#endif
|
||||
};
|
||||
|
|
|
@ -27,6 +27,8 @@ class InputBuffer; // This for some reason needs to be fwd-decl'd
|
|||
|
||||
#include "../cascadia/TerminalCore/Terminal.hpp"
|
||||
|
||||
#include "TestUtils.h"
|
||||
|
||||
using namespace WEX::Common;
|
||||
using namespace WEX::Logging;
|
||||
using namespace WEX::TestExecution;
|
||||
|
@ -40,8 +42,17 @@ using namespace Microsoft::Console::Types;
|
|||
|
||||
using namespace Microsoft::Terminal::Core;
|
||||
|
||||
class ConptyRoundtripTests
|
||||
namespace TerminalCoreUnitTests
|
||||
{
|
||||
class TerminalBufferTests;
|
||||
};
|
||||
using namespace TerminalCoreUnitTests;
|
||||
|
||||
class TerminalCoreUnitTests::ConptyRoundtripTests final
|
||||
{
|
||||
static const SHORT TerminalViewWidth = 80;
|
||||
static const SHORT TerminalViewHeight = 32;
|
||||
|
||||
TEST_CLASS(ConptyRoundtripTests);
|
||||
|
||||
TEST_CLASS_SETUP(ClassSetup)
|
||||
|
@ -50,7 +61,7 @@ class ConptyRoundtripTests
|
|||
|
||||
m_state->InitEvents();
|
||||
m_state->PrepareGlobalFont();
|
||||
m_state->PrepareGlobalScreenBuffer();
|
||||
m_state->PrepareGlobalScreenBuffer(TerminalViewWidth, TerminalViewHeight, TerminalViewWidth, TerminalViewHeight);
|
||||
m_state->PrepareGlobalInputBuffer();
|
||||
|
||||
return true;
|
||||
|
@ -71,18 +82,19 @@ class ConptyRoundtripTests
|
|||
{
|
||||
// STEP 1: Set up the Terminal
|
||||
term = std::make_unique<Terminal>();
|
||||
term->Create({ CommonState::s_csBufferWidth, CommonState::s_csBufferHeight }, 0, emptyRT);
|
||||
term->Create({ TerminalViewWidth, TerminalViewHeight }, 100, emptyRT);
|
||||
|
||||
// STEP 2: Set up the Conpty
|
||||
|
||||
// Set up some sane defaults
|
||||
auto& g = ServiceLocator::LocateGlobals();
|
||||
auto& gci = g.getConsoleInformation();
|
||||
|
||||
gci.SetDefaultForegroundColor(INVALID_COLOR);
|
||||
gci.SetDefaultBackgroundColor(INVALID_COLOR);
|
||||
gci.SetFillAttribute(0x07); // DARK_WHITE on DARK_BLACK
|
||||
|
||||
m_state->PrepareNewTextBufferInfo(true);
|
||||
m_state->PrepareNewTextBufferInfo(true, TerminalViewWidth, TerminalViewHeight);
|
||||
auto& currentBuffer = gci.GetActiveOutputBuffer();
|
||||
// Make sure a test hasn't left us in the alt buffer on accident
|
||||
VERIFY_IS_FALSE(currentBuffer._IsAltBuffer());
|
||||
|
@ -106,6 +118,13 @@ class ConptyRoundtripTests
|
|||
g.pRender->AddRenderEngine(_pVtRenderEngine.get());
|
||||
gci.GetActiveOutputBuffer().SetTerminalConnection(_pVtRenderEngine.get());
|
||||
|
||||
_pConApi = std::make_unique<ConhostInternalGetSet>(gci);
|
||||
|
||||
// Manually set the console into conpty mode. We're not actually going
|
||||
// to set up the pipes for conpty, but we want the console to behave
|
||||
// like it would in conpty mode.
|
||||
g.EnableConptyModeForTests();
|
||||
|
||||
expectedOutput.clear();
|
||||
|
||||
return true;
|
||||
|
@ -133,9 +152,15 @@ class ConptyRoundtripTests
|
|||
private:
|
||||
bool _writeCallback(const char* const pch, size_t const cch);
|
||||
void _flushFirstFrame();
|
||||
void _resizeConpty(const unsigned short sx, const unsigned short sy);
|
||||
std::deque<std::string> expectedOutput;
|
||||
std::unique_ptr<Microsoft::Console::Render::VtEngine> _pVtRenderEngine;
|
||||
std::unique_ptr<CommonState> m_state;
|
||||
std::unique_ptr<Microsoft::Console::VirtualTerminal::ConGetSet> _pConApi;
|
||||
|
||||
// Tests can set these variables how they link to configure the behavior of the test harness.
|
||||
bool _checkConptyOutput{ true }; // If true, the test class will check that the output from conpty was expected
|
||||
bool _logConpty{ false }; // If true, the test class will log all the output from conpty. Helpful for debugging.
|
||||
|
||||
DummyRenderTarget emptyRT;
|
||||
std::unique_ptr<Terminal> term;
|
||||
|
@ -144,18 +169,27 @@ private:
|
|||
bool ConptyRoundtripTests::_writeCallback(const char* const pch, size_t const cch)
|
||||
{
|
||||
std::string actualString = std::string(pch, cch);
|
||||
VERIFY_IS_GREATER_THAN(expectedOutput.size(),
|
||||
static_cast<size_t>(0),
|
||||
NoThrowString().Format(L"writing=\"%hs\", expecting %u strings", actualString.c_str(), expectedOutput.size()));
|
||||
|
||||
std::string first = expectedOutput.front();
|
||||
expectedOutput.pop_front();
|
||||
if (_checkConptyOutput)
|
||||
{
|
||||
VERIFY_IS_GREATER_THAN(expectedOutput.size(),
|
||||
static_cast<size_t>(0),
|
||||
NoThrowString().Format(L"writing=\"%hs\", expecting %u strings", TestUtils::ReplaceEscapes(actualString).c_str(), expectedOutput.size()));
|
||||
|
||||
Log::Comment(NoThrowString().Format(L"Expected =\t\"%hs\"", first.c_str()));
|
||||
Log::Comment(NoThrowString().Format(L"Actual =\t\"%hs\"", actualString.c_str()));
|
||||
std::string first = expectedOutput.front();
|
||||
expectedOutput.pop_front();
|
||||
|
||||
VERIFY_ARE_EQUAL(first.length(), cch);
|
||||
VERIFY_ARE_EQUAL(first, actualString);
|
||||
Log::Comment(NoThrowString().Format(L"Expected =\t\"%hs\"", TestUtils::ReplaceEscapes(first).c_str()));
|
||||
Log::Comment(NoThrowString().Format(L"Actual =\t\"%hs\"", TestUtils::ReplaceEscapes(actualString).c_str()));
|
||||
|
||||
VERIFY_ARE_EQUAL(first.length(), cch);
|
||||
VERIFY_ARE_EQUAL(first, actualString);
|
||||
}
|
||||
else if (_logConpty)
|
||||
{
|
||||
Log::Comment(NoThrowString().Format(
|
||||
L"Writing \"%hs\" to Terminal", TestUtils::ReplaceEscapes(actualString).c_str()));
|
||||
}
|
||||
|
||||
// Write the string back to our Terminal
|
||||
const auto converted = ConvertToW(CP_UTF8, actualString);
|
||||
|
@ -177,75 +211,17 @@ void ConptyRoundtripTests::_flushFirstFrame()
|
|||
VERIFY_SUCCEEDED(renderer.PaintFrame());
|
||||
}
|
||||
|
||||
// Function Description:
|
||||
// - Helper function to validate that a number of characters in a row are all
|
||||
// the same. Validates that the next end-start characters are all equal to the
|
||||
// provided string. Will move the provided iterator as it validates. The
|
||||
// caller should ensure that `iter` starts where they would like to validate.
|
||||
// Arguments:
|
||||
// - expectedChar: The character (or characters) we're expecting
|
||||
// - iter: a iterator pointing to the cell we'd like to start validating at.
|
||||
// - start: the first index in the range we'd like to validate
|
||||
// - end: the last index in the range we'd like to validate
|
||||
// Return Value:
|
||||
// - <none>
|
||||
void _verifySpanOfText(const wchar_t* const expectedChar,
|
||||
TextBufferCellIterator& iter,
|
||||
const int start,
|
||||
const int end)
|
||||
void ConptyRoundtripTests::_resizeConpty(const unsigned short sx,
|
||||
const unsigned short sy)
|
||||
{
|
||||
for (int x = start; x < end; x++)
|
||||
// Largely taken from implementation in PtySignalInputThread::_InputThread
|
||||
if (DispatchCommon::s_ResizeWindow(*_pConApi, sx, sy))
|
||||
{
|
||||
SetVerifyOutput settings(VerifyOutputSettings::LogOnlyFailures);
|
||||
if (iter->Chars() != expectedChar)
|
||||
{
|
||||
Log::Comment(NoThrowString().Format(L"character [%d] was mismatched", x));
|
||||
}
|
||||
VERIFY_ARE_EQUAL(expectedChar, (iter++)->Chars());
|
||||
// Instead of going through the VtIo to suppress the resize repaint,
|
||||
// just call the method directly on the renderer. This is implemented in
|
||||
// VtIo::SuppressResizeRepaint
|
||||
VERIFY_SUCCEEDED(_pVtRenderEngine->SuppressResizeRepaint());
|
||||
}
|
||||
Log::Comment(NoThrowString().Format(
|
||||
L"Successfully validated %d characters were '%s'", end - start, expectedChar));
|
||||
}
|
||||
|
||||
// Function Description:
|
||||
// - Helper function to validate that the next characters pointed to by `iter`
|
||||
// are the provided string. Will increment iter as it walks the provided
|
||||
// string of characters. It will leave `iter` on the first character after the
|
||||
// expectedString.
|
||||
// Arguments:
|
||||
// - expectedString: The characters we're expecting
|
||||
// - iter: a iterator pointing to the cell we'd like to start validating at.
|
||||
// Return Value:
|
||||
// - <none>
|
||||
void _verifyExpectedString(std::wstring_view expectedString,
|
||||
TextBufferCellIterator& iter)
|
||||
{
|
||||
for (const auto wch : expectedString)
|
||||
{
|
||||
wchar_t buffer[]{ wch, L'\0' };
|
||||
std::wstring_view view{ buffer, 1 };
|
||||
VERIFY_IS_TRUE(iter, L"Ensure iterator is still valid");
|
||||
VERIFY_ARE_EQUAL(view, (iter++)->Chars(), NoThrowString().Format(L"%s", view.data()));
|
||||
}
|
||||
}
|
||||
|
||||
// Function Description:
|
||||
// - Helper function to validate that the next characters in the buffer at the
|
||||
// given location are the provided string. Will return an iterator on the
|
||||
// first character after the expectedString.
|
||||
// Arguments:
|
||||
// - tb: the buffer who's content we should check
|
||||
// - expectedString: The characters we're expecting
|
||||
// - pos: the starting position in the buffer to check the contents of
|
||||
// Return Value:
|
||||
// - an iterator on the first character after the expectedString.
|
||||
TextBufferCellIterator _verifyExpectedString(const TextBuffer& tb,
|
||||
std::wstring_view expectedString,
|
||||
const COORD pos)
|
||||
{
|
||||
auto iter = tb.GetCellDataAt(pos);
|
||||
_verifyExpectedString(expectedString, iter);
|
||||
return iter;
|
||||
}
|
||||
|
||||
void ConptyRoundtripTests::ConptyOutputTestCanary()
|
||||
|
@ -278,7 +254,7 @@ void ConptyRoundtripTests::SimpleWriteOutputTest()
|
|||
|
||||
VERIFY_SUCCEEDED(renderer.PaintFrame());
|
||||
|
||||
_verifyExpectedString(termTb, L"Hello World ", { 0, 0 });
|
||||
TestUtils::VerifyExpectedString(termTb, L"Hello World ", { 0, 0 });
|
||||
}
|
||||
|
||||
void ConptyRoundtripTests::WriteTwoLinesUsesNewline()
|
||||
|
@ -302,8 +278,8 @@ void ConptyRoundtripTests::WriteTwoLinesUsesNewline()
|
|||
hostSm.ProcessString(L"BBB");
|
||||
|
||||
auto verifyData = [](TextBuffer& tb) {
|
||||
_verifyExpectedString(tb, L"AAA", { 0, 0 });
|
||||
_verifyExpectedString(tb, L"BBB", { 0, 1 });
|
||||
TestUtils::VerifyExpectedString(tb, L"AAA", { 0, 0 });
|
||||
TestUtils::VerifyExpectedString(tb, L"BBB", { 0, 1 });
|
||||
};
|
||||
|
||||
verifyData(hostTb);
|
||||
|
@ -338,10 +314,10 @@ void ConptyRoundtripTests::WriteAFewSimpleLines()
|
|||
hostSm.ProcessString(L"\n");
|
||||
hostSm.ProcessString(L"CCC");
|
||||
auto verifyData = [](TextBuffer& tb) {
|
||||
_verifyExpectedString(tb, L"AAA", { 0, 0 });
|
||||
_verifyExpectedString(tb, L"BBB", { 0, 1 });
|
||||
_verifyExpectedString(tb, L" ", { 0, 2 });
|
||||
_verifyExpectedString(tb, L"CCC", { 0, 3 });
|
||||
TestUtils::VerifyExpectedString(tb, L"AAA", { 0, 0 });
|
||||
TestUtils::VerifyExpectedString(tb, L"BBB", { 0, 1 });
|
||||
TestUtils::VerifyExpectedString(tb, L" ", { 0, 2 });
|
||||
TestUtils::VerifyExpectedString(tb, L"CCC", { 0, 3 });
|
||||
};
|
||||
|
||||
verifyData(hostTb);
|
||||
|
|
68
src/cascadia/UnitTests_TerminalCore/TerminalBufferTests.cpp
Normal file
68
src/cascadia/UnitTests_TerminalCore/TerminalBufferTests.cpp
Normal file
|
@ -0,0 +1,68 @@
|
|||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
#include "precomp.h"
|
||||
#include <WexTestClass.h>
|
||||
|
||||
#include "../renderer/inc/DummyRenderTarget.hpp"
|
||||
#include "../cascadia/TerminalCore/Terminal.hpp"
|
||||
#include "MockTermSettings.h"
|
||||
#include "consoletaeftemplates.hpp"
|
||||
#include "TestUtils.h"
|
||||
|
||||
using namespace winrt::Microsoft::Terminal::Settings;
|
||||
using namespace Microsoft::Terminal::Core;
|
||||
|
||||
using namespace WEX::Common;
|
||||
using namespace WEX::Logging;
|
||||
using namespace WEX::TestExecution;
|
||||
|
||||
namespace TerminalCoreUnitTests
|
||||
{
|
||||
class TerminalBufferTests;
|
||||
};
|
||||
using namespace TerminalCoreUnitTests;
|
||||
|
||||
class TerminalCoreUnitTests::TerminalBufferTests final
|
||||
{
|
||||
TEST_CLASS(TerminalBufferTests);
|
||||
|
||||
TEST_METHOD(TestSimpleBufferWriting);
|
||||
|
||||
TEST_METHOD_SETUP(MethodSetup)
|
||||
{
|
||||
// STEP 1: Set up the Terminal
|
||||
term = std::make_unique<Terminal>();
|
||||
term->Create({ 80, 32 }, 100, emptyRT);
|
||||
return true;
|
||||
}
|
||||
|
||||
TEST_METHOD_CLEANUP(MethodCleanup)
|
||||
{
|
||||
term = nullptr;
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
DummyRenderTarget emptyRT;
|
||||
std::unique_ptr<Terminal> term;
|
||||
};
|
||||
|
||||
void TerminalBufferTests::TestSimpleBufferWriting()
|
||||
{
|
||||
auto& termTb = *term->_buffer;
|
||||
auto& termSm = *term->_stateMachine;
|
||||
const auto initialView = term->GetViewport();
|
||||
|
||||
VERIFY_ARE_EQUAL(0, initialView.Top());
|
||||
VERIFY_ARE_EQUAL(32, initialView.BottomExclusive());
|
||||
|
||||
termSm.ProcessString(L"Hello World");
|
||||
|
||||
const auto secondView = term->GetViewport();
|
||||
|
||||
VERIFY_ARE_EQUAL(0, secondView.Top());
|
||||
VERIFY_ARE_EQUAL(32, secondView.BottomExclusive());
|
||||
|
||||
TestUtils::VerifyExpectedString(termTb, L"Hello World", { 0, 0 });
|
||||
}
|
138
src/cascadia/UnitTests_TerminalCore/TestUtils.h
Normal file
138
src/cascadia/UnitTests_TerminalCore/TestUtils.h
Normal file
|
@ -0,0 +1,138 @@
|
|||
/*++
|
||||
Copyright (c) Microsoft Corporation
|
||||
Licensed under the MIT license.
|
||||
|
||||
Module Name:
|
||||
- TestUtils.h
|
||||
|
||||
Abstract:
|
||||
- This file has helper functions for writing tests for the TerminalCore project.
|
||||
|
||||
Author(s):
|
||||
Mike Griese (migrie) January-2020
|
||||
--*/
|
||||
|
||||
#include "../../buffer/out/textBuffer.hpp"
|
||||
|
||||
namespace TerminalCoreUnitTests
|
||||
{
|
||||
class TestUtils;
|
||||
};
|
||||
class TerminalCoreUnitTests::TestUtils
|
||||
{
|
||||
public:
|
||||
// Function Description:
|
||||
// - Helper function to validate that a number of characters in a row are all
|
||||
// the same. Validates that the next end-start characters are all equal to the
|
||||
// provided string. Will move the provided iterator as it validates. The
|
||||
// caller should ensure that `iter` starts where they would like to validate.
|
||||
// Arguments:
|
||||
// - expectedChar: The character (or characters) we're expecting
|
||||
// - iter: a iterator pointing to the cell we'd like to start validating at.
|
||||
// - start: the first index in the range we'd like to validate
|
||||
// - end: the last index in the range we'd like to validate
|
||||
// Return Value:
|
||||
// - <none>
|
||||
static void VerifySpanOfText(const wchar_t* const expectedChar,
|
||||
TextBufferCellIterator& iter,
|
||||
const int start,
|
||||
const int end)
|
||||
{
|
||||
for (int x = start; x < end; x++)
|
||||
{
|
||||
WEX::TestExecution::SetVerifyOutput settings(WEX::TestExecution::VerifyOutputSettings::LogOnlyFailures);
|
||||
if (iter->Chars() != expectedChar)
|
||||
{
|
||||
WEX::Logging::Log::Comment(WEX::Common::NoThrowString().Format(L"character [%d] was mismatched", x));
|
||||
}
|
||||
VERIFY_ARE_EQUAL(expectedChar, (iter++)->Chars());
|
||||
}
|
||||
WEX::Logging::Log::Comment(WEX::Common::NoThrowString().Format(
|
||||
L"Successfully validated %d characters were '%s'", end - start, expectedChar));
|
||||
};
|
||||
|
||||
// Function Description:
|
||||
// - Helper function to validate that the next characters pointed to by `iter`
|
||||
// are the provided string. Will increment iter as it walks the provided
|
||||
// string of characters. It will leave `iter` on the first character after the
|
||||
// expectedString.
|
||||
// Arguments:
|
||||
// - expectedString: The characters we're expecting
|
||||
// - iter: a iterator pointing to the cell we'd like to start validating at.
|
||||
// Return Value:
|
||||
// - <none>
|
||||
static void VerifyExpectedString(std::wstring_view expectedString,
|
||||
TextBufferCellIterator& iter)
|
||||
{
|
||||
for (const auto wch : expectedString)
|
||||
{
|
||||
wchar_t buffer[]{ wch, L'\0' };
|
||||
std::wstring_view view{ buffer, 1 };
|
||||
VERIFY_IS_TRUE(iter, L"Ensure iterator is still valid");
|
||||
VERIFY_ARE_EQUAL(view, (iter++)->Chars(), WEX::Common::NoThrowString().Format(L"%s", view.data()));
|
||||
}
|
||||
};
|
||||
|
||||
// Function Description:
|
||||
// - Helper function to validate that the next characters in the buffer at the
|
||||
// given location are the provided string. Will return an iterator on the
|
||||
// first character after the expectedString.
|
||||
// Arguments:
|
||||
// - tb: the buffer who's content we should check
|
||||
// - expectedString: The characters we're expecting
|
||||
// - pos: the starting position in the buffer to check the contents of
|
||||
// Return Value:
|
||||
// - an iterator on the first character after the expectedString.
|
||||
static TextBufferCellIterator VerifyExpectedString(const TextBuffer& tb,
|
||||
std::wstring_view expectedString,
|
||||
const COORD pos)
|
||||
{
|
||||
auto iter = tb.GetCellDataAt(pos);
|
||||
VerifyExpectedString(expectedString, iter);
|
||||
return iter;
|
||||
};
|
||||
|
||||
// Function Description:
|
||||
// - Replaces all escapes with the printable symbol for that escape
|
||||
// character. This makes log parsing easier for debugging, as the literal
|
||||
// escapes won't be written to the console output.
|
||||
// Arguments:
|
||||
// - str: the string to escape.
|
||||
// Return Value:
|
||||
// - A modified version of that string with non-printable characters replaced.
|
||||
static std::string ReplaceEscapes(const std::string& str)
|
||||
{
|
||||
std::string escaped = str;
|
||||
auto replaceFn = [&escaped](const std::string& search, const std::string& replace) {
|
||||
size_t pos = escaped.find(search, 0);
|
||||
while (pos != std::string::npos)
|
||||
{
|
||||
escaped.replace(pos, search.length(), replace);
|
||||
pos = escaped.find(search, pos + replace.length());
|
||||
}
|
||||
};
|
||||
replaceFn("\x1b", "^\x5b"); // ESC
|
||||
replaceFn("\x08", "^\x48"); // BS
|
||||
replaceFn("\x0A", "^\x4A"); // LF
|
||||
replaceFn("\x0D", "^\x4D"); // CR
|
||||
return escaped;
|
||||
}
|
||||
|
||||
// Function Description:
|
||||
// - Replaces all escapes with the printable symbol for that escape
|
||||
// character. This makes log parsing easier for debugging, as the literal
|
||||
// escapes won't be written to the console output.
|
||||
// Arguments:
|
||||
// - wstr: the string to escape.
|
||||
// Return Value:
|
||||
// - A modified version of that string with non-printable characters replaced.
|
||||
static std::wstring ReplaceEscapes(const std::wstring& wstr)
|
||||
{
|
||||
std::wstring escaped = wstr;
|
||||
std::replace(escaped.begin(), escaped.end(), L'\x1b', L'\x241b'); // ESC
|
||||
std::replace(escaped.begin(), escaped.end(), L'\x08', L'\x2408'); // BS
|
||||
std::replace(escaped.begin(), escaped.end(), L'\x0A', L'\x240A'); // LF
|
||||
std::replace(escaped.begin(), escaped.end(), L'\x0D', L'\x240D'); // CR
|
||||
return escaped;
|
||||
}
|
||||
};
|
|
@ -19,6 +19,7 @@
|
|||
</ClCompile>
|
||||
<ClCompile Include="TerminalApiTest.cpp" />
|
||||
<ClCompile Include="ConptyRoundtripTests.cpp" />
|
||||
<ClCompile Include="TerminalBufferTests.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\buffer\out\lib\bufferout.vcxproj">
|
||||
|
|
|
@ -638,3 +638,17 @@ void ConsoleArguments::SetExpectedSize(COORD dimensions) noexcept
|
|||
_recievedEarlySizeChange = true;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef UNIT_TESTING
|
||||
// Method Description:
|
||||
// - This is a test helper method. It can be used to trick us into thinking
|
||||
// we're headless (in conpty mode), even without parsing any arguments.
|
||||
// Arguments:
|
||||
// - <none>
|
||||
// Return Value:
|
||||
// - <none>
|
||||
void ConsoleArguments::EnableConptyModeForTests()
|
||||
{
|
||||
_headless = true;
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -53,6 +53,10 @@ public:
|
|||
|
||||
void SetExpectedSize(COORD dimensions) noexcept;
|
||||
|
||||
#ifdef UNIT_TESTING
|
||||
void EnableConptyModeForTests();
|
||||
#endif
|
||||
|
||||
static const std::wstring_view VT_MODE_ARG;
|
||||
static const std::wstring_view HEADLESS_ARG;
|
||||
static const std::wstring_view SERVER_HANDLE_ARG;
|
||||
|
|
|
@ -431,3 +431,18 @@ void VtIo::EndResize()
|
|||
_pVtRenderEngine->EndResizeRequest();
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef UNIT_TESTING
|
||||
// Method Description:
|
||||
// - This is a test helper method. It can be used to trick VtIo into responding
|
||||
// true to `IsUsingVt`, which will cause the console host to act in conpty
|
||||
// mode.
|
||||
// Arguments:
|
||||
// - <none>
|
||||
// Return Value:
|
||||
// - <none>
|
||||
void VtIo::EnableConptyModeForTests()
|
||||
{
|
||||
_objectsCreated = true;
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -39,6 +39,10 @@ namespace Microsoft::Console::VirtualTerminal
|
|||
void BeginResize();
|
||||
void EndResize();
|
||||
|
||||
#ifdef UNIT_TESTING
|
||||
void EnableConptyModeForTests();
|
||||
#endif
|
||||
|
||||
private:
|
||||
// After CreateIoHandlers is called, these will be invalid.
|
||||
wil::unique_hfile _hInput;
|
||||
|
|
|
@ -16,3 +16,19 @@ bool Globals::IsHeadless() const
|
|||
{
|
||||
return launchArgs.IsHeadless();
|
||||
}
|
||||
|
||||
#ifdef UNIT_TESTING
|
||||
// Method Description:
|
||||
// - This is a test helper method. It can be used to trick us into responding
|
||||
// true to `IsHeadless`, which will cause the console host to act in conpty
|
||||
// mode.
|
||||
// Arguments:
|
||||
// - <none>
|
||||
// Return Value:
|
||||
// - <none>
|
||||
void Globals::EnableConptyModeForTests()
|
||||
{
|
||||
launchArgs.EnableConptyModeForTests();
|
||||
getConsoleInformation().GetVtIo()->EnableConptyModeForTests();
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -69,6 +69,10 @@ public:
|
|||
|
||||
ApiRoutines api;
|
||||
|
||||
#ifdef UNIT_TESTING
|
||||
void EnableConptyModeForTests();
|
||||
#endif
|
||||
|
||||
private:
|
||||
CONSOLE_INFORMATION ciConsoleInformation;
|
||||
};
|
||||
|
|
|
@ -50,6 +50,14 @@ Revision History:
|
|||
#include "../types/IConsoleWindow.hpp"
|
||||
class ConversionAreaInfo; // forward decl window. circular reference
|
||||
|
||||
// fwdecl unittest classes
|
||||
#ifdef UNIT_TESTING
|
||||
namespace TerminalCoreUnitTests
|
||||
{
|
||||
class ConptyRoundtripTests;
|
||||
};
|
||||
#endif
|
||||
|
||||
class SCREEN_INFORMATION : public ConsoleObjectHeader, public Microsoft::Console::IIoProvider
|
||||
{
|
||||
public:
|
||||
|
@ -308,6 +316,6 @@ private:
|
|||
friend class ScreenBufferTests;
|
||||
friend class CommonState;
|
||||
friend class ConptyOutputTests;
|
||||
friend class ConptyRoundtripTests;
|
||||
friend class TerminalCoreUnitTests::ConptyRoundtripTests;
|
||||
#endif
|
||||
};
|
||||
|
|
|
@ -87,6 +87,11 @@ class ConptyOutputTests
|
|||
|
||||
expectedOutput.clear();
|
||||
|
||||
// Manually set the console into conpty mode. We're not actually going
|
||||
// to set up the pipes for conpty, but we want the console to behave
|
||||
// like it would in conpty mode.
|
||||
g.EnableConptyModeForTests();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -81,16 +81,19 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
void PrepareGlobalScreenBuffer()
|
||||
void PrepareGlobalScreenBuffer(const short viewWidth = s_csWindowWidth,
|
||||
const short viewHeight = s_csWindowHeight,
|
||||
const short bufferWidth = s_csBufferWidth,
|
||||
const short bufferHeight = s_csBufferHeight)
|
||||
{
|
||||
CONSOLE_INFORMATION& gci = Microsoft::Console::Interactivity::ServiceLocator::LocateGlobals().getConsoleInformation();
|
||||
COORD coordWindowSize;
|
||||
coordWindowSize.X = s_csWindowWidth;
|
||||
coordWindowSize.Y = s_csWindowHeight;
|
||||
coordWindowSize.X = viewWidth;
|
||||
coordWindowSize.Y = viewHeight;
|
||||
|
||||
COORD coordScreenBufferSize;
|
||||
coordScreenBufferSize.X = s_csBufferWidth;
|
||||
coordScreenBufferSize.Y = s_csBufferHeight;
|
||||
coordScreenBufferSize.X = bufferWidth;
|
||||
coordScreenBufferSize.Y = bufferHeight;
|
||||
|
||||
UINT uiCursorSize = 12;
|
||||
|
||||
|
@ -143,12 +146,14 @@ public:
|
|||
gci.SetCookedReadData(nullptr);
|
||||
}
|
||||
|
||||
void PrepareNewTextBufferInfo(const bool useDefaultAttributes = false)
|
||||
void PrepareNewTextBufferInfo(const bool useDefaultAttributes = false,
|
||||
const short bufferWidth = s_csBufferWidth,
|
||||
const short bufferHeight = s_csBufferHeight)
|
||||
{
|
||||
CONSOLE_INFORMATION& gci = Microsoft::Console::Interactivity::ServiceLocator::LocateGlobals().getConsoleInformation();
|
||||
COORD coordScreenBufferSize;
|
||||
coordScreenBufferSize.X = s_csBufferWidth;
|
||||
coordScreenBufferSize.Y = s_csBufferHeight;
|
||||
coordScreenBufferSize.X = bufferWidth;
|
||||
coordScreenBufferSize.Y = bufferHeight;
|
||||
|
||||
UINT uiCursorSize = 12;
|
||||
|
||||
|
|
|
@ -26,7 +26,10 @@ Author(s):
|
|||
|
||||
// fwdecl unittest classes
|
||||
#ifdef UNIT_TESTING
|
||||
class ConptyRoundtripTests;
|
||||
namespace TerminalCoreUnitTests
|
||||
{
|
||||
class ConptyRoundtripTests;
|
||||
};
|
||||
#endif
|
||||
|
||||
namespace Microsoft::Console::Render
|
||||
|
@ -226,7 +229,7 @@ namespace Microsoft::Console::Render
|
|||
|
||||
friend class VtRendererTest;
|
||||
friend class ConptyOutputTests;
|
||||
friend class ConptyRoundtripTests;
|
||||
friend class TerminalCoreUnitTests::ConptyRoundtripTests;
|
||||
#endif
|
||||
|
||||
void SetTestCallback(_In_ std::function<bool(const char* const, size_t const)> pfn);
|
||||
|
|
Loading…
Reference in a new issue