1aff3bc216
* Created a ViewModel class in the Command Palette called FilteredCommand, aggregating the Command, the filter and the highlighted presentation of the command name * This ListView of the filtered commands is bound to the vector of FilteredCommands * Introduced HighlightedTextControl user control with HighlightedText view model * Added this control to the ListView Item's grid * Bound the FilteredCommand's highlighted command name to the user control ## Validation Steps Performed * UT for matching algorithm * Only manual tests * Searching in CommandLine, SwitchTab and Nested Command modes * Checking for bot matching an non matching filters * Dogfooding Closes #6646
272 lines
14 KiB
C++
272 lines
14 KiB
C++
// Copyright (c) Microsoft Corporation.
|
|
// Licensed under the MIT license.
|
|
|
|
#include "pch.h"
|
|
#include "../TerminalApp/TerminalSettings.h"
|
|
#include "../TerminalApp/CommandPalette.h"
|
|
|
|
using namespace Microsoft::Console;
|
|
using namespace WEX::Logging;
|
|
using namespace WEX::TestExecution;
|
|
using namespace WEX::Common;
|
|
using namespace winrt::Microsoft::Terminal::Settings::Model;
|
|
using namespace winrt::Microsoft::Terminal::TerminalControl;
|
|
|
|
namespace TerminalAppLocalTests
|
|
{
|
|
class FilteredCommandTests
|
|
{
|
|
BEGIN_TEST_CLASS(FilteredCommandTests)
|
|
TEST_CLASS_PROPERTY(L"RunAs", L"UAP")
|
|
TEST_CLASS_PROPERTY(L"UAP:AppXManifest", L"TestHostAppXManifest.xml")
|
|
END_TEST_CLASS()
|
|
|
|
TEST_METHOD(VerifyHighlighting);
|
|
TEST_METHOD(VerifyWeight);
|
|
TEST_METHOD(VerifyCompare);
|
|
};
|
|
|
|
void FilteredCommandTests::VerifyHighlighting()
|
|
{
|
|
const std::string settingsJson{ R"(
|
|
{
|
|
"defaultProfile": "{6239a42c-0000-49a3-80bd-e8fdd045185c}",
|
|
"profiles": [
|
|
{
|
|
"name": "profile0",
|
|
"guid": "{6239a42c-0000-49a3-80bd-e8fdd045185c}",
|
|
"historySize": 1,
|
|
"commandline": "cmd.exe"
|
|
}
|
|
],
|
|
"keybindings": [
|
|
{ "keys": ["ctrl+a"], "command": { "action": "splitPane", "split": "vertical" }, "name": "AAAAAABBBBBBCCC" }
|
|
]
|
|
})" };
|
|
|
|
CascadiaSettings settings{ til::u8u16(settingsJson) };
|
|
const auto commands = settings.GlobalSettings().Commands();
|
|
VERIFY_ARE_EQUAL(1u, commands.Size());
|
|
|
|
const auto command = commands.Lookup(L"AAAAAABBBBBBCCC");
|
|
VERIFY_IS_NOT_NULL(command);
|
|
VERIFY_ARE_EQUAL(command.Name(), L"AAAAAABBBBBBCCC");
|
|
{
|
|
Log::Comment(L"Testing command name segmentation with no filter");
|
|
const auto filteredCommand = winrt::make_self<winrt::TerminalApp::implementation::FilteredCommand>(command);
|
|
auto segments = filteredCommand->_computeHighlightedName().Segments();
|
|
VERIFY_ARE_EQUAL(segments.Size(), 1u);
|
|
VERIFY_ARE_EQUAL(segments.GetAt(0).TextSegment(), L"AAAAAABBBBBBCCC");
|
|
VERIFY_IS_FALSE(segments.GetAt(0).IsHighlighted());
|
|
}
|
|
{
|
|
Log::Comment(L"Testing command name segmentation with empty filter");
|
|
const auto filteredCommand = winrt::make_self<winrt::TerminalApp::implementation::FilteredCommand>(command);
|
|
filteredCommand->_Filter = L"";
|
|
auto segments = filteredCommand->_computeHighlightedName().Segments();
|
|
VERIFY_ARE_EQUAL(segments.Size(), 1u);
|
|
VERIFY_ARE_EQUAL(segments.GetAt(0).TextSegment(), L"AAAAAABBBBBBCCC");
|
|
VERIFY_IS_FALSE(segments.GetAt(0).IsHighlighted());
|
|
}
|
|
{
|
|
Log::Comment(L"Testing command name segmentation with filter equals to the string");
|
|
const auto filteredCommand = winrt::make_self<winrt::TerminalApp::implementation::FilteredCommand>(command);
|
|
filteredCommand->_Filter = L"AAAAAABBBBBBCCC";
|
|
auto segments = filteredCommand->_computeHighlightedName().Segments();
|
|
VERIFY_ARE_EQUAL(segments.Size(), 1u);
|
|
VERIFY_ARE_EQUAL(segments.GetAt(0).TextSegment(), L"AAAAAABBBBBBCCC");
|
|
VERIFY_IS_TRUE(segments.GetAt(0).IsHighlighted());
|
|
}
|
|
{
|
|
Log::Comment(L"Testing command name segmentation with filter with first character matching");
|
|
const auto filteredCommand = winrt::make_self<winrt::TerminalApp::implementation::FilteredCommand>(command);
|
|
filteredCommand->_Filter = L"A";
|
|
auto segments = filteredCommand->_computeHighlightedName().Segments();
|
|
VERIFY_ARE_EQUAL(segments.Size(), 2u);
|
|
VERIFY_ARE_EQUAL(segments.GetAt(0).TextSegment(), L"A");
|
|
VERIFY_IS_TRUE(segments.GetAt(0).IsHighlighted());
|
|
VERIFY_ARE_EQUAL(segments.GetAt(1).TextSegment(), L"AAAAABBBBBBCCC");
|
|
VERIFY_IS_FALSE(segments.GetAt(1).IsHighlighted());
|
|
}
|
|
{
|
|
Log::Comment(L"Testing command name segmentation with filter with other case");
|
|
const auto filteredCommand = winrt::make_self<winrt::TerminalApp::implementation::FilteredCommand>(command);
|
|
filteredCommand->_Filter = L"a";
|
|
auto segments = filteredCommand->_computeHighlightedName().Segments();
|
|
VERIFY_ARE_EQUAL(segments.Size(), 2u);
|
|
VERIFY_ARE_EQUAL(segments.GetAt(0).TextSegment(), L"A");
|
|
VERIFY_IS_TRUE(segments.GetAt(0).IsHighlighted());
|
|
VERIFY_ARE_EQUAL(segments.GetAt(1).TextSegment(), L"AAAAABBBBBBCCC");
|
|
VERIFY_IS_FALSE(segments.GetAt(1).IsHighlighted());
|
|
}
|
|
{
|
|
Log::Comment(L"Testing command name segmentation with filter matching several characters");
|
|
const auto filteredCommand = winrt::make_self<winrt::TerminalApp::implementation::FilteredCommand>(command);
|
|
filteredCommand->_Filter = L"ab";
|
|
auto segments = filteredCommand->_computeHighlightedName().Segments();
|
|
VERIFY_ARE_EQUAL(segments.Size(), 4u);
|
|
VERIFY_ARE_EQUAL(segments.GetAt(0).TextSegment(), L"A");
|
|
VERIFY_IS_TRUE(segments.GetAt(0).IsHighlighted());
|
|
VERIFY_ARE_EQUAL(segments.GetAt(1).TextSegment(), L"AAAAA");
|
|
VERIFY_IS_FALSE(segments.GetAt(1).IsHighlighted());
|
|
VERIFY_ARE_EQUAL(segments.GetAt(2).TextSegment(), L"B");
|
|
VERIFY_IS_TRUE(segments.GetAt(2).IsHighlighted());
|
|
VERIFY_ARE_EQUAL(segments.GetAt(3).TextSegment(), L"BBBBBCCC");
|
|
VERIFY_IS_FALSE(segments.GetAt(3).IsHighlighted());
|
|
}
|
|
{
|
|
Log::Comment(L"Testing command name segmentation with non matching filter");
|
|
const auto filteredCommand = winrt::make_self<winrt::TerminalApp::implementation::FilteredCommand>(command);
|
|
filteredCommand->_Filter = L"abcd";
|
|
auto segments = filteredCommand->_computeHighlightedName().Segments();
|
|
VERIFY_ARE_EQUAL(segments.Size(), 1u);
|
|
VERIFY_ARE_EQUAL(segments.GetAt(0).TextSegment(), L"AAAAAABBBBBBCCC");
|
|
VERIFY_IS_FALSE(segments.GetAt(0).IsHighlighted());
|
|
}
|
|
}
|
|
|
|
void FilteredCommandTests::VerifyWeight()
|
|
{
|
|
const std::string settingsJson{ R"(
|
|
{
|
|
"defaultProfile": "{6239a42c-0000-49a3-80bd-e8fdd045185c}",
|
|
"profiles": [
|
|
{
|
|
"name": "profile0",
|
|
"guid": "{6239a42c-0000-49a3-80bd-e8fdd045185c}",
|
|
"historySize": 1,
|
|
"commandline": "cmd.exe"
|
|
}
|
|
],
|
|
"keybindings": [
|
|
{ "keys": ["ctrl+a"], "command": { "action": "splitPane", "split": "vertical" }, "name": "AAAAAABBBBBBCCC" }
|
|
]
|
|
})" };
|
|
|
|
CascadiaSettings settings{ til::u8u16(settingsJson) };
|
|
const auto commands = settings.GlobalSettings().Commands();
|
|
VERIFY_ARE_EQUAL(1u, commands.Size());
|
|
|
|
const auto command = commands.Lookup(L"AAAAAABBBBBBCCC");
|
|
VERIFY_IS_NOT_NULL(command);
|
|
VERIFY_ARE_EQUAL(command.Name(), L"AAAAAABBBBBBCCC");
|
|
{
|
|
Log::Comment(L"Testing weight of command with no filter");
|
|
const auto filteredCommand = winrt::make_self<winrt::TerminalApp::implementation::FilteredCommand>(command);
|
|
filteredCommand->_HighlightedName = filteredCommand->_computeHighlightedName();
|
|
auto weight = filteredCommand->_computeWeight();
|
|
VERIFY_ARE_EQUAL(weight, 0);
|
|
}
|
|
{
|
|
Log::Comment(L"Testing weight of command with empty filter");
|
|
const auto filteredCommand = winrt::make_self<winrt::TerminalApp::implementation::FilteredCommand>(command);
|
|
filteredCommand->_Filter = L"";
|
|
filteredCommand->_HighlightedName = filteredCommand->_computeHighlightedName();
|
|
auto weight = filteredCommand->_computeWeight();
|
|
VERIFY_ARE_EQUAL(weight, 0);
|
|
}
|
|
{
|
|
Log::Comment(L"Testing weight of command with filter equals to the string");
|
|
const auto filteredCommand = winrt::make_self<winrt::TerminalApp::implementation::FilteredCommand>(command);
|
|
filteredCommand->_Filter = L"AAAAAABBBBBBCCC";
|
|
filteredCommand->_HighlightedName = filteredCommand->_computeHighlightedName();
|
|
auto weight = filteredCommand->_computeWeight();
|
|
VERIFY_ARE_EQUAL(weight, 30); // 1 point for the first char and 2 points for the 14 consequent ones + 1 point for the beginning of the word
|
|
}
|
|
{
|
|
Log::Comment(L"Testing weight of command with filter with first character matching");
|
|
const auto filteredCommand = winrt::make_self<winrt::TerminalApp::implementation::FilteredCommand>(command);
|
|
filteredCommand->_Filter = L"A";
|
|
filteredCommand->_HighlightedName = filteredCommand->_computeHighlightedName();
|
|
auto weight = filteredCommand->_computeWeight();
|
|
VERIFY_ARE_EQUAL(weight, 2); // 1 point for the first char match + 1 point for the beginning of the word
|
|
}
|
|
{
|
|
Log::Comment(L"Testing weight of command with filter with other case");
|
|
const auto filteredCommand = winrt::make_self<winrt::TerminalApp::implementation::FilteredCommand>(command);
|
|
filteredCommand->_Filter = L"a";
|
|
filteredCommand->_HighlightedName = filteredCommand->_computeHighlightedName();
|
|
auto weight = filteredCommand->_computeWeight();
|
|
VERIFY_ARE_EQUAL(weight, 2); // 1 point for the first char match + 1 point for the beginning of the word
|
|
}
|
|
{
|
|
Log::Comment(L"Testing weight of command with filter matching several characters");
|
|
const auto filteredCommand = winrt::make_self<winrt::TerminalApp::implementation::FilteredCommand>(command);
|
|
filteredCommand->_Filter = L"ab";
|
|
filteredCommand->_HighlightedName = filteredCommand->_computeHighlightedName();
|
|
auto weight = filteredCommand->_computeWeight();
|
|
VERIFY_ARE_EQUAL(weight, 3); // 1 point for the first char match + 1 point for the beginning of the word + 1 point for the match of "b"
|
|
}
|
|
}
|
|
|
|
void FilteredCommandTests::VerifyCompare()
|
|
{
|
|
const std::string settingsJson{ R"(
|
|
{
|
|
"defaultProfile": "{6239a42c-0000-49a3-80bd-e8fdd045185c}",
|
|
"profiles": [
|
|
{
|
|
"name": "profile0",
|
|
"guid": "{6239a42c-0000-49a3-80bd-e8fdd045185c}",
|
|
"historySize": 1,
|
|
"commandline": "cmd.exe"
|
|
}
|
|
],
|
|
"keybindings": [
|
|
{ "keys": ["ctrl+a"], "command": { "action": "splitPane", "split": "vertical" }, "name": "AAAAAABBBBBBCCC" },
|
|
{ "keys": ["ctrl+b"], "command": { "action": "splitPane", "split": "horizontal" }, "name": "BBBBBCCC" }
|
|
]
|
|
})" };
|
|
|
|
CascadiaSettings settings{ til::u8u16(settingsJson) };
|
|
const auto commands = settings.GlobalSettings().Commands();
|
|
VERIFY_ARE_EQUAL(2u, commands.Size());
|
|
|
|
const auto command = commands.Lookup(L"AAAAAABBBBBBCCC");
|
|
VERIFY_IS_NOT_NULL(command);
|
|
VERIFY_ARE_EQUAL(command.Name(), L"AAAAAABBBBBBCCC");
|
|
|
|
const auto command2 = commands.Lookup(L"BBBBBCCC");
|
|
VERIFY_IS_NOT_NULL(command2);
|
|
VERIFY_ARE_EQUAL(command2.Name(), L"BBBBBCCC");
|
|
{
|
|
Log::Comment(L"Testing comparison of commands with no filter");
|
|
const auto filteredCommand = winrt::make_self<winrt::TerminalApp::implementation::FilteredCommand>(command);
|
|
const auto filteredCommand2 = winrt::make_self<winrt::TerminalApp::implementation::FilteredCommand>(command2);
|
|
|
|
VERIFY_ARE_EQUAL(filteredCommand->Weight(), filteredCommand2->Weight());
|
|
VERIFY_IS_TRUE(winrt::TerminalApp::implementation::FilteredCommand::Compare(*filteredCommand, *filteredCommand2));
|
|
}
|
|
{
|
|
Log::Comment(L"Testing comparison of commands with empty filter");
|
|
const auto filteredCommand = winrt::make_self<winrt::TerminalApp::implementation::FilteredCommand>(command);
|
|
filteredCommand->_Filter = L"";
|
|
filteredCommand->_HighlightedName = filteredCommand->_computeHighlightedName();
|
|
filteredCommand->_Weight = filteredCommand->_computeWeight();
|
|
|
|
const auto filteredCommand2 = winrt::make_self<winrt::TerminalApp::implementation::FilteredCommand>(command2);
|
|
filteredCommand2->_Filter = L"";
|
|
filteredCommand2->_HighlightedName = filteredCommand2->_computeHighlightedName();
|
|
filteredCommand2->_Weight = filteredCommand2->_computeWeight();
|
|
|
|
VERIFY_ARE_EQUAL(filteredCommand->Weight(), filteredCommand2->Weight());
|
|
VERIFY_IS_TRUE(winrt::TerminalApp::implementation::FilteredCommand::Compare(*filteredCommand, *filteredCommand2));
|
|
}
|
|
{
|
|
Log::Comment(L"Testing comparison of commands with different weights");
|
|
const auto filteredCommand = winrt::make_self<winrt::TerminalApp::implementation::FilteredCommand>(command);
|
|
filteredCommand->_Filter = L"B";
|
|
filteredCommand->_HighlightedName = filteredCommand->_computeHighlightedName();
|
|
filteredCommand->_Weight = filteredCommand->_computeWeight();
|
|
|
|
const auto filteredCommand2 = winrt::make_self<winrt::TerminalApp::implementation::FilteredCommand>(command2);
|
|
filteredCommand2->_Filter = L"B";
|
|
filteredCommand2->_HighlightedName = filteredCommand2->_computeHighlightedName();
|
|
filteredCommand2->_Weight = filteredCommand2->_computeWeight();
|
|
|
|
VERIFY_IS_TRUE(filteredCommand->Weight() < filteredCommand2->Weight()); // Second command gets more points due to the beginning of the word
|
|
VERIFY_IS_FALSE(winrt::TerminalApp::implementation::FilteredCommand::Compare(*filteredCommand, *filteredCommand2));
|
|
}
|
|
}
|
|
}
|