Repository: microsoft/terminal
File: src/host/ut_host/CommandLineTests.cpp (C++)

Code before:
    {
        auto buffer = std::make_unique<wchar_t[]>(PROMPT_SIZE);
        VERIFY_IS_NOT_NULL(buffer.get());

        auto& cookedReadData = ServiceLocator::LocateGlobals().getConsoleInformation().CookedReadData();
        InitCookedReadData(cookedReadData, m_pHistory, buffer.get(), PROMPT_SIZE);

        VERIFY_SUCCEEDED(m_pHistory->Add(L"I'm a little teapot", false));
        SetPrompt(cookedReadData, L"short and stout");

        auto& commandLine = CommandLine::Instance();
        commandLine._fillPromptWithPreviousCommandFragment(cookedReadData);
        VerifyPromptText(cookedReadData, L"short and stoutapot");
    }

    TEST_METHOD(CanCycleMatchingCommandHistory)
    {
        auto buffer = std::make_unique<wchar_t[]>(PROMPT_SIZE);
        VERIFY_IS_NOT_NULL(buffer.get());

        auto& cookedReadData = ServiceLocator::LocateGlobals().getConsoleInformation().CookedReadData();
        InitCookedReadData(cookedReadData, m_pHistory, buffer.get(), PROMPT_SIZE);

        VERIFY_SUCCEEDED(m_pHistory->Add(L"I'm a little teapot", false));
        VERIFY_SUCCEEDED(m_pHistory->Add(L"short and stout", false));
        VERIFY_SUCCEEDED(m_pHistory->Add(L"Inflammable", false));

        SetPrompt(cookedReadData, L"I");

        auto& commandLine = CommandLine::Instance();
        commandLine._cycleMatchingCommandHistoryToPrompt(cookedReadData);
        VerifyPromptText(cookedReadData, L"Inflammable");

        // make sure we skip to the next "I" history item
        commandLine._cycleMatchingCommandHistoryToPrompt(cookedReadData);
        VerifyPromptText(cookedReadData, L"I'm a little teapot");

        // should cycle back to the start of the command history
        commandLine._cycleMatchingCommandHistoryToPrompt(cookedReadData);
        VerifyPromptText(cookedReadData, L"Inflammable");
    }

    TEST_METHOD(CmdlineCtrlHomeFullwidthChars)
    {
        Log::Comment(L"Set up buffers, create cooked read data, get screen information.");
        auto buffer = std::make_unique<wchar_t[]>(PROMPT_SIZE);
        VERIFY_IS_NOT_NULL(buffer.get());
        auto& consoleInfo = ServiceLocator::LocateGlobals().getConsoleInformation();
        auto& screenInfo = consoleInfo.GetActiveOutputBuffer();
        auto& cookedReadData = consoleInfo.CookedReadData();
        InitCookedReadData(cookedReadData, m_pHistory, buffer.get(), PROMPT_SIZE);

Review comment (security):
ideally this test would be updated to verify that it does *not* match `i` with `Inflammable`.. or something? Right?

Are users going to be surprised by this change? When did we make it case-insensitive?

Code after:
    {
        auto buffer = std::make_unique<wchar_t[]>(PROMPT_SIZE);
        VERIFY_IS_NOT_NULL(buffer.get());

        auto& cookedReadData = ServiceLocator::LocateGlobals().getConsoleInformation().CookedReadData();
        InitCookedReadData(cookedReadData, m_pHistory, buffer.get(), PROMPT_SIZE);

        VERIFY_SUCCEEDED(m_pHistory->Add(L"I'm a little teapot", false));
        SetPrompt(cookedReadData, L"short and stout");

        auto& commandLine = CommandLine::Instance();
        commandLine._fillPromptWithPreviousCommandFragment(cookedReadData);
        VerifyPromptText(cookedReadData, L"short and stoutapot");
    }

    TEST_METHOD(CanCycleMatchingCommandHistory)
    {
        auto buffer = std::make_unique<wchar_t[]>(PROMPT_SIZE);
        VERIFY_IS_NOT_NULL(buffer.get());

        auto& cookedReadData = ServiceLocator::LocateGlobals().getConsoleInformation().CookedReadData();
        InitCookedReadData(cookedReadData, m_pHistory, buffer.get(), PROMPT_SIZE);

        VERIFY_SUCCEEDED(m_pHistory->Add(L"I'm a little teapot", false));
        VERIFY_SUCCEEDED(m_pHistory->Add(L"short and stout", false));
        VERIFY_SUCCEEDED(m_pHistory->Add(L"inflammable", false));
        VERIFY_SUCCEEDED(m_pHistory->Add(L"Indestructible", false));

        SetPrompt(cookedReadData, L"I");

        auto& commandLine = CommandLine::Instance();
        commandLine._cycleMatchingCommandHistoryToPrompt(cookedReadData);
        VerifyPromptText(cookedReadData, L"Indestructible");

        // make sure we skip to the next "I" history item
        commandLine._cycleMatchingCommandHistoryToPrompt(cookedReadData);
        VerifyPromptText(cookedReadData, L"I'm a little teapot");

        // should cycle back to the start of the command history
        commandLine._cycleMatchingCommandHistoryToPrompt(cookedReadData);
        VerifyPromptText(cookedReadData, L"Indestructible");
    }

    TEST_METHOD(CmdlineCtrlHomeFullwidthChars)
    {
        Log::Comment(L"Set up buffers, create cooked read data, get screen information.");
        auto buffer = std::make_unique<wchar_t[]>(PROMPT_SIZE);
        VERIFY_IS_NOT_NULL(buffer.get());
        auto& consoleInfo = ServiceLocator::LocateGlobals().getConsoleInformation();
        auto& screenInfo = consoleInfo.GetActiveOutputBuffer();
        auto& cookedReadData = consoleInfo.CookedReadData();