terminal/src/cascadia/LocalTests_TerminalApp/SettingsTests.cpp
Leonard Hecker 0b552e1ae8
Fix failing TestHostApp unit tests (#11394)
This commit fixes various failing TestHostApp unit tests.
Most of these broke as part of 168d28b (#11184).

## PR Checklist
* [x] Closes #11339
* [x] I work here
* [x] Tests added/passed
2021-10-05 18:21:03 +00:00

1271 lines
58 KiB
C++

// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
#include "pch.h"
#include "../TerminalApp/TerminalPage.h"
#include "../LocalTests_SettingsModel/TestUtils.h"
using namespace Microsoft::Console;
using namespace WEX::Logging;
using namespace WEX::TestExecution;
using namespace WEX::Common;
using namespace winrt::TerminalApp;
using namespace winrt::Microsoft::Terminal::Settings::Model;
using namespace winrt::Microsoft::Terminal::Control;
namespace TerminalAppLocalTests
{
static constexpr std::wstring_view inboxSettings{ LR"({
"schemes": [{
"name": "Campbell",
"foreground": "#CCCCCC",
"background": "#0C0C0C",
"cursorColor": "#FFFFFF",
"black": "#0C0C0C",
"red": "#C50F1F",
"green": "#13A10E",
"yellow": "#C19C00",
"blue": "#0037DA",
"purple": "#881798",
"cyan": "#3A96DD",
"white": "#CCCCCC",
"brightBlack": "#767676",
"brightRed": "#E74856",
"brightGreen": "#16C60C",
"brightYellow": "#F9F1A5",
"brightBlue": "#3B78FF",
"brightPurple": "#B4009E",
"brightCyan": "#61D6D6",
"brightWhite": "#F2F2F2"
}]
})" };
// TODO:microsoft/terminal#3838:
// Unfortunately, these tests _WILL NOT_ work in our CI. We're waiting for
// an updated TAEF that will let us install framework packages when the test
// package is deployed. Until then, these tests won't deploy in CI.
class SettingsTests
{
// Use a custom AppxManifest to ensure that we can activate winrt types
// from our test. This property will tell taef to manually use this as
// the AppxManifest for this test class.
// This does not yet work for anything XAML-y. See TabTests.cpp for more
// details on that.
BEGIN_TEST_CLASS(SettingsTests)
TEST_CLASS_PROPERTY(L"RunAs", L"UAP")
TEST_CLASS_PROPERTY(L"UAP:AppXManifest", L"TestHostAppXManifest.xml")
END_TEST_CLASS()
TEST_METHOD(TestIterateCommands);
TEST_METHOD(TestIterateOnGeneratedNamedCommands);
TEST_METHOD(TestIterateOnBadJson);
TEST_METHOD(TestNestedCommands);
TEST_METHOD(TestNestedInNestedCommand);
TEST_METHOD(TestNestedInIterableCommand);
TEST_METHOD(TestIterableInNestedCommand);
TEST_METHOD(TestMixedNestedAndIterableCommand);
TEST_METHOD(TestIterableColorSchemeCommands);
TEST_CLASS_SETUP(ClassSetup)
{
return true;
}
private:
void _logCommandNames(winrt::Windows::Foundation::Collections::IMapView<winrt::hstring, Command> commands, const int indentation = 1)
{
if (indentation == 1)
{
Log::Comment((commands.Size() == 0) ? L"Commands:\n <none>" : L"Commands:");
}
for (const auto& nameAndCommand : commands)
{
Log::Comment(fmt::format(L"{0:>{1}}* {2}->{3}",
L"",
indentation,
nameAndCommand.Key(),
nameAndCommand.Value().Name())
.c_str());
if (nameAndCommand.Value().HasNestedCommands())
{
_logCommandNames(nameAndCommand.Value().NestedCommands(), indentation + 2);
}
}
}
};
void SettingsTests::TestIterateCommands()
{
// For this test, put an iterable command with a given `name`,
// containing a ${profile.name} to replace. When we expand it, it should
// have created one command for each profile.
static constexpr std::wstring_view settingsJson{ LR"(
{
"defaultProfile": "{6239a42c-0000-49a3-80bd-e8fdd045185c}",
"profiles": [
{
"name": "profile0",
"guid": "{6239a42c-0000-49a3-80bd-e8fdd045185c}",
"historySize": 1,
"commandline": "cmd.exe"
},
{
"name": "profile1",
"guid": "{6239a42c-1111-49a3-80bd-e8fdd045185c}",
"historySize": 2,
"commandline": "pwsh.exe"
},
{
"name": "profile2",
"historySize": 3,
"commandline": "wsl.exe"
}
],
"actions": [
{
"name": "iterable command ${profile.name}",
"iterateOn": "profiles",
"command": { "action": "splitPane", "profile": "${profile.name}" }
},
]
})" };
CascadiaSettings settings{ settingsJson, inboxSettings };
VERIFY_ARE_EQUAL(0u, settings.Warnings().Size());
VERIFY_ARE_EQUAL(3u, settings.ActiveProfiles().Size());
auto nameMap{ settings.ActionMap().NameMap() };
VERIFY_ARE_EQUAL(1u, nameMap.Size());
{
auto command = nameMap.TryLookup(L"iterable command ${profile.name}");
VERIFY_IS_NOT_NULL(command);
auto actionAndArgs = command.ActionAndArgs();
VERIFY_IS_NOT_NULL(actionAndArgs);
VERIFY_ARE_EQUAL(ShortcutAction::SplitPane, actionAndArgs.Action());
const auto& realArgs = actionAndArgs.Args().try_as<SplitPaneArgs>();
VERIFY_IS_NOT_NULL(realArgs);
// Verify the args have the expected value
VERIFY_ARE_EQUAL(SplitDirection::Automatic, realArgs.SplitDirection());
VERIFY_IS_NOT_NULL(realArgs.TerminalArgs());
VERIFY_IS_TRUE(realArgs.TerminalArgs().Commandline().empty());
VERIFY_IS_TRUE(realArgs.TerminalArgs().StartingDirectory().empty());
VERIFY_IS_TRUE(realArgs.TerminalArgs().TabTitle().empty());
VERIFY_IS_FALSE(realArgs.TerminalArgs().Profile().empty());
VERIFY_ARE_EQUAL(L"${profile.name}", realArgs.TerminalArgs().Profile());
}
auto expandedCommands = winrt::TerminalApp::implementation::TerminalPage::_ExpandCommands(nameMap, settings.ActiveProfiles().GetView(), settings.GlobalSettings().ColorSchemes());
_logCommandNames(expandedCommands.GetView());
VERIFY_ARE_EQUAL(0u, settings.Warnings().Size());
VERIFY_ARE_EQUAL(3u, expandedCommands.Size());
{
auto command = expandedCommands.Lookup(L"iterable command profile0");
VERIFY_IS_NOT_NULL(command);
auto actionAndArgs = command.ActionAndArgs();
VERIFY_IS_NOT_NULL(actionAndArgs);
VERIFY_ARE_EQUAL(ShortcutAction::SplitPane, actionAndArgs.Action());
const auto& realArgs = actionAndArgs.Args().try_as<SplitPaneArgs>();
VERIFY_IS_NOT_NULL(realArgs);
// Verify the args have the expected value
VERIFY_ARE_EQUAL(SplitDirection::Automatic, realArgs.SplitDirection());
VERIFY_IS_NOT_NULL(realArgs.TerminalArgs());
VERIFY_IS_TRUE(realArgs.TerminalArgs().Commandline().empty());
VERIFY_IS_TRUE(realArgs.TerminalArgs().StartingDirectory().empty());
VERIFY_IS_TRUE(realArgs.TerminalArgs().TabTitle().empty());
VERIFY_IS_FALSE(realArgs.TerminalArgs().Profile().empty());
VERIFY_ARE_EQUAL(L"profile0", realArgs.TerminalArgs().Profile());
}
{
auto command = expandedCommands.Lookup(L"iterable command profile1");
VERIFY_IS_NOT_NULL(command);
auto actionAndArgs = command.ActionAndArgs();
VERIFY_IS_NOT_NULL(actionAndArgs);
VERIFY_ARE_EQUAL(ShortcutAction::SplitPane, actionAndArgs.Action());
const auto& realArgs = actionAndArgs.Args().try_as<SplitPaneArgs>();
VERIFY_IS_NOT_NULL(realArgs);
// Verify the args have the expected value
VERIFY_ARE_EQUAL(SplitDirection::Automatic, realArgs.SplitDirection());
VERIFY_IS_NOT_NULL(realArgs.TerminalArgs());
VERIFY_IS_TRUE(realArgs.TerminalArgs().Commandline().empty());
VERIFY_IS_TRUE(realArgs.TerminalArgs().StartingDirectory().empty());
VERIFY_IS_TRUE(realArgs.TerminalArgs().TabTitle().empty());
VERIFY_IS_FALSE(realArgs.TerminalArgs().Profile().empty());
VERIFY_ARE_EQUAL(L"profile1", realArgs.TerminalArgs().Profile());
}
{
auto command = expandedCommands.Lookup(L"iterable command profile2");
VERIFY_IS_NOT_NULL(command);
auto actionAndArgs = command.ActionAndArgs();
VERIFY_IS_NOT_NULL(actionAndArgs);
VERIFY_ARE_EQUAL(ShortcutAction::SplitPane, actionAndArgs.Action());
const auto& realArgs = actionAndArgs.Args().try_as<SplitPaneArgs>();
VERIFY_IS_NOT_NULL(realArgs);
// Verify the args have the expected value
VERIFY_ARE_EQUAL(SplitDirection::Automatic, realArgs.SplitDirection());
VERIFY_IS_NOT_NULL(realArgs.TerminalArgs());
VERIFY_IS_TRUE(realArgs.TerminalArgs().Commandline().empty());
VERIFY_IS_TRUE(realArgs.TerminalArgs().StartingDirectory().empty());
VERIFY_IS_TRUE(realArgs.TerminalArgs().TabTitle().empty());
VERIFY_IS_FALSE(realArgs.TerminalArgs().Profile().empty());
VERIFY_ARE_EQUAL(L"profile2", realArgs.TerminalArgs().Profile());
}
}
void SettingsTests::TestIterateOnGeneratedNamedCommands()
{
// For this test, put an iterable command without a given `name` to
// replace. When we expand it, it should still work.
static constexpr std::wstring_view settingsJson{ LR"(
{
"defaultProfile": "{6239a42c-0000-49a3-80bd-e8fdd045185c}",
"profiles": [
{
"name": "profile0",
"guid": "{6239a42c-0000-49a3-80bd-e8fdd045185c}",
"historySize": 1,
"commandline": "cmd.exe"
},
{
"name": "profile1",
"guid": "{6239a42c-1111-49a3-80bd-e8fdd045185c}",
"historySize": 2,
"commandline": "pwsh.exe"
},
{
"name": "profile2",
"historySize": 3,
"commandline": "wsl.exe"
}
],
"actions": [
{
"iterateOn": "profiles",
"command": { "action": "splitPane", "profile": "${profile.name}" }
},
]
})" };
CascadiaSettings settings{ settingsJson, inboxSettings };
VERIFY_ARE_EQUAL(0u, settings.Warnings().Size());
VERIFY_ARE_EQUAL(3u, settings.ActiveProfiles().Size());
auto nameMap{ settings.ActionMap().NameMap() };
VERIFY_ARE_EQUAL(1u, nameMap.Size());
{
auto command = nameMap.TryLookup(L"Split pane, profile: ${profile.name}");
VERIFY_IS_NOT_NULL(command);
auto actionAndArgs = command.ActionAndArgs();
VERIFY_IS_NOT_NULL(actionAndArgs);
VERIFY_ARE_EQUAL(ShortcutAction::SplitPane, actionAndArgs.Action());
const auto& realArgs = actionAndArgs.Args().try_as<SplitPaneArgs>();
VERIFY_IS_NOT_NULL(realArgs);
// Verify the args have the expected value
VERIFY_ARE_EQUAL(SplitDirection::Automatic, realArgs.SplitDirection());
VERIFY_IS_NOT_NULL(realArgs.TerminalArgs());
VERIFY_IS_TRUE(realArgs.TerminalArgs().Commandline().empty());
VERIFY_IS_TRUE(realArgs.TerminalArgs().StartingDirectory().empty());
VERIFY_IS_TRUE(realArgs.TerminalArgs().TabTitle().empty());
VERIFY_IS_FALSE(realArgs.TerminalArgs().Profile().empty());
VERIFY_ARE_EQUAL(L"${profile.name}", realArgs.TerminalArgs().Profile());
}
auto expandedCommands = winrt::TerminalApp::implementation::TerminalPage::_ExpandCommands(nameMap, settings.ActiveProfiles().GetView(), settings.GlobalSettings().ColorSchemes());
_logCommandNames(expandedCommands.GetView());
VERIFY_ARE_EQUAL(0u, settings.Warnings().Size());
VERIFY_ARE_EQUAL(3u, expandedCommands.Size());
{
auto command = expandedCommands.Lookup(L"Split pane, profile: profile0");
VERIFY_IS_NOT_NULL(command);
auto actionAndArgs = command.ActionAndArgs();
VERIFY_IS_NOT_NULL(actionAndArgs);
VERIFY_ARE_EQUAL(ShortcutAction::SplitPane, actionAndArgs.Action());
const auto& realArgs = actionAndArgs.Args().try_as<SplitPaneArgs>();
VERIFY_IS_NOT_NULL(realArgs);
// Verify the args have the expected value
VERIFY_ARE_EQUAL(SplitDirection::Automatic, realArgs.SplitDirection());
VERIFY_IS_NOT_NULL(realArgs.TerminalArgs());
VERIFY_IS_TRUE(realArgs.TerminalArgs().Commandline().empty());
VERIFY_IS_TRUE(realArgs.TerminalArgs().StartingDirectory().empty());
VERIFY_IS_TRUE(realArgs.TerminalArgs().TabTitle().empty());
VERIFY_IS_FALSE(realArgs.TerminalArgs().Profile().empty());
VERIFY_ARE_EQUAL(L"profile0", realArgs.TerminalArgs().Profile());
}
{
auto command = expandedCommands.Lookup(L"Split pane, profile: profile1");
VERIFY_IS_NOT_NULL(command);
auto actionAndArgs = command.ActionAndArgs();
VERIFY_IS_NOT_NULL(actionAndArgs);
VERIFY_ARE_EQUAL(ShortcutAction::SplitPane, actionAndArgs.Action());
const auto& realArgs = actionAndArgs.Args().try_as<SplitPaneArgs>();
VERIFY_IS_NOT_NULL(realArgs);
// Verify the args have the expected value
VERIFY_ARE_EQUAL(SplitDirection::Automatic, realArgs.SplitDirection());
VERIFY_IS_NOT_NULL(realArgs.TerminalArgs());
VERIFY_IS_TRUE(realArgs.TerminalArgs().Commandline().empty());
VERIFY_IS_TRUE(realArgs.TerminalArgs().StartingDirectory().empty());
VERIFY_IS_TRUE(realArgs.TerminalArgs().TabTitle().empty());
VERIFY_IS_FALSE(realArgs.TerminalArgs().Profile().empty());
VERIFY_ARE_EQUAL(L"profile1", realArgs.TerminalArgs().Profile());
}
{
auto command = expandedCommands.Lookup(L"Split pane, profile: profile2");
VERIFY_IS_NOT_NULL(command);
auto actionAndArgs = command.ActionAndArgs();
VERIFY_IS_NOT_NULL(actionAndArgs);
VERIFY_ARE_EQUAL(ShortcutAction::SplitPane, actionAndArgs.Action());
const auto& realArgs = actionAndArgs.Args().try_as<SplitPaneArgs>();
VERIFY_IS_NOT_NULL(realArgs);
// Verify the args have the expected value
VERIFY_ARE_EQUAL(SplitDirection::Automatic, realArgs.SplitDirection());
VERIFY_IS_NOT_NULL(realArgs.TerminalArgs());
VERIFY_IS_TRUE(realArgs.TerminalArgs().Commandline().empty());
VERIFY_IS_TRUE(realArgs.TerminalArgs().StartingDirectory().empty());
VERIFY_IS_TRUE(realArgs.TerminalArgs().TabTitle().empty());
VERIFY_IS_FALSE(realArgs.TerminalArgs().Profile().empty());
VERIFY_ARE_EQUAL(L"profile2", realArgs.TerminalArgs().Profile());
}
}
void SettingsTests::TestIterateOnBadJson()
{
// For this test, put an iterable command with a profile name that would
// cause bad json to be filled in. Something like a profile with a name
// of "Foo\"", so the trailing '"' might break the json parsing.
static constexpr std::wstring_view settingsJson{ LR"(
{
"defaultProfile": "{6239a42c-0000-49a3-80bd-e8fdd045185c}",
"profiles": [
{
"name": "profile0",
"guid": "{6239a42c-0000-49a3-80bd-e8fdd045185c}",
"historySize": 1,
"commandline": "cmd.exe"
},
{
"name": "profile1\"",
"guid": "{6239a42c-1111-49a3-80bd-e8fdd045185c}",
"historySize": 2,
"commandline": "pwsh.exe"
},
{
"name": "profile2",
"historySize": 3,
"commandline": "wsl.exe"
}
],
"actions": [
{
"name": "iterable command ${profile.name}",
"iterateOn": "profiles",
"command": { "action": "splitPane", "profile": "${profile.name}" }
},
]
})" };
CascadiaSettings settings{ settingsJson, inboxSettings };
VERIFY_ARE_EQUAL(0u, settings.Warnings().Size());
VERIFY_ARE_EQUAL(3u, settings.ActiveProfiles().Size());
auto nameMap{ settings.ActionMap().NameMap() };
VERIFY_ARE_EQUAL(1u, nameMap.Size());
{
auto command = nameMap.TryLookup(L"iterable command ${profile.name}");
VERIFY_IS_NOT_NULL(command);
auto actionAndArgs = command.ActionAndArgs();
VERIFY_IS_NOT_NULL(actionAndArgs);
VERIFY_ARE_EQUAL(ShortcutAction::SplitPane, actionAndArgs.Action());
const auto& realArgs = actionAndArgs.Args().try_as<SplitPaneArgs>();
VERIFY_IS_NOT_NULL(realArgs);
// Verify the args have the expected value
VERIFY_ARE_EQUAL(SplitDirection::Automatic, realArgs.SplitDirection());
VERIFY_IS_NOT_NULL(realArgs.TerminalArgs());
VERIFY_IS_TRUE(realArgs.TerminalArgs().Commandline().empty());
VERIFY_IS_TRUE(realArgs.TerminalArgs().StartingDirectory().empty());
VERIFY_IS_TRUE(realArgs.TerminalArgs().TabTitle().empty());
VERIFY_IS_FALSE(realArgs.TerminalArgs().Profile().empty());
VERIFY_ARE_EQUAL(L"${profile.name}", realArgs.TerminalArgs().Profile());
}
auto expandedCommands = winrt::TerminalApp::implementation::TerminalPage::_ExpandCommands(nameMap, settings.ActiveProfiles().GetView(), settings.GlobalSettings().ColorSchemes());
_logCommandNames(expandedCommands.GetView());
VERIFY_ARE_EQUAL(0u, settings.Warnings().Size());
VERIFY_ARE_EQUAL(3u, expandedCommands.Size());
{
auto command = expandedCommands.Lookup(L"iterable command profile0");
VERIFY_IS_NOT_NULL(command);
auto actionAndArgs = command.ActionAndArgs();
VERIFY_IS_NOT_NULL(actionAndArgs);
VERIFY_ARE_EQUAL(ShortcutAction::SplitPane, actionAndArgs.Action());
const auto& realArgs = actionAndArgs.Args().try_as<SplitPaneArgs>();
VERIFY_IS_NOT_NULL(realArgs);
// Verify the args have the expected value
VERIFY_ARE_EQUAL(SplitDirection::Automatic, realArgs.SplitDirection());
VERIFY_IS_NOT_NULL(realArgs.TerminalArgs());
VERIFY_IS_TRUE(realArgs.TerminalArgs().Commandline().empty());
VERIFY_IS_TRUE(realArgs.TerminalArgs().StartingDirectory().empty());
VERIFY_IS_TRUE(realArgs.TerminalArgs().TabTitle().empty());
VERIFY_IS_FALSE(realArgs.TerminalArgs().Profile().empty());
VERIFY_ARE_EQUAL(L"profile0", realArgs.TerminalArgs().Profile());
}
{
auto command = expandedCommands.Lookup(L"iterable command profile1\"");
VERIFY_IS_NOT_NULL(command);
auto actionAndArgs = command.ActionAndArgs();
VERIFY_IS_NOT_NULL(actionAndArgs);
VERIFY_ARE_EQUAL(ShortcutAction::SplitPane, actionAndArgs.Action());
const auto& realArgs = actionAndArgs.Args().try_as<SplitPaneArgs>();
VERIFY_IS_NOT_NULL(realArgs);
// Verify the args have the expected value
VERIFY_ARE_EQUAL(SplitDirection::Automatic, realArgs.SplitDirection());
VERIFY_IS_NOT_NULL(realArgs.TerminalArgs());
VERIFY_IS_TRUE(realArgs.TerminalArgs().Commandline().empty());
VERIFY_IS_TRUE(realArgs.TerminalArgs().StartingDirectory().empty());
VERIFY_IS_TRUE(realArgs.TerminalArgs().TabTitle().empty());
VERIFY_IS_FALSE(realArgs.TerminalArgs().Profile().empty());
VERIFY_ARE_EQUAL(L"profile1\"", realArgs.TerminalArgs().Profile());
}
{
auto command = expandedCommands.Lookup(L"iterable command profile2");
VERIFY_IS_NOT_NULL(command);
auto actionAndArgs = command.ActionAndArgs();
VERIFY_IS_NOT_NULL(actionAndArgs);
VERIFY_ARE_EQUAL(ShortcutAction::SplitPane, actionAndArgs.Action());
const auto& realArgs = actionAndArgs.Args().try_as<SplitPaneArgs>();
VERIFY_IS_NOT_NULL(realArgs);
// Verify the args have the expected value
VERIFY_ARE_EQUAL(SplitDirection::Automatic, realArgs.SplitDirection());
VERIFY_IS_NOT_NULL(realArgs.TerminalArgs());
VERIFY_IS_TRUE(realArgs.TerminalArgs().Commandline().empty());
VERIFY_IS_TRUE(realArgs.TerminalArgs().StartingDirectory().empty());
VERIFY_IS_TRUE(realArgs.TerminalArgs().TabTitle().empty());
VERIFY_IS_FALSE(realArgs.TerminalArgs().Profile().empty());
VERIFY_ARE_EQUAL(L"profile2", realArgs.TerminalArgs().Profile());
}
}
void SettingsTests::TestNestedCommands()
{
// This test checks a nested command.
// The commands should look like:
//
// <Command Palette>
// └─ Connect to ssh...
// ├─ first.com
// └─ second.com
static constexpr std::wstring_view settingsJson{ LR"(
{
"defaultProfile": "{6239a42c-0000-49a3-80bd-e8fdd045185c}",
"profiles": [
{
"name": "profile0",
"guid": "{6239a42c-0000-49a3-80bd-e8fdd045185c}",
"historySize": 1,
"commandline": "cmd.exe"
},
{
"name": "profile1",
"guid": "{6239a42c-1111-49a3-80bd-e8fdd045185c}",
"historySize": 2,
"commandline": "pwsh.exe"
},
{
"name": "profile2",
"historySize": 3,
"commandline": "wsl.exe"
}
],
"actions": [
{
"name": "Connect to ssh...",
"commands": [
{
"name": "first.com",
"command": { "action": "newTab", "commandline": "ssh me@first.com" }
},
{
"name": "second.com",
"command": { "action": "newTab", "commandline": "ssh me@second.com" }
}
]
},
]
})" };
CascadiaSettings settings{ settingsJson, inboxSettings };
VERIFY_ARE_EQUAL(0u, settings.Warnings().Size());
VERIFY_ARE_EQUAL(3u, settings.ActiveProfiles().Size());
auto expandedCommands = winrt::TerminalApp::implementation::TerminalPage::_ExpandCommands(settings.ActionMap().NameMap(), settings.ActiveProfiles().GetView(), settings.GlobalSettings().ColorSchemes());
_logCommandNames(expandedCommands.GetView());
VERIFY_ARE_EQUAL(0u, settings.Warnings().Size());
VERIFY_ARE_EQUAL(1u, expandedCommands.Size());
auto rootCommand = expandedCommands.Lookup(L"Connect to ssh...");
VERIFY_IS_NOT_NULL(rootCommand);
auto rootActionAndArgs = rootCommand.ActionAndArgs();
VERIFY_IS_NOT_NULL(rootActionAndArgs);
VERIFY_ARE_EQUAL(ShortcutAction::Invalid, rootActionAndArgs.Action());
VERIFY_ARE_EQUAL(2u, rootCommand.NestedCommands().Size());
{
winrt::hstring commandName{ L"first.com" };
auto command = rootCommand.NestedCommands().Lookup(commandName);
VERIFY_IS_NOT_NULL(command);
auto actionAndArgs = command.ActionAndArgs();
VERIFY_IS_NOT_NULL(actionAndArgs);
VERIFY_IS_FALSE(command.HasNestedCommands());
}
{
winrt::hstring commandName{ L"second.com" };
auto command = rootCommand.NestedCommands().Lookup(commandName);
VERIFY_IS_NOT_NULL(command);
auto actionAndArgs = command.ActionAndArgs();
VERIFY_IS_NOT_NULL(actionAndArgs);
VERIFY_IS_FALSE(command.HasNestedCommands());
}
}
void SettingsTests::TestNestedInNestedCommand()
{
// This test checks a nested command that includes nested commands.
// The commands should look like:
//
// <Command Palette>
// └─ grandparent
// └─ parent
// ├─ child1
// └─ child2
static constexpr std::wstring_view settingsJson{ LR"(
{
"defaultProfile": "{6239a42c-0000-49a3-80bd-e8fdd045185c}",
"profiles": [
{
"name": "profile0",
"guid": "{6239a42c-0000-49a3-80bd-e8fdd045185c}",
"historySize": 1,
"commandline": "cmd.exe"
},
{
"name": "profile1",
"guid": "{6239a42c-1111-49a3-80bd-e8fdd045185c}",
"historySize": 2,
"commandline": "pwsh.exe"
},
{
"name": "profile2",
"historySize": 3,
"commandline": "wsl.exe"
}
],
"actions": [
{
"name": "grandparent",
"commands": [
{
"name": "parent",
"commands": [
{
"name": "child1",
"command": { "action": "newTab", "commandline": "ssh me@first.com" }
},
{
"name": "child2",
"command": { "action": "newTab", "commandline": "ssh me@second.com" }
}
]
},
]
},
]
})" };
CascadiaSettings settings{ settingsJson, inboxSettings };
VERIFY_ARE_EQUAL(0u, settings.Warnings().Size());
VERIFY_ARE_EQUAL(3u, settings.ActiveProfiles().Size());
auto expandedCommands = winrt::TerminalApp::implementation::TerminalPage::_ExpandCommands(settings.ActionMap().NameMap(), settings.ActiveProfiles().GetView(), settings.GlobalSettings().ColorSchemes());
_logCommandNames(expandedCommands.GetView());
VERIFY_ARE_EQUAL(0u, settings.Warnings().Size());
VERIFY_ARE_EQUAL(1u, expandedCommands.Size());
auto grandparentCommand = expandedCommands.Lookup(L"grandparent");
VERIFY_IS_NOT_NULL(grandparentCommand);
auto grandparentActionAndArgs = grandparentCommand.ActionAndArgs();
VERIFY_IS_NOT_NULL(grandparentActionAndArgs);
VERIFY_ARE_EQUAL(ShortcutAction::Invalid, grandparentActionAndArgs.Action());
VERIFY_ARE_EQUAL(1u, grandparentCommand.NestedCommands().Size());
winrt::hstring parentName{ L"parent" };
auto parent = grandparentCommand.NestedCommands().Lookup(parentName);
VERIFY_IS_NOT_NULL(parent);
auto parentActionAndArgs = parent.ActionAndArgs();
VERIFY_IS_NOT_NULL(parentActionAndArgs);
VERIFY_ARE_EQUAL(ShortcutAction::Invalid, parentActionAndArgs.Action());
VERIFY_ARE_EQUAL(2u, parent.NestedCommands().Size());
{
winrt::hstring childName{ L"child1" };
auto child = parent.NestedCommands().Lookup(childName);
VERIFY_IS_NOT_NULL(child);
auto childActionAndArgs = child.ActionAndArgs();
VERIFY_IS_NOT_NULL(childActionAndArgs);
VERIFY_ARE_EQUAL(ShortcutAction::NewTab, childActionAndArgs.Action());
const auto& realArgs = childActionAndArgs.Args().try_as<NewTabArgs>();
VERIFY_IS_NOT_NULL(realArgs);
// Verify the args have the expected value
VERIFY_IS_NOT_NULL(realArgs.TerminalArgs());
VERIFY_IS_FALSE(realArgs.TerminalArgs().Commandline().empty());
VERIFY_IS_TRUE(realArgs.TerminalArgs().StartingDirectory().empty());
VERIFY_IS_TRUE(realArgs.TerminalArgs().TabTitle().empty());
VERIFY_IS_TRUE(realArgs.TerminalArgs().Profile().empty());
VERIFY_ARE_EQUAL(L"ssh me@first.com", realArgs.TerminalArgs().Commandline());
VERIFY_IS_FALSE(child.HasNestedCommands());
}
{
winrt::hstring childName{ L"child2" };
auto child = parent.NestedCommands().Lookup(childName);
VERIFY_IS_NOT_NULL(child);
auto childActionAndArgs = child.ActionAndArgs();
VERIFY_IS_NOT_NULL(childActionAndArgs);
VERIFY_ARE_EQUAL(ShortcutAction::NewTab, childActionAndArgs.Action());
const auto& realArgs = childActionAndArgs.Args().try_as<NewTabArgs>();
VERIFY_IS_NOT_NULL(realArgs);
// Verify the args have the expected value
VERIFY_IS_NOT_NULL(realArgs.TerminalArgs());
VERIFY_IS_FALSE(realArgs.TerminalArgs().Commandline().empty());
VERIFY_IS_TRUE(realArgs.TerminalArgs().StartingDirectory().empty());
VERIFY_IS_TRUE(realArgs.TerminalArgs().TabTitle().empty());
VERIFY_IS_TRUE(realArgs.TerminalArgs().Profile().empty());
VERIFY_ARE_EQUAL(L"ssh me@second.com", realArgs.TerminalArgs().Commandline());
VERIFY_IS_FALSE(child.HasNestedCommands());
}
}
void SettingsTests::TestNestedInIterableCommand()
{
// This test checks a iterable command that includes a nested command.
// The commands should look like:
//
// <Command Palette>
// ├─ profile0...
// | ├─ Split pane, profile: profile0
// | ├─ Split pane, direction: right, profile: profile0
// | └─ Split pane, direction: down, profile: profile0
// ├─ profile1...
// | ├─Split pane, profile: profile1
// | ├─Split pane, direction: right, profile: profile1
// | └─Split pane, direction: down, profile: profile1
// └─ profile2...
// ├─ Split pane, profile: profile2
// ├─ Split pane, direction: right, profile: profile2
// └─ Split pane, direction: down, profile: profile2
static constexpr std::wstring_view settingsJson{ LR"(
{
"defaultProfile": "{6239a42c-0000-49a3-80bd-e8fdd045185c}",
"profiles": [
{
"name": "profile0",
"guid": "{6239a42c-0000-49a3-80bd-e8fdd045185c}",
"historySize": 1,
"commandline": "cmd.exe"
},
{
"name": "profile1",
"guid": "{6239a42c-1111-49a3-80bd-e8fdd045185c}",
"historySize": 2,
"commandline": "pwsh.exe"
},
{
"name": "profile2",
"historySize": 3,
"commandline": "wsl.exe"
}
],
"actions": [
{
"iterateOn": "profiles",
"name": "${profile.name}...",
"commands": [
{ "command": { "action": "splitPane", "profile": "${profile.name}", "split": "auto" } },
{ "command": { "action": "splitPane", "profile": "${profile.name}", "split": "right" } },
{ "command": { "action": "splitPane", "profile": "${profile.name}", "split": "down" } }
]
}
]
})" };
CascadiaSettings settings{ settingsJson, inboxSettings };
VERIFY_ARE_EQUAL(0u, settings.Warnings().Size());
VERIFY_ARE_EQUAL(3u, settings.ActiveProfiles().Size());
auto expandedCommands = winrt::TerminalApp::implementation::TerminalPage::_ExpandCommands(settings.ActionMap().NameMap(), settings.ActiveProfiles().GetView(), settings.GlobalSettings().ColorSchemes());
_logCommandNames(expandedCommands.GetView());
VERIFY_ARE_EQUAL(0u, settings.Warnings().Size());
VERIFY_ARE_EQUAL(3u, expandedCommands.Size());
for (auto name : std::vector<std::wstring>({ L"profile0", L"profile1", L"profile2" }))
{
winrt::hstring commandName{ name + L"..." };
auto command = expandedCommands.Lookup(commandName);
VERIFY_IS_NOT_NULL(command);
auto actionAndArgs = command.ActionAndArgs();
VERIFY_IS_NOT_NULL(actionAndArgs);
VERIFY_ARE_EQUAL(ShortcutAction::Invalid, actionAndArgs.Action());
VERIFY_IS_TRUE(command.HasNestedCommands());
VERIFY_ARE_EQUAL(3u, command.NestedCommands().Size());
_logCommandNames(command.NestedCommands());
{
winrt::hstring childCommandName{ fmt::format(L"Split pane, profile: {}", name) };
auto childCommand = command.NestedCommands().Lookup(childCommandName);
VERIFY_IS_NOT_NULL(childCommand);
auto childActionAndArgs = childCommand.ActionAndArgs();
VERIFY_IS_NOT_NULL(childActionAndArgs);
VERIFY_ARE_EQUAL(ShortcutAction::SplitPane, childActionAndArgs.Action());
const auto& realArgs = childActionAndArgs.Args().try_as<SplitPaneArgs>();
VERIFY_IS_NOT_NULL(realArgs);
// Verify the args have the expected value
VERIFY_ARE_EQUAL(SplitDirection::Automatic, realArgs.SplitDirection());
VERIFY_IS_NOT_NULL(realArgs.TerminalArgs());
VERIFY_IS_TRUE(realArgs.TerminalArgs().Commandline().empty());
VERIFY_IS_TRUE(realArgs.TerminalArgs().StartingDirectory().empty());
VERIFY_IS_TRUE(realArgs.TerminalArgs().TabTitle().empty());
VERIFY_IS_FALSE(realArgs.TerminalArgs().Profile().empty());
VERIFY_ARE_EQUAL(name, realArgs.TerminalArgs().Profile());
VERIFY_IS_FALSE(childCommand.HasNestedCommands());
}
{
winrt::hstring childCommandName{ fmt::format(L"Split pane, split: down, profile: {}", name) };
auto childCommand = command.NestedCommands().Lookup(childCommandName);
VERIFY_IS_NOT_NULL(childCommand);
auto childActionAndArgs = childCommand.ActionAndArgs();
VERIFY_IS_NOT_NULL(childActionAndArgs);
VERIFY_ARE_EQUAL(ShortcutAction::SplitPane, childActionAndArgs.Action());
const auto& realArgs = childActionAndArgs.Args().try_as<SplitPaneArgs>();
VERIFY_IS_NOT_NULL(realArgs);
// Verify the args have the expected value
VERIFY_ARE_EQUAL(SplitDirection::Down, realArgs.SplitDirection());
VERIFY_IS_NOT_NULL(realArgs.TerminalArgs());
VERIFY_IS_TRUE(realArgs.TerminalArgs().Commandline().empty());
VERIFY_IS_TRUE(realArgs.TerminalArgs().StartingDirectory().empty());
VERIFY_IS_TRUE(realArgs.TerminalArgs().TabTitle().empty());
VERIFY_IS_FALSE(realArgs.TerminalArgs().Profile().empty());
VERIFY_ARE_EQUAL(name, realArgs.TerminalArgs().Profile());
VERIFY_IS_FALSE(childCommand.HasNestedCommands());
}
{
winrt::hstring childCommandName{ fmt::format(L"Split pane, split: right, profile: {}", name) };
auto childCommand = command.NestedCommands().Lookup(childCommandName);
VERIFY_IS_NOT_NULL(childCommand);
auto childActionAndArgs = childCommand.ActionAndArgs();
VERIFY_IS_NOT_NULL(childActionAndArgs);
VERIFY_ARE_EQUAL(ShortcutAction::SplitPane, childActionAndArgs.Action());
const auto& realArgs = childActionAndArgs.Args().try_as<SplitPaneArgs>();
VERIFY_IS_NOT_NULL(realArgs);
// Verify the args have the expected value
VERIFY_ARE_EQUAL(SplitDirection::Right, realArgs.SplitDirection());
VERIFY_IS_NOT_NULL(realArgs.TerminalArgs());
VERIFY_IS_TRUE(realArgs.TerminalArgs().Commandline().empty());
VERIFY_IS_TRUE(realArgs.TerminalArgs().StartingDirectory().empty());
VERIFY_IS_TRUE(realArgs.TerminalArgs().TabTitle().empty());
VERIFY_IS_FALSE(realArgs.TerminalArgs().Profile().empty());
VERIFY_ARE_EQUAL(name, realArgs.TerminalArgs().Profile());
VERIFY_IS_FALSE(childCommand.HasNestedCommands());
}
}
}
void SettingsTests::TestIterableInNestedCommand()
{
// This test checks a nested command that includes an iterable command.
// The commands should look like:
//
// <Command Palette>
// └─ New Tab With Profile...
// ├─ Profile 1
// ├─ Profile 2
// └─ Profile 3
static constexpr std::wstring_view settingsJson{ LR"(
{
"defaultProfile": "{6239a42c-0000-49a3-80bd-e8fdd045185c}",
"profiles": [
{
"name": "profile0",
"guid": "{6239a42c-0000-49a3-80bd-e8fdd045185c}",
"historySize": 1,
"commandline": "cmd.exe"
},
{
"name": "profile1",
"guid": "{6239a42c-1111-49a3-80bd-e8fdd045185c}",
"historySize": 2,
"commandline": "pwsh.exe"
},
{
"name": "profile2",
"historySize": 3,
"commandline": "wsl.exe"
}
],
"actions": [
{
"name": "New Tab With Profile...",
"commands": [
{
"iterateOn": "profiles",
"command": { "action": "newTab", "profile": "${profile.name}" }
}
]
}
]
})" };
CascadiaSettings settings{ settingsJson, inboxSettings };
VERIFY_ARE_EQUAL(0u, settings.Warnings().Size());
VERIFY_ARE_EQUAL(3u, settings.ActiveProfiles().Size());
auto expandedCommands = winrt::TerminalApp::implementation::TerminalPage::_ExpandCommands(settings.ActionMap().NameMap(), settings.ActiveProfiles().GetView(), settings.GlobalSettings().ColorSchemes());
_logCommandNames(expandedCommands.GetView());
VERIFY_ARE_EQUAL(0u, settings.Warnings().Size());
VERIFY_ARE_EQUAL(1u, expandedCommands.Size());
auto rootCommand = expandedCommands.Lookup(L"New Tab With Profile...");
VERIFY_IS_NOT_NULL(rootCommand);
auto rootActionAndArgs = rootCommand.ActionAndArgs();
VERIFY_IS_NOT_NULL(rootActionAndArgs);
VERIFY_ARE_EQUAL(ShortcutAction::Invalid, rootActionAndArgs.Action());
VERIFY_ARE_EQUAL(3u, rootCommand.NestedCommands().Size());
for (auto name : std::vector<std::wstring>({ L"profile0", L"profile1", L"profile2" }))
{
winrt::hstring commandName{ fmt::format(L"New tab, profile: {}", name) };
auto command = rootCommand.NestedCommands().Lookup(commandName);
VERIFY_IS_NOT_NULL(command);
auto actionAndArgs = command.ActionAndArgs();
VERIFY_IS_NOT_NULL(actionAndArgs);
VERIFY_ARE_EQUAL(ShortcutAction::NewTab, actionAndArgs.Action());
const auto& realArgs = actionAndArgs.Args().try_as<NewTabArgs>();
VERIFY_IS_NOT_NULL(realArgs);
// Verify the args have the expected value
VERIFY_IS_NOT_NULL(realArgs.TerminalArgs());
VERIFY_IS_TRUE(realArgs.TerminalArgs().Commandline().empty());
VERIFY_IS_TRUE(realArgs.TerminalArgs().StartingDirectory().empty());
VERIFY_IS_TRUE(realArgs.TerminalArgs().TabTitle().empty());
VERIFY_IS_FALSE(realArgs.TerminalArgs().Profile().empty());
VERIFY_ARE_EQUAL(name, realArgs.TerminalArgs().Profile());
VERIFY_IS_FALSE(command.HasNestedCommands());
}
}
void SettingsTests::TestMixedNestedAndIterableCommand()
{
// This test checks a nested commands that includes an iterable command
// that includes a nested command.
// The commands should look like:
//
// <Command Palette>
// └─ New Pane...
// ├─ profile0...
// | ├─ Split automatically
// | ├─ Split right
// | └─ Split down
// ├─ profile1...
// | ├─ Split automatically
// | ├─ Split right
// | └─ Split down
// └─ profile2...
// ├─ Split automatically
// ├─ Split right
// └─ Split down
static constexpr std::wstring_view settingsJson{ LR"(
{
"defaultProfile": "{6239a42c-0000-49a3-80bd-e8fdd045185c}",
"profiles": [
{
"name": "profile0",
"guid": "{6239a42c-0000-49a3-80bd-e8fdd045185c}",
"historySize": 1,
"commandline": "cmd.exe"
},
{
"name": "profile1",
"guid": "{6239a42c-1111-49a3-80bd-e8fdd045185c}",
"historySize": 2,
"commandline": "pwsh.exe"
},
{
"name": "profile2",
"historySize": 3,
"commandline": "wsl.exe"
}
],
"actions": [
{
"name": "New Pane...",
"commands": [
{
"iterateOn": "profiles",
"name": "${profile.name}...",
"commands": [
{ "command": { "action": "splitPane", "profile": "${profile.name}", "split": "auto" } },
{ "command": { "action": "splitPane", "profile": "${profile.name}", "split": "right" } },
{ "command": { "action": "splitPane", "profile": "${profile.name}", "split": "down" } }
]
}
]
}
]
})" };
CascadiaSettings settings{ settingsJson, inboxSettings };
VERIFY_ARE_EQUAL(0u, settings.Warnings().Size());
VERIFY_ARE_EQUAL(3u, settings.ActiveProfiles().Size());
auto expandedCommands = winrt::TerminalApp::implementation::TerminalPage::_ExpandCommands(settings.ActionMap().NameMap(), settings.ActiveProfiles().GetView(), settings.GlobalSettings().ColorSchemes());
_logCommandNames(expandedCommands.GetView());
VERIFY_ARE_EQUAL(0u, settings.Warnings().Size());
VERIFY_ARE_EQUAL(1u, expandedCommands.Size());
auto rootCommand = expandedCommands.Lookup(L"New Pane...");
VERIFY_IS_NOT_NULL(rootCommand);
auto rootActionAndArgs = rootCommand.ActionAndArgs();
VERIFY_IS_NOT_NULL(rootActionAndArgs);
VERIFY_ARE_EQUAL(ShortcutAction::Invalid, rootActionAndArgs.Action());
VERIFY_ARE_EQUAL(3u, rootCommand.NestedCommands().Size());
for (auto name : std::vector<std::wstring>({ L"profile0", L"profile1", L"profile2" }))
{
winrt::hstring commandName{ name + L"..." };
auto command = rootCommand.NestedCommands().Lookup(commandName);
VERIFY_IS_NOT_NULL(command);
auto actionAndArgs = command.ActionAndArgs();
VERIFY_IS_NOT_NULL(actionAndArgs);
VERIFY_ARE_EQUAL(ShortcutAction::Invalid, actionAndArgs.Action());
VERIFY_IS_TRUE(command.HasNestedCommands());
VERIFY_ARE_EQUAL(3u, command.NestedCommands().Size());
_logCommandNames(command.NestedCommands());
{
winrt::hstring childCommandName{ fmt::format(L"Split pane, profile: {}", name) };
auto childCommand = command.NestedCommands().Lookup(childCommandName);
VERIFY_IS_NOT_NULL(childCommand);
auto childActionAndArgs = childCommand.ActionAndArgs();
VERIFY_IS_NOT_NULL(childActionAndArgs);
VERIFY_ARE_EQUAL(ShortcutAction::SplitPane, childActionAndArgs.Action());
const auto& realArgs = childActionAndArgs.Args().try_as<SplitPaneArgs>();
VERIFY_IS_NOT_NULL(realArgs);
// Verify the args have the expected value
VERIFY_ARE_EQUAL(SplitDirection::Automatic, realArgs.SplitDirection());
VERIFY_IS_NOT_NULL(realArgs.TerminalArgs());
VERIFY_IS_TRUE(realArgs.TerminalArgs().Commandline().empty());
VERIFY_IS_TRUE(realArgs.TerminalArgs().StartingDirectory().empty());
VERIFY_IS_TRUE(realArgs.TerminalArgs().TabTitle().empty());
VERIFY_IS_FALSE(realArgs.TerminalArgs().Profile().empty());
VERIFY_ARE_EQUAL(name, realArgs.TerminalArgs().Profile());
VERIFY_IS_FALSE(childCommand.HasNestedCommands());
}
{
winrt::hstring childCommandName{ fmt::format(L"Split pane, split: down, profile: {}", name) };
auto childCommand = command.NestedCommands().Lookup(childCommandName);
VERIFY_IS_NOT_NULL(childCommand);
auto childActionAndArgs = childCommand.ActionAndArgs();
VERIFY_IS_NOT_NULL(childActionAndArgs);
VERIFY_ARE_EQUAL(ShortcutAction::SplitPane, childActionAndArgs.Action());
const auto& realArgs = childActionAndArgs.Args().try_as<SplitPaneArgs>();
VERIFY_IS_NOT_NULL(realArgs);
// Verify the args have the expected value
VERIFY_ARE_EQUAL(SplitDirection::Down, realArgs.SplitDirection());
VERIFY_IS_NOT_NULL(realArgs.TerminalArgs());
VERIFY_IS_TRUE(realArgs.TerminalArgs().Commandline().empty());
VERIFY_IS_TRUE(realArgs.TerminalArgs().StartingDirectory().empty());
VERIFY_IS_TRUE(realArgs.TerminalArgs().TabTitle().empty());
VERIFY_IS_FALSE(realArgs.TerminalArgs().Profile().empty());
VERIFY_ARE_EQUAL(name, realArgs.TerminalArgs().Profile());
VERIFY_IS_FALSE(childCommand.HasNestedCommands());
}
{
winrt::hstring childCommandName{ fmt::format(L"Split pane, split: right, profile: {}", name) };
auto childCommand = command.NestedCommands().Lookup(childCommandName);
VERIFY_IS_NOT_NULL(childCommand);
auto childActionAndArgs = childCommand.ActionAndArgs();
VERIFY_IS_NOT_NULL(childActionAndArgs);
VERIFY_ARE_EQUAL(ShortcutAction::SplitPane, childActionAndArgs.Action());
const auto& realArgs = childActionAndArgs.Args().try_as<SplitPaneArgs>();
VERIFY_IS_NOT_NULL(realArgs);
// Verify the args have the expected value
VERIFY_ARE_EQUAL(SplitDirection::Right, realArgs.SplitDirection());
VERIFY_IS_NOT_NULL(realArgs.TerminalArgs());
VERIFY_IS_TRUE(realArgs.TerminalArgs().Commandline().empty());
VERIFY_IS_TRUE(realArgs.TerminalArgs().StartingDirectory().empty());
VERIFY_IS_TRUE(realArgs.TerminalArgs().TabTitle().empty());
VERIFY_IS_FALSE(realArgs.TerminalArgs().Profile().empty());
VERIFY_ARE_EQUAL(name, realArgs.TerminalArgs().Profile());
VERIFY_IS_FALSE(childCommand.HasNestedCommands());
}
}
}
void SettingsTests::TestIterableColorSchemeCommands()
{
// For this test, put an iterable command with a given `name`,
// containing a ${profile.name} to replace. When we expand it, it should
// have created one command for each profile.
static constexpr std::wstring_view settingsJson{ LR"(
{
"defaultProfile": "{6239a42c-0000-49a3-80bd-e8fdd045185c}",
"profiles": [
{
"name": "profile0",
"guid": "{6239a42c-0000-49a3-80bd-e8fdd045185c}",
"historySize": 1,
"commandline": "cmd.exe"
},
{
"name": "profile1",
"guid": "{6239a42c-1111-49a3-80bd-e8fdd045185c}",
"historySize": 2,
"commandline": "pwsh.exe"
},
{
"name": "profile2",
"historySize": 3,
"commandline": "wsl.exe"
}
],
"schemes": [
{
"name": "Campbell",
"foreground": "#CCCCCC",
"background": "#0C0C0C",
"cursorColor": "#FFFFFF",
"black": "#0C0C0C",
"red": "#C50F1F",
"green": "#13A10E",
"yellow": "#C19C00",
"blue": "#0037DA",
"purple": "#881798",
"cyan": "#3A96DD",
"white": "#CCCCCC",
"brightBlack": "#767676",
"brightRed": "#E74856",
"brightGreen": "#16C60C",
"brightYellow": "#F9F1A5",
"brightBlue": "#3B78FF",
"brightPurple": "#B4009E",
"brightCyan": "#61D6D6",
"brightWhite": "#F2F2F2"
},
{
"name": "Campbell PowerShell",
"foreground": "#CCCCCC",
"background": "#012456",
"cursorColor": "#FFFFFF",
"black": "#0C0C0C",
"red": "#C50F1F",
"green": "#13A10E",
"yellow": "#C19C00",
"blue": "#0037DA",
"purple": "#881798",
"cyan": "#3A96DD",
"white": "#CCCCCC",
"brightBlack": "#767676",
"brightRed": "#E74856",
"brightGreen": "#16C60C",
"brightYellow": "#F9F1A5",
"brightBlue": "#3B78FF",
"brightPurple": "#B4009E",
"brightCyan": "#61D6D6",
"brightWhite": "#F2F2F2"
},
{
"name": "Vintage",
"foreground": "#C0C0C0",
"background": "#000000",
"cursorColor": "#FFFFFF",
"black": "#000000",
"red": "#800000",
"green": "#008000",
"yellow": "#808000",
"blue": "#000080",
"purple": "#800080",
"cyan": "#008080",
"white": "#C0C0C0",
"brightBlack": "#808080",
"brightRed": "#FF0000",
"brightGreen": "#00FF00",
"brightYellow": "#FFFF00",
"brightBlue": "#0000FF",
"brightPurple": "#FF00FF",
"brightCyan": "#00FFFF",
"brightWhite": "#FFFFFF"
}
],
"actions": [
{
"name": "iterable command ${scheme.name}",
"iterateOn": "schemes",
"command": { "action": "splitPane", "profile": "${scheme.name}" }
},
]
})" };
CascadiaSettings settings{ settingsJson, {} };
VERIFY_ARE_EQUAL(3u, settings.ActiveProfiles().Size());
auto nameMap{ settings.ActionMap().NameMap() };
VERIFY_ARE_EQUAL(1u, nameMap.Size());
{
auto command = nameMap.TryLookup(L"iterable command ${scheme.name}");
VERIFY_IS_NOT_NULL(command);
auto actionAndArgs = command.ActionAndArgs();
VERIFY_IS_NOT_NULL(actionAndArgs);
VERIFY_ARE_EQUAL(ShortcutAction::SplitPane, actionAndArgs.Action());
const auto& realArgs = actionAndArgs.Args().try_as<SplitPaneArgs>();
VERIFY_IS_NOT_NULL(realArgs);
// Verify the args have the expected value
VERIFY_ARE_EQUAL(SplitDirection::Automatic, realArgs.SplitDirection());
VERIFY_IS_NOT_NULL(realArgs.TerminalArgs());
VERIFY_IS_TRUE(realArgs.TerminalArgs().Commandline().empty());
VERIFY_IS_TRUE(realArgs.TerminalArgs().StartingDirectory().empty());
VERIFY_IS_TRUE(realArgs.TerminalArgs().TabTitle().empty());
VERIFY_IS_FALSE(realArgs.TerminalArgs().Profile().empty());
VERIFY_ARE_EQUAL(L"${scheme.name}", realArgs.TerminalArgs().Profile());
}
auto expandedCommands = winrt::TerminalApp::implementation::TerminalPage::_ExpandCommands(nameMap, settings.ActiveProfiles().GetView(), settings.GlobalSettings().ColorSchemes());
_logCommandNames(expandedCommands.GetView());
VERIFY_ARE_EQUAL(3u, expandedCommands.Size());
// Yes, this test is testing splitPane with profiles named after each
// color scheme. These would obviously not work in real life, they're
// just easy tests to write.
{
auto command = expandedCommands.Lookup(L"iterable command Campbell");
VERIFY_IS_NOT_NULL(command);
auto actionAndArgs = command.ActionAndArgs();
VERIFY_IS_NOT_NULL(actionAndArgs);
VERIFY_ARE_EQUAL(ShortcutAction::SplitPane, actionAndArgs.Action());
const auto& realArgs = actionAndArgs.Args().try_as<SplitPaneArgs>();
VERIFY_IS_NOT_NULL(realArgs);
// Verify the args have the expected value
VERIFY_ARE_EQUAL(SplitDirection::Automatic, realArgs.SplitDirection());
VERIFY_IS_NOT_NULL(realArgs.TerminalArgs());
VERIFY_IS_TRUE(realArgs.TerminalArgs().Commandline().empty());
VERIFY_IS_TRUE(realArgs.TerminalArgs().StartingDirectory().empty());
VERIFY_IS_TRUE(realArgs.TerminalArgs().TabTitle().empty());
VERIFY_IS_FALSE(realArgs.TerminalArgs().Profile().empty());
VERIFY_ARE_EQUAL(L"Campbell", realArgs.TerminalArgs().Profile());
}
{
auto command = expandedCommands.Lookup(L"iterable command Campbell PowerShell");
VERIFY_IS_NOT_NULL(command);
auto actionAndArgs = command.ActionAndArgs();
VERIFY_IS_NOT_NULL(actionAndArgs);
VERIFY_ARE_EQUAL(ShortcutAction::SplitPane, actionAndArgs.Action());
const auto& realArgs = actionAndArgs.Args().try_as<SplitPaneArgs>();
VERIFY_IS_NOT_NULL(realArgs);
// Verify the args have the expected value
VERIFY_ARE_EQUAL(SplitDirection::Automatic, realArgs.SplitDirection());
VERIFY_IS_NOT_NULL(realArgs.TerminalArgs());
VERIFY_IS_TRUE(realArgs.TerminalArgs().Commandline().empty());
VERIFY_IS_TRUE(realArgs.TerminalArgs().StartingDirectory().empty());
VERIFY_IS_TRUE(realArgs.TerminalArgs().TabTitle().empty());
VERIFY_IS_FALSE(realArgs.TerminalArgs().Profile().empty());
VERIFY_ARE_EQUAL(L"Campbell PowerShell", realArgs.TerminalArgs().Profile());
}
{
auto command = expandedCommands.Lookup(L"iterable command Vintage");
VERIFY_IS_NOT_NULL(command);
auto actionAndArgs = command.ActionAndArgs();
VERIFY_IS_NOT_NULL(actionAndArgs);
VERIFY_ARE_EQUAL(ShortcutAction::SplitPane, actionAndArgs.Action());
const auto& realArgs = actionAndArgs.Args().try_as<SplitPaneArgs>();
VERIFY_IS_NOT_NULL(realArgs);
// Verify the args have the expected value
VERIFY_ARE_EQUAL(SplitDirection::Automatic, realArgs.SplitDirection());
VERIFY_IS_NOT_NULL(realArgs.TerminalArgs());
VERIFY_IS_TRUE(realArgs.TerminalArgs().Commandline().empty());
VERIFY_IS_TRUE(realArgs.TerminalArgs().StartingDirectory().empty());
VERIFY_IS_TRUE(realArgs.TerminalArgs().TabTitle().empty());
VERIFY_IS_FALSE(realArgs.TerminalArgs().Profile().empty());
VERIFY_ARE_EQUAL(L"Vintage", realArgs.TerminalArgs().Profile());
}
}
}