diff --git a/OpenConsole.sln b/OpenConsole.sln
index 82ab30fdc5a..b0934815d1a 100644
--- a/OpenConsole.sln
+++ b/OpenConsole.sln
@@ -87,8 +87,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Host.Tests.Feature", "src\h
ProjectSection(ProjectDependencies) = postProject
{18D09A24-8240-42D6-8CB6-236EEE820263} = {18D09A24-8240-42D6-8CB6-236EEE820263}
{FC802440-AD6A-4919-8F2C-7701F2B38D79} = {FC802440-AD6A-4919-8F2C-7701F2B38D79}
- {9CBD7DFA-1754-4A9D-93D7-857A9D17CB1B} = {9CBD7DFA-1754-4A9D-93D7-857A9D17CB1B}
{58A03BB2-DF5A-4B66-91A0-7EF3BA01269A} = {58A03BB2-DF5A-4B66-91A0-7EF3BA01269A}
+ {9CBD7DFA-1754-4A9D-93D7-857A9D17CB1B} = {9CBD7DFA-1754-4A9D-93D7-857A9D17CB1B}
EndProjectSection
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "TerminalParser.UnitTests", "src\terminal\parser\ut_parser\Parser.UnitTests.vcxproj", "{12144E07-FE63-4D33-9231-748B8D8C3792}"
@@ -180,6 +180,7 @@ EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "TerminalApp", "src\cascadia\TerminalApp\dll\TerminalApp.vcxproj", "{CA5CAD1A-44BD-4AC7-AC72-F16E576FDD12}"
ProjectSection(ProjectDependencies) = postProject
{CA5CAD1A-9A12-429C-B551-8562EC954746} = {CA5CAD1A-9A12-429C-B551-8562EC954746}
+ {CA5CAD1A-082C-4476-9F33-94B339494076} = {CA5CAD1A-082C-4476-9F33-94B339494076}
{CA5CAD1A-C46D-4588-B1C0-40F31AE9100B} = {CA5CAD1A-C46D-4588-B1C0-40F31AE9100B}
{CA5CAD1A-44BD-4AC7-AC72-6CA5B3AB89ED} = {CA5CAD1A-44BD-4AC7-AC72-6CA5B3AB89ED}
EndProjectSection
@@ -225,16 +226,21 @@ EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "UnitTests_TerminalApp", "src\cascadia\ut_app\TerminalApp.UnitTests.vcxproj", "{CA5CAD1A-9333-4D05-B12A-1905CBF112F9}"
ProjectSection(ProjectDependencies) = postProject
{CA5CAD1A-9A12-429C-B551-8562EC954746} = {CA5CAD1A-9A12-429C-B551-8562EC954746}
+ {CA5CAD1A-D7EC-4107-B7C6-79CB77AE2907} = {CA5CAD1A-D7EC-4107-B7C6-79CB77AE2907}
EndProjectSection
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "TerminalAppLib", "src\cascadia\TerminalApp\TerminalAppLib.vcxproj", "{CA5CAD1A-9A12-429C-B551-8562EC954746}"
ProjectSection(ProjectDependencies) = postProject
+ {CA5CAD1A-082C-4476-9F33-94B339494076} = {CA5CAD1A-082C-4476-9F33-94B339494076}
{CA5CAD1A-44BD-4AC7-AC72-6CA5B3AB89ED} = {CA5CAD1A-44BD-4AC7-AC72-6CA5B3AB89ED}
EndProjectSection
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "LocalTests_TerminalApp", "src\cascadia\LocalTests_TerminalApp\TerminalApp.LocalTests.vcxproj", "{CA5CAD1A-B11C-4DDB-A4FE-C3AFAE9B5506}"
ProjectSection(ProjectDependencies) = postProject
{CA5CAD1A-9A12-429C-B551-8562EC954746} = {CA5CAD1A-9A12-429C-B551-8562EC954746}
+ {CA5CAD1A-082C-4476-9F33-94B339494076} = {CA5CAD1A-082C-4476-9F33-94B339494076}
+ {CA5CAD1A-44BD-4AC7-AC72-F16E576FDD12} = {CA5CAD1A-44BD-4AC7-AC72-F16E576FDD12}
+ {CA5CAD1A-D7EC-4107-B7C6-79CB77AE2907} = {CA5CAD1A-D7EC-4107-B7C6-79CB77AE2907}
EndProjectSection
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "RendererUia", "src\renderer\uia\lib\uia.vcxproj", "{48D21369-3D7B-4431-9967-24E81292CF63}"
@@ -250,6 +256,8 @@ EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "TestHostApp", "src\cascadia\LocalTests_TerminalApp\TestHostApp\TestHostApp.vcxproj", "{A021EDFF-45C8-4DC2-BEF7-36E1B3B8CFE8}"
ProjectSection(ProjectDependencies) = postProject
{CA5CAD1A-B11C-4DDB-A4FE-C3AFAE9B5506} = {CA5CAD1A-B11C-4DDB-A4FE-C3AFAE9B5506}
+ {CA5CAD1A-082C-4476-9F33-94B339494076} = {CA5CAD1A-082C-4476-9F33-94B339494076}
+ {CA5CAD1A-9B68-456A-B13E-C8218070DC42} = {CA5CAD1A-9B68-456A-B13E-C8218070DC42}
EndProjectSection
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{BDB237B6-1D1D-400F-84CC-40A58FA59C8E}"
@@ -307,6 +315,24 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WpfTerminalTestNetCore", "s
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "wt", "src\cascadia\wt\wt.vcxproj", "{506FD703-BAA7-4F6E-9361-64F550EC8FCA}"
EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Microsoft.Terminal.Settings.Model.Lib", "src\cascadia\TerminalSettingsModel\Microsoft.Terminal.Settings.ModelLib.vcxproj", "{CA5CAD1A-D7EC-4107-B7C6-79CB77AE2907}"
+ ProjectSection(ProjectDependencies) = postProject
+ {CA5CAD1A-44BD-4AC7-AC72-6CA5B3AB89ED} = {CA5CAD1A-44BD-4AC7-AC72-6CA5B3AB89ED}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Microsoft.Terminal.Settings.Model", "src\cascadia\TerminalSettingsModel\dll\Microsoft.Terminal.Settings.Model.vcxproj", "{CA5CAD1A-082C-4476-9F33-94B339494076}"
+ ProjectSection(ProjectDependencies) = postProject
+ {CA5CAD1A-D7EC-4107-B7C6-79CB77AE2907} = {CA5CAD1A-D7EC-4107-B7C6-79CB77AE2907}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "LocalTests_SettingsModel", "src\cascadia\LocalTests_SettingsModel\SettingsModel.LocalTests.vcxproj", "{CA5CAD1A-9B68-456A-B13E-C8218070DC42}"
+ ProjectSection(ProjectDependencies) = postProject
+ {CA5CAD1A-082C-4476-9F33-94B339494076} = {CA5CAD1A-082C-4476-9F33-94B339494076}
+ {CA5CAD1A-C46D-4588-B1C0-40F31AE9100B} = {CA5CAD1A-C46D-4588-B1C0-40F31AE9100B}
+ {CA5CAD1A-44BD-4AC7-AC72-6CA5B3AB89ED} = {CA5CAD1A-44BD-4AC7-AC72-6CA5B3AB89ED}
+ {CA5CAD1A-D7EC-4107-B7C6-79CB77AE2907} = {CA5CAD1A-D7EC-4107-B7C6-79CB77AE2907}
+ EndProjectSection
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
AuditMode|Any CPU = AuditMode|Any CPU
@@ -1986,6 +2012,84 @@ Global
{506FD703-BAA7-4F6E-9361-64F550EC8FCA}.Release|x64.Build.0 = Release|x64
{506FD703-BAA7-4F6E-9361-64F550EC8FCA}.Release|x86.ActiveCfg = Release|Win32
{506FD703-BAA7-4F6E-9361-64F550EC8FCA}.Release|x86.Build.0 = Release|Win32
+ {CA5CAD1A-D7EC-4107-B7C6-79CB77AE2907}.AuditMode|Any CPU.ActiveCfg = AuditMode|Win32
+ {CA5CAD1A-D7EC-4107-B7C6-79CB77AE2907}.AuditMode|ARM64.ActiveCfg = AuditMode|ARM64
+ {CA5CAD1A-D7EC-4107-B7C6-79CB77AE2907}.AuditMode|ARM64.Build.0 = AuditMode|ARM64
+ {CA5CAD1A-D7EC-4107-B7C6-79CB77AE2907}.AuditMode|DotNet_x64Test.ActiveCfg = AuditMode|Win32
+ {CA5CAD1A-D7EC-4107-B7C6-79CB77AE2907}.AuditMode|DotNet_x86Test.ActiveCfg = AuditMode|Win32
+ {CA5CAD1A-D7EC-4107-B7C6-79CB77AE2907}.AuditMode|x64.ActiveCfg = Release|x64
+ {CA5CAD1A-D7EC-4107-B7C6-79CB77AE2907}.AuditMode|x86.ActiveCfg = AuditMode|Win32
+ {CA5CAD1A-D7EC-4107-B7C6-79CB77AE2907}.AuditMode|x86.Build.0 = AuditMode|Win32
+ {CA5CAD1A-D7EC-4107-B7C6-79CB77AE2907}.Debug|Any CPU.ActiveCfg = Debug|Win32
+ {CA5CAD1A-D7EC-4107-B7C6-79CB77AE2907}.Debug|ARM64.ActiveCfg = Debug|ARM64
+ {CA5CAD1A-D7EC-4107-B7C6-79CB77AE2907}.Debug|ARM64.Build.0 = Debug|ARM64
+ {CA5CAD1A-D7EC-4107-B7C6-79CB77AE2907}.Debug|DotNet_x64Test.ActiveCfg = Debug|Win32
+ {CA5CAD1A-D7EC-4107-B7C6-79CB77AE2907}.Debug|DotNet_x86Test.ActiveCfg = Debug|Win32
+ {CA5CAD1A-D7EC-4107-B7C6-79CB77AE2907}.Debug|x64.ActiveCfg = Debug|x64
+ {CA5CAD1A-D7EC-4107-B7C6-79CB77AE2907}.Debug|x64.Build.0 = Debug|x64
+ {CA5CAD1A-D7EC-4107-B7C6-79CB77AE2907}.Debug|x86.ActiveCfg = Debug|Win32
+ {CA5CAD1A-D7EC-4107-B7C6-79CB77AE2907}.Debug|x86.Build.0 = Debug|Win32
+ {CA5CAD1A-D7EC-4107-B7C6-79CB77AE2907}.Release|Any CPU.ActiveCfg = Release|Win32
+ {CA5CAD1A-D7EC-4107-B7C6-79CB77AE2907}.Release|ARM64.ActiveCfg = Release|ARM64
+ {CA5CAD1A-D7EC-4107-B7C6-79CB77AE2907}.Release|ARM64.Build.0 = Release|ARM64
+ {CA5CAD1A-D7EC-4107-B7C6-79CB77AE2907}.Release|DotNet_x64Test.ActiveCfg = Release|Win32
+ {CA5CAD1A-D7EC-4107-B7C6-79CB77AE2907}.Release|DotNet_x86Test.ActiveCfg = Release|Win32
+ {CA5CAD1A-D7EC-4107-B7C6-79CB77AE2907}.Release|x64.ActiveCfg = Release|x64
+ {CA5CAD1A-D7EC-4107-B7C6-79CB77AE2907}.Release|x64.Build.0 = Release|x64
+ {CA5CAD1A-D7EC-4107-B7C6-79CB77AE2907}.Release|x86.ActiveCfg = Release|Win32
+ {CA5CAD1A-D7EC-4107-B7C6-79CB77AE2907}.Release|x86.Build.0 = Release|Win32
+ {CA5CAD1A-082C-4476-9F33-94B339494076}.AuditMode|Any CPU.ActiveCfg = AuditMode|Win32
+ {CA5CAD1A-082C-4476-9F33-94B339494076}.AuditMode|ARM64.ActiveCfg = AuditMode|ARM64
+ {CA5CAD1A-082C-4476-9F33-94B339494076}.AuditMode|ARM64.Build.0 = AuditMode|ARM64
+ {CA5CAD1A-082C-4476-9F33-94B339494076}.AuditMode|DotNet_x64Test.ActiveCfg = AuditMode|Win32
+ {CA5CAD1A-082C-4476-9F33-94B339494076}.AuditMode|DotNet_x86Test.ActiveCfg = AuditMode|Win32
+ {CA5CAD1A-082C-4476-9F33-94B339494076}.AuditMode|x64.ActiveCfg = Release|x64
+ {CA5CAD1A-082C-4476-9F33-94B339494076}.AuditMode|x86.ActiveCfg = AuditMode|Win32
+ {CA5CAD1A-082C-4476-9F33-94B339494076}.AuditMode|x86.Build.0 = AuditMode|Win32
+ {CA5CAD1A-082C-4476-9F33-94B339494076}.Debug|Any CPU.ActiveCfg = Debug|Win32
+ {CA5CAD1A-082C-4476-9F33-94B339494076}.Debug|ARM64.ActiveCfg = Debug|ARM64
+ {CA5CAD1A-082C-4476-9F33-94B339494076}.Debug|ARM64.Build.0 = Debug|ARM64
+ {CA5CAD1A-082C-4476-9F33-94B339494076}.Debug|DotNet_x64Test.ActiveCfg = Debug|Win32
+ {CA5CAD1A-082C-4476-9F33-94B339494076}.Debug|DotNet_x86Test.ActiveCfg = Debug|Win32
+ {CA5CAD1A-082C-4476-9F33-94B339494076}.Debug|x64.ActiveCfg = Debug|x64
+ {CA5CAD1A-082C-4476-9F33-94B339494076}.Debug|x64.Build.0 = Debug|x64
+ {CA5CAD1A-082C-4476-9F33-94B339494076}.Debug|x86.ActiveCfg = Debug|Win32
+ {CA5CAD1A-082C-4476-9F33-94B339494076}.Debug|x86.Build.0 = Debug|Win32
+ {CA5CAD1A-082C-4476-9F33-94B339494076}.Release|Any CPU.ActiveCfg = Release|Win32
+ {CA5CAD1A-082C-4476-9F33-94B339494076}.Release|ARM64.ActiveCfg = Release|ARM64
+ {CA5CAD1A-082C-4476-9F33-94B339494076}.Release|ARM64.Build.0 = Release|ARM64
+ {CA5CAD1A-082C-4476-9F33-94B339494076}.Release|DotNet_x64Test.ActiveCfg = Release|Win32
+ {CA5CAD1A-082C-4476-9F33-94B339494076}.Release|DotNet_x86Test.ActiveCfg = Release|Win32
+ {CA5CAD1A-082C-4476-9F33-94B339494076}.Release|x64.ActiveCfg = Release|x64
+ {CA5CAD1A-082C-4476-9F33-94B339494076}.Release|x64.Build.0 = Release|x64
+ {CA5CAD1A-082C-4476-9F33-94B339494076}.Release|x86.ActiveCfg = Release|Win32
+ {CA5CAD1A-082C-4476-9F33-94B339494076}.Release|x86.Build.0 = Release|Win32
+ {CA5CAD1A-9B68-456A-B13E-C8218070DC42}.AuditMode|Any CPU.ActiveCfg = AuditMode|Win32
+ {CA5CAD1A-9B68-456A-B13E-C8218070DC42}.AuditMode|ARM64.ActiveCfg = AuditMode|ARM64
+ {CA5CAD1A-9B68-456A-B13E-C8218070DC42}.AuditMode|ARM64.Build.0 = AuditMode|ARM64
+ {CA5CAD1A-9B68-456A-B13E-C8218070DC42}.AuditMode|DotNet_x64Test.ActiveCfg = AuditMode|Win32
+ {CA5CAD1A-9B68-456A-B13E-C8218070DC42}.AuditMode|DotNet_x86Test.ActiveCfg = AuditMode|Win32
+ {CA5CAD1A-9B68-456A-B13E-C8218070DC42}.AuditMode|x64.ActiveCfg = AuditMode|x64
+ {CA5CAD1A-9B68-456A-B13E-C8218070DC42}.AuditMode|x86.ActiveCfg = AuditMode|Win32
+ {CA5CAD1A-9B68-456A-B13E-C8218070DC42}.AuditMode|x86.Build.0 = AuditMode|Win32
+ {CA5CAD1A-9B68-456A-B13E-C8218070DC42}.Debug|Any CPU.ActiveCfg = Debug|Win32
+ {CA5CAD1A-9B68-456A-B13E-C8218070DC42}.Debug|ARM64.ActiveCfg = Debug|ARM64
+ {CA5CAD1A-9B68-456A-B13E-C8218070DC42}.Debug|ARM64.Build.0 = Debug|ARM64
+ {CA5CAD1A-9B68-456A-B13E-C8218070DC42}.Debug|DotNet_x64Test.ActiveCfg = Debug|Win32
+ {CA5CAD1A-9B68-456A-B13E-C8218070DC42}.Debug|DotNet_x86Test.ActiveCfg = Debug|Win32
+ {CA5CAD1A-9B68-456A-B13E-C8218070DC42}.Debug|x64.ActiveCfg = Debug|x64
+ {CA5CAD1A-9B68-456A-B13E-C8218070DC42}.Debug|x64.Build.0 = Debug|x64
+ {CA5CAD1A-9B68-456A-B13E-C8218070DC42}.Debug|x86.ActiveCfg = Debug|Win32
+ {CA5CAD1A-9B68-456A-B13E-C8218070DC42}.Debug|x86.Build.0 = Debug|Win32
+ {CA5CAD1A-9B68-456A-B13E-C8218070DC42}.Release|Any CPU.ActiveCfg = Release|Win32
+ {CA5CAD1A-9B68-456A-B13E-C8218070DC42}.Release|ARM64.ActiveCfg = Release|ARM64
+ {CA5CAD1A-9B68-456A-B13E-C8218070DC42}.Release|ARM64.Build.0 = Release|ARM64
+ {CA5CAD1A-9B68-456A-B13E-C8218070DC42}.Release|DotNet_x64Test.ActiveCfg = Release|Win32
+ {CA5CAD1A-9B68-456A-B13E-C8218070DC42}.Release|DotNet_x86Test.ActiveCfg = Release|Win32
+ {CA5CAD1A-9B68-456A-B13E-C8218070DC42}.Release|x64.ActiveCfg = Release|x64
+ {CA5CAD1A-9B68-456A-B13E-C8218070DC42}.Release|x64.Build.0 = Release|x64
+ {CA5CAD1A-9B68-456A-B13E-C8218070DC42}.Release|x86.ActiveCfg = Release|Win32
+ {CA5CAD1A-9B68-456A-B13E-C8218070DC42}.Release|x86.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -2066,6 +2170,9 @@ Global
{6BAE5851-50D5-4934-8D5E-30361A8A40F3} = {81C352DB-1818-45B7-A284-18E259F1CC87}
{1588FD7C-241E-4E7D-9113-43735F3E6BAD} = {59840756-302F-44DF-AA47-441A9D673202}
{506FD703-BAA7-4F6E-9361-64F550EC8FCA} = {59840756-302F-44DF-AA47-441A9D673202}
+ {CA5CAD1A-D7EC-4107-B7C6-79CB77AE2907} = {59840756-302F-44DF-AA47-441A9D673202}
+ {CA5CAD1A-082C-4476-9F33-94B339494076} = {59840756-302F-44DF-AA47-441A9D673202}
+ {CA5CAD1A-9B68-456A-B13E-C8218070DC42} = {BDB237B6-1D1D-400F-84CC-40A58FA59C8E}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {3140B1B7-C8EE-43D1-A772-D82A7061A271}
diff --git a/src/cascadia/CascadiaResources.build.items b/src/cascadia/CascadiaResources.build.items
index 4eb234e5164..b99fc3ba69d 100644
--- a/src/cascadia/CascadiaResources.build.items
+++ b/src/cascadia/CascadiaResources.build.items
@@ -26,7 +26,7 @@
ProfileIcons\%(RecursiveDir)%(FileName)%(Extension)
-
+
true
%(RecursiveDir)%(FileName)%(Extension)
diff --git a/src/cascadia/LocalTests_TerminalApp/ColorSchemeTests.cpp b/src/cascadia/LocalTests_SettingsModel/ColorSchemeTests.cpp
similarity index 95%
rename from src/cascadia/LocalTests_TerminalApp/ColorSchemeTests.cpp
rename to src/cascadia/LocalTests_SettingsModel/ColorSchemeTests.cpp
index ac8d9a84d9c..64b96dd8490 100644
--- a/src/cascadia/LocalTests_TerminalApp/ColorSchemeTests.cpp
+++ b/src/cascadia/LocalTests_SettingsModel/ColorSchemeTests.cpp
@@ -3,18 +3,17 @@
#include "pch.h"
-#include "../TerminalApp/ColorScheme.h"
-#include "../TerminalApp/CascadiaSettings.h"
+#include "../TerminalSettingsModel/ColorScheme.h"
+#include "../TerminalSettingsModel/CascadiaSettings.h"
#include "JsonTestClass.h"
using namespace Microsoft::Console;
-using namespace TerminalApp;
-using namespace winrt::TerminalApp::implementation;
+using namespace winrt::Microsoft::Terminal::Settings::Model::implementation;
using namespace WEX::Logging;
using namespace WEX::TestExecution;
using namespace WEX::Common;
-namespace TerminalAppLocalTests
+namespace SettingsModelLocalTests
{
// TODO:microsoft/terminal#3838:
// Unfortunately, these tests _WILL NOT_ work in our CI. We're waiting for
@@ -193,7 +192,7 @@ namespace TerminalAppLocalTests
const auto scheme2Json = VerifyParseSucceeded(scheme2String);
const auto scheme3Json = VerifyParseSucceeded(scheme3String);
- auto settings = winrt::make_self();
+ auto settings = winrt::make_self();
VERIFY_ARE_EQUAL(0u, settings->_globals->ColorSchemes().Size());
VERIFY_IS_NULL(settings->_FindMatchingColorScheme(scheme0Json));
diff --git a/src/cascadia/LocalTests_TerminalApp/CommandTests.cpp b/src/cascadia/LocalTests_SettingsModel/CommandTests.cpp
similarity index 86%
rename from src/cascadia/LocalTests_TerminalApp/CommandTests.cpp
rename to src/cascadia/LocalTests_SettingsModel/CommandTests.cpp
index c2fcc95af9c..b50dd6059d8 100644
--- a/src/cascadia/LocalTests_TerminalApp/CommandTests.cpp
+++ b/src/cascadia/LocalTests_SettingsModel/CommandTests.cpp
@@ -3,20 +3,19 @@
#include "pch.h"
-#include "../TerminalApp/CascadiaSettings.h"
+#include "../TerminalSettingsModel/CascadiaSettings.h"
#include "JsonTestClass.h"
#include "TestUtils.h"
using namespace Microsoft::Console;
-using namespace TerminalApp;
-using namespace winrt::TerminalApp;
+using namespace winrt::Microsoft::Terminal::Settings::Model;
using namespace winrt::Microsoft::Terminal::TerminalControl;
using namespace winrt::Windows::Foundation::Collections;
using namespace WEX::Logging;
using namespace WEX::TestExecution;
using namespace WEX::Common;
-namespace TerminalAppLocalTests
+namespace SettingsModelLocalTests
{
// TODO:microsoft/terminal#3838:
// Unfortunately, these tests _WILL NOT_ work in our CI. We're waiting for
@@ -62,7 +61,7 @@ namespace TerminalAppLocalTests
const auto commands1Json = VerifyParseSucceeded(commands1String);
const auto commands2Json = VerifyParseSucceeded(commands2String);
- IMap commands = winrt::single_threaded_map();
+ IMap commands = winrt::single_threaded_map();
VERIFY_ARE_EQUAL(0u, commands.Size());
{
auto warnings = implementation::Command::LayerJson(commands, commands0Json);
@@ -96,7 +95,7 @@ namespace TerminalAppLocalTests
const auto commands2Json = VerifyParseSucceeded(commands2String);
const auto commands3Json = VerifyParseSucceeded(commands3String);
- IMap commands = winrt::single_threaded_map();
+ IMap commands = winrt::single_threaded_map();
VERIFY_ARE_EQUAL(0u, commands.Size());
{
auto warnings = implementation::Command::LayerJson(commands, commands0Json);
@@ -154,7 +153,7 @@ namespace TerminalAppLocalTests
const auto commands0Json = VerifyParseSucceeded(commands0String);
- IMap commands = winrt::single_threaded_map();
+ IMap commands = winrt::single_threaded_map();
VERIFY_ARE_EQUAL(0u, commands.Size());
auto warnings = implementation::Command::LayerJson(commands, commands0Json);
VERIFY_ARE_EQUAL(0u, warnings.size());
@@ -168,7 +167,7 @@ namespace TerminalAppLocalTests
const auto& realArgs = command.Action().Args().try_as();
VERIFY_IS_NOT_NULL(realArgs);
// Verify the args have the expected value
- VERIFY_ARE_EQUAL(winrt::TerminalApp::SplitState::Automatic, realArgs.SplitStyle());
+ VERIFY_ARE_EQUAL(SplitState::Automatic, realArgs.SplitStyle());
}
{
auto command = commands.Lookup(L"command1");
@@ -178,7 +177,7 @@ namespace TerminalAppLocalTests
const auto& realArgs = command.Action().Args().try_as();
VERIFY_IS_NOT_NULL(realArgs);
// Verify the args have the expected value
- VERIFY_ARE_EQUAL(winrt::TerminalApp::SplitState::Vertical, realArgs.SplitStyle());
+ VERIFY_ARE_EQUAL(SplitState::Vertical, realArgs.SplitStyle());
}
{
auto command = commands.Lookup(L"command2");
@@ -188,7 +187,7 @@ namespace TerminalAppLocalTests
const auto& realArgs = command.Action().Args().try_as();
VERIFY_IS_NOT_NULL(realArgs);
// Verify the args have the expected value
- VERIFY_ARE_EQUAL(winrt::TerminalApp::SplitState::Horizontal, realArgs.SplitStyle());
+ VERIFY_ARE_EQUAL(SplitState::Horizontal, realArgs.SplitStyle());
}
{
auto command = commands.Lookup(L"command4");
@@ -198,7 +197,7 @@ namespace TerminalAppLocalTests
const auto& realArgs = command.Action().Args().try_as();
VERIFY_IS_NOT_NULL(realArgs);
// Verify the args have the expected value
- VERIFY_ARE_EQUAL(winrt::TerminalApp::SplitState::Automatic, realArgs.SplitStyle());
+ VERIFY_ARE_EQUAL(SplitState::Automatic, realArgs.SplitStyle());
}
{
auto command = commands.Lookup(L"command5");
@@ -208,7 +207,7 @@ namespace TerminalAppLocalTests
const auto& realArgs = command.Action().Args().try_as();
VERIFY_IS_NOT_NULL(realArgs);
// Verify the args have the expected value
- VERIFY_ARE_EQUAL(winrt::TerminalApp::SplitState::Automatic, realArgs.SplitStyle());
+ VERIFY_ARE_EQUAL(SplitState::Automatic, realArgs.SplitStyle());
}
}
void CommandTests::TestResourceKeyName()
@@ -218,7 +217,7 @@ namespace TerminalAppLocalTests
const std::string commands0String{ R"([ { "name": { "key": "DuplicateTabCommandKey"}, "command": "copy" } ])" };
const auto commands0Json = VerifyParseSucceeded(commands0String);
- IMap commands = winrt::single_threaded_map();
+ IMap commands = winrt::single_threaded_map();
VERIFY_ARE_EQUAL(0u, commands.Size());
{
auto warnings = implementation::Command::LayerJson(commands, commands0Json);
@@ -266,7 +265,7 @@ namespace TerminalAppLocalTests
const auto commands0Json = VerifyParseSucceeded(commands0String);
- IMap commands = winrt::single_threaded_map();
+ IMap commands = winrt::single_threaded_map();
VERIFY_ARE_EQUAL(0u, commands.Size());
auto warnings = implementation::Command::LayerJson(commands, commands0Json);
VERIFY_ARE_EQUAL(0u, warnings.size());
@@ -284,7 +283,7 @@ namespace TerminalAppLocalTests
const auto& realArgs = command.Action().Args().try_as();
VERIFY_IS_NOT_NULL(realArgs);
// Verify the args have the expected value
- VERIFY_ARE_EQUAL(winrt::TerminalApp::SplitState::Automatic, realArgs.SplitStyle());
+ VERIFY_ARE_EQUAL(SplitState::Automatic, realArgs.SplitStyle());
}
{
auto command = commands.Lookup(L"Split pane, split: vertical");
@@ -294,7 +293,7 @@ namespace TerminalAppLocalTests
const auto& realArgs = command.Action().Args().try_as();
VERIFY_IS_NOT_NULL(realArgs);
// Verify the args have the expected value
- VERIFY_ARE_EQUAL(winrt::TerminalApp::SplitState::Vertical, realArgs.SplitStyle());
+ VERIFY_ARE_EQUAL(SplitState::Vertical, realArgs.SplitStyle());
}
{
auto command = commands.Lookup(L"Split pane, split: horizontal");
@@ -304,7 +303,7 @@ namespace TerminalAppLocalTests
const auto& realArgs = command.Action().Args().try_as();
VERIFY_IS_NOT_NULL(realArgs);
// Verify the args have the expected value
- VERIFY_ARE_EQUAL(winrt::TerminalApp::SplitState::Horizontal, realArgs.SplitStyle());
+ VERIFY_ARE_EQUAL(SplitState::Horizontal, realArgs.SplitStyle());
}
}
void CommandTests::TestLayerOnAutogeneratedName()
@@ -316,7 +315,7 @@ namespace TerminalAppLocalTests
const auto commands0Json = VerifyParseSucceeded(commands0String);
- IMap commands = winrt::single_threaded_map();
+ IMap commands = winrt::single_threaded_map();
VERIFY_ARE_EQUAL(0u, commands.Size());
auto warnings = implementation::Command::LayerJson(commands, commands0Json);
VERIFY_ARE_EQUAL(0u, warnings.size());
@@ -330,7 +329,7 @@ namespace TerminalAppLocalTests
const auto& realArgs = command.Action().Args().try_as();
VERIFY_IS_NOT_NULL(realArgs);
// Verify the args have the expected value
- VERIFY_ARE_EQUAL(winrt::TerminalApp::SplitState::Vertical, realArgs.SplitStyle());
+ VERIFY_ARE_EQUAL(SplitState::Vertical, realArgs.SplitStyle());
}
}
}
diff --git a/src/cascadia/LocalTests_SettingsModel/DeserializationTests.cpp b/src/cascadia/LocalTests_SettingsModel/DeserializationTests.cpp
new file mode 100644
index 00000000000..e6e9037760e
--- /dev/null
+++ b/src/cascadia/LocalTests_SettingsModel/DeserializationTests.cpp
@@ -0,0 +1,2373 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT license.
+
+#include "pch.h"
+
+#include "../TerminalSettingsModel/ColorScheme.h"
+#include "../TerminalSettingsModel/CascadiaSettings.h"
+#include "JsonTestClass.h"
+#include "TestUtils.h"
+#include
+#include "../ut_app/TestDynamicProfileGenerator.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 SettingsModelLocalTests
+{
+ // 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 DeserializationTests : public JsonTestClass
+ {
+ // 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(DeserializationTests)
+ TEST_CLASS_PROPERTY(L"RunAs", L"UAP")
+ TEST_CLASS_PROPERTY(L"UAP:AppXManifest", L"TestHostAppXManifest.xml")
+ END_TEST_CLASS()
+
+ TEST_METHOD(ValidateProfilesExist);
+ TEST_METHOD(ValidateDefaultProfileExists);
+ TEST_METHOD(ValidateDuplicateProfiles);
+ TEST_METHOD(ValidateManyWarnings);
+ TEST_METHOD(LayerGlobalProperties);
+ TEST_METHOD(ValidateProfileOrdering);
+ TEST_METHOD(ValidateHideProfiles);
+ TEST_METHOD(ValidateProfilesGenerateGuids);
+ TEST_METHOD(GeneratedGuidRoundtrips);
+ TEST_METHOD(TestAllValidationsWithNullGuids);
+ TEST_METHOD(TestReorderWithNullGuids);
+ TEST_METHOD(TestReorderingWithoutGuid);
+ TEST_METHOD(TestLayeringNameOnlyProfiles);
+ TEST_METHOD(TestExplodingNameOnlyProfiles);
+ TEST_METHOD(TestHideAllProfiles);
+ TEST_METHOD(TestInvalidColorSchemeName);
+ TEST_METHOD(TestHelperFunctions);
+
+ TEST_METHOD(TestProfileIconWithEnvVar);
+ TEST_METHOD(TestProfileBackgroundImageWithEnvVar);
+
+ TEST_METHOD(TestCloseOnExitParsing);
+ TEST_METHOD(TestCloseOnExitCompatibilityShim);
+
+ TEST_METHOD(TestLayerUserDefaultsBeforeProfiles);
+ TEST_METHOD(TestDontLayerGuidFromUserDefaults);
+ TEST_METHOD(TestLayerUserDefaultsOnDynamics);
+
+ TEST_METHOD(FindMissingProfile);
+
+ TEST_METHOD(ValidateKeybindingsWarnings);
+
+ TEST_METHOD(ValidateExecuteCommandlineWarning);
+
+ TEST_METHOD(ValidateLegacyGlobalsWarning);
+
+ TEST_METHOD(TestTrailingCommas);
+
+ TEST_METHOD(TestCommandsAndKeybindings);
+
+ TEST_METHOD(TestNestedCommandWithoutName);
+ TEST_METHOD(TestUnbindNestedCommand);
+ TEST_METHOD(TestRebindNestedCommand);
+
+ TEST_CLASS_SETUP(ClassSetup)
+ {
+ InitializeJsonReader();
+ return true;
+ }
+
+ private:
+ void _logCommandNames(winrt::Windows::Foundation::Collections::IMapView commands, const int indentation = 1)
+ {
+ if (indentation == 1)
+ {
+ Log::Comment((commands.Size() == 0) ? L"Commands:\n " : 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());
+
+ winrt::com_ptr cmdImpl;
+ cmdImpl.copy_from(winrt::get_self(nameAndCommand.Value()));
+ if (cmdImpl->HasNestedCommands())
+ {
+ _logCommandNames(cmdImpl->_subcommands.GetView(), indentation + 2);
+ }
+ }
+ }
+ };
+
+ void DeserializationTests::ValidateProfilesExist()
+ {
+ const std::string settingsWithProfiles{ R"(
+ {
+ "profiles": [
+ {
+ "name" : "profile0"
+ }
+ ]
+ })" };
+
+ const std::string settingsWithoutProfiles{ R"(
+ {
+ "defaultProfile": "{6239a42c-1de4-49a3-80bd-e8fdd045185c}"
+ })" };
+
+ const std::string settingsWithEmptyProfiles{ R"(
+ {
+ "profiles": []
+ })" };
+
+ {
+ // Case 1: Good settings
+ const auto settingsObject = VerifyParseSucceeded(settingsWithProfiles);
+ auto settings = implementation::CascadiaSettings::FromJson(settingsObject);
+ settings->_ValidateProfilesExist();
+ }
+ {
+ // Case 2: Bad settings
+ const auto settingsObject = VerifyParseSucceeded(settingsWithoutProfiles);
+ auto settings = implementation::CascadiaSettings::FromJson(settingsObject);
+ bool caughtExpectedException = false;
+ try
+ {
+ settings->_ValidateProfilesExist();
+ }
+ catch (const implementation::SettingsException& ex)
+ {
+ VERIFY_IS_TRUE(ex.Error() == SettingsLoadErrors::NoProfiles);
+ caughtExpectedException = true;
+ }
+ VERIFY_IS_TRUE(caughtExpectedException);
+ }
+ {
+ // Case 3: Bad settings
+ const auto settingsObject = VerifyParseSucceeded(settingsWithEmptyProfiles);
+ auto settings = implementation::CascadiaSettings::FromJson(settingsObject);
+ bool caughtExpectedException = false;
+ try
+ {
+ settings->_ValidateProfilesExist();
+ }
+ catch (const implementation::SettingsException& ex)
+ {
+ VERIFY_IS_TRUE(ex.Error() == SettingsLoadErrors::NoProfiles);
+ caughtExpectedException = true;
+ }
+ VERIFY_IS_TRUE(caughtExpectedException);
+ }
+ }
+
+ void DeserializationTests::ValidateDefaultProfileExists()
+ {
+ const std::string goodProfiles{ R"(
+ {
+ "defaultProfile": "{6239a42c-1111-49a3-80bd-e8fdd045185c}",
+ "profiles": [
+ {
+ "name" : "profile0",
+ "guid": "{6239a42c-1111-49a3-80bd-e8fdd045185c}"
+ },
+ {
+ "name" : "profile0",
+ "guid": "{6239a42c-2222-49a3-80bd-e8fdd045185c}"
+ }
+ ]
+ })" };
+
+ const std::string badProfiles{ R"(
+ {
+ "defaultProfile": "{6239a42c-1111-49a3-80bd-e8fdd045185c}",
+ "profiles": [
+ {
+ "name" : "profile0",
+ "guid": "{6239a42c-3333-49a3-80bd-e8fdd045185c}"
+ },
+ {
+ "name" : "profile1",
+ "guid": "{6239a42c-4444-49a3-80bd-e8fdd045185c}"
+ }
+ ]
+ })" };
+
+ const std::string noDefaultAtAll{ R"(
+ {
+ "alwaysShowTabs": true,
+ "profiles": [
+ {
+ "name" : "profile0",
+ "guid": "{6239a42c-5555-49a3-80bd-e8fdd045185c}"
+ },
+ {
+ "name" : "profile1",
+ "guid": "{6239a42c-6666-49a3-80bd-e8fdd045185c}"
+ }
+ ]
+ })" };
+
+ const std::string goodProfilesSpecifiedByName{ R"(
+ {
+ "defaultProfile": "profile1",
+ "profiles": [
+ {
+ "name" : "profile0",
+ "guid": "{6239a42c-1111-49a3-80bd-e8fdd045185c}"
+ },
+ {
+ "name" : "profile1",
+ "guid": "{6239a42c-2222-49a3-80bd-e8fdd045185c}"
+ }
+ ]
+ })" };
+
+ {
+ // Case 1: Good settings
+ Log::Comment(NoThrowString().Format(
+ L"Testing a pair of profiles with unique guids, and the defaultProfile is one of those guids"));
+ const auto settingsObject = VerifyParseSucceeded(goodProfiles);
+ auto settings = implementation::CascadiaSettings::FromJson(settingsObject);
+ settings->_ResolveDefaultProfile();
+ settings->_ValidateDefaultProfileExists();
+ VERIFY_ARE_EQUAL(static_cast(0), settings->_warnings.Size());
+ VERIFY_ARE_EQUAL(static_cast(2), settings->_profiles.Size());
+ VERIFY_ARE_EQUAL(settings->_globals->DefaultProfile(), settings->_profiles.GetAt(0).Guid());
+ }
+ {
+ // Case 2: Bad settings
+ Log::Comment(NoThrowString().Format(
+ L"Testing a pair of profiles with unique guids, but the defaultProfile is NOT one of those guids"));
+ const auto settingsObject = VerifyParseSucceeded(badProfiles);
+ auto settings = implementation::CascadiaSettings::FromJson(settingsObject);
+ settings->_ResolveDefaultProfile();
+ settings->_ValidateDefaultProfileExists();
+ VERIFY_ARE_EQUAL(static_cast(1), settings->_warnings.Size());
+ VERIFY_ARE_EQUAL(SettingsLoadWarnings::MissingDefaultProfile, settings->_warnings.GetAt(0));
+
+ VERIFY_ARE_EQUAL(static_cast(2), settings->_profiles.Size());
+ VERIFY_ARE_EQUAL(settings->_globals->DefaultProfile(), settings->_profiles.GetAt(0).Guid());
+ }
+ {
+ // Case 2: Bad settings
+ Log::Comment(NoThrowString().Format(
+ L"Testing a pair of profiles with unique guids, and no defaultProfile at all"));
+ const auto settingsObject = VerifyParseSucceeded(badProfiles);
+ auto settings = implementation::CascadiaSettings::FromJson(settingsObject);
+ settings->_ResolveDefaultProfile();
+ settings->_ValidateDefaultProfileExists();
+ VERIFY_ARE_EQUAL(static_cast(1), settings->_warnings.Size());
+ VERIFY_ARE_EQUAL(SettingsLoadWarnings::MissingDefaultProfile, settings->_warnings.GetAt(0));
+
+ VERIFY_ARE_EQUAL(static_cast(2), settings->_profiles.Size());
+ VERIFY_ARE_EQUAL(settings->_globals->DefaultProfile(), settings->_profiles.GetAt(0).Guid());
+ }
+ {
+ // Case 4: Good settings, default profile is a string
+ Log::Comment(NoThrowString().Format(
+ L"Testing a pair of profiles with unique guids, and the defaultProfile is one of the profile names"));
+ const auto settingsObject = VerifyParseSucceeded(goodProfilesSpecifiedByName);
+ auto settings = implementation::CascadiaSettings::FromJson(settingsObject);
+ settings->_ResolveDefaultProfile();
+ settings->_ValidateDefaultProfileExists();
+ VERIFY_ARE_EQUAL(static_cast(0), settings->_warnings.Size());
+ VERIFY_ARE_EQUAL(static_cast(2), settings->_profiles.Size());
+ VERIFY_ARE_EQUAL(settings->_globals->DefaultProfile(), settings->_profiles.GetAt(1).Guid());
+ }
+ }
+
+ void DeserializationTests::ValidateDuplicateProfiles()
+ {
+ const std::string goodProfiles{ R"(
+ {
+ "profiles": [
+ {
+ "name" : "profile0",
+ "guid": "{6239a42c-1111-49a3-80bd-e8fdd045185c}"
+ },
+ {
+ "name" : "profile0",
+ "guid": "{6239a42c-2222-49a3-80bd-e8fdd045185c}"
+ }
+ ]
+ })" };
+
+ const std::string badProfiles{ R"(
+ {
+ "profiles": [
+ {
+ "name" : "profile0",
+ "guid": "{6239a42c-3333-49a3-80bd-e8fdd045185c}"
+ },
+ {
+ "name" : "profile1",
+ "guid": "{6239a42c-3333-49a3-80bd-e8fdd045185c}"
+ }
+ ]
+ })" };
+
+ const std::string veryBadProfiles{ R"(
+ {
+ "profiles": [
+ {
+ "name" : "profile0",
+ "guid": "{6239a42c-4444-49a3-80bd-e8fdd045185c}"
+ },
+ {
+ "name" : "profile1",
+ "guid": "{6239a42c-5555-49a3-80bd-e8fdd045185c}"
+ },
+ {
+ "name" : "profile2",
+ "guid": "{6239a42c-4444-49a3-80bd-e8fdd045185c}"
+ },
+ {
+ "name" : "profile3",
+ "guid": "{6239a42c-4444-49a3-80bd-e8fdd045185c}"
+ },
+ {
+ "name" : "profile4",
+ "guid": "{6239a42c-6666-49a3-80bd-e8fdd045185c}"
+ },
+ {
+ "name" : "profile5",
+ "guid": "{6239a42c-5555-49a3-80bd-e8fdd045185c}"
+ },
+ {
+ "name" : "profile6",
+ "guid": "{6239a42c-7777-49a3-80bd-e8fdd045185c}"
+ }
+ ]
+ })" };
+ Profile profile0 = winrt::make(::Microsoft::Console::Utils::GuidFromString(L"{6239a42c-4444-49a3-80bd-e8fdd045185c}"));
+ profile0.Name(L"profile0");
+ Profile profile1 = winrt::make(::Microsoft::Console::Utils::GuidFromString(L"{6239a42c-5555-49a3-80bd-e8fdd045185c}"));
+ profile1.Name(L"profile1");
+ Profile profile2 = winrt::make(::Microsoft::Console::Utils::GuidFromString(L"{6239a42c-4444-49a3-80bd-e8fdd045185c}"));
+ profile2.Name(L"profile2");
+ Profile profile3 = winrt::make(::Microsoft::Console::Utils::GuidFromString(L"{6239a42c-4444-49a3-80bd-e8fdd045185c}"));
+ profile3.Name(L"profile3");
+ Profile profile4 = winrt::make(::Microsoft::Console::Utils::GuidFromString(L"{6239a42c-6666-49a3-80bd-e8fdd045185c}"));
+ profile4.Name(L"profile4");
+ Profile profile5 = winrt::make(::Microsoft::Console::Utils::GuidFromString(L"{6239a42c-5555-49a3-80bd-e8fdd045185c}"));
+ profile5.Name(L"profile5");
+ Profile profile6 = winrt::make(::Microsoft::Console::Utils::GuidFromString(L"{6239a42c-7777-49a3-80bd-e8fdd045185c}"));
+ profile6.Name(L"profile6");
+
+ {
+ // Case 1: Good settings
+ Log::Comment(NoThrowString().Format(
+ L"Testing a pair of profiles with unique guids"));
+
+ auto settings = winrt::make_self();
+ settings->_profiles.Append(profile0);
+ settings->_profiles.Append(profile1);
+
+ settings->_ValidateNoDuplicateProfiles();
+
+ VERIFY_ARE_EQUAL(static_cast(0), settings->_warnings.Size());
+ VERIFY_ARE_EQUAL(static_cast(2), settings->_profiles.Size());
+ }
+ {
+ // Case 2: Bad settings
+ Log::Comment(NoThrowString().Format(
+ L"Testing a pair of profiles with the same guid"));
+
+ auto settings = winrt::make_self();
+ settings->_profiles.Append(profile2);
+ settings->_profiles.Append(profile3);
+
+ settings->_ValidateNoDuplicateProfiles();
+
+ VERIFY_ARE_EQUAL(static_cast(1), settings->_warnings.Size());
+ VERIFY_ARE_EQUAL(SettingsLoadWarnings::DuplicateProfile, settings->_warnings.GetAt(0));
+
+ VERIFY_ARE_EQUAL(static_cast(1), settings->_profiles.Size());
+ VERIFY_ARE_EQUAL(L"profile2", settings->_profiles.GetAt(0).Name());
+ }
+ {
+ // Case 3: Very bad settings
+ Log::Comment(NoThrowString().Format(
+ L"Testing a set of profiles, many of which with duplicated guids"));
+
+ auto settings = winrt::make_self();
+ settings->_profiles.Append(profile0);
+ settings->_profiles.Append(profile1);
+ settings->_profiles.Append(profile2);
+ settings->_profiles.Append(profile3);
+ settings->_profiles.Append(profile4);
+ settings->_profiles.Append(profile5);
+ settings->_profiles.Append(profile6);
+
+ settings->_ValidateNoDuplicateProfiles();
+
+ VERIFY_ARE_EQUAL(static_cast(1), settings->_warnings.Size());
+ VERIFY_ARE_EQUAL(SettingsLoadWarnings::DuplicateProfile, settings->_warnings.GetAt(0));
+
+ VERIFY_ARE_EQUAL(static_cast(4), settings->_profiles.Size());
+ VERIFY_ARE_EQUAL(L"profile0", settings->_profiles.GetAt(0).Name());
+ VERIFY_ARE_EQUAL(L"profile1", settings->_profiles.GetAt(1).Name());
+ VERIFY_ARE_EQUAL(L"profile4", settings->_profiles.GetAt(2).Name());
+ VERIFY_ARE_EQUAL(L"profile6", settings->_profiles.GetAt(3).Name());
+ }
+ }
+
+ void DeserializationTests::ValidateManyWarnings()
+ {
+ const std::string badProfiles{ R"(
+ {
+ "defaultProfile": "{6239a42c-1111-49a3-80bd-e8fdd045185c}",
+ "profiles": [
+ {
+ "name" : "profile0",
+ "guid": "{6239a42c-2222-49a3-80bd-e8fdd045185c}"
+ },
+ {
+ "name" : "profile1",
+ "guid": "{6239a42c-3333-49a3-80bd-e8fdd045185c}"
+ },
+ {
+ "name" : "profile2",
+ "guid": "{6239a42c-2222-49a3-80bd-e8fdd045185c}"
+ }
+ ]
+ })" };
+ Profile profile4 = winrt::make(::Microsoft::Console::Utils::GuidFromString(L"{6239a42c-4444-49a3-80bd-e8fdd045185c}"));
+ profile4.Name(L"profile4");
+ Profile profile5 = winrt::make(::Microsoft::Console::Utils::GuidFromString(L"{6239a42c-4444-49a3-80bd-e8fdd045185c}"));
+ profile5.Name(L"profile5");
+
+ // Case 2: Bad settings
+ Log::Comment(NoThrowString().Format(
+ L"Testing a pair of profiles with the same guid"));
+ const auto settingsObject = VerifyParseSucceeded(badProfiles);
+ auto settings = implementation::CascadiaSettings::FromJson(settingsObject);
+
+ settings->_profiles.Append(profile4);
+ settings->_profiles.Append(profile5);
+
+ settings->_ValidateSettings();
+
+ VERIFY_ARE_EQUAL(3u, settings->_warnings.Size());
+ VERIFY_ARE_EQUAL(SettingsLoadWarnings::DuplicateProfile, settings->_warnings.GetAt(0));
+ VERIFY_ARE_EQUAL(SettingsLoadWarnings::MissingDefaultProfile, settings->_warnings.GetAt(1));
+ VERIFY_ARE_EQUAL(SettingsLoadWarnings::UnknownColorScheme, settings->_warnings.GetAt(2));
+
+ VERIFY_ARE_EQUAL(3u, settings->_profiles.Size());
+ VERIFY_ARE_EQUAL(settings->_globals->DefaultProfile(), settings->_profiles.GetAt(0).Guid());
+ VERIFY_IS_TRUE(settings->_profiles.GetAt(0).HasGuid());
+ VERIFY_IS_TRUE(settings->_profiles.GetAt(1).HasGuid());
+ VERIFY_IS_TRUE(settings->_profiles.GetAt(2).HasGuid());
+ }
+
+ void DeserializationTests::LayerGlobalProperties()
+ {
+ const std::string settings0String{ R"(
+ {
+ "alwaysShowTabs": true,
+ "initialCols" : 120,
+ "initialRows" : 30
+ })" };
+ const std::string settings1String{ R"(
+ {
+ "showTabsInTitlebar": false,
+ "initialCols" : 240,
+ "initialRows" : 60
+ })" };
+ const auto settings0Json = VerifyParseSucceeded(settings0String);
+ const auto settings1Json = VerifyParseSucceeded(settings1String);
+
+ auto settings = winrt::make_self();
+
+ settings->LayerJson(settings0Json);
+ VERIFY_ARE_EQUAL(true, settings->_globals->AlwaysShowTabs());
+ VERIFY_ARE_EQUAL(120, settings->_globals->InitialCols());
+ VERIFY_ARE_EQUAL(30, settings->_globals->InitialRows());
+ VERIFY_ARE_EQUAL(true, settings->_globals->ShowTabsInTitlebar());
+
+ settings->LayerJson(settings1Json);
+ VERIFY_ARE_EQUAL(true, settings->_globals->AlwaysShowTabs());
+ VERIFY_ARE_EQUAL(240, settings->_globals->InitialCols());
+ VERIFY_ARE_EQUAL(60, settings->_globals->InitialRows());
+ VERIFY_ARE_EQUAL(false, settings->_globals->ShowTabsInTitlebar());
+ }
+
+ void DeserializationTests::ValidateProfileOrdering()
+ {
+ const std::string userProfiles0String{ R"(
+ {
+ "profiles": [
+ {
+ "name" : "profile0",
+ "guid": "{6239a42c-0000-49a3-80bd-e8fdd045185c}"
+ },
+ {
+ "name" : "profile1",
+ "guid": "{6239a42c-1111-49a3-80bd-e8fdd045185c}"
+ }
+ ]
+ })" };
+
+ const std::string defaultProfilesString{ R"(
+ {
+ "profiles": [
+ {
+ "name" : "profile2",
+ "guid": "{6239a42c-1111-49a3-80bd-e8fdd045185c}"
+ },
+ {
+ "name" : "profile3",
+ "guid": "{6239a42c-0000-49a3-80bd-e8fdd045185c}"
+ }
+ ]
+ })" };
+
+ const std::string userProfiles1String{ R"(
+ {
+ "profiles": [
+ {
+ "name" : "profile4",
+ "guid": "{6239a42c-0000-49a3-80bd-e8fdd045185c}"
+ },
+ {
+ "name" : "profile5",
+ "guid": "{6239a42c-2222-49a3-80bd-e8fdd045185c}"
+ }
+ ]
+ })" };
+
+ const auto userProfiles0Json = VerifyParseSucceeded(userProfiles0String);
+ const auto userProfiles1Json = VerifyParseSucceeded(userProfiles1String);
+ const auto defaultProfilesJson = VerifyParseSucceeded(defaultProfilesString);
+
+ {
+ Log::Comment(NoThrowString().Format(
+ L"Case 1: Simple swapping of the ordering. The user has the "
+ L"default profiles in the opposite order of the default ordering."));
+
+ auto settings = winrt::make_self();
+ settings->_ParseJsonString(defaultProfilesString, true);
+ settings->LayerJson(settings->_defaultSettings);
+ VERIFY_ARE_EQUAL(2u, settings->_profiles.Size());
+ VERIFY_ARE_EQUAL(L"profile2", settings->_profiles.GetAt(0).Name());
+ VERIFY_ARE_EQUAL(L"profile3", settings->_profiles.GetAt(1).Name());
+
+ settings->_ParseJsonString(userProfiles0String, false);
+ settings->LayerJson(settings->_userSettings);
+ VERIFY_ARE_EQUAL(2u, settings->_profiles.Size());
+ VERIFY_ARE_EQUAL(L"profile1", settings->_profiles.GetAt(0).Name());
+ VERIFY_ARE_EQUAL(L"profile0", settings->_profiles.GetAt(1).Name());
+
+ settings->_ReorderProfilesToMatchUserSettingsOrder();
+ VERIFY_ARE_EQUAL(2u, settings->_profiles.Size());
+ VERIFY_ARE_EQUAL(L"profile0", settings->_profiles.GetAt(0).Name());
+ VERIFY_ARE_EQUAL(L"profile1", settings->_profiles.GetAt(1).Name());
+ }
+
+ {
+ Log::Comment(NoThrowString().Format(
+ L"Case 2: Make sure all the user's profiles appear before the defaults."));
+
+ auto settings = winrt::make_self();
+ settings->_ParseJsonString(defaultProfilesString, true);
+ settings->LayerJson(settings->_defaultSettings);
+ VERIFY_ARE_EQUAL(2u, settings->_profiles.Size());
+ VERIFY_ARE_EQUAL(L"profile2", settings->_profiles.GetAt(0).Name());
+ VERIFY_ARE_EQUAL(L"profile3", settings->_profiles.GetAt(1).Name());
+
+ settings->_ParseJsonString(userProfiles1String, false);
+ settings->LayerJson(settings->_userSettings);
+ VERIFY_ARE_EQUAL(3u, settings->_profiles.Size());
+ VERIFY_ARE_EQUAL(L"profile2", settings->_profiles.GetAt(0).Name());
+ VERIFY_ARE_EQUAL(L"profile4", settings->_profiles.GetAt(1).Name());
+ VERIFY_ARE_EQUAL(L"profile5", settings->_profiles.GetAt(2).Name());
+
+ settings->_ReorderProfilesToMatchUserSettingsOrder();
+ VERIFY_ARE_EQUAL(3u, settings->_profiles.Size());
+ VERIFY_ARE_EQUAL(L"profile4", settings->_profiles.GetAt(0).Name());
+ VERIFY_ARE_EQUAL(L"profile5", settings->_profiles.GetAt(1).Name());
+ VERIFY_ARE_EQUAL(L"profile2", settings->_profiles.GetAt(2).Name());
+ }
+ }
+
+ void DeserializationTests::ValidateHideProfiles()
+ {
+ const std::string defaultProfilesString{ R"(
+ {
+ "profiles": [
+ {
+ "name" : "profile2",
+ "guid": "{6239a42c-1111-49a3-80bd-e8fdd045185c}"
+ },
+ {
+ "name" : "profile3",
+ "guid": "{6239a42c-0000-49a3-80bd-e8fdd045185c}"
+ }
+ ]
+ })" };
+
+ const std::string userProfiles0String{ R"(
+ {
+ "profiles": [
+ {
+ "name" : "profile0",
+ "guid": "{6239a42c-0000-49a3-80bd-e8fdd045185c}",
+ "hidden": true
+ },
+ {
+ "name" : "profile1",
+ "guid": "{6239a42c-1111-49a3-80bd-e8fdd045185c}"
+ }
+ ]
+ })" };
+
+ const std::string userProfiles1String{ R"(
+ {
+ "profiles": [
+ {
+ "name" : "profile4",
+ "guid": "{6239a42c-0000-49a3-80bd-e8fdd045185c}",
+ "hidden": true
+ },
+ {
+ "name" : "profile5",
+ "guid": "{6239a42c-2222-49a3-80bd-e8fdd045185c}"
+ },
+ {
+ "name" : "profile6",
+ "guid": "{6239a42c-3333-49a3-80bd-e8fdd045185c}",
+ "hidden": true
+ }
+ ]
+ })" };
+
+ const auto userProfiles0Json = VerifyParseSucceeded(userProfiles0String);
+ const auto userProfiles1Json = VerifyParseSucceeded(userProfiles1String);
+ const auto defaultProfilesJson = VerifyParseSucceeded(defaultProfilesString);
+
+ {
+ auto settings = winrt::make_self();
+ settings->_ParseJsonString(defaultProfilesString, true);
+ settings->LayerJson(settings->_defaultSettings);
+ VERIFY_ARE_EQUAL(2u, settings->_profiles.Size());
+ VERIFY_ARE_EQUAL(L"profile2", settings->_profiles.GetAt(0).Name());
+ VERIFY_ARE_EQUAL(L"profile3", settings->_profiles.GetAt(1).Name());
+ VERIFY_ARE_EQUAL(false, settings->_profiles.GetAt(0).Hidden());
+ VERIFY_ARE_EQUAL(false, settings->_profiles.GetAt(1).Hidden());
+
+ settings->_ParseJsonString(userProfiles0String, false);
+ settings->LayerJson(settings->_userSettings);
+ VERIFY_ARE_EQUAL(2u, settings->_profiles.Size());
+ VERIFY_ARE_EQUAL(L"profile1", settings->_profiles.GetAt(0).Name());
+ VERIFY_ARE_EQUAL(L"profile0", settings->_profiles.GetAt(1).Name());
+ VERIFY_ARE_EQUAL(false, settings->_profiles.GetAt(0).Hidden());
+ VERIFY_ARE_EQUAL(true, settings->_profiles.GetAt(1).Hidden());
+
+ settings->_ReorderProfilesToMatchUserSettingsOrder();
+ settings->_RemoveHiddenProfiles();
+ VERIFY_ARE_EQUAL(1u, settings->_profiles.Size());
+ VERIFY_ARE_EQUAL(L"profile1", settings->_profiles.GetAt(0).Name());
+ VERIFY_ARE_EQUAL(false, settings->_profiles.GetAt(0).Hidden());
+ }
+
+ {
+ auto settings = winrt::make_self();
+ settings->_ParseJsonString(defaultProfilesString, true);
+ settings->LayerJson(settings->_defaultSettings);
+ VERIFY_ARE_EQUAL(2u, settings->_profiles.Size());
+ VERIFY_ARE_EQUAL(L"profile2", settings->_profiles.GetAt(0).Name());
+ VERIFY_ARE_EQUAL(L"profile3", settings->_profiles.GetAt(1).Name());
+ VERIFY_ARE_EQUAL(false, settings->_profiles.GetAt(0).Hidden());
+ VERIFY_ARE_EQUAL(false, settings->_profiles.GetAt(1).Hidden());
+
+ settings->_ParseJsonString(userProfiles1String, false);
+ settings->LayerJson(settings->_userSettings);
+ VERIFY_ARE_EQUAL(4u, settings->_profiles.Size());
+ VERIFY_ARE_EQUAL(L"profile2", settings->_profiles.GetAt(0).Name());
+ VERIFY_ARE_EQUAL(L"profile4", settings->_profiles.GetAt(1).Name());
+ VERIFY_ARE_EQUAL(L"profile5", settings->_profiles.GetAt(2).Name());
+ VERIFY_ARE_EQUAL(L"profile6", settings->_profiles.GetAt(3).Name());
+ VERIFY_ARE_EQUAL(false, settings->_profiles.GetAt(0).Hidden());
+ VERIFY_ARE_EQUAL(true, settings->_profiles.GetAt(1).Hidden());
+ VERIFY_ARE_EQUAL(false, settings->_profiles.GetAt(2).Hidden());
+ VERIFY_ARE_EQUAL(true, settings->_profiles.GetAt(3).Hidden());
+
+ settings->_ReorderProfilesToMatchUserSettingsOrder();
+ settings->_RemoveHiddenProfiles();
+ VERIFY_ARE_EQUAL(2u, settings->_profiles.Size());
+ VERIFY_ARE_EQUAL(L"profile5", settings->_profiles.GetAt(0).Name());
+ VERIFY_ARE_EQUAL(L"profile2", settings->_profiles.GetAt(1).Name());
+ VERIFY_ARE_EQUAL(false, settings->_profiles.GetAt(0).Hidden());
+ VERIFY_ARE_EQUAL(false, settings->_profiles.GetAt(1).Hidden());
+ }
+ }
+
+ void DeserializationTests::ValidateProfilesGenerateGuids()
+ {
+ const std::string profile0String{ R"(
+ {
+ "name" : "profile0"
+ })" };
+ const std::string profile1String{ R"(
+ {
+ "name" : "profile1"
+ })" };
+ const std::string profile2String{ R"(
+ {
+ "name" : "profile2",
+ "guid" : null
+ })" };
+ const std::string profile3String{ R"(
+ {
+ "name" : "profile3",
+ "guid" : "{00000000-0000-0000-0000-000000000000}"
+ })" };
+ const std::string profile4String{ R"(
+ {
+ "name" : "profile4",
+ "guid" : "{6239a42c-1de4-49a3-80bd-e8fdd045185c}"
+ })" };
+ const std::string profile5String{ R"(
+ {
+ "name" : "profile2"
+ })" };
+
+ const auto profile0Json = VerifyParseSucceeded(profile0String);
+ const auto profile1Json = VerifyParseSucceeded(profile1String);
+ const auto profile2Json = VerifyParseSucceeded(profile2String);
+ const auto profile3Json = VerifyParseSucceeded(profile3String);
+ const auto profile4Json = VerifyParseSucceeded(profile4String);
+ const auto profile5Json = VerifyParseSucceeded(profile5String);
+
+ const auto profile0 = implementation::Profile::FromJson(profile0Json);
+ const auto profile1 = implementation::Profile::FromJson(profile1Json);
+ const auto profile2 = implementation::Profile::FromJson(profile2Json);
+ const auto profile3 = implementation::Profile::FromJson(profile3Json);
+ const auto profile4 = implementation::Profile::FromJson(profile4Json);
+ const auto profile5 = implementation::Profile::FromJson(profile5Json);
+
+ const winrt::guid cmdGuid{ Utils::GuidFromString(L"{6239a42c-1de4-49a3-80bd-e8fdd045185c}") };
+ const winrt::guid nullGuid{};
+
+ VERIFY_IS_FALSE(profile0->HasGuid());
+ VERIFY_IS_FALSE(profile1->HasGuid());
+ VERIFY_IS_FALSE(profile2->HasGuid());
+ VERIFY_IS_TRUE(profile3->HasGuid());
+ VERIFY_IS_TRUE(profile4->HasGuid());
+ VERIFY_IS_FALSE(profile5->HasGuid());
+
+ VERIFY_ARE_EQUAL(profile3->Guid(), nullGuid);
+ VERIFY_ARE_EQUAL(profile4->Guid(), cmdGuid);
+
+ auto settings = winrt::make_self();
+ settings->_profiles.Append(*profile0);
+ settings->_profiles.Append(*profile1);
+ settings->_profiles.Append(*profile2);
+ settings->_profiles.Append(*profile3);
+ settings->_profiles.Append(*profile4);
+ settings->_profiles.Append(*profile5);
+
+ settings->_ValidateProfilesHaveGuid();
+ VERIFY_IS_TRUE(settings->_profiles.GetAt(0).HasGuid());
+ VERIFY_IS_TRUE(settings->_profiles.GetAt(1).HasGuid());
+ VERIFY_IS_TRUE(settings->_profiles.GetAt(2).HasGuid());
+ VERIFY_IS_TRUE(settings->_profiles.GetAt(3).HasGuid());
+ VERIFY_IS_TRUE(settings->_profiles.GetAt(4).HasGuid());
+ VERIFY_IS_TRUE(settings->_profiles.GetAt(5).HasGuid());
+
+ VERIFY_ARE_NOT_EQUAL(settings->_profiles.GetAt(0).Guid(), nullGuid);
+ VERIFY_ARE_NOT_EQUAL(settings->_profiles.GetAt(1).Guid(), nullGuid);
+ VERIFY_ARE_NOT_EQUAL(settings->_profiles.GetAt(2).Guid(), nullGuid);
+ VERIFY_ARE_EQUAL(settings->_profiles.GetAt(3).Guid(), nullGuid);
+ VERIFY_ARE_NOT_EQUAL(settings->_profiles.GetAt(4).Guid(), nullGuid);
+ VERIFY_ARE_NOT_EQUAL(settings->_profiles.GetAt(5).Guid(), nullGuid);
+
+ VERIFY_ARE_NOT_EQUAL(settings->_profiles.GetAt(0).Guid(), cmdGuid);
+ VERIFY_ARE_NOT_EQUAL(settings->_profiles.GetAt(1).Guid(), cmdGuid);
+ VERIFY_ARE_NOT_EQUAL(settings->_profiles.GetAt(2).Guid(), cmdGuid);
+ VERIFY_ARE_NOT_EQUAL(settings->_profiles.GetAt(3).Guid(), cmdGuid);
+ VERIFY_ARE_EQUAL(settings->_profiles.GetAt(4).Guid(), cmdGuid);
+ VERIFY_ARE_NOT_EQUAL(settings->_profiles.GetAt(5).Guid(), cmdGuid);
+
+ VERIFY_ARE_NOT_EQUAL(settings->_profiles.GetAt(0).Guid(), settings->_profiles.GetAt(2).Guid());
+ VERIFY_ARE_NOT_EQUAL(settings->_profiles.GetAt(1).Guid(), settings->_profiles.GetAt(2).Guid());
+ VERIFY_ARE_EQUAL(settings->_profiles.GetAt(2).Guid(), settings->_profiles.GetAt(2).Guid());
+ VERIFY_ARE_NOT_EQUAL(settings->_profiles.GetAt(3).Guid(), settings->_profiles.GetAt(2).Guid());
+ VERIFY_ARE_NOT_EQUAL(settings->_profiles.GetAt(4).Guid(), settings->_profiles.GetAt(2).Guid());
+ VERIFY_ARE_EQUAL(settings->_profiles.GetAt(5).Guid(), settings->_profiles.GetAt(2).Guid());
+ }
+
+ void DeserializationTests::GeneratedGuidRoundtrips()
+ {
+ // Parse a profile without a guid.
+ // We should automatically generate a GUID for that profile.
+ // When that profile is serialized and deserialized again, the GUID we
+ // generated for it should persist.
+ const std::string profileWithoutGuid{ R"({
+ "name" : "profile0"
+ })" };
+ const auto profile0Json = VerifyParseSucceeded(profileWithoutGuid);
+
+ const auto profile0 = implementation::Profile::FromJson(profile0Json);
+ const GUID nullGuid{ 0 };
+
+ VERIFY_IS_FALSE(profile0->HasGuid());
+
+ const auto serialized0Profile = profile0->GenerateStub();
+ const auto profile1 = implementation::Profile::FromJson(serialized0Profile);
+ VERIFY_IS_FALSE(profile0->HasGuid());
+ VERIFY_IS_FALSE(profile1->HasGuid());
+
+ auto settings = winrt::make_self();
+ settings->_profiles.Append(*profile1);
+ settings->_ValidateProfilesHaveGuid();
+
+ VERIFY_IS_TRUE(settings->_profiles.GetAt(0).HasGuid());
+
+ const auto profileImpl = winrt::get_self(settings->_profiles.GetAt(0));
+ const auto serialized1Profile = profileImpl->GenerateStub();
+
+ const auto profile2 = implementation::Profile::FromJson(serialized1Profile);
+ VERIFY_IS_TRUE(settings->_profiles.GetAt(0).HasGuid());
+ VERIFY_IS_TRUE(profile2->HasGuid());
+ VERIFY_ARE_EQUAL(settings->_profiles.GetAt(0).Guid(), profile2->Guid());
+ }
+
+ void DeserializationTests::TestAllValidationsWithNullGuids()
+ {
+ const std::string settings0String{ R"(
+ {
+ "defaultProfile": "{6239a42c-1111-49a3-80bd-e8fdd045185c}",
+ "profiles": [
+ {
+ "name" : "profile0",
+ "guid" : "{6239a42c-1111-49a3-80bd-e8fdd045185c}"
+ },
+ {
+ "name" : "profile1"
+ }
+ ],
+ "schemes": [
+ { "name": "Campbell" }
+ ]
+ })" };
+
+ const auto settings0Json = VerifyParseSucceeded(settings0String);
+
+ auto settings = winrt::make_self();
+ settings->_ParseJsonString(settings0String, false);
+ settings->LayerJson(settings->_userSettings);
+
+ VERIFY_ARE_EQUAL(2u, settings->_profiles.Size());
+ VERIFY_IS_TRUE(settings->_profiles.GetAt(0).HasGuid());
+ VERIFY_IS_FALSE(settings->_profiles.GetAt(1).HasGuid());
+
+ settings->_ValidateSettings();
+ VERIFY_ARE_EQUAL(0u, settings->_warnings.Size());
+ VERIFY_ARE_EQUAL(2u, settings->_profiles.Size());
+ VERIFY_IS_TRUE(settings->_profiles.GetAt(0).HasGuid());
+ VERIFY_IS_TRUE(settings->_profiles.GetAt(1).HasGuid());
+ }
+
+ void DeserializationTests::TestReorderWithNullGuids()
+ {
+ const std::string settings0String{ R"(
+ {
+ "defaultProfile": "{6239a42c-1111-49a3-80bd-e8fdd045185c}",
+ "profiles": [
+ {
+ "name" : "profile0",
+ "guid" : "{6239a42c-1111-49a3-80bd-e8fdd045185c}"
+ },
+ {
+ "name" : "profile1"
+ },
+ {
+ "name" : "cmdFromUserSettings",
+ "guid" : "{0caa0dad-35be-5f56-a8ff-afceeeaa6101}" // from defaults.json
+ }
+ ]
+ })" };
+
+ const auto settings0Json = VerifyParseSucceeded(settings0String);
+
+ auto settings = winrt::make_self();
+ settings->_ParseJsonString(DefaultJson, true);
+ settings->LayerJson(settings->_defaultSettings);
+ VERIFY_ARE_EQUAL(2u, settings->_profiles.Size());
+ VERIFY_IS_TRUE(settings->_profiles.GetAt(0).HasGuid());
+ VERIFY_IS_TRUE(settings->_profiles.GetAt(1).HasGuid());
+ VERIFY_ARE_EQUAL(L"Windows PowerShell", settings->_profiles.GetAt(0).Name());
+ VERIFY_ARE_EQUAL(L"Command Prompt", settings->_profiles.GetAt(1).Name());
+
+ settings->_ParseJsonString(settings0String, false);
+ settings->LayerJson(settings->_userSettings);
+
+ VERIFY_ARE_EQUAL(4u, settings->_profiles.Size());
+ VERIFY_IS_TRUE(settings->_profiles.GetAt(0).HasGuid());
+ VERIFY_IS_TRUE(settings->_profiles.GetAt(1).HasGuid());
+ VERIFY_IS_TRUE(settings->_profiles.GetAt(2).HasGuid());
+ VERIFY_IS_FALSE(settings->_profiles.GetAt(3).HasGuid());
+ VERIFY_ARE_EQUAL(L"Windows PowerShell", settings->_profiles.GetAt(0).Name());
+ VERIFY_ARE_EQUAL(L"cmdFromUserSettings", settings->_profiles.GetAt(1).Name());
+ VERIFY_ARE_EQUAL(L"profile0", settings->_profiles.GetAt(2).Name());
+ VERIFY_ARE_EQUAL(L"profile1", settings->_profiles.GetAt(3).Name());
+
+ settings->_ValidateSettings();
+ VERIFY_ARE_EQUAL(0u, settings->_warnings.Size());
+ VERIFY_ARE_EQUAL(4u, settings->_profiles.Size());
+ VERIFY_IS_TRUE(settings->_profiles.GetAt(0).HasGuid());
+ VERIFY_IS_TRUE(settings->_profiles.GetAt(1).HasGuid());
+ VERIFY_IS_TRUE(settings->_profiles.GetAt(2).HasGuid());
+ VERIFY_IS_TRUE(settings->_profiles.GetAt(3).HasGuid());
+ VERIFY_ARE_EQUAL(L"profile0", settings->_profiles.GetAt(0).Name());
+ VERIFY_ARE_EQUAL(L"profile1", settings->_profiles.GetAt(1).Name());
+ VERIFY_ARE_EQUAL(L"cmdFromUserSettings", settings->_profiles.GetAt(2).Name());
+ VERIFY_ARE_EQUAL(L"Windows PowerShell", settings->_profiles.GetAt(3).Name());
+ }
+
+ void DeserializationTests::TestReorderingWithoutGuid()
+ {
+ Log::Comment(NoThrowString().Format(
+ L"During the GH#2515 PR, this set of settings was found to cause an"
+ L" exception, crashing the terminal. This test ensures that it doesn't."));
+
+ Log::Comment(NoThrowString().Format(
+ L"While similar to TestReorderWithNullGuids, there's something else"
+ L" about this scenario specifically that causes a crash, when "
+ L" TestReorderWithNullGuids did _not_."));
+
+ const std::string settings0String{ R"(
+ {
+ "defaultProfile" : "{0caa0dad-35be-5f56-a8ff-afceeeaa6101}",
+ "profiles": [
+ {
+ "guid" : "{0caa0dad-35be-5f56-a8ff-afceeeaa6101}",
+ "acrylicOpacity" : 0.5,
+ "closeOnExit" : true,
+ "background" : "#8A00FF",
+ "foreground" : "#F2F2F2",
+ "commandline" : "cmd.exe",
+ "cursorColor" : "#FFFFFF",
+ "fontFace" : "Cascadia Code",
+ "fontSize" : 10,
+ "historySize" : 9001,
+ "padding" : "20",
+ "snapOnInput" : true,
+ "startingDirectory" : "%USERPROFILE%",
+ "useAcrylic" : true
+ },
+ {
+ "name" : "ThisProfileShouldNotCrash",
+ "tabTitle" : "Ubuntu",
+ "acrylicOpacity" : 0.5,
+ "background" : "#2C001E",
+ "closeOnExit" : true,
+ "colorScheme" : "Campbell",
+ "commandline" : "wsl.exe",
+ "cursorColor" : "#FFFFFF",
+ "cursorShape" : "bar",
+ "fontSize" : 10,
+ "historySize" : 9001,
+ "padding" : "0, 0, 0, 0",
+ "snapOnInput" : true,
+ "useAcrylic" : true
+ },
+ {
+ // This is the same profile that would be generated by the WSL profile generator.
+ "name" : "Ubuntu",
+ "guid" : "{2C4DE342-38B7-51CF-B940-2309A097F518}",
+ "acrylicOpacity" : 0.5,
+ "background" : "#2C001E",
+ "closeOnExit" : false,
+ "cursorColor" : "#FFFFFF",
+ "cursorShape" : "bar",
+ "fontSize" : 10,
+ "historySize" : 9001,
+ "snapOnInput" : true,
+ "useAcrylic" : true
+ }
+ ]
+ })" };
+
+ const auto settings0Json = VerifyParseSucceeded(settings0String);
+
+ auto settings = winrt::make_self();
+ settings->_ParseJsonString(DefaultJson, true);
+ settings->LayerJson(settings->_defaultSettings);
+ VERIFY_ARE_EQUAL(2u, settings->_profiles.Size());
+ VERIFY_IS_TRUE(settings->_profiles.GetAt(0).HasGuid());
+ VERIFY_IS_TRUE(settings->_profiles.GetAt(1).HasGuid());
+ VERIFY_ARE_EQUAL(L"Windows PowerShell", settings->_profiles.GetAt(0).Name());
+ VERIFY_ARE_EQUAL(L"Command Prompt", settings->_profiles.GetAt(1).Name());
+
+ settings->_ParseJsonString(settings0String, false);
+ settings->LayerJson(settings->_userSettings);
+
+ VERIFY_ARE_EQUAL(4u, settings->_profiles.Size());
+ VERIFY_IS_TRUE(settings->_profiles.GetAt(0).HasGuid());
+ VERIFY_IS_TRUE(settings->_profiles.GetAt(1).HasGuid());
+ VERIFY_IS_FALSE(settings->_profiles.GetAt(2).HasGuid());
+ VERIFY_IS_TRUE(settings->_profiles.GetAt(3).HasGuid());
+ VERIFY_ARE_EQUAL(L"Windows PowerShell", settings->_profiles.GetAt(0).Name());
+ VERIFY_ARE_EQUAL(L"Command Prompt", settings->_profiles.GetAt(1).Name());
+ VERIFY_ARE_EQUAL(L"ThisProfileShouldNotCrash", settings->_profiles.GetAt(2).Name());
+ VERIFY_ARE_EQUAL(L"Ubuntu", settings->_profiles.GetAt(3).Name());
+
+ settings->_ValidateSettings();
+ VERIFY_ARE_EQUAL(0u, settings->_warnings.Size());
+ VERIFY_ARE_EQUAL(4u, settings->_profiles.Size());
+ VERIFY_IS_TRUE(settings->_profiles.GetAt(0).HasGuid());
+ VERIFY_IS_TRUE(settings->_profiles.GetAt(1).HasGuid());
+ VERIFY_IS_TRUE(settings->_profiles.GetAt(2).HasGuid());
+ VERIFY_IS_TRUE(settings->_profiles.GetAt(3).HasGuid());
+ VERIFY_ARE_EQUAL(L"Command Prompt", settings->_profiles.GetAt(0).Name());
+ VERIFY_ARE_EQUAL(L"ThisProfileShouldNotCrash", settings->_profiles.GetAt(1).Name());
+ VERIFY_ARE_EQUAL(L"Ubuntu", settings->_profiles.GetAt(2).Name());
+ VERIFY_ARE_EQUAL(L"Windows PowerShell", settings->_profiles.GetAt(3).Name());
+ }
+
+ void DeserializationTests::TestLayeringNameOnlyProfiles()
+ {
+ // This is a test discovered during GH#2782. When we add a name-only
+ // profile, it should only layer with other name-only profiles with the
+ // _same name_
+
+ const std::string settings0String{ R"(
+ {
+ "defaultProfile" : "{00000000-0000-5f56-a8ff-afceeeaa6101}",
+ "profiles": [
+ {
+ "guid" : "{00000000-0000-5f56-a8ff-afceeeaa6101}",
+ "name" : "ThisProfileIsGood"
+
+ },
+ {
+ "name" : "ThisProfileShouldNotLayer"
+ },
+ {
+ "name" : "NeitherShouldThisOne"
+ }
+ ]
+ })" };
+
+ const auto settings0Json = VerifyParseSucceeded(settings0String);
+
+ auto settings = winrt::make_self();
+ settings->_ParseJsonString(DefaultJson, true);
+ settings->LayerJson(settings->_defaultSettings);
+ VERIFY_ARE_EQUAL(2u, settings->_profiles.Size());
+ VERIFY_IS_TRUE(settings->_profiles.GetAt(0).HasGuid());
+ VERIFY_IS_TRUE(settings->_profiles.GetAt(1).HasGuid());
+ VERIFY_ARE_EQUAL(L"Windows PowerShell", settings->_profiles.GetAt(0).Name());
+ VERIFY_ARE_EQUAL(L"Command Prompt", settings->_profiles.GetAt(1).Name());
+
+ Log::Comment(NoThrowString().Format(
+ L"Parse the user settings"));
+ settings->_ParseJsonString(settings0String, false);
+ settings->LayerJson(settings->_userSettings);
+
+ VERIFY_ARE_EQUAL(5u, settings->_profiles.Size());
+ VERIFY_IS_TRUE(settings->_profiles.GetAt(0).HasGuid());
+ VERIFY_IS_TRUE(settings->_profiles.GetAt(1).HasGuid());
+ VERIFY_IS_TRUE(settings->_profiles.GetAt(2).HasGuid());
+ VERIFY_IS_FALSE(settings->_profiles.GetAt(3).HasGuid());
+ VERIFY_IS_FALSE(settings->_profiles.GetAt(4).HasGuid());
+ VERIFY_ARE_EQUAL(L"Windows PowerShell", settings->_profiles.GetAt(0).Name());
+ VERIFY_ARE_EQUAL(L"Command Prompt", settings->_profiles.GetAt(1).Name());
+ VERIFY_ARE_EQUAL(L"ThisProfileIsGood", settings->_profiles.GetAt(2).Name());
+ VERIFY_ARE_EQUAL(L"ThisProfileShouldNotLayer", settings->_profiles.GetAt(3).Name());
+ VERIFY_ARE_EQUAL(L"NeitherShouldThisOne", settings->_profiles.GetAt(4).Name());
+ }
+
+ void DeserializationTests::TestExplodingNameOnlyProfiles()
+ {
+ // This is a test for GH#2782. When we add a name-only profile, we'll
+ // generate a GUID for it. We should make sure that we don't re-append
+ // that profile to the list of profiles.
+
+ const std::string settings0String{ R"(
+ {
+ "defaultProfile" : "{00000000-0000-5f56-a8ff-afceeeaa6101}",
+ "profiles": [
+ {
+ "guid" : "{00000000-0000-5f56-a8ff-afceeeaa6101}",
+ "name" : "ThisProfileIsGood"
+
+ },
+ {
+ "name" : "ThisProfileShouldNotDuplicate"
+ },
+ {
+ "name" : "NeitherShouldThisOne"
+ }
+ ]
+ })" };
+
+ const auto settings0Json = VerifyParseSucceeded(settings0String);
+
+ auto settings = winrt::make_self();
+ settings->_ParseJsonString(DefaultJson, true);
+ settings->LayerJson(settings->_defaultSettings);
+ VERIFY_ARE_EQUAL(2u, settings->_profiles.Size());
+ VERIFY_IS_TRUE(settings->_profiles.GetAt(0).HasGuid());
+ VERIFY_IS_TRUE(settings->_profiles.GetAt(1).HasGuid());
+ VERIFY_ARE_EQUAL(L"Windows PowerShell", settings->_profiles.GetAt(0).Name());
+ VERIFY_ARE_EQUAL(L"Command Prompt", settings->_profiles.GetAt(1).Name());
+
+ Log::Comment(NoThrowString().Format(
+ L"Parse the user settings"));
+ settings->_ParseJsonString(settings0String, false);
+ settings->LayerJson(settings->_userSettings);
+
+ VERIFY_ARE_EQUAL(5u, settings->_profiles.Size());
+ VERIFY_IS_TRUE(settings->_profiles.GetAt(0).HasGuid());
+ VERIFY_IS_TRUE(settings->_profiles.GetAt(1).HasGuid());
+ VERIFY_IS_TRUE(settings->_profiles.GetAt(2).HasGuid());
+ VERIFY_IS_FALSE(settings->_profiles.GetAt(3).HasGuid());
+ VERIFY_IS_FALSE(settings->_profiles.GetAt(4).HasGuid());
+ VERIFY_ARE_EQUAL(L"Windows PowerShell", settings->_profiles.GetAt(0).Name());
+ VERIFY_ARE_EQUAL(L"Command Prompt", settings->_profiles.GetAt(1).Name());
+ VERIFY_ARE_EQUAL(L"ThisProfileIsGood", settings->_profiles.GetAt(2).Name());
+ VERIFY_ARE_EQUAL(L"ThisProfileShouldNotDuplicate", settings->_profiles.GetAt(3).Name());
+ VERIFY_ARE_EQUAL(L"NeitherShouldThisOne", settings->_profiles.GetAt(4).Name());
+
+ Log::Comment(NoThrowString().Format(
+ L"Pretend like we're checking to append dynamic profiles to the "
+ L"user's settings file. We absolutely _shouldn't_ be adding anything here."));
+ bool const needToWriteFile = settings->_AppendDynamicProfilesToUserSettings();
+ VERIFY_IS_FALSE(needToWriteFile);
+ VERIFY_ARE_EQUAL(settings0String.size(), settings->_userSettingsString.size());
+
+ Log::Comment(NoThrowString().Format(
+ L"Re-parse the settings file. We should have the _same_ settings as before."));
+ Log::Comment(NoThrowString().Format(
+ L"Do this to a _new_ settings object, to make sure it turns out the same."));
+ {
+ auto settings2 = winrt::make_self();
+ settings2->_ParseJsonString(DefaultJson, true);
+ settings2->LayerJson(settings2->_defaultSettings);
+ VERIFY_ARE_EQUAL(2u, settings2->_profiles.Size());
+ // Initialize the second settings object from the first settings
+ // object's settings string, the one that we synthesized.
+ const auto firstSettingsString = settings->_userSettingsString;
+ settings2->_ParseJsonString(firstSettingsString, false);
+ settings2->LayerJson(settings2->_userSettings);
+ VERIFY_ARE_EQUAL(5u, settings2->_profiles.Size());
+ VERIFY_IS_TRUE(settings2->_profiles.GetAt(0).HasGuid());
+ VERIFY_IS_TRUE(settings2->_profiles.GetAt(1).HasGuid());
+ VERIFY_IS_TRUE(settings2->_profiles.GetAt(2).HasGuid());
+ VERIFY_IS_FALSE(settings2->_profiles.GetAt(3).HasGuid());
+ VERIFY_IS_FALSE(settings2->_profiles.GetAt(4).HasGuid());
+ VERIFY_ARE_EQUAL(L"Windows PowerShell", settings2->_profiles.GetAt(0).Name());
+ VERIFY_ARE_EQUAL(L"Command Prompt", settings2->_profiles.GetAt(1).Name());
+ VERIFY_ARE_EQUAL(L"ThisProfileIsGood", settings2->_profiles.GetAt(2).Name());
+ VERIFY_ARE_EQUAL(L"ThisProfileShouldNotDuplicate", settings2->_profiles.GetAt(3).Name());
+ VERIFY_ARE_EQUAL(L"NeitherShouldThisOne", settings2->_profiles.GetAt(4).Name());
+ }
+
+ Log::Comment(NoThrowString().Format(
+ L"Validate the settings. All the profiles we have should be valid."));
+ settings->_ValidateSettings();
+
+ VERIFY_ARE_EQUAL(5u, settings->_profiles.Size());
+ VERIFY_IS_TRUE(settings->_profiles.GetAt(0).HasGuid());
+ VERIFY_IS_TRUE(settings->_profiles.GetAt(1).HasGuid());
+ VERIFY_IS_TRUE(settings->_profiles.GetAt(2).HasGuid());
+ VERIFY_IS_TRUE(settings->_profiles.GetAt(3).HasGuid());
+ VERIFY_IS_TRUE(settings->_profiles.GetAt(4).HasGuid());
+ VERIFY_ARE_EQUAL(L"ThisProfileIsGood", settings->_profiles.GetAt(0).Name());
+ VERIFY_ARE_EQUAL(L"ThisProfileShouldNotDuplicate", settings->_profiles.GetAt(1).Name());
+ VERIFY_ARE_EQUAL(L"NeitherShouldThisOne", settings->_profiles.GetAt(2).Name());
+ VERIFY_ARE_EQUAL(L"Windows PowerShell", settings->_profiles.GetAt(3).Name());
+ VERIFY_ARE_EQUAL(L"Command Prompt", settings->_profiles.GetAt(4).Name());
+ }
+
+ void DeserializationTests::TestHideAllProfiles()
+ {
+ const std::string settingsWithProfiles{ R"(
+ {
+ "profiles": [
+ {
+ "name" : "profile0",
+ "hidden": false
+ },
+ {
+ "name" : "profile1",
+ "hidden": true
+ }
+ ]
+ })" };
+
+ const std::string settingsWithoutProfiles{ R"(
+ {
+ "profiles": [
+ {
+ "name" : "profile0",
+ "hidden": true
+ },
+ {
+ "name" : "profile1",
+ "hidden": true
+ }
+ ]
+ })" };
+
+ VerifyParseSucceeded(settingsWithProfiles);
+ VerifyParseSucceeded(settingsWithoutProfiles);
+
+ {
+ // Case 1: Good settings
+ auto settings = winrt::make_self();
+ settings->_ParseJsonString(settingsWithProfiles, false);
+ settings->LayerJson(settings->_userSettings);
+
+ settings->_RemoveHiddenProfiles();
+ Log::Comment(NoThrowString().Format(
+ L"settingsWithProfiles successfully parsed and validated"));
+ VERIFY_ARE_EQUAL(1u, settings->_profiles.Size());
+ }
+ {
+ // Case 2: Bad settings
+ auto settings = winrt::make_self();
+ settings->_ParseJsonString(settingsWithoutProfiles, false);
+ settings->LayerJson(settings->_userSettings);
+
+ bool caughtExpectedException = false;
+ try
+ {
+ settings->_RemoveHiddenProfiles();
+ }
+ catch (const implementation::SettingsException& ex)
+ {
+ VERIFY_IS_TRUE(ex.Error() == SettingsLoadErrors::AllProfilesHidden);
+ caughtExpectedException = true;
+ }
+ VERIFY_IS_TRUE(caughtExpectedException);
+ }
+ }
+
+ void DeserializationTests::TestInvalidColorSchemeName()
+ {
+ Log::Comment(NoThrowString().Format(
+ L"Ensure that setting a profile's scheme to a non-existent scheme causes a warning."));
+
+ const std::string settings0String{ R"(
+ {
+ "profiles": [
+ {
+ "name" : "profile0",
+ "colorScheme": "schemeOne"
+ },
+ {
+ "name" : "profile1",
+ "colorScheme": "InvalidSchemeName"
+ },
+ {
+ "name" : "profile2"
+ // Will use the Profile default value, "Campbell"
+ }
+ ],
+ "schemes": [
+ {
+ "name": "schemeOne",
+ "foreground": "#111111"
+ },
+ {
+ "name": "schemeTwo",
+ "foreground": "#222222"
+ }
+ ]
+ })" };
+
+ VerifyParseSucceeded(settings0String);
+
+ auto settings = winrt::make_self();
+ settings->_ParseJsonString(settings0String, false);
+ settings->LayerJson(settings->_userSettings);
+
+ VERIFY_ARE_EQUAL(3u, settings->_profiles.Size());
+ VERIFY_ARE_EQUAL(2u, settings->_globals->ColorSchemes().Size());
+
+ VERIFY_ARE_EQUAL(L"schemeOne", settings->_profiles.GetAt(0).ColorSchemeName());
+ VERIFY_ARE_EQUAL(L"InvalidSchemeName", settings->_profiles.GetAt(1).ColorSchemeName());
+ VERIFY_ARE_EQUAL(L"Campbell", settings->_profiles.GetAt(2).ColorSchemeName());
+
+ settings->_ValidateAllSchemesExist();
+
+ VERIFY_ARE_EQUAL(1u, settings->_warnings.Size());
+ VERIFY_ARE_EQUAL(SettingsLoadWarnings::UnknownColorScheme, settings->_warnings.GetAt(0));
+
+ VERIFY_ARE_EQUAL(3u, settings->_profiles.Size());
+ VERIFY_ARE_EQUAL(2u, settings->_globals->ColorSchemes().Size());
+
+ VERIFY_ARE_EQUAL(L"schemeOne", settings->_profiles.GetAt(0).ColorSchemeName());
+ VERIFY_ARE_EQUAL(L"Campbell", settings->_profiles.GetAt(1).ColorSchemeName());
+ VERIFY_ARE_EQUAL(L"Campbell", settings->_profiles.GetAt(2).ColorSchemeName());
+ }
+
+ void DeserializationTests::TestHelperFunctions()
+ {
+ const std::string settings0String{ R"(
+ {
+ "defaultProfile" : "{2C4DE342-38B7-51CF-B940-2309A097F518}",
+ "profiles": [
+ {
+ "name" : "profile0",
+ "guid": "{6239a42c-5555-49a3-80bd-e8fdd045185c}"
+ },
+ {
+ "name" : "profile1",
+ "guid": "{6239a42c-6666-49a3-80bd-e8fdd045185c}"
+ },
+ {
+ "name" : "ThisProfileShouldNotThrow"
+ },
+ {
+ "name" : "Ubuntu",
+ "guid" : "{2C4DE342-38B7-51CF-B940-2309A097F518}"
+ }
+ ]
+ })" };
+
+ auto name0{ L"profile0" };
+ auto name1{ L"profile1" };
+ auto name2{ L"Ubuntu" };
+ auto name3{ L"ThisProfileShouldNotThrow" };
+ auto badName{ L"DoesNotExist" };
+
+ const winrt::guid guid0{ ::Microsoft::Console::Utils::GuidFromString(L"{6239a42c-5555-49a3-80bd-e8fdd045185c}") };
+ const winrt::guid guid1{ ::Microsoft::Console::Utils::GuidFromString(L"{6239a42c-6666-49a3-80bd-e8fdd045185c}") };
+ const winrt::guid guid2{ ::Microsoft::Console::Utils::GuidFromString(L"{2C4DE342-38B7-51CF-B940-2309A097F518}") };
+ const winrt::guid fakeGuid{ ::Microsoft::Console::Utils::GuidFromString(L"{FFFFFFFF-FFFF-FFFF-FFFF-FFFFFFFFFFFF}") };
+ const std::optional badGuid{};
+
+ VerifyParseSucceeded(settings0String);
+
+ auto settings = winrt::make_self();
+ settings->_ParseJsonString(settings0String, false);
+ settings->LayerJson(settings->_userSettings);
+
+ VERIFY_ARE_EQUAL(guid0, settings->_GetProfileGuidByName(name0));
+ VERIFY_ARE_EQUAL(guid1, settings->_GetProfileGuidByName(name1));
+ VERIFY_ARE_EQUAL(guid2, settings->_GetProfileGuidByName(name2));
+ VERIFY_ARE_EQUAL(badGuid, settings->_GetProfileGuidByName(name3));
+ VERIFY_ARE_EQUAL(badGuid, settings->_GetProfileGuidByName(badName));
+
+ auto prof0{ settings->FindProfile(guid0) };
+ auto prof1{ settings->FindProfile(guid1) };
+ auto prof2{ settings->FindProfile(guid2) };
+
+ auto badProf{ settings->FindProfile(fakeGuid) };
+ VERIFY_ARE_EQUAL(badProf, nullptr);
+
+ VERIFY_ARE_EQUAL(name0, prof0.Name());
+ VERIFY_ARE_EQUAL(name1, prof1.Name());
+ VERIFY_ARE_EQUAL(name2, prof2.Name());
+ }
+
+ void DeserializationTests::TestProfileIconWithEnvVar()
+ {
+ const auto expectedPath = wil::ExpandEnvironmentStringsW(L"%WINDIR%\\System32\\x_80.png");
+
+ const std::string settingsJson{ R"(
+ {
+ "profiles": [
+ {
+ "name": "profile0",
+ "icon": "%WINDIR%\\System32\\x_80.png"
+ }
+ ]
+ })" };
+
+ VerifyParseSucceeded(settingsJson);
+
+ auto settings = winrt::make_self();
+ settings->_ParseJsonString(settingsJson, false);
+ settings->LayerJson(settings->_userSettings);
+ VERIFY_ARE_NOT_EQUAL(0u, settings->_profiles.Size());
+ VERIFY_ARE_EQUAL(expectedPath, settings->_profiles.GetAt(0).ExpandedIconPath());
+ }
+ void DeserializationTests::TestProfileBackgroundImageWithEnvVar()
+ {
+ const auto expectedPath = wil::ExpandEnvironmentStringsW(L"%WINDIR%\\System32\\x_80.png");
+
+ const std::string settingsJson{ R"(
+ {
+ "profiles": [
+ {
+ "name": "profile0",
+ "backgroundImage": "%WINDIR%\\System32\\x_80.png"
+ }
+ ]
+ })" };
+
+ VerifyParseSucceeded(settingsJson);
+
+ auto settings = winrt::make_self();
+ settings->_ParseJsonString(settingsJson, false);
+ settings->LayerJson(settings->_userSettings);
+ VERIFY_ARE_NOT_EQUAL(0u, settings->_profiles.Size());
+ VERIFY_ARE_EQUAL(expectedPath, settings->_profiles.GetAt(0).ExpandedBackgroundImagePath());
+ }
+ void DeserializationTests::TestCloseOnExitParsing()
+ {
+ const std::string settingsJson{ R"(
+ {
+ "profiles": [
+ {
+ "name": "profile0",
+ "closeOnExit": "graceful"
+ },
+ {
+ "name": "profile1",
+ "closeOnExit": "always"
+ },
+ {
+ "name": "profile2",
+ "closeOnExit": "never"
+ },
+ {
+ "name": "profile3",
+ "closeOnExit": null
+ }
+ ]
+ })" };
+
+ VerifyParseSucceeded(settingsJson);
+
+ auto settings = winrt::make_self();
+ settings->_ParseJsonString(settingsJson, false);
+ settings->LayerJson(settings->_userSettings);
+ VERIFY_ARE_EQUAL(CloseOnExitMode::Graceful, settings->_profiles.GetAt(0).CloseOnExit());
+ VERIFY_ARE_EQUAL(CloseOnExitMode::Always, settings->_profiles.GetAt(1).CloseOnExit());
+ VERIFY_ARE_EQUAL(CloseOnExitMode::Never, settings->_profiles.GetAt(2).CloseOnExit());
+
+ // Unknown modes parse as "Graceful"
+ VERIFY_ARE_EQUAL(CloseOnExitMode::Graceful, settings->_profiles.GetAt(3).CloseOnExit());
+ }
+ void DeserializationTests::TestCloseOnExitCompatibilityShim()
+ {
+ const std::string settingsJson{ R"(
+ {
+ "profiles": [
+ {
+ "name": "profile0",
+ "closeOnExit": true
+ },
+ {
+ "name": "profile1",
+ "closeOnExit": false
+ }
+ ]
+ })" };
+
+ VerifyParseSucceeded(settingsJson);
+
+ auto settings = winrt::make_self();
+ settings->_ParseJsonString(settingsJson, false);
+ settings->LayerJson(settings->_userSettings);
+ VERIFY_ARE_EQUAL(CloseOnExitMode::Graceful, settings->_profiles.GetAt(0).CloseOnExit());
+ VERIFY_ARE_EQUAL(CloseOnExitMode::Never, settings->_profiles.GetAt(1).CloseOnExit());
+ }
+
+ void DeserializationTests::TestLayerUserDefaultsBeforeProfiles()
+ {
+ // Test for microsoft/terminal#2325. For this test, we'll be setting the
+ // "historySize" in the "defaultSettings", so it should apply to all
+ // profiles, unless they override it. In one of the user's profiles,
+ // we'll override that value, and in the other, we'll leave it
+ // untouched.
+
+ const std::string settings0String{ R"(
+ {
+ "defaultProfile": "{6239a42c-1111-49a3-80bd-e8fdd045185c}",
+ "profiles": {
+ "defaults": {
+ "historySize": 1234
+ },
+ "list": [
+ {
+ "guid": "{6239a42c-1111-49a3-80bd-e8fdd045185c}",
+ "name": "profile0",
+ "historySize": 2345
+ },
+ {
+ "guid": "{6239a42c-2222-49a3-80bd-e8fdd045185c}",
+ "name": "profile1"
+ }
+ ]
+ }
+ })" };
+ VerifyParseSucceeded(settings0String);
+
+ const auto guid1String = L"{6239a42c-1111-49a3-80bd-e8fdd045185c}";
+
+ {
+ auto settings = winrt::make_self(false);
+ settings->_ParseJsonString(settings0String, false);
+ VERIFY_IS_TRUE(settings->_userDefaultProfileSettings == Json::Value::null);
+ settings->_ApplyDefaultsFromUserSettings();
+ VERIFY_IS_FALSE(settings->_userDefaultProfileSettings == Json::Value::null);
+ settings->LayerJson(settings->_userSettings);
+
+ VERIFY_ARE_EQUAL(guid1String, settings->_globals->UnparsedDefaultProfile());
+ VERIFY_ARE_EQUAL(2u, settings->_profiles.Size());
+
+ VERIFY_ARE_EQUAL(2345, settings->_profiles.GetAt(0).HistorySize());
+ VERIFY_ARE_EQUAL(1234, settings->_profiles.GetAt(1).HistorySize());
+ }
+ }
+
+ void DeserializationTests::TestDontLayerGuidFromUserDefaults()
+ {
+ // Test for microsoft/terminal#2325. We don't want the user to put a
+ // "guid" in the "defaultSettings", and have that apply to all the other
+ // profiles
+
+ const std::string settings0String{ R"(
+ {
+ "defaultProfile": "{6239a42c-1111-49a3-80bd-e8fdd045185c}",
+ "profiles": {
+ "defaults": {
+ "guid": "{6239a42c-2222-49a3-80bd-e8fdd045185c}"
+ },
+ "list": [
+ {
+ "guid": "{6239a42c-1111-49a3-80bd-e8fdd045185c}",
+ "name": "profile0",
+ "historySize": 2345
+ },
+ {
+ // Doesn't have a GUID, we'll auto-generate one
+ "name": "profile1"
+ }
+ ]
+ }
+ })" };
+ VerifyParseSucceeded(settings0String);
+
+ const auto guid1String = L"{6239a42c-1111-49a3-80bd-e8fdd045185c}";
+ const winrt::guid guid1{ ::Microsoft::Console::Utils::GuidFromString(guid1String) };
+ const winrt::guid guid2{ ::Microsoft::Console::Utils::GuidFromString(L"{6239a42c-2222-49a3-80bd-e8fdd045185c}") };
+
+ {
+ auto settings = winrt::make_self(false);
+ settings->_ParseJsonString(DefaultJson, true);
+ settings->LayerJson(settings->_defaultSettings);
+ VERIFY_ARE_EQUAL(2u, settings->_profiles.Size());
+
+ settings->_ParseJsonString(settings0String, false);
+ VERIFY_IS_TRUE(settings->_userDefaultProfileSettings == Json::Value::null);
+ settings->_ApplyDefaultsFromUserSettings();
+ VERIFY_IS_FALSE(settings->_userDefaultProfileSettings == Json::Value::null);
+
+ Log::Comment(NoThrowString().Format(
+ L"Ensure that cmd and powershell don't get their GUIDs overwritten"));
+ VERIFY_ARE_NOT_EQUAL(guid2, settings->_profiles.GetAt(0).Guid());
+ VERIFY_ARE_NOT_EQUAL(guid2, settings->_profiles.GetAt(1).Guid());
+
+ settings->LayerJson(settings->_userSettings);
+
+ VERIFY_ARE_EQUAL(guid1String, settings->_globals->UnparsedDefaultProfile());
+ VERIFY_ARE_EQUAL(4u, settings->_profiles.Size());
+
+ VERIFY_ARE_EQUAL(guid1, settings->_profiles.GetAt(2).Guid());
+ VERIFY_IS_FALSE(settings->_profiles.GetAt(3).HasGuid());
+ }
+ }
+
+ void DeserializationTests::TestLayerUserDefaultsOnDynamics()
+ {
+ // Test for microsoft/terminal#2325. For this test, we'll be setting the
+ // "historySize" in the "defaultSettings", so it should apply to all
+ // profiles, unless they override it. The dynamic profiles will _also_
+ // set this value, but from discussion in GH#2325, we decided that
+ // settings in defaultSettings should apply _on top_ of settings from
+ // dynamic profiles.
+
+ const winrt::guid guid1{ ::Microsoft::Console::Utils::GuidFromString(L"{6239a42c-1111-49a3-80bd-e8fdd045185c}") };
+ const winrt::guid guid2{ ::Microsoft::Console::Utils::GuidFromString(L"{6239a42c-2222-49a3-80bd-e8fdd045185c}") };
+ const winrt::guid guid3{ ::Microsoft::Console::Utils::GuidFromString(L"{6239a42c-3333-49a3-80bd-e8fdd045185c}") };
+
+ const std::string userProfiles{ R"(
+ {
+ "defaultProfile": "{6239a42c-1111-49a3-80bd-e8fdd045185c}",
+ "profiles": {
+ "defaults": {
+ "historySize": 1234
+ },
+ "list": [
+ {
+ "name" : "profile0FromUserSettings", // this is _profiles.GetAt(0)
+ "guid": "{6239a42c-1111-49a3-80bd-e8fdd045185c}",
+ "source": "Terminal.App.UnitTest.0"
+ },
+ {
+ "name" : "profile1FromUserSettings", // this is _profiles.GetAt(2)
+ "guid": "{6239a42c-2222-49a3-80bd-e8fdd045185c}",
+ "source": "Terminal.App.UnitTest.1",
+ "historySize": 4444
+ },
+ {
+ "name" : "profile2FromUserSettings", // this is _profiles.GetAt(3)
+ "guid": "{6239a42c-3333-49a3-80bd-e8fdd045185c}",
+ "historySize": 5555
+ }
+ ]
+ }
+ })" };
+
+ auto gen0 = std::make_unique(L"Terminal.App.UnitTest.0");
+ gen0->pfnGenerate = [guid1, guid2]() {
+ std::vector profiles;
+ Profile p0 = winrt::make(guid1);
+ p0.Name(L"profile0"); // this is _profiles.GetAt(0)
+ p0.HistorySize(1111);
+ profiles.push_back(p0);
+ return profiles;
+ };
+ auto gen1 = std::make_unique(L"Terminal.App.UnitTest.1");
+ gen1->pfnGenerate = [guid1, guid2]() {
+ std::vector profiles;
+ Profile p0 = winrt::make(guid1);
+ Profile p1 = winrt::make(guid2);
+ p0.Name(L"profile0"); // this is _profiles.GetAt(1)
+ p1.Name(L"profile1"); // this is _profiles.GetAt(2)
+ p0.HistorySize(2222);
+ profiles.push_back(p0);
+ p1.HistorySize(3333);
+ profiles.push_back(p1);
+ return profiles;
+ };
+
+ auto settings = winrt::make_self(false);
+ settings->_profileGenerators.emplace_back(std::move(gen0));
+ settings->_profileGenerators.emplace_back(std::move(gen1));
+
+ Log::Comment(NoThrowString().Format(
+ L"All profiles with the same name have the same GUID. However, they"
+ L" will not be layered, because they have different source's"));
+
+ // parse userProfiles as the user settings
+ settings->_ParseJsonString(userProfiles, false);
+ VERIFY_ARE_EQUAL(0u, settings->_profiles.Size(), L"Just parsing the user settings doesn't actually layer them");
+ settings->_LoadDynamicProfiles();
+ VERIFY_ARE_EQUAL(3u, settings->_profiles.Size());
+
+ VERIFY_ARE_EQUAL(1111, settings->_profiles.GetAt(0).HistorySize());
+ VERIFY_ARE_EQUAL(2222, settings->_profiles.GetAt(1).HistorySize());
+ VERIFY_ARE_EQUAL(3333, settings->_profiles.GetAt(2).HistorySize());
+
+ settings->_ApplyDefaultsFromUserSettings();
+
+ VERIFY_ARE_EQUAL(1234, settings->_profiles.GetAt(0).HistorySize());
+ VERIFY_ARE_EQUAL(1234, settings->_profiles.GetAt(1).HistorySize());
+ VERIFY_ARE_EQUAL(1234, settings->_profiles.GetAt(2).HistorySize());
+
+ settings->LayerJson(settings->_userSettings);
+ VERIFY_ARE_EQUAL(4u, settings->_profiles.Size());
+
+ VERIFY_IS_FALSE(settings->_profiles.GetAt(0).Source().empty());
+ VERIFY_IS_FALSE(settings->_profiles.GetAt(1).Source().empty());
+ VERIFY_IS_FALSE(settings->_profiles.GetAt(2).Source().empty());
+ VERIFY_IS_TRUE(settings->_profiles.GetAt(3).Source().empty());
+
+ VERIFY_ARE_EQUAL(L"Terminal.App.UnitTest.0", settings->_profiles.GetAt(0).Source());
+ VERIFY_ARE_EQUAL(L"Terminal.App.UnitTest.1", settings->_profiles.GetAt(1).Source());
+ VERIFY_ARE_EQUAL(L"Terminal.App.UnitTest.1", settings->_profiles.GetAt(2).Source());
+
+ VERIFY_IS_TRUE(settings->_profiles.GetAt(0).HasGuid());
+ VERIFY_IS_TRUE(settings->_profiles.GetAt(1).HasGuid());
+ VERIFY_IS_TRUE(settings->_profiles.GetAt(2).HasGuid());
+
+ VERIFY_ARE_EQUAL(guid1, settings->_profiles.GetAt(0).Guid());
+ VERIFY_ARE_EQUAL(guid1, settings->_profiles.GetAt(1).Guid());
+ VERIFY_ARE_EQUAL(guid2, settings->_profiles.GetAt(2).Guid());
+
+ VERIFY_ARE_EQUAL(L"profile0FromUserSettings", settings->_profiles.GetAt(0).Name());
+ VERIFY_ARE_EQUAL(L"profile0", settings->_profiles.GetAt(1).Name());
+ VERIFY_ARE_EQUAL(L"profile1FromUserSettings", settings->_profiles.GetAt(2).Name());
+ VERIFY_ARE_EQUAL(L"profile2FromUserSettings", settings->_profiles.GetAt(3).Name());
+
+ Log::Comment(NoThrowString().Format(
+ L"This is the real meat of the test: The two dynamic profiles that "
+ L"_didn't_ have historySize set in the userSettings should have "
+ L"1234 as their historySize(from the defaultSettings).The other two"
+ L" profiles should have their custom historySize value."));
+
+ VERIFY_ARE_EQUAL(1234, settings->_profiles.GetAt(0).HistorySize());
+ VERIFY_ARE_EQUAL(1234, settings->_profiles.GetAt(1).HistorySize());
+ VERIFY_ARE_EQUAL(4444, settings->_profiles.GetAt(2).HistorySize());
+ VERIFY_ARE_EQUAL(5555, settings->_profiles.GetAt(3).HistorySize());
+ }
+
+ void DeserializationTests::FindMissingProfile()
+ {
+ // Test that CascadiaSettings::FindProfile returns null for a GUID that
+ // doesn't exist
+ const std::string settingsString{ R"(
+ {
+ "defaultProfile": "{6239a42c-1111-49a3-80bd-e8fdd045185c}",
+ "profiles": [
+ {
+ "name" : "profile0",
+ "guid": "{6239a42c-1111-49a3-80bd-e8fdd045185c}"
+ },
+ {
+ "name" : "profile1",
+ "guid": "{6239a42c-2222-49a3-80bd-e8fdd045185c}"
+ }
+ ]
+ })" };
+ const auto settingsJsonObj = VerifyParseSucceeded(settingsString);
+ auto settings = implementation::CascadiaSettings::FromJson(settingsJsonObj);
+
+ const auto guid1 = ::Microsoft::Console::Utils::GuidFromString(L"{6239a42c-1111-49a3-80bd-e8fdd045185c}");
+ const auto guid2 = ::Microsoft::Console::Utils::GuidFromString(L"{6239a42c-2222-49a3-80bd-e8fdd045185c}");
+ const auto guid3 = ::Microsoft::Console::Utils::GuidFromString(L"{6239a42c-3333-49a3-80bd-e8fdd045185c}");
+
+ const auto profile1 = settings->FindProfile(guid1);
+ const auto profile2 = settings->FindProfile(guid2);
+ const auto profile3 = settings->FindProfile(guid3);
+
+ VERIFY_IS_NOT_NULL(profile1);
+ VERIFY_IS_NOT_NULL(profile2);
+ VERIFY_IS_NULL(profile3);
+
+ VERIFY_ARE_EQUAL(L"profile0", profile1.Name());
+ VERIFY_ARE_EQUAL(L"profile1", profile2.Name());
+ }
+
+ void DeserializationTests::ValidateKeybindingsWarnings()
+ {
+ const std::string badSettings{ R"(
+ {
+ "defaultProfile": "{6239a42c-2222-49a3-80bd-e8fdd045185c}",
+ "profiles": [
+ {
+ "name" : "profile0",
+ "guid": "{6239a42c-2222-49a3-80bd-e8fdd045185c}"
+ },
+ {
+ "name" : "profile1",
+ "guid": "{6239a42c-3333-49a3-80bd-e8fdd045185c}"
+ }
+ ],
+ "keybindings": [
+ { "command": { "action": "splitPane", "split":"auto" }, "keys": [ "ctrl+alt+t", "ctrl+a" ] },
+ { "command": { "action": "moveFocus" }, "keys": [ "ctrl+a" ] },
+ { "command": { "action": "resizePane" }, "keys": [ "ctrl+b" ] }
+ ]
+ })" };
+
+ const auto settingsObject = VerifyParseSucceeded(badSettings);
+ auto settings = implementation::CascadiaSettings::FromJson(settingsObject);
+
+ VERIFY_ARE_EQUAL(0u, settings->_globals->_keymap->_keyShortcuts.size());
+
+ VERIFY_ARE_EQUAL(3u, settings->_globals->_keybindingsWarnings.size());
+ VERIFY_ARE_EQUAL(SettingsLoadWarnings::TooManyKeysForChord, settings->_globals->_keybindingsWarnings.at(0));
+ VERIFY_ARE_EQUAL(SettingsLoadWarnings::MissingRequiredParameter, settings->_globals->_keybindingsWarnings.at(1));
+ VERIFY_ARE_EQUAL(SettingsLoadWarnings::MissingRequiredParameter, settings->_globals->_keybindingsWarnings.at(2));
+
+ settings->_ValidateKeybindings();
+
+ VERIFY_ARE_EQUAL(4u, settings->_warnings.Size());
+ VERIFY_ARE_EQUAL(SettingsLoadWarnings::AtLeastOneKeybindingWarning, settings->_warnings.GetAt(0));
+ VERIFY_ARE_EQUAL(SettingsLoadWarnings::TooManyKeysForChord, settings->_warnings.GetAt(1));
+ VERIFY_ARE_EQUAL(SettingsLoadWarnings::MissingRequiredParameter, settings->_warnings.GetAt(2));
+ VERIFY_ARE_EQUAL(SettingsLoadWarnings::MissingRequiredParameter, settings->_warnings.GetAt(3));
+ }
+
+ void DeserializationTests::ValidateExecuteCommandlineWarning()
+ {
+ const std::string badSettings{ R"(
+ {
+ "defaultProfile": "{6239a42c-2222-49a3-80bd-e8fdd045185c}",
+ "profiles": [
+ {
+ "name" : "profile0",
+ "guid": "{6239a42c-2222-49a3-80bd-e8fdd045185c}"
+ },
+ {
+ "name" : "profile1",
+ "guid": "{6239a42c-3333-49a3-80bd-e8fdd045185c}"
+ }
+ ],
+ "keybindings": [
+ { "name":null, "command": { "action": "wt" }, "keys": [ "ctrl+a" ] },
+ { "name":null, "command": { "action": "wt", "commandline":"" }, "keys": [ "ctrl+b" ] },
+ { "name":null, "command": { "action": "wt", "commandline":null }, "keys": [ "ctrl+c" ] }
+ ]
+ })" };
+
+ const auto settingsObject = VerifyParseSucceeded(badSettings);
+
+ auto settings = implementation::CascadiaSettings::FromJson(settingsObject);
+
+ VERIFY_ARE_EQUAL(0u, settings->_globals->_keymap->_keyShortcuts.size());
+
+ for (const auto& warning : settings->_globals->_keybindingsWarnings)
+ {
+ Log::Comment(NoThrowString().Format(
+ L"warning:%d", warning));
+ }
+ VERIFY_ARE_EQUAL(3u, settings->_globals->_keybindingsWarnings.size());
+ VERIFY_ARE_EQUAL(SettingsLoadWarnings::MissingRequiredParameter, settings->_globals->_keybindingsWarnings.at(0));
+ VERIFY_ARE_EQUAL(SettingsLoadWarnings::MissingRequiredParameter, settings->_globals->_keybindingsWarnings.at(1));
+ VERIFY_ARE_EQUAL(SettingsLoadWarnings::MissingRequiredParameter, settings->_globals->_keybindingsWarnings.at(2));
+
+ settings->_ValidateKeybindings();
+
+ VERIFY_ARE_EQUAL(4u, settings->_warnings.Size());
+ VERIFY_ARE_EQUAL(SettingsLoadWarnings::AtLeastOneKeybindingWarning, settings->_warnings.GetAt(0));
+ VERIFY_ARE_EQUAL(SettingsLoadWarnings::MissingRequiredParameter, settings->_warnings.GetAt(1));
+ VERIFY_ARE_EQUAL(SettingsLoadWarnings::MissingRequiredParameter, settings->_warnings.GetAt(2));
+ VERIFY_ARE_EQUAL(SettingsLoadWarnings::MissingRequiredParameter, settings->_warnings.GetAt(3));
+ }
+
+ void DeserializationTests::ValidateLegacyGlobalsWarning()
+ {
+ const std::string badSettings{ R"(
+ {
+ "globals": {},
+ "defaultProfile": "{6239a42c-2222-49a3-80bd-e8fdd045185c}",
+ "profiles": [
+ {
+ "name" : "profile0",
+ "guid": "{6239a42c-2222-49a3-80bd-e8fdd045185c}"
+ },
+ {
+ "name" : "profile1",
+ "guid": "{6239a42c-3333-49a3-80bd-e8fdd045185c}"
+ }
+ ],
+ "keybindings": []
+ })" };
+
+ // Create the default settings
+ auto settings = winrt::make_self();
+ settings->_ParseJsonString(DefaultJson, true);
+ settings->LayerJson(settings->_defaultSettings);
+
+ settings->_ValidateNoGlobalsKey();
+ VERIFY_ARE_EQUAL(0u, settings->_warnings.Size());
+
+ // Now layer on the user's settings
+ settings->_ParseJsonString(badSettings, false);
+ settings->LayerJson(settings->_userSettings);
+
+ settings->_ValidateNoGlobalsKey();
+ VERIFY_ARE_EQUAL(1u, settings->_warnings.Size());
+ VERIFY_ARE_EQUAL(SettingsLoadWarnings::LegacyGlobalsProperty, settings->_warnings.GetAt(0));
+ }
+
+ void DeserializationTests::TestTrailingCommas()
+ {
+ const std::string badSettings{ R"(
+ {
+ "defaultProfile": "{6239a42c-2222-49a3-80bd-e8fdd045185c}",
+ "profiles": [
+ {
+ "name" : "profile0",
+ "guid": "{6239a42c-2222-49a3-80bd-e8fdd045185c}"
+ },
+ {
+ "name" : "profile1",
+ "guid": "{6239a42c-3333-49a3-80bd-e8fdd045185c}"
+ },
+ ],
+ "keybindings": [],
+ })" };
+
+ // Create the default settings
+ auto settings = winrt::make_self();
+ settings->_ParseJsonString(DefaultJson, true);
+ settings->LayerJson(settings->_defaultSettings);
+
+ // Now layer on the user's settings
+ try
+ {
+ settings->_ParseJsonString(badSettings, false);
+ settings->LayerJson(settings->_userSettings);
+ }
+ catch (...)
+ {
+ VERIFY_IS_TRUE(false, L"This call to LayerJson should succeed, even with the trailing comma");
+ }
+ }
+
+ void DeserializationTests::TestCommandsAndKeybindings()
+ {
+ 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"
+ },
+ {
+ "name": "profile1",
+ "guid": "{6239a42c-1111-49a3-80bd-e8fdd045185c}",
+ "historySize": 2,
+ "commandline": "pwsh.exe"
+ },
+ {
+ "name": "profile2",
+ "historySize": 3,
+ "commandline": "wsl.exe"
+ }
+ ],
+ "actions": [
+ { "keys": "ctrl+a", "command": { "action": "splitPane", "split": "vertical" } },
+ { "name": "ctrl+b", "command": { "action": "splitPane", "split": "vertical" } },
+ { "keys": "ctrl+c", "name": "ctrl+c", "command": { "action": "splitPane", "split": "vertical" } },
+ { "keys": "ctrl+d", "command": { "action": "splitPane", "split": "vertical" } },
+ { "keys": "ctrl+e", "command": { "action": "splitPane", "split": "horizontal" } },
+ { "keys": "ctrl+f", "name":null, "command": { "action": "splitPane", "split": "horizontal" } }
+ ]
+ })" };
+
+ const auto guid0 = ::Microsoft::Console::Utils::GuidFromString(L"{6239a42c-0000-49a3-80bd-e8fdd045185c}");
+ const auto guid1 = ::Microsoft::Console::Utils::GuidFromString(L"{6239a42c-1111-49a3-80bd-e8fdd045185c}");
+
+ VerifyParseSucceeded(settingsJson);
+
+ auto settings = winrt::make_self();
+ settings->_ParseJsonString(settingsJson, false);
+ settings->LayerJson(settings->_userSettings);
+ settings->_ValidateSettings();
+
+ VERIFY_ARE_EQUAL(3u, settings->_profiles.Size());
+
+ const auto profile2Guid = settings->_profiles.GetAt(2).Guid();
+ VERIFY_ARE_NOT_EQUAL(winrt::guid{}, profile2Guid);
+
+ auto keymap = winrt::get_self(settings->_globals->KeyMap());
+ VERIFY_ARE_EQUAL(5u, keymap->_keyShortcuts.size());
+
+ // A/D, B, C, E will be in the list of commands, for 4 total.
+ // * A and D share the same name, so they'll only generate a single action.
+ // * F's name is set manually to `null`
+ auto commands = settings->_globals->Commands();
+ VERIFY_ARE_EQUAL(4u, commands.Size());
+
+ {
+ KeyChord kc{ true, false, false, static_cast('A') };
+ auto actionAndArgs = ::TestUtils::GetActionAndArgs(*keymap, kc);
+ VERIFY_ARE_EQUAL(ShortcutAction::SplitPane, actionAndArgs.Action());
+ const auto& realArgs = actionAndArgs.Args().try_as();
+ VERIFY_IS_NOT_NULL(realArgs);
+ // Verify the args have the expected value
+ VERIFY_ARE_EQUAL(SplitState::Vertical, realArgs.SplitStyle());
+ 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_TRUE(realArgs.TerminalArgs().Profile().empty());
+ }
+
+ Log::Comment(L"Note that we're skipping ctrl+B, since that doesn't have `keys` set.");
+
+ {
+ KeyChord kc{ true, false, false, static_cast('C') };
+ auto actionAndArgs = ::TestUtils::GetActionAndArgs(*keymap, kc);
+ VERIFY_ARE_EQUAL(ShortcutAction::SplitPane, actionAndArgs.Action());
+ const auto& realArgs = actionAndArgs.Args().try_as();
+ VERIFY_IS_NOT_NULL(realArgs);
+ // Verify the args have the expected value
+ VERIFY_ARE_EQUAL(SplitState::Vertical, realArgs.SplitStyle());
+ 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_TRUE(realArgs.TerminalArgs().Profile().empty());
+ }
+ {
+ KeyChord kc{ true, false, false, static_cast('D') };
+ auto actionAndArgs = ::TestUtils::GetActionAndArgs(*keymap, kc);
+ VERIFY_ARE_EQUAL(ShortcutAction::SplitPane, actionAndArgs.Action());
+ const auto& realArgs = actionAndArgs.Args().try_as();
+ VERIFY_IS_NOT_NULL(realArgs);
+ // Verify the args have the expected value
+ VERIFY_ARE_EQUAL(SplitState::Vertical, realArgs.SplitStyle());
+ 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_TRUE(realArgs.TerminalArgs().Profile().empty());
+ }
+ {
+ KeyChord kc{ true, false, false, static_cast('E') };
+ auto actionAndArgs = ::TestUtils::GetActionAndArgs(*keymap, kc);
+ VERIFY_ARE_EQUAL(ShortcutAction::SplitPane, actionAndArgs.Action());
+ const auto& realArgs = actionAndArgs.Args().try_as();
+ VERIFY_IS_NOT_NULL(realArgs);
+ // Verify the args have the expected value
+ VERIFY_ARE_EQUAL(SplitState::Horizontal, realArgs.SplitStyle());
+ 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_TRUE(realArgs.TerminalArgs().Profile().empty());
+ }
+ {
+ KeyChord kc{ true, false, false, static_cast('F') };
+ auto actionAndArgs = ::TestUtils::GetActionAndArgs(*keymap, kc);
+ VERIFY_ARE_EQUAL(ShortcutAction::SplitPane, actionAndArgs.Action());
+ const auto& realArgs = actionAndArgs.Args().try_as();
+ VERIFY_IS_NOT_NULL(realArgs);
+ // Verify the args have the expected value
+ VERIFY_ARE_EQUAL(SplitState::Horizontal, realArgs.SplitStyle());
+ 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_TRUE(realArgs.TerminalArgs().Profile().empty());
+ }
+
+ Log::Comment(L"Now verify the commands");
+ _logCommandNames(commands);
+ {
+ auto command = commands.Lookup(L"Split pane, split: vertical");
+ VERIFY_IS_NOT_NULL(command);
+ auto actionAndArgs = command.Action();
+ VERIFY_IS_NOT_NULL(actionAndArgs);
+ VERIFY_ARE_EQUAL(ShortcutAction::SplitPane, actionAndArgs.Action());
+ const auto& realArgs = actionAndArgs.Args().try_as();
+ VERIFY_IS_NOT_NULL(realArgs);
+ // Verify the args have the expected value
+ VERIFY_ARE_EQUAL(SplitState::Vertical, realArgs.SplitStyle());
+ 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_TRUE(realArgs.TerminalArgs().Profile().empty());
+ }
+ {
+ auto command = commands.Lookup(L"ctrl+b");
+ VERIFY_IS_NOT_NULL(command);
+ auto actionAndArgs = command.Action();
+ VERIFY_IS_NOT_NULL(actionAndArgs);
+ VERIFY_ARE_EQUAL(ShortcutAction::SplitPane, actionAndArgs.Action());
+ const auto& realArgs = actionAndArgs.Args().try_as();
+ VERIFY_IS_NOT_NULL(realArgs);
+ // Verify the args have the expected value
+ VERIFY_ARE_EQUAL(SplitState::Vertical, realArgs.SplitStyle());
+ 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_TRUE(realArgs.TerminalArgs().Profile().empty());
+ }
+ {
+ auto command = commands.Lookup(L"ctrl+c");
+ VERIFY_IS_NOT_NULL(command);
+ auto actionAndArgs = command.Action();
+ VERIFY_IS_NOT_NULL(actionAndArgs);
+ VERIFY_ARE_EQUAL(ShortcutAction::SplitPane, actionAndArgs.Action());
+ const auto& realArgs = actionAndArgs.Args().try_as();
+ VERIFY_IS_NOT_NULL(realArgs);
+ // Verify the args have the expected value
+ VERIFY_ARE_EQUAL(SplitState::Vertical, realArgs.SplitStyle());
+ 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_TRUE(realArgs.TerminalArgs().Profile().empty());
+ }
+ {
+ auto command = commands.Lookup(L"Split pane, split: horizontal");
+ VERIFY_IS_NOT_NULL(command);
+ auto actionAndArgs = command.Action();
+ VERIFY_IS_NOT_NULL(actionAndArgs);
+ VERIFY_ARE_EQUAL(ShortcutAction::SplitPane, actionAndArgs.Action());
+ const auto& realArgs = actionAndArgs.Args().try_as();
+ VERIFY_IS_NOT_NULL(realArgs);
+ // Verify the args have the expected value
+ VERIFY_ARE_EQUAL(SplitState::Horizontal, realArgs.SplitStyle());
+ 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_TRUE(realArgs.TerminalArgs().Profile().empty());
+ }
+ }
+
+ void DeserializationTests::TestNestedCommandWithoutName()
+ {
+ // This test tests a nested command without a name specified. This type
+ // of command should just be ignored, since we can't auto-generate names
+ // for nested commands, they _must_ have names specified.
+
+ 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"
+ },
+ {
+ "name": "profile1",
+ "guid": "{6239a42c-1111-49a3-80bd-e8fdd045185c}",
+ "historySize": 2,
+ "commandline": "pwsh.exe"
+ },
+ {
+ "name": "profile2",
+ "historySize": 3,
+ "commandline": "wsl.exe"
+ }
+ ],
+ "actions": [
+ {
+ "commands": [
+ {
+ "name": "child1",
+ "command": { "action": "newTab", "commandline": "ssh me@first.com" }
+ },
+ {
+ "name": "child2",
+ "command": { "action": "newTab", "commandline": "ssh me@second.com" }
+ }
+ ]
+ },
+ ],
+ "schemes": [ { "name": "Campbell" } ] // This is included here to prevent settings validation errors.
+ })" };
+
+ VerifyParseSucceeded(settingsJson);
+
+ auto settings = winrt::make_self();
+ settings->_ParseJsonString(settingsJson, false);
+ settings->LayerJson(settings->_userSettings);
+
+ VERIFY_ARE_EQUAL(0u, settings->_warnings.Size());
+ VERIFY_ARE_EQUAL(3u, settings->_profiles.Size());
+
+ auto commands = settings->_globals->Commands();
+ settings->_ValidateSettings();
+ _logCommandNames(commands);
+
+ VERIFY_ARE_EQUAL(0u, settings->_warnings.Size());
+
+ // Because the "parent" command didn't have a name, it couldn't be
+ // placed into the list of commands. It and it's children are just
+ // ignored.
+ VERIFY_ARE_EQUAL(0u, commands.Size());
+ }
+
+ void DeserializationTests::TestUnbindNestedCommand()
+ {
+ // Test that layering a command with `"commands": null` set will unbind a command that already exists.
+
+ 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"
+ },
+ {
+ "name": "profile1",
+ "guid": "{6239a42c-1111-49a3-80bd-e8fdd045185c}",
+ "historySize": 2,
+ "commandline": "pwsh.exe"
+ },
+ {
+ "name": "profile2",
+ "historySize": 3,
+ "commandline": "wsl.exe"
+ }
+ ],
+ "actions": [
+ {
+ "name": "parent",
+ "commands": [
+ {
+ "name": "child1",
+ "command": { "action": "newTab", "commandline": "ssh me@first.com" }
+ },
+ {
+ "name": "child2",
+ "command": { "action": "newTab", "commandline": "ssh me@second.com" }
+ }
+ ]
+ },
+ ],
+ "schemes": [ { "name": "Campbell" } ] // This is included here to prevent settings validation errors.
+ })" };
+
+ const std::string settings1Json{ R"(
+ {
+ "defaultProfile": "{6239a42c-0000-49a3-80bd-e8fdd045185c}",
+ "actions": [
+ {
+ "name": "parent",
+ "commands": null
+ },
+ ],
+ })" };
+
+ VerifyParseSucceeded(settingsJson);
+ VerifyParseSucceeded(settings1Json);
+
+ auto settings = winrt::make_self();
+ settings->_ParseJsonString(settingsJson, false);
+ settings->LayerJson(settings->_userSettings);
+
+ VERIFY_ARE_EQUAL(0u, settings->_warnings.Size());
+ VERIFY_ARE_EQUAL(3u, settings->_profiles.Size());
+
+ auto commands = settings->_globals->Commands();
+ settings->_ValidateSettings();
+ _logCommandNames(commands);
+
+ VERIFY_ARE_EQUAL(0u, settings->_warnings.Size());
+ VERIFY_ARE_EQUAL(1u, commands.Size());
+
+ Log::Comment(L"Layer second bit of json, to unbind the original command.");
+
+ settings->_ParseJsonString(settings1Json, false);
+ settings->LayerJson(settings->_userSettings);
+ settings->_ValidateSettings();
+ _logCommandNames(commands);
+ VERIFY_ARE_EQUAL(0u, settings->_warnings.Size());
+ VERIFY_ARE_EQUAL(0u, commands.Size());
+ }
+
+ void DeserializationTests::TestRebindNestedCommand()
+ {
+ // Test that layering a command with an action set on top of a command
+ // with nested commands replaces the nested commands with an action.
+
+ 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"
+ },
+ {
+ "name": "profile1",
+ "guid": "{6239a42c-1111-49a3-80bd-e8fdd045185c}",
+ "historySize": 2,
+ "commandline": "pwsh.exe"
+ },
+ {
+ "name": "profile2",
+ "historySize": 3,
+ "commandline": "wsl.exe"
+ }
+ ],
+ "actions": [
+ {
+ "name": "parent",
+ "commands": [
+ {
+ "name": "child1",
+ "command": { "action": "newTab", "commandline": "ssh me@first.com" }
+ },
+ {
+ "name": "child2",
+ "command": { "action": "newTab", "commandline": "ssh me@second.com" }
+ }
+ ]
+ },
+ ],
+ "schemes": [ { "name": "Campbell" } ] // This is included here to prevent settings validation errors.
+ })" };
+
+ const std::string settings1Json{ R"(
+ {
+ "defaultProfile": "{6239a42c-0000-49a3-80bd-e8fdd045185c}",
+ "actions": [
+ {
+ "name": "parent",
+ "command": "newTab"
+ },
+ ],
+ })" };
+
+ VerifyParseSucceeded(settingsJson);
+ VerifyParseSucceeded(settings1Json);
+
+ auto settings = winrt::make_self();
+ settings->_ParseJsonString(settingsJson, false);
+ settings->LayerJson(settings->_userSettings);
+
+ VERIFY_ARE_EQUAL(0u, settings->_warnings.Size());
+ VERIFY_ARE_EQUAL(3u, settings->_profiles.Size());
+
+ auto commands = settings->_globals->Commands();
+ settings->_ValidateSettings();
+ _logCommandNames(commands);
+
+ VERIFY_ARE_EQUAL(0u, settings->_warnings.Size());
+ VERIFY_ARE_EQUAL(1u, commands.Size());
+
+ {
+ winrt::hstring commandName{ L"parent" };
+ auto commandProj = commands.Lookup(commandName);
+ VERIFY_IS_NOT_NULL(commandProj);
+
+ winrt::com_ptr commandImpl;
+ commandImpl.copy_from(winrt::get_self(commandProj));
+
+ VERIFY_IS_TRUE(commandImpl->HasNestedCommands());
+ VERIFY_ARE_EQUAL(2u, commandImpl->_subcommands.Size());
+ }
+
+ Log::Comment(L"Layer second bit of json, to unbind the original command.");
+ settings->_ParseJsonString(settings1Json, false);
+ settings->LayerJson(settings->_userSettings);
+ settings->_ValidateSettings();
+ _logCommandNames(commands);
+ VERIFY_ARE_EQUAL(0u, settings->_warnings.Size());
+ VERIFY_ARE_EQUAL(1u, commands.Size());
+
+ {
+ winrt::hstring commandName{ L"parent" };
+ auto commandProj = commands.Lookup(commandName);
+
+ VERIFY_IS_NOT_NULL(commandProj);
+ auto actionAndArgs = commandProj.Action();
+ VERIFY_IS_NOT_NULL(actionAndArgs);
+ VERIFY_ARE_EQUAL(ShortcutAction::NewTab, actionAndArgs.Action());
+ const auto& realArgs = actionAndArgs.Args().try_as();
+ VERIFY_IS_NOT_NULL(realArgs);
+
+ winrt::com_ptr commandImpl;
+ commandImpl.copy_from(winrt::get_self(commandProj));
+
+ VERIFY_IS_FALSE(commandImpl->HasNestedCommands());
+ }
+ }
+
+}
diff --git a/src/cascadia/LocalTests_TerminalApp/JsonTestClass.h b/src/cascadia/LocalTests_SettingsModel/JsonTestClass.h
similarity index 100%
rename from src/cascadia/LocalTests_TerminalApp/JsonTestClass.h
rename to src/cascadia/LocalTests_SettingsModel/JsonTestClass.h
diff --git a/src/cascadia/LocalTests_TerminalApp/KeyBindingsTests.cpp b/src/cascadia/LocalTests_SettingsModel/KeyBindingsTests.cpp
similarity index 85%
rename from src/cascadia/LocalTests_TerminalApp/KeyBindingsTests.cpp
rename to src/cascadia/LocalTests_SettingsModel/KeyBindingsTests.cpp
index 3115d76abd4..5ff3f2facad 100644
--- a/src/cascadia/LocalTests_TerminalApp/KeyBindingsTests.cpp
+++ b/src/cascadia/LocalTests_SettingsModel/KeyBindingsTests.cpp
@@ -3,21 +3,20 @@
#include "pch.h"
-#include "../TerminalApp/ColorScheme.h"
-#include "../TerminalApp/CascadiaSettings.h"
-#include "../KeyMapping.h"
+#include "../TerminalSettingsModel/ColorScheme.h"
+#include "../TerminalSettingsModel/CascadiaSettings.h"
+#include "../TerminalSettingsModel/KeyMapping.h"
#include "JsonTestClass.h"
#include "TestUtils.h"
using namespace Microsoft::Console;
-using namespace TerminalApp;
-using namespace winrt::TerminalApp;
+using namespace winrt::Microsoft::Terminal::Settings::Model;
using namespace winrt::Microsoft::Terminal::TerminalControl;
using namespace WEX::Logging;
using namespace WEX::TestExecution;
using namespace WEX::Common;
-namespace TerminalAppLocalTests
+namespace SettingsModelLocalTests
{
// TODO:microsoft/terminal#3838:
// Unfortunately, these tests _WILL NOT_ work in our CI. We're waiting for
@@ -67,7 +66,7 @@ namespace TerminalAppLocalTests
const auto bindings1Json = VerifyParseSucceeded(bindings1String);
const auto bindings2Json = VerifyParseSucceeded(bindings2String);
- auto keymap = winrt::make_self();
+ auto keymap = winrt::make_self();
VERIFY_IS_NOT_NULL(keymap);
VERIFY_ARE_EQUAL(0u, keymap->_keyShortcuts.size());
@@ -91,7 +90,7 @@ namespace TerminalAppLocalTests
const auto bindings1Json = VerifyParseSucceeded(bindings1String);
const auto bindings2Json = VerifyParseSucceeded(bindings2String);
- auto keymap = winrt::make_self();
+ auto keymap = winrt::make_self();
VERIFY_IS_NOT_NULL(keymap);
VERIFY_ARE_EQUAL(0u, keymap->_keyShortcuts.size());
@@ -121,7 +120,7 @@ namespace TerminalAppLocalTests
const auto bindings4Json = VerifyParseSucceeded(bindings4String);
const auto bindings5Json = VerifyParseSucceeded(bindings5String);
- auto keymap = winrt::make_self();
+ auto keymap = winrt::make_self();
VERIFY_IS_NOT_NULL(keymap);
VERIFY_ARE_EQUAL(0u, keymap->_keyShortcuts.size());
@@ -190,7 +189,7 @@ namespace TerminalAppLocalTests
const auto bindings0Json = VerifyParseSucceeded(bindings0String);
- auto keymap = winrt::make_self();
+ auto keymap = winrt::make_self();
VERIFY_IS_NOT_NULL(keymap);
VERIFY_ARE_EQUAL(0u, keymap->_keyShortcuts.size());
keymap->LayerJson(bindings0Json);
@@ -200,7 +199,7 @@ namespace TerminalAppLocalTests
Log::Comment(NoThrowString().Format(
L"Verify that `copy` without args parses as Copy(SingleLine=false)"));
KeyChord kc{ true, false, false, static_cast('C') };
- auto actionAndArgs = TestUtils::GetActionAndArgs(*keymap, kc);
+ auto actionAndArgs = ::TestUtils::GetActionAndArgs(*keymap, kc);
const auto& realArgs = actionAndArgs.Args().try_as();
VERIFY_IS_NOT_NULL(realArgs);
// Verify the args have the expected value
@@ -211,7 +210,7 @@ namespace TerminalAppLocalTests
Log::Comment(NoThrowString().Format(
L"Verify that `copy` with args parses them correctly"));
KeyChord kc{ true, false, true, static_cast('C') };
- auto actionAndArgs = TestUtils::GetActionAndArgs(*keymap, kc);
+ auto actionAndArgs = ::TestUtils::GetActionAndArgs(*keymap, kc);
const auto& realArgs = actionAndArgs.Args().try_as();
VERIFY_IS_NOT_NULL(realArgs);
// Verify the args have the expected value
@@ -222,7 +221,7 @@ namespace TerminalAppLocalTests
Log::Comment(NoThrowString().Format(
L"Verify that `copy` with args parses them correctly"));
KeyChord kc{ false, true, true, static_cast('C') };
- auto actionAndArgs = TestUtils::GetActionAndArgs(*keymap, kc);
+ auto actionAndArgs = ::TestUtils::GetActionAndArgs(*keymap, kc);
const auto& realArgs = actionAndArgs.Args().try_as();
VERIFY_IS_NOT_NULL(realArgs);
// Verify the args have the expected value
@@ -233,7 +232,7 @@ namespace TerminalAppLocalTests
Log::Comment(NoThrowString().Format(
L"Verify that `newTab` without args parses as NewTab(Index=null)"));
KeyChord kc{ true, false, false, static_cast('T') };
- auto actionAndArgs = TestUtils::GetActionAndArgs(*keymap, kc);
+ auto actionAndArgs = ::TestUtils::GetActionAndArgs(*keymap, kc);
VERIFY_ARE_EQUAL(ShortcutAction::NewTab, actionAndArgs.Action());
const auto& realArgs = actionAndArgs.Args().try_as();
VERIFY_IS_NOT_NULL(realArgs);
@@ -245,7 +244,7 @@ namespace TerminalAppLocalTests
Log::Comment(NoThrowString().Format(
L"Verify that `newTab` parses args correctly"));
KeyChord kc{ true, false, true, static_cast('T') };
- auto actionAndArgs = TestUtils::GetActionAndArgs(*keymap, kc);
+ auto actionAndArgs = ::TestUtils::GetActionAndArgs(*keymap, kc);
VERIFY_ARE_EQUAL(ShortcutAction::NewTab, actionAndArgs.Action());
const auto& realArgs = actionAndArgs.Args().try_as();
VERIFY_IS_NOT_NULL(realArgs);
@@ -259,7 +258,7 @@ namespace TerminalAppLocalTests
L"Verify that `newTab` with an index greater than the legacy "
L"args afforded parses correctly"));
KeyChord kc{ true, false, true, static_cast('Y') };
- auto actionAndArgs = TestUtils::GetActionAndArgs(*keymap, kc);
+ auto actionAndArgs = ::TestUtils::GetActionAndArgs(*keymap, kc);
VERIFY_ARE_EQUAL(ShortcutAction::NewTab, actionAndArgs.Action());
const auto& realArgs = actionAndArgs.Args().try_as();
VERIFY_IS_NOT_NULL(realArgs);
@@ -273,7 +272,7 @@ namespace TerminalAppLocalTests
Log::Comment(NoThrowString().Format(
L"Verify that `copy` ignores args it doesn't understand"));
KeyChord kc{ true, false, true, static_cast('B') };
- auto actionAndArgs = TestUtils::GetActionAndArgs(*keymap, kc);
+ auto actionAndArgs = ::TestUtils::GetActionAndArgs(*keymap, kc);
VERIFY_ARE_EQUAL(ShortcutAction::CopyText, actionAndArgs.Action());
const auto& realArgs = actionAndArgs.Args().try_as();
VERIFY_IS_NOT_NULL(realArgs);
@@ -285,7 +284,7 @@ namespace TerminalAppLocalTests
Log::Comment(NoThrowString().Format(
L"Verify that `copy` null as it's `args` parses as the default option"));
KeyChord kc{ true, false, true, static_cast('B') };
- auto actionAndArgs = TestUtils::GetActionAndArgs(*keymap, kc);
+ auto actionAndArgs = ::TestUtils::GetActionAndArgs(*keymap, kc);
VERIFY_ARE_EQUAL(ShortcutAction::CopyText, actionAndArgs.Action());
const auto& realArgs = actionAndArgs.Args().try_as();
VERIFY_IS_NOT_NULL(realArgs);
@@ -297,7 +296,7 @@ namespace TerminalAppLocalTests
Log::Comment(NoThrowString().Format(
L"Verify that `adjustFontSize` with a positive delta parses args correctly"));
KeyChord kc{ true, false, false, static_cast('F') };
- auto actionAndArgs = TestUtils::GetActionAndArgs(*keymap, kc);
+ auto actionAndArgs = ::TestUtils::GetActionAndArgs(*keymap, kc);
VERIFY_ARE_EQUAL(ShortcutAction::AdjustFontSize, actionAndArgs.Action());
const auto& realArgs = actionAndArgs.Args().try_as();
VERIFY_IS_NOT_NULL(realArgs);
@@ -309,7 +308,7 @@ namespace TerminalAppLocalTests
Log::Comment(NoThrowString().Format(
L"Verify that `adjustFontSize` with a negative delta parses args correctly"));
KeyChord kc{ true, false, false, static_cast('G') };
- auto actionAndArgs = TestUtils::GetActionAndArgs(*keymap, kc);
+ auto actionAndArgs = ::TestUtils::GetActionAndArgs(*keymap, kc);
VERIFY_ARE_EQUAL(ShortcutAction::AdjustFontSize, actionAndArgs.Action());
const auto& realArgs = actionAndArgs.Args().try_as();
VERIFY_IS_NOT_NULL(realArgs);
@@ -330,7 +329,7 @@ namespace TerminalAppLocalTests
const auto bindings0Json = VerifyParseSucceeded(bindings0String);
- auto keymap = winrt::make_self();
+ auto keymap = winrt::make_self();
VERIFY_IS_NOT_NULL(keymap);
VERIFY_ARE_EQUAL(0u, keymap->_keyShortcuts.size());
keymap->LayerJson(bindings0Json);
@@ -338,48 +337,48 @@ namespace TerminalAppLocalTests
{
KeyChord kc{ true, false, false, static_cast('C') };
- auto actionAndArgs = TestUtils::GetActionAndArgs(*keymap, kc);
+ auto actionAndArgs = ::TestUtils::GetActionAndArgs(*keymap, kc);
VERIFY_ARE_EQUAL(ShortcutAction::SplitPane, actionAndArgs.Action());
const auto& realArgs = actionAndArgs.Args().try_as();
VERIFY_IS_NOT_NULL(realArgs);
// Verify the args have the expected value
- VERIFY_ARE_EQUAL(winrt::TerminalApp::SplitState::Automatic, realArgs.SplitStyle());
+ VERIFY_ARE_EQUAL(SplitState::Automatic, realArgs.SplitStyle());
}
{
KeyChord kc{ true, false, false, static_cast('D') };
- auto actionAndArgs = TestUtils::GetActionAndArgs(*keymap, kc);
+ auto actionAndArgs = ::TestUtils::GetActionAndArgs(*keymap, kc);
VERIFY_ARE_EQUAL(ShortcutAction::SplitPane, actionAndArgs.Action());
const auto& realArgs = actionAndArgs.Args().try_as();
VERIFY_IS_NOT_NULL(realArgs);
// Verify the args have the expected value
- VERIFY_ARE_EQUAL(winrt::TerminalApp::SplitState::Vertical, realArgs.SplitStyle());
+ VERIFY_ARE_EQUAL(SplitState::Vertical, realArgs.SplitStyle());
}
{
KeyChord kc{ true, false, false, static_cast('E') };
- auto actionAndArgs = TestUtils::GetActionAndArgs(*keymap, kc);
+ auto actionAndArgs = ::TestUtils::GetActionAndArgs(*keymap, kc);
VERIFY_ARE_EQUAL(ShortcutAction::SplitPane, actionAndArgs.Action());
const auto& realArgs = actionAndArgs.Args().try_as();
VERIFY_IS_NOT_NULL(realArgs);
// Verify the args have the expected value
- VERIFY_ARE_EQUAL(winrt::TerminalApp::SplitState::Horizontal, realArgs.SplitStyle());
+ VERIFY_ARE_EQUAL(SplitState::Horizontal, realArgs.SplitStyle());
}
{
KeyChord kc{ true, false, false, static_cast('G') };
- auto actionAndArgs = TestUtils::GetActionAndArgs(*keymap, kc);
+ auto actionAndArgs = ::TestUtils::GetActionAndArgs(*keymap, kc);
VERIFY_ARE_EQUAL(ShortcutAction::SplitPane, actionAndArgs.Action());
const auto& realArgs = actionAndArgs.Args().try_as();
VERIFY_IS_NOT_NULL(realArgs);
// Verify the args have the expected value
- VERIFY_ARE_EQUAL(winrt::TerminalApp::SplitState::Automatic, realArgs.SplitStyle());
+ VERIFY_ARE_EQUAL(SplitState::Automatic, realArgs.SplitStyle());
}
{
KeyChord kc{ true, false, false, static_cast('H') };
- auto actionAndArgs = TestUtils::GetActionAndArgs(*keymap, kc);
+ auto actionAndArgs = ::TestUtils::GetActionAndArgs(*keymap, kc);
VERIFY_ARE_EQUAL(ShortcutAction::SplitPane, actionAndArgs.Action());
const auto& realArgs = actionAndArgs.Args().try_as();
VERIFY_IS_NOT_NULL(realArgs);
// Verify the args have the expected value
- VERIFY_ARE_EQUAL(winrt::TerminalApp::SplitState::Automatic, realArgs.SplitStyle());
+ VERIFY_ARE_EQUAL(SplitState::Automatic, realArgs.SplitStyle());
}
}
@@ -393,7 +392,7 @@ namespace TerminalAppLocalTests
const auto bindings0Json = VerifyParseSucceeded(bindings0String);
- auto keymap = winrt::make_self();
+ auto keymap = winrt::make_self();
VERIFY_IS_NOT_NULL(keymap);
VERIFY_ARE_EQUAL(0u, keymap->_keyShortcuts.size());
keymap->LayerJson(bindings0Json);
@@ -401,7 +400,7 @@ namespace TerminalAppLocalTests
{
KeyChord kc{ true, false, false, static_cast('C') };
- auto actionAndArgs = TestUtils::GetActionAndArgs(*keymap, kc);
+ auto actionAndArgs = ::TestUtils::GetActionAndArgs(*keymap, kc);
VERIFY_ARE_EQUAL(ShortcutAction::SetTabColor, actionAndArgs.Action());
const auto& realArgs = actionAndArgs.Args().try_as();
VERIFY_IS_NOT_NULL(realArgs);
@@ -410,7 +409,7 @@ namespace TerminalAppLocalTests
}
{
KeyChord kc{ true, false, false, static_cast('D') };
- auto actionAndArgs = TestUtils::GetActionAndArgs(*keymap, kc);
+ auto actionAndArgs = ::TestUtils::GetActionAndArgs(*keymap, kc);
VERIFY_ARE_EQUAL(ShortcutAction::SetTabColor, actionAndArgs.Action());
const auto& realArgs = actionAndArgs.Args().try_as();
VERIFY_IS_NOT_NULL(realArgs);
@@ -421,7 +420,7 @@ namespace TerminalAppLocalTests
}
{
KeyChord kc{ true, false, false, static_cast('F') };
- auto actionAndArgs = TestUtils::GetActionAndArgs(*keymap, kc);
+ auto actionAndArgs = ::TestUtils::GetActionAndArgs(*keymap, kc);
VERIFY_ARE_EQUAL(ShortcutAction::SetTabColor, actionAndArgs.Action());
const auto& realArgs = actionAndArgs.Args().try_as();
VERIFY_IS_NOT_NULL(realArgs);
@@ -438,7 +437,7 @@ namespace TerminalAppLocalTests
const auto bindings0Json = VerifyParseSucceeded(bindings0String);
- auto keymap = winrt::make_self();
+ auto keymap = winrt::make_self();
VERIFY_IS_NOT_NULL(keymap);
VERIFY_ARE_EQUAL(0u, keymap->_keyShortcuts.size());
keymap->LayerJson(bindings0Json);
@@ -446,7 +445,7 @@ namespace TerminalAppLocalTests
{
KeyChord kc{ true, false, false, static_cast('C') };
- auto actionAndArgs = TestUtils::GetActionAndArgs(*keymap, kc);
+ auto actionAndArgs = ::TestUtils::GetActionAndArgs(*keymap, kc);
const auto& realArgs = actionAndArgs.Args().try_as();
VERIFY_IS_NOT_NULL(realArgs);
// Verify the args have the expected value
diff --git a/src/cascadia/LocalTests_SettingsModel/LocalTests_SettingsModel.def b/src/cascadia/LocalTests_SettingsModel/LocalTests_SettingsModel.def
new file mode 100644
index 00000000000..8c1a02932d0
--- /dev/null
+++ b/src/cascadia/LocalTests_SettingsModel/LocalTests_SettingsModel.def
@@ -0,0 +1,3 @@
+EXPORTS
+DllCanUnloadNow = WINRT_CanUnloadNow PRIVATE
+DllGetActivationFactory = WINRT_GetActivationFactory PRIVATE
diff --git a/src/cascadia/LocalTests_TerminalApp/ProfileTests.cpp b/src/cascadia/LocalTests_SettingsModel/ProfileTests.cpp
similarity index 95%
rename from src/cascadia/LocalTests_TerminalApp/ProfileTests.cpp
rename to src/cascadia/LocalTests_SettingsModel/ProfileTests.cpp
index 8f489bbf801..09f4fa053be 100644
--- a/src/cascadia/LocalTests_TerminalApp/ProfileTests.cpp
+++ b/src/cascadia/LocalTests_SettingsModel/ProfileTests.cpp
@@ -3,18 +3,17 @@
#include "pch.h"
-#include "../TerminalApp/ColorScheme.h"
-#include "../TerminalApp/CascadiaSettings.h"
+#include "../TerminalSettingsModel/ColorScheme.h"
+#include "../TerminalSettingsModel/CascadiaSettings.h"
#include "JsonTestClass.h"
using namespace Microsoft::Console;
-using namespace TerminalApp;
-using namespace winrt::TerminalApp;
+using namespace winrt::Microsoft::Terminal::Settings::Model;
using namespace WEX::Logging;
using namespace WEX::TestExecution;
using namespace WEX::Common;
-namespace TerminalAppLocalTests
+namespace SettingsModelLocalTests
{
// TODO:microsoft/terminal#3838:
// Unfortunately, these tests _WILL NOT_ work in our CI. We're waiting for
@@ -253,7 +252,7 @@ namespace TerminalAppLocalTests
const auto profile3Json = VerifyParseSucceeded(profile3String);
const auto profile4Json = VerifyParseSucceeded(profile4String);
- auto settings = winrt::make_self();
+ auto settings = winrt::make_self();
VERIFY_ARE_EQUAL(0u, settings->_profiles.Size());
VERIFY_IS_NULL(settings->_FindMatchingProfile(profile0Json));
diff --git a/src/cascadia/LocalTests_SettingsModel/SettingsModel.LocalTests.vcxproj b/src/cascadia/LocalTests_SettingsModel/SettingsModel.LocalTests.vcxproj
new file mode 100644
index 00000000000..44615a31755
--- /dev/null
+++ b/src/cascadia/LocalTests_SettingsModel/SettingsModel.LocalTests.vcxproj
@@ -0,0 +1,112 @@
+
+
+
+
+
+
+ {CA5CAD1A-9B68-456A-B13E-C8218070DC42}
+ Win32Proj
+ SettingsModelLocalTests
+ LocalTests_SettingsModel
+ SettingsModel.LocalTests
+ DynamicLibrary
+ 10.0.18362.0
+ 10.0.18362.0
+
+ true
+
+
+
+
+ $(SolutionDir)bin\$(Platform)\$(Configuration)\$(ProjectName)\
+ $(SolutionDir)obj\$(Platform)\$(Configuration)\$(ProjectName)\
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Create
+
+
+
+ NotUsing
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ..;$(OpenConsoleDir)\dep;$(OpenConsoleDir)\dep\jsoncpp\json;$(OpenConsoleDir)src\inc;$(OpenConsoleDir)src\inc\test;$(WinRT_IncludePath)\..\cppwinrt\winrt;"$(OpenConsoleDir)\src\cascadia\TerminalSettingsModel\Generated Files";%(AdditionalIncludeDirectories)
+ pch.h
+
+
+ 4702;%(DisableSpecificWarnings)
+
+
+ onecoreuap.lib;%(AdditionalDependencies)
+
+
+
+
+ true
+ true
+
+
+
+
+
+
+
+ <_CppWinrtBinRoot>"$(OpenConsoleDir)$(Platform)\$(Configuration)\"
+
+ x86
+ $(Platform)
+ <_MUXBinRoot>"$(OpenConsoleDir)packages\Microsoft.UI.Xaml.2.5.0-prerelease.200609001\runtimes\win10-$(Native-Platform)\native\"
+
+
+
+
+
+
diff --git a/src/cascadia/LocalTests_TerminalApp/TestUtils.h b/src/cascadia/LocalTests_SettingsModel/TestUtils.h
similarity index 83%
rename from src/cascadia/LocalTests_TerminalApp/TestUtils.h
rename to src/cascadia/LocalTests_SettingsModel/TestUtils.h
index 0e06231432a..e211d50c43c 100644
--- a/src/cascadia/LocalTests_TerminalApp/TestUtils.h
+++ b/src/cascadia/LocalTests_SettingsModel/TestUtils.h
@@ -12,7 +12,7 @@ Author(s):
Mike Griese (migrie) December-2019
--*/
-class TerminalAppLocalTests::TestUtils
+class TestUtils
{
public:
// Function Description:
@@ -23,8 +23,8 @@ class TerminalAppLocalTests::TestUtils
// - kc: The key chord to look up the bound ActionAndArgs for.
// Return Value:
// - The ActionAndArgs bound to the given key, or nullptr if nothing is bound to it.
- static const winrt::TerminalApp::ActionAndArgs GetActionAndArgs(const winrt::TerminalApp::implementation::KeyMapping& keymap,
- const winrt::Microsoft::Terminal::TerminalControl::KeyChord& kc)
+ static const winrt::Microsoft::Terminal::Settings::Model::ActionAndArgs GetActionAndArgs(const winrt::Microsoft::Terminal::Settings::Model::KeyMapping& keymap,
+ const winrt::Microsoft::Terminal::TerminalControl::KeyChord& kc)
{
std::wstring buffer{ L"" };
if (WI_IsFlagSet(kc.Modifiers(), winrt::Microsoft::Terminal::TerminalControl::KeyModifiers::Ctrl))
diff --git a/src/cascadia/LocalTests_SettingsModel/pch.cpp b/src/cascadia/LocalTests_SettingsModel/pch.cpp
new file mode 100644
index 00000000000..3c27d44d570
--- /dev/null
+++ b/src/cascadia/LocalTests_SettingsModel/pch.cpp
@@ -0,0 +1,4 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT license.
+
+#include "pch.h"
diff --git a/src/cascadia/LocalTests_SettingsModel/pch.h b/src/cascadia/LocalTests_SettingsModel/pch.h
new file mode 100644
index 00000000000..9a06e029cc6
--- /dev/null
+++ b/src/cascadia/LocalTests_SettingsModel/pch.h
@@ -0,0 +1,65 @@
+/*++
+Copyright (c) Microsoft Corporation
+Licensed under the MIT license.
+
+Module Name:
+- precomp.h
+
+Abstract:
+- Contains external headers to include in the precompile phase of console build process.
+- Avoid including internal project headers. Instead include them only in the classes that need them (helps with test project building).
+
+Author(s):
+- Carlos Zamora (cazamor) April 2019
+--*/
+
+#pragma once
+
+// Manually include til after we include Windows.Foundation to give it winrt superpowers
+#define BLOCK_TIL
+// This includes support libraries from the CRT, STL, WIL, and GSL
+#include "LibraryIncludes.h"
+// This is inexplicable, but for whatever reason, cppwinrt conflicts with the
+// SDK definition of this function, so the only fix is to undef it.
+// from WinBase.h
+// Windows::UI::Xaml::Media::Animation::IStoryboard::GetCurrentTime
+#ifdef GetCurrentTime
+#undef GetCurrentTime
+#endif
+
+#include
+#include
+#include
+
+#include
+#include
+#include "consoletaeftemplates.hpp"
+
+#include
+#include "winrt/Windows.UI.Xaml.Markup.h"
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include
+
+#include
+
+#include
+
+// Manually include til after we include Windows.Foundation to give it winrt superpowers
+#include "til.h"
+
+// Common includes for most tests:
+#include "../../inc/argb.h"
+#include "../../inc/conattrs.hpp"
+#include "../../types/inc/utils.hpp"
+#include "../../inc/DefaultSettings.h"
diff --git a/src/cascadia/LocalTests_TerminalApp/CommandlineTest.cpp b/src/cascadia/LocalTests_TerminalApp/CommandlineTest.cpp
index d9735e2ccd4..897bc4984f2 100644
--- a/src/cascadia/LocalTests_TerminalApp/CommandlineTest.cpp
+++ b/src/cascadia/LocalTests_TerminalApp/CommandlineTest.cpp
@@ -6,12 +6,12 @@
#include "../TerminalApp/TerminalPage.h"
#include "../TerminalApp/AppCommandlineArgs.h"
-#include "../TerminalApp/ActionArgs.h"
using namespace WEX::Logging;
using namespace WEX::Common;
using namespace WEX::TestExecution;
+using namespace winrt::Microsoft::Terminal::Settings::Model;
using namespace winrt::TerminalApp;
using namespace ::TerminalApp;
@@ -1076,9 +1076,8 @@ namespace TerminalAppLocalTests
void CommandlineTest::TestSimpleExecuteCommandlineAction()
{
- auto args = winrt::make_self();
- args->Commandline(L"new-tab");
- auto actions = implementation::TerminalPage::ConvertExecuteCommandlineToActions(*args);
+ ExecuteCommandlineArgs args{ L"new-tab" };
+ auto actions = implementation::TerminalPage::ConvertExecuteCommandlineToActions(args);
VERIFY_ARE_EQUAL(1u, actions.size());
auto actionAndArgs = actions.at(0);
VERIFY_ARE_EQUAL(ShortcutAction::NewTab, actionAndArgs.Action());
@@ -1095,9 +1094,8 @@ namespace TerminalAppLocalTests
void CommandlineTest::TestMultipleCommandExecuteCommandlineAction()
{
- auto args = winrt::make_self();
- args->Commandline(L"new-tab ; split-pane");
- auto actions = implementation::TerminalPage::ConvertExecuteCommandlineToActions(*args);
+ ExecuteCommandlineArgs args{ L"new-tab ; split-pane" };
+ auto actions = implementation::TerminalPage::ConvertExecuteCommandlineToActions(args);
VERIFY_ARE_EQUAL(2u, actions.size());
{
auto actionAndArgs = actions.at(0);
@@ -1129,10 +1127,9 @@ namespace TerminalAppLocalTests
void CommandlineTest::TestInvalidExecuteCommandlineAction()
{
- auto args = winrt::make_self();
// -H and -V cannot be combined.
- args->Commandline(L"split-pane -H -V");
- auto actions = implementation::TerminalPage::ConvertExecuteCommandlineToActions(*args);
+ ExecuteCommandlineArgs args{ L"split-pane -H -V" };
+ auto actions = implementation::TerminalPage::ConvertExecuteCommandlineToActions(args);
VERIFY_ARE_EQUAL(0u, actions.size());
}
}
diff --git a/src/cascadia/LocalTests_TerminalApp/SettingsTests.cpp b/src/cascadia/LocalTests_TerminalApp/SettingsTests.cpp
index 12bd087a6db..af9cda0776e 100644
--- a/src/cascadia/LocalTests_TerminalApp/SettingsTests.cpp
+++ b/src/cascadia/LocalTests_TerminalApp/SettingsTests.cpp
@@ -3,21 +3,16 @@
#include "pch.h"
-#include "../TerminalApp/ColorScheme.h"
-#include "../TerminalApp/CascadiaSettings.h"
#include "../TerminalApp/TerminalPage.h"
#include "../TerminalApp/TerminalSettings.h"
-#include "JsonTestClass.h"
-#include "TestUtils.h"
-#include
-#include "../ut_app/TestDynamicProfileGenerator.h"
+#include "../LocalTests_SettingsModel/TestUtils.h"
using namespace Microsoft::Console;
-using namespace TerminalApp;
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::TerminalControl;
namespace TerminalAppLocalTests
@@ -27,7 +22,7 @@ namespace TerminalAppLocalTests
// 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 : public JsonTestClass
+ 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
@@ -40,52 +35,14 @@ namespace TerminalAppLocalTests
END_TEST_CLASS()
TEST_METHOD(TryCreateWinRTType);
- TEST_METHOD(ValidateProfilesExist);
- TEST_METHOD(ValidateDefaultProfileExists);
- TEST_METHOD(ValidateDuplicateProfiles);
- TEST_METHOD(ValidateManyWarnings);
- TEST_METHOD(LayerGlobalProperties);
- TEST_METHOD(ValidateProfileOrdering);
- TEST_METHOD(ValidateHideProfiles);
- TEST_METHOD(ValidateProfilesGenerateGuids);
- TEST_METHOD(GeneratedGuidRoundtrips);
- TEST_METHOD(TestAllValidationsWithNullGuids);
- TEST_METHOD(TestReorderWithNullGuids);
- TEST_METHOD(TestReorderingWithoutGuid);
- TEST_METHOD(TestLayeringNameOnlyProfiles);
- TEST_METHOD(TestExplodingNameOnlyProfiles);
- TEST_METHOD(TestHideAllProfiles);
- TEST_METHOD(TestInvalidColorSchemeName);
- TEST_METHOD(TestHelperFunctions);
-
- TEST_METHOD(TestProfileIconWithEnvVar);
- TEST_METHOD(TestProfileBackgroundImageWithEnvVar);
-
- TEST_METHOD(TestCloseOnExitParsing);
- TEST_METHOD(TestCloseOnExitCompatibilityShim);
-
- TEST_METHOD(TestLayerUserDefaultsBeforeProfiles);
- TEST_METHOD(TestDontLayerGuidFromUserDefaults);
- TEST_METHOD(TestLayerUserDefaultsOnDynamics);
TEST_METHOD(TestTerminalArgsForBinding);
- TEST_METHOD(FindMissingProfile);
TEST_METHOD(MakeSettingsForProfileThatDoesntExist);
TEST_METHOD(MakeSettingsForDefaultProfileThatDoesntExist);
TEST_METHOD(TestLayerProfileOnColorScheme);
- TEST_METHOD(ValidateKeybindingsWarnings);
-
- TEST_METHOD(ValidateExecuteCommandlineWarning);
-
- TEST_METHOD(ValidateLegacyGlobalsWarning);
-
- TEST_METHOD(TestTrailingCommas);
-
- TEST_METHOD(TestCommandsAndKeybindings);
-
TEST_METHOD(TestIterateCommands);
TEST_METHOD(TestIterateOnGeneratedNamedCommands);
TEST_METHOD(TestIterateOnBadJson);
@@ -94,20 +51,16 @@ namespace TerminalAppLocalTests
TEST_METHOD(TestNestedInIterableCommand);
TEST_METHOD(TestIterableInNestedCommand);
TEST_METHOD(TestMixedNestedAndIterableCommand);
- TEST_METHOD(TestNestedCommandWithoutName);
- TEST_METHOD(TestUnbindNestedCommand);
- TEST_METHOD(TestRebindNestedCommand);
TEST_METHOD(TestIterableColorSchemeCommands);
TEST_CLASS_SETUP(ClassSetup)
{
- InitializeJsonReader();
return true;
}
private:
- void _logCommandNames(winrt::Windows::Foundation::Collections::IMapView commands, const int indentation = 1)
+ void _logCommandNames(winrt::Windows::Foundation::Collections::IMapView commands, const int indentation = 1)
{
if (indentation == 1)
{
@@ -122,11 +75,9 @@ namespace TerminalAppLocalTests
nameAndCommand.Value().Name())
.c_str());
- winrt::com_ptr cmdImpl;
- cmdImpl.copy_from(winrt::get_self(nameAndCommand.Value()));
- if (cmdImpl->HasNestedCommands())
+ if (nameAndCommand.Value().HasNestedCommands())
{
- _logCommandNames(cmdImpl->_subcommands.GetView(), indentation + 2);
+ _logCommandNames(nameAndCommand.Value().NestedCommands(), indentation + 2);
}
}
}
@@ -142,2493 +93,476 @@ namespace TerminalAppLocalTests
VERIFY_ARE_NOT_EQUAL(oldFontSize, newFontSize);
}
- void SettingsTests::ValidateProfilesExist()
- {
- const std::string settingsWithProfiles{ R"(
- {
- "profiles": [
- {
- "name" : "profile0"
- }
- ]
- })" };
-
- const std::string settingsWithoutProfiles{ R"(
- {
- "defaultProfile": "{6239a42c-1de4-49a3-80bd-e8fdd045185c}"
- })" };
-
- const std::string settingsWithEmptyProfiles{ R"(
- {
- "profiles": []
- })" };
-
- {
- // Case 1: Good settings
- const auto settingsObject = VerifyParseSucceeded(settingsWithProfiles);
- auto settings = implementation::CascadiaSettings::FromJson(settingsObject);
- settings->_ValidateProfilesExist();
- }
- {
- // Case 2: Bad settings
- const auto settingsObject = VerifyParseSucceeded(settingsWithoutProfiles);
- auto settings = implementation::CascadiaSettings::FromJson(settingsObject);
- bool caughtExpectedException = false;
- try
- {
- settings->_ValidateProfilesExist();
- }
- catch (const winrt::TerminalApp::implementation::SettingsException& ex)
- {
- VERIFY_IS_TRUE(ex.Error() == winrt::TerminalApp::SettingsLoadErrors::NoProfiles);
- caughtExpectedException = true;
- }
- VERIFY_IS_TRUE(caughtExpectedException);
- }
- {
- // Case 3: Bad settings
- const auto settingsObject = VerifyParseSucceeded(settingsWithEmptyProfiles);
- auto settings = implementation::CascadiaSettings::FromJson(settingsObject);
- bool caughtExpectedException = false;
- try
- {
- settings->_ValidateProfilesExist();
- }
- catch (const winrt::TerminalApp::implementation::SettingsException& ex)
- {
- VERIFY_IS_TRUE(ex.Error() == winrt::TerminalApp::SettingsLoadErrors::NoProfiles);
- caughtExpectedException = true;
- }
- VERIFY_IS_TRUE(caughtExpectedException);
- }
- }
-
- void SettingsTests::ValidateDefaultProfileExists()
- {
- const std::string goodProfiles{ R"(
- {
- "defaultProfile": "{6239a42c-1111-49a3-80bd-e8fdd045185c}",
- "profiles": [
- {
- "name" : "profile0",
- "guid": "{6239a42c-1111-49a3-80bd-e8fdd045185c}"
- },
- {
- "name" : "profile0",
- "guid": "{6239a42c-2222-49a3-80bd-e8fdd045185c}"
- }
- ]
- })" };
-
- const std::string badProfiles{ R"(
- {
- "defaultProfile": "{6239a42c-1111-49a3-80bd-e8fdd045185c}",
- "profiles": [
- {
- "name" : "profile0",
- "guid": "{6239a42c-3333-49a3-80bd-e8fdd045185c}"
- },
- {
- "name" : "profile1",
- "guid": "{6239a42c-4444-49a3-80bd-e8fdd045185c}"
- }
- ]
- })" };
-
- const std::string noDefaultAtAll{ R"(
- {
- "alwaysShowTabs": true,
- "profiles": [
- {
- "name" : "profile0",
- "guid": "{6239a42c-5555-49a3-80bd-e8fdd045185c}"
- },
- {
- "name" : "profile1",
- "guid": "{6239a42c-6666-49a3-80bd-e8fdd045185c}"
- }
- ]
- })" };
-
- const std::string goodProfilesSpecifiedByName{ R"(
- {
- "defaultProfile": "profile1",
- "profiles": [
- {
- "name" : "profile0",
- "guid": "{6239a42c-1111-49a3-80bd-e8fdd045185c}"
- },
- {
- "name" : "profile1",
- "guid": "{6239a42c-2222-49a3-80bd-e8fdd045185c}"
- }
- ]
- })" };
-
- {
- // Case 1: Good settings
- Log::Comment(NoThrowString().Format(
- L"Testing a pair of profiles with unique guids, and the defaultProfile is one of those guids"));
- const auto settingsObject = VerifyParseSucceeded(goodProfiles);
- auto settings = implementation::CascadiaSettings::FromJson(settingsObject);
- settings->_ResolveDefaultProfile();
- settings->_ValidateDefaultProfileExists();
- VERIFY_ARE_EQUAL(static_cast(0), settings->_warnings.Size());
- VERIFY_ARE_EQUAL(static_cast(2), settings->_profiles.Size());
- VERIFY_ARE_EQUAL(settings->_globals->DefaultProfile(), settings->_profiles.GetAt(0).Guid());
- }
- {
- // Case 2: Bad settings
- Log::Comment(NoThrowString().Format(
- L"Testing a pair of profiles with unique guids, but the defaultProfile is NOT one of those guids"));
- const auto settingsObject = VerifyParseSucceeded(badProfiles);
- auto settings = implementation::CascadiaSettings::FromJson(settingsObject);
- settings->_ResolveDefaultProfile();
- settings->_ValidateDefaultProfileExists();
- VERIFY_ARE_EQUAL(static_cast(1), settings->_warnings.Size());
- VERIFY_ARE_EQUAL(winrt::TerminalApp::SettingsLoadWarnings::MissingDefaultProfile, settings->_warnings.GetAt(0));
-
- VERIFY_ARE_EQUAL(static_cast(2), settings->_profiles.Size());
- VERIFY_ARE_EQUAL(settings->_globals->DefaultProfile(), settings->_profiles.GetAt(0).Guid());
- }
- {
- // Case 2: Bad settings
- Log::Comment(NoThrowString().Format(
- L"Testing a pair of profiles with unique guids, and no defaultProfile at all"));
- const auto settingsObject = VerifyParseSucceeded(badProfiles);
- auto settings = implementation::CascadiaSettings::FromJson(settingsObject);
- settings->_ResolveDefaultProfile();
- settings->_ValidateDefaultProfileExists();
- VERIFY_ARE_EQUAL(static_cast(1), settings->_warnings.Size());
- VERIFY_ARE_EQUAL(winrt::TerminalApp::SettingsLoadWarnings::MissingDefaultProfile, settings->_warnings.GetAt(0));
-
- VERIFY_ARE_EQUAL(static_cast(2), settings->_profiles.Size());
- VERIFY_ARE_EQUAL(settings->_globals->DefaultProfile(), settings->_profiles.GetAt(0).Guid());
- }
- {
- // Case 4: Good settings, default profile is a string
- Log::Comment(NoThrowString().Format(
- L"Testing a pair of profiles with unique guids, and the defaultProfile is one of the profile names"));
- const auto settingsObject = VerifyParseSucceeded(goodProfilesSpecifiedByName);
- auto settings = implementation::CascadiaSettings::FromJson(settingsObject);
- settings->_ResolveDefaultProfile();
- settings->_ValidateDefaultProfileExists();
- VERIFY_ARE_EQUAL(static_cast(0), settings->_warnings.Size());
- VERIFY_ARE_EQUAL(static_cast(2), settings->_profiles.Size());
- VERIFY_ARE_EQUAL(settings->_globals->DefaultProfile(), settings->_profiles.GetAt(1).Guid());
- }
- }
-
- void SettingsTests::ValidateDuplicateProfiles()
- {
- const std::string goodProfiles{ R"(
- {
- "profiles": [
- {
- "name" : "profile0",
- "guid": "{6239a42c-1111-49a3-80bd-e8fdd045185c}"
- },
- {
- "name" : "profile0",
- "guid": "{6239a42c-2222-49a3-80bd-e8fdd045185c}"
- }
- ]
- })" };
-
- const std::string badProfiles{ R"(
- {
- "profiles": [
- {
- "name" : "profile0",
- "guid": "{6239a42c-3333-49a3-80bd-e8fdd045185c}"
- },
- {
- "name" : "profile1",
- "guid": "{6239a42c-3333-49a3-80bd-e8fdd045185c}"
- }
- ]
- })" };
-
- const std::string veryBadProfiles{ R"(
- {
- "profiles": [
- {
- "name" : "profile0",
- "guid": "{6239a42c-4444-49a3-80bd-e8fdd045185c}"
- },
- {
- "name" : "profile1",
- "guid": "{6239a42c-5555-49a3-80bd-e8fdd045185c}"
- },
- {
- "name" : "profile2",
- "guid": "{6239a42c-4444-49a3-80bd-e8fdd045185c}"
- },
- {
- "name" : "profile3",
- "guid": "{6239a42c-4444-49a3-80bd-e8fdd045185c}"
- },
- {
- "name" : "profile4",
- "guid": "{6239a42c-6666-49a3-80bd-e8fdd045185c}"
- },
- {
- "name" : "profile5",
- "guid": "{6239a42c-5555-49a3-80bd-e8fdd045185c}"
- },
- {
- "name" : "profile6",
- "guid": "{6239a42c-7777-49a3-80bd-e8fdd045185c}"
- }
- ]
- })" };
- Profile profile0 = winrt::make(::Microsoft::Console::Utils::GuidFromString(L"{6239a42c-4444-49a3-80bd-e8fdd045185c}"));
- profile0.Name(L"profile0");
- Profile profile1 = winrt::make(::Microsoft::Console::Utils::GuidFromString(L"{6239a42c-5555-49a3-80bd-e8fdd045185c}"));
- profile1.Name(L"profile1");
- Profile profile2 = winrt::make(::Microsoft::Console::Utils::GuidFromString(L"{6239a42c-4444-49a3-80bd-e8fdd045185c}"));
- profile2.Name(L"profile2");
- Profile profile3 = winrt::make(::Microsoft::Console::Utils::GuidFromString(L"{6239a42c-4444-49a3-80bd-e8fdd045185c}"));
- profile3.Name(L"profile3");
- Profile profile4 = winrt::make(::Microsoft::Console::Utils::GuidFromString(L"{6239a42c-6666-49a3-80bd-e8fdd045185c}"));
- profile4.Name(L"profile4");
- Profile profile5 = winrt::make(::Microsoft::Console::Utils::GuidFromString(L"{6239a42c-5555-49a3-80bd-e8fdd045185c}"));
- profile5.Name(L"profile5");
- Profile profile6 = winrt::make(::Microsoft::Console::Utils::GuidFromString(L"{6239a42c-7777-49a3-80bd-e8fdd045185c}"));
- profile6.Name(L"profile6");
-
- {
- // Case 1: Good settings
- Log::Comment(NoThrowString().Format(
- L"Testing a pair of profiles with unique guids"));
-
- auto settings = winrt::make_self();
- settings->_profiles.Append(profile0);
- settings->_profiles.Append(profile1);
-
- settings->_ValidateNoDuplicateProfiles();
-
- VERIFY_ARE_EQUAL(static_cast(0), settings->_warnings.Size());
- VERIFY_ARE_EQUAL(static_cast(2), settings->_profiles.Size());
- }
- {
- // Case 2: Bad settings
- Log::Comment(NoThrowString().Format(
- L"Testing a pair of profiles with the same guid"));
-
- auto settings = winrt::make_self();
- settings->_profiles.Append(profile2);
- settings->_profiles.Append(profile3);
-
- settings->_ValidateNoDuplicateProfiles();
-
- VERIFY_ARE_EQUAL(static_cast(1), settings->_warnings.Size());
- VERIFY_ARE_EQUAL(winrt::TerminalApp::SettingsLoadWarnings::DuplicateProfile, settings->_warnings.GetAt(0));
-
- VERIFY_ARE_EQUAL(static_cast(1), settings->_profiles.Size());
- VERIFY_ARE_EQUAL(L"profile2", settings->_profiles.GetAt(0).Name());
- }
- {
- // Case 3: Very bad settings
- Log::Comment(NoThrowString().Format(
- L"Testing a set of profiles, many of which with duplicated guids"));
-
- auto settings = winrt::make_self();
- settings->_profiles.Append(profile0);
- settings->_profiles.Append(profile1);
- settings->_profiles.Append(profile2);
- settings->_profiles.Append(profile3);
- settings->_profiles.Append(profile4);
- settings->_profiles.Append(profile5);
- settings->_profiles.Append(profile6);
-
- settings->_ValidateNoDuplicateProfiles();
-
- VERIFY_ARE_EQUAL(static_cast(1), settings->_warnings.Size());
- VERIFY_ARE_EQUAL(winrt::TerminalApp::SettingsLoadWarnings::DuplicateProfile, settings->_warnings.GetAt(0));
-
- VERIFY_ARE_EQUAL(static_cast(4), settings->_profiles.Size());
- VERIFY_ARE_EQUAL(L"profile0", settings->_profiles.GetAt(0).Name());
- VERIFY_ARE_EQUAL(L"profile1", settings->_profiles.GetAt(1).Name());
- VERIFY_ARE_EQUAL(L"profile4", settings->_profiles.GetAt(2).Name());
- VERIFY_ARE_EQUAL(L"profile6", settings->_profiles.GetAt(3).Name());
- }
- }
-
- void SettingsTests::ValidateManyWarnings()
+ void SettingsTests::TestTerminalArgsForBinding()
{
- const std::string badProfiles{ R"(
+ const std::string settingsJson{ R"(
{
- "defaultProfile": "{6239a42c-1111-49a3-80bd-e8fdd045185c}",
+ "defaultProfile": "{6239a42c-0000-49a3-80bd-e8fdd045185c}",
"profiles": [
{
- "name" : "profile0",
- "guid": "{6239a42c-2222-49a3-80bd-e8fdd045185c}"
+ "name": "profile0",
+ "guid": "{6239a42c-0000-49a3-80bd-e8fdd045185c}",
+ "historySize": 1,
+ "commandline": "cmd.exe"
},
{
- "name" : "profile1",
- "guid": "{6239a42c-3333-49a3-80bd-e8fdd045185c}"
+ "name": "profile1",
+ "guid": "{6239a42c-1111-49a3-80bd-e8fdd045185c}",
+ "historySize": 2,
+ "commandline": "pwsh.exe"
},
{
- "name" : "profile2",
- "guid": "{6239a42c-2222-49a3-80bd-e8fdd045185c}"
+ "name": "profile2",
+ "historySize": 3,
+ "commandline": "wsl.exe"
}
+ ],
+ "keybindings": [
+ { "keys": ["ctrl+a"], "command": { "action": "splitPane", "split": "vertical" } },
+ { "keys": ["ctrl+b"], "command": { "action": "splitPane", "split": "vertical", "profile": "{6239a42c-1111-49a3-80bd-e8fdd045185c}" } },
+ { "keys": ["ctrl+c"], "command": { "action": "splitPane", "split": "vertical", "profile": "profile1" } },
+ { "keys": ["ctrl+d"], "command": { "action": "splitPane", "split": "vertical", "profile": "profile2" } },
+ { "keys": ["ctrl+e"], "command": { "action": "splitPane", "split": "horizontal", "commandline": "foo.exe" } },
+ { "keys": ["ctrl+f"], "command": { "action": "splitPane", "split": "horizontal", "profile": "profile1", "commandline": "foo.exe" } },
+ { "keys": ["ctrl+g"], "command": { "action": "newTab" } },
+ { "keys": ["ctrl+h"], "command": { "action": "newTab", "startingDirectory": "c:\\foo" } },
+ { "keys": ["ctrl+i"], "command": { "action": "newTab", "profile": "profile2", "startingDirectory": "c:\\foo" } },
+ { "keys": ["ctrl+j"], "command": { "action": "newTab", "tabTitle": "bar" } },
+ { "keys": ["ctrl+k"], "command": { "action": "newTab", "profile": "profile2", "tabTitle": "bar" } },
+ { "keys": ["ctrl+l"], "command": { "action": "newTab", "profile": "profile1", "tabTitle": "bar", "startingDirectory": "c:\\foo", "commandline":"foo.exe" } }
]
})" };
- Profile profile4 = winrt::make(::Microsoft::Console::Utils::GuidFromString(L"{6239a42c-4444-49a3-80bd-e8fdd045185c}"));
- profile4.Name(L"profile4");
- Profile profile5 = winrt::make(::Microsoft::Console::Utils::GuidFromString(L"{6239a42c-4444-49a3-80bd-e8fdd045185c}"));
- profile5.Name(L"profile5");
-
- // Case 2: Bad settings
- Log::Comment(NoThrowString().Format(
- L"Testing a pair of profiles with the same guid"));
- const auto settingsObject = VerifyParseSucceeded(badProfiles);
- auto settings = implementation::CascadiaSettings::FromJson(settingsObject);
-
- settings->_profiles.Append(profile4);
- settings->_profiles.Append(profile5);
-
- settings->_ValidateSettings();
-
- VERIFY_ARE_EQUAL(3u, settings->_warnings.Size());
- VERIFY_ARE_EQUAL(winrt::TerminalApp::SettingsLoadWarnings::DuplicateProfile, settings->_warnings.GetAt(0));
- VERIFY_ARE_EQUAL(winrt::TerminalApp::SettingsLoadWarnings::MissingDefaultProfile, settings->_warnings.GetAt(1));
- VERIFY_ARE_EQUAL(winrt::TerminalApp::SettingsLoadWarnings::UnknownColorScheme, settings->_warnings.GetAt(2));
-
- VERIFY_ARE_EQUAL(3u, settings->_profiles.Size());
- VERIFY_ARE_EQUAL(settings->_globals->DefaultProfile(), settings->_profiles.GetAt(0).Guid());
- VERIFY_IS_TRUE(settings->_profiles.GetAt(0).HasGuid());
- VERIFY_IS_TRUE(settings->_profiles.GetAt(1).HasGuid());
- VERIFY_IS_TRUE(settings->_profiles.GetAt(2).HasGuid());
- }
-
- void SettingsTests::LayerGlobalProperties()
- {
- const std::string settings0String{ R"(
- {
- "alwaysShowTabs": true,
- "initialCols" : 120,
- "initialRows" : 30
- })" };
- const std::string settings1String{ R"(
- {
- "showTabsInTitlebar": false,
- "initialCols" : 240,
- "initialRows" : 60
- })" };
- const auto settings0Json = VerifyParseSucceeded(settings0String);
- const auto settings1Json = VerifyParseSucceeded(settings1String);
-
- auto settings = winrt::make_self();
-
- settings->LayerJson(settings0Json);
- VERIFY_ARE_EQUAL(true, settings->_globals->AlwaysShowTabs());
- VERIFY_ARE_EQUAL(120, settings->_globals->InitialCols());
- VERIFY_ARE_EQUAL(30, settings->_globals->InitialRows());
- VERIFY_ARE_EQUAL(true, settings->_globals->ShowTabsInTitlebar());
-
- settings->LayerJson(settings1Json);
- VERIFY_ARE_EQUAL(true, settings->_globals->AlwaysShowTabs());
- VERIFY_ARE_EQUAL(240, settings->_globals->InitialCols());
- VERIFY_ARE_EQUAL(60, settings->_globals->InitialRows());
- VERIFY_ARE_EQUAL(false, settings->_globals->ShowTabsInTitlebar());
- }
- void SettingsTests::ValidateProfileOrdering()
- {
- const std::string userProfiles0String{ R"(
- {
- "profiles": [
- {
- "name" : "profile0",
- "guid": "{6239a42c-0000-49a3-80bd-e8fdd045185c}"
- },
- {
- "name" : "profile1",
- "guid": "{6239a42c-1111-49a3-80bd-e8fdd045185c}"
- }
- ]
- })" };
+ const winrt::guid guid0{ ::Microsoft::Console::Utils::GuidFromString(L"{6239a42c-0000-49a3-80bd-e8fdd045185c}") };
+ const winrt::guid guid1{ ::Microsoft::Console::Utils::GuidFromString(L"{6239a42c-1111-49a3-80bd-e8fdd045185c}") };
- const std::string defaultProfilesString{ R"(
- {
- "profiles": [
- {
- "name" : "profile2",
- "guid": "{6239a42c-1111-49a3-80bd-e8fdd045185c}"
- },
- {
- "name" : "profile3",
- "guid": "{6239a42c-0000-49a3-80bd-e8fdd045185c}"
- }
- ]
- })" };
+ CascadiaSettings settings{ til::u8u16(settingsJson) };
- const std::string userProfiles1String{ R"(
- {
- "profiles": [
- {
- "name" : "profile4",
- "guid": "{6239a42c-0000-49a3-80bd-e8fdd045185c}"
- },
- {
- "name" : "profile5",
- "guid": "{6239a42c-2222-49a3-80bd-e8fdd045185c}"
- }
- ]
- })" };
+ auto keymap = settings.GlobalSettings().KeyMap();
+ VERIFY_ARE_EQUAL(3u, settings.Profiles().Size());
- const auto userProfiles0Json = VerifyParseSucceeded(userProfiles0String);
- const auto userProfiles1Json = VerifyParseSucceeded(userProfiles1String);
- const auto defaultProfilesJson = VerifyParseSucceeded(defaultProfilesString);
+ const auto profile2Guid = settings.Profiles().GetAt(2).Guid();
+ VERIFY_ARE_NOT_EQUAL(winrt::guid{}, profile2Guid);
- {
- Log::Comment(NoThrowString().Format(
- L"Case 1: Simple swapping of the ordering. The user has the "
- L"default profiles in the opposite order of the default ordering."));
-
- auto settings = winrt::make_self();
- settings->_ParseJsonString(defaultProfilesString, true);
- settings->LayerJson(settings->_defaultSettings);
- VERIFY_ARE_EQUAL(2u, settings->_profiles.Size());
- VERIFY_ARE_EQUAL(L"profile2", settings->_profiles.GetAt(0).Name());
- VERIFY_ARE_EQUAL(L"profile3", settings->_profiles.GetAt(1).Name());
-
- settings->_ParseJsonString(userProfiles0String, false);
- settings->LayerJson(settings->_userSettings);
- VERIFY_ARE_EQUAL(2u, settings->_profiles.Size());
- VERIFY_ARE_EQUAL(L"profile1", settings->_profiles.GetAt(0).Name());
- VERIFY_ARE_EQUAL(L"profile0", settings->_profiles.GetAt(1).Name());
-
- settings->_ReorderProfilesToMatchUserSettingsOrder();
- VERIFY_ARE_EQUAL(2u, settings->_profiles.Size());
- VERIFY_ARE_EQUAL(L"profile0", settings->_profiles.GetAt(0).Name());
- VERIFY_ARE_EQUAL(L"profile1", settings->_profiles.GetAt(1).Name());
- }
+ VERIFY_ARE_EQUAL(12u, keymap.Size());
{
- Log::Comment(NoThrowString().Format(
- L"Case 2: Make sure all the user's profiles appear before the defaults."));
-
- auto settings = winrt::make_self();
- settings->_ParseJsonString(defaultProfilesString, true);
- settings->LayerJson(settings->_defaultSettings);
- VERIFY_ARE_EQUAL(2u, settings->_profiles.Size());
- VERIFY_ARE_EQUAL(L"profile2", settings->_profiles.GetAt(0).Name());
- VERIFY_ARE_EQUAL(L"profile3", settings->_profiles.GetAt(1).Name());
-
- settings->_ParseJsonString(userProfiles1String, false);
- settings->LayerJson(settings->_userSettings);
- VERIFY_ARE_EQUAL(3u, settings->_profiles.Size());
- VERIFY_ARE_EQUAL(L"profile2", settings->_profiles.GetAt(0).Name());
- VERIFY_ARE_EQUAL(L"profile4", settings->_profiles.GetAt(1).Name());
- VERIFY_ARE_EQUAL(L"profile5", settings->_profiles.GetAt(2).Name());
-
- settings->_ReorderProfilesToMatchUserSettingsOrder();
- VERIFY_ARE_EQUAL(3u, settings->_profiles.Size());
- VERIFY_ARE_EQUAL(L"profile4", settings->_profiles.GetAt(0).Name());
- VERIFY_ARE_EQUAL(L"profile5", settings->_profiles.GetAt(1).Name());
- VERIFY_ARE_EQUAL(L"profile2", settings->_profiles.GetAt(2).Name());
- }
- }
-
- void SettingsTests::ValidateHideProfiles()
- {
- const std::string defaultProfilesString{ R"(
- {
- "profiles": [
- {
- "name" : "profile2",
- "guid": "{6239a42c-1111-49a3-80bd-e8fdd045185c}"
- },
- {
- "name" : "profile3",
- "guid": "{6239a42c-0000-49a3-80bd-e8fdd045185c}"
- }
- ]
- })" };
-
- const std::string userProfiles0String{ R"(
- {
- "profiles": [
- {
- "name" : "profile0",
- "guid": "{6239a42c-0000-49a3-80bd-e8fdd045185c}",
- "hidden": true
- },
- {
- "name" : "profile1",
- "guid": "{6239a42c-1111-49a3-80bd-e8fdd045185c}"
- }
- ]
- })" };
-
- const std::string userProfiles1String{ R"(
- {
- "profiles": [
- {
- "name" : "profile4",
- "guid": "{6239a42c-0000-49a3-80bd-e8fdd045185c}",
- "hidden": true
- },
- {
- "name" : "profile5",
- "guid": "{6239a42c-2222-49a3-80bd-e8fdd045185c}"
- },
- {
- "name" : "profile6",
- "guid": "{6239a42c-3333-49a3-80bd-e8fdd045185c}",
- "hidden": true
- }
- ]
- })" };
-
- const auto userProfiles0Json = VerifyParseSucceeded(userProfiles0String);
- const auto userProfiles1Json = VerifyParseSucceeded(userProfiles1String);
- const auto defaultProfilesJson = VerifyParseSucceeded(defaultProfilesString);
-
- {
- auto settings = winrt::make_self();
- settings->_ParseJsonString(defaultProfilesString, true);
- settings->LayerJson(settings->_defaultSettings);
- VERIFY_ARE_EQUAL(2u, settings->_profiles.Size());
- VERIFY_ARE_EQUAL(L"profile2", settings->_profiles.GetAt(0).Name());
- VERIFY_ARE_EQUAL(L"profile3", settings->_profiles.GetAt(1).Name());
- VERIFY_ARE_EQUAL(false, settings->_profiles.GetAt(0).Hidden());
- VERIFY_ARE_EQUAL(false, settings->_profiles.GetAt(1).Hidden());
-
- settings->_ParseJsonString(userProfiles0String, false);
- settings->LayerJson(settings->_userSettings);
- VERIFY_ARE_EQUAL(2u, settings->_profiles.Size());
- VERIFY_ARE_EQUAL(L"profile1", settings->_profiles.GetAt(0).Name());
- VERIFY_ARE_EQUAL(L"profile0", settings->_profiles.GetAt(1).Name());
- VERIFY_ARE_EQUAL(false, settings->_profiles.GetAt(0).Hidden());
- VERIFY_ARE_EQUAL(true, settings->_profiles.GetAt(1).Hidden());
-
- settings->_ReorderProfilesToMatchUserSettingsOrder();
- settings->_RemoveHiddenProfiles();
- VERIFY_ARE_EQUAL(1u, settings->_profiles.Size());
- VERIFY_ARE_EQUAL(L"profile1", settings->_profiles.GetAt(0).Name());
- VERIFY_ARE_EQUAL(false, settings->_profiles.GetAt(0).Hidden());
- }
-
- {
- auto settings = winrt::make_self();
- settings->_ParseJsonString(defaultProfilesString, true);
- settings->LayerJson(settings->_defaultSettings);
- VERIFY_ARE_EQUAL(2u, settings->_profiles.Size());
- VERIFY_ARE_EQUAL(L"profile2", settings->_profiles.GetAt(0).Name());
- VERIFY_ARE_EQUAL(L"profile3", settings->_profiles.GetAt(1).Name());
- VERIFY_ARE_EQUAL(false, settings->_profiles.GetAt(0).Hidden());
- VERIFY_ARE_EQUAL(false, settings->_profiles.GetAt(1).Hidden());
-
- settings->_ParseJsonString(userProfiles1String, false);
- settings->LayerJson(settings->_userSettings);
- VERIFY_ARE_EQUAL(4u, settings->_profiles.Size());
- VERIFY_ARE_EQUAL(L"profile2", settings->_profiles.GetAt(0).Name());
- VERIFY_ARE_EQUAL(L"profile4", settings->_profiles.GetAt(1).Name());
- VERIFY_ARE_EQUAL(L"profile5", settings->_profiles.GetAt(2).Name());
- VERIFY_ARE_EQUAL(L"profile6", settings->_profiles.GetAt(3).Name());
- VERIFY_ARE_EQUAL(false, settings->_profiles.GetAt(0).Hidden());
- VERIFY_ARE_EQUAL(true, settings->_profiles.GetAt(1).Hidden());
- VERIFY_ARE_EQUAL(false, settings->_profiles.GetAt(2).Hidden());
- VERIFY_ARE_EQUAL(true, settings->_profiles.GetAt(3).Hidden());
-
- settings->_ReorderProfilesToMatchUserSettingsOrder();
- settings->_RemoveHiddenProfiles();
- VERIFY_ARE_EQUAL(2u, settings->_profiles.Size());
- VERIFY_ARE_EQUAL(L"profile5", settings->_profiles.GetAt(0).Name());
- VERIFY_ARE_EQUAL(L"profile2", settings->_profiles.GetAt(1).Name());
- VERIFY_ARE_EQUAL(false, settings->_profiles.GetAt(0).Hidden());
- VERIFY_ARE_EQUAL(false, settings->_profiles.GetAt(1).Hidden());
- }
- }
-
- void SettingsTests::ValidateProfilesGenerateGuids()
- {
- const std::string profile0String{ R"(
- {
- "name" : "profile0"
- })" };
- const std::string profile1String{ R"(
- {
- "name" : "profile1"
- })" };
- const std::string profile2String{ R"(
- {
- "name" : "profile2",
- "guid" : null
- })" };
- const std::string profile3String{ R"(
- {
- "name" : "profile3",
- "guid" : "{00000000-0000-0000-0000-000000000000}"
- })" };
- const std::string profile4String{ R"(
- {
- "name" : "profile4",
- "guid" : "{6239a42c-1de4-49a3-80bd-e8fdd045185c}"
- })" };
- const std::string profile5String{ R"(
- {
- "name" : "profile2"
- })" };
-
- const auto profile0Json = VerifyParseSucceeded(profile0String);
- const auto profile1Json = VerifyParseSucceeded(profile1String);
- const auto profile2Json = VerifyParseSucceeded(profile2String);
- const auto profile3Json = VerifyParseSucceeded(profile3String);
- const auto profile4Json = VerifyParseSucceeded(profile4String);
- const auto profile5Json = VerifyParseSucceeded(profile5String);
-
- const auto profile0 = implementation::Profile::FromJson(profile0Json);
- const auto profile1 = implementation::Profile::FromJson(profile1Json);
- const auto profile2 = implementation::Profile::FromJson(profile2Json);
- const auto profile3 = implementation::Profile::FromJson(profile3Json);
- const auto profile4 = implementation::Profile::FromJson(profile4Json);
- const auto profile5 = implementation::Profile::FromJson(profile5Json);
-
- const winrt::guid cmdGuid{ Utils::GuidFromString(L"{6239a42c-1de4-49a3-80bd-e8fdd045185c}") };
- const winrt::guid nullGuid{};
-
- VERIFY_IS_FALSE(profile0->HasGuid());
- VERIFY_IS_FALSE(profile1->HasGuid());
- VERIFY_IS_FALSE(profile2->HasGuid());
- VERIFY_IS_TRUE(profile3->HasGuid());
- VERIFY_IS_TRUE(profile4->HasGuid());
- VERIFY_IS_FALSE(profile5->HasGuid());
-
- VERIFY_ARE_EQUAL(profile3->Guid(), nullGuid);
- VERIFY_ARE_EQUAL(profile4->Guid(), cmdGuid);
-
- auto settings = winrt::make_self();
- settings->_profiles.Append(*profile0);
- settings->_profiles.Append(*profile1);
- settings->_profiles.Append(*profile2);
- settings->_profiles.Append(*profile3);
- settings->_profiles.Append(*profile4);
- settings->_profiles.Append(*profile5);
-
- settings->_ValidateProfilesHaveGuid();
- VERIFY_IS_TRUE(settings->_profiles.GetAt(0).HasGuid());
- VERIFY_IS_TRUE(settings->_profiles.GetAt(1).HasGuid());
- VERIFY_IS_TRUE(settings->_profiles.GetAt(2).HasGuid());
- VERIFY_IS_TRUE(settings->_profiles.GetAt(3).HasGuid());
- VERIFY_IS_TRUE(settings->_profiles.GetAt(4).HasGuid());
- VERIFY_IS_TRUE(settings->_profiles.GetAt(5).HasGuid());
-
- VERIFY_ARE_NOT_EQUAL(settings->_profiles.GetAt(0).Guid(), nullGuid);
- VERIFY_ARE_NOT_EQUAL(settings->_profiles.GetAt(1).Guid(), nullGuid);
- VERIFY_ARE_NOT_EQUAL(settings->_profiles.GetAt(2).Guid(), nullGuid);
- VERIFY_ARE_EQUAL(settings->_profiles.GetAt(3).Guid(), nullGuid);
- VERIFY_ARE_NOT_EQUAL(settings->_profiles.GetAt(4).Guid(), nullGuid);
- VERIFY_ARE_NOT_EQUAL(settings->_profiles.GetAt(5).Guid(), nullGuid);
-
- VERIFY_ARE_NOT_EQUAL(settings->_profiles.GetAt(0).Guid(), cmdGuid);
- VERIFY_ARE_NOT_EQUAL(settings->_profiles.GetAt(1).Guid(), cmdGuid);
- VERIFY_ARE_NOT_EQUAL(settings->_profiles.GetAt(2).Guid(), cmdGuid);
- VERIFY_ARE_NOT_EQUAL(settings->_profiles.GetAt(3).Guid(), cmdGuid);
- VERIFY_ARE_EQUAL(settings->_profiles.GetAt(4).Guid(), cmdGuid);
- VERIFY_ARE_NOT_EQUAL(settings->_profiles.GetAt(5).Guid(), cmdGuid);
-
- VERIFY_ARE_NOT_EQUAL(settings->_profiles.GetAt(0).Guid(), settings->_profiles.GetAt(2).Guid());
- VERIFY_ARE_NOT_EQUAL(settings->_profiles.GetAt(1).Guid(), settings->_profiles.GetAt(2).Guid());
- VERIFY_ARE_EQUAL(settings->_profiles.GetAt(2).Guid(), settings->_profiles.GetAt(2).Guid());
- VERIFY_ARE_NOT_EQUAL(settings->_profiles.GetAt(3).Guid(), settings->_profiles.GetAt(2).Guid());
- VERIFY_ARE_NOT_EQUAL(settings->_profiles.GetAt(4).Guid(), settings->_profiles.GetAt(2).Guid());
- VERIFY_ARE_EQUAL(settings->_profiles.GetAt(5).Guid(), settings->_profiles.GetAt(2).Guid());
- }
-
- void SettingsTests::GeneratedGuidRoundtrips()
- {
- // Parse a profile without a guid.
- // We should automatically generate a GUID for that profile.
- // When that profile is serialized and deserialized again, the GUID we
- // generated for it should persist.
- const std::string profileWithoutGuid{ R"({
- "name" : "profile0"
- })" };
- const auto profile0Json = VerifyParseSucceeded(profileWithoutGuid);
-
- const auto profile0 = implementation::Profile::FromJson(profile0Json);
- const GUID nullGuid{ 0 };
-
- VERIFY_IS_FALSE(profile0->HasGuid());
-
- const auto serialized0Profile = profile0->GenerateStub();
- const auto profile1 = implementation::Profile::FromJson(serialized0Profile);
- VERIFY_IS_FALSE(profile0->HasGuid());
- VERIFY_IS_FALSE(profile1->HasGuid());
-
- auto settings = winrt::make_self();
- settings->_profiles.Append(*profile1);
- settings->_ValidateProfilesHaveGuid();
-
- VERIFY_IS_TRUE(settings->_profiles.GetAt(0).HasGuid());
-
- const auto profileImpl = winrt::get_self(settings->_profiles.GetAt(0));
- const auto serialized1Profile = profileImpl->GenerateStub();
-
- const auto profile2 = implementation::Profile::FromJson(serialized1Profile);
- VERIFY_IS_TRUE(settings->_profiles.GetAt(0).HasGuid());
- VERIFY_IS_TRUE(profile2->HasGuid());
- VERIFY_ARE_EQUAL(settings->_profiles.GetAt(0).Guid(), profile2->Guid());
- }
-
- void SettingsTests::TestAllValidationsWithNullGuids()
- {
- const std::string settings0String{ R"(
- {
- "defaultProfile": "{6239a42c-1111-49a3-80bd-e8fdd045185c}",
- "profiles": [
- {
- "name" : "profile0",
- "guid" : "{6239a42c-1111-49a3-80bd-e8fdd045185c}"
- },
- {
- "name" : "profile1"
- }
- ],
- "schemes": [
- { "name": "Campbell" }
- ]
- })" };
-
- const auto settings0Json = VerifyParseSucceeded(settings0String);
-
- auto settings = winrt::make_self();
- settings->_ParseJsonString(settings0String, false);
- settings->LayerJson(settings->_userSettings);
-
- VERIFY_ARE_EQUAL(2u, settings->_profiles.Size());
- VERIFY_IS_TRUE(settings->_profiles.GetAt(0).HasGuid());
- VERIFY_IS_FALSE(settings->_profiles.GetAt(1).HasGuid());
-
- settings->_ValidateSettings();
- VERIFY_ARE_EQUAL(0u, settings->_warnings.Size());
- VERIFY_ARE_EQUAL(2u, settings->_profiles.Size());
- VERIFY_IS_TRUE(settings->_profiles.GetAt(0).HasGuid());
- VERIFY_IS_TRUE(settings->_profiles.GetAt(1).HasGuid());
- }
-
- void SettingsTests::TestReorderWithNullGuids()
- {
- const std::string settings0String{ R"(
- {
- "defaultProfile": "{6239a42c-1111-49a3-80bd-e8fdd045185c}",
- "profiles": [
- {
- "name" : "profile0",
- "guid" : "{6239a42c-1111-49a3-80bd-e8fdd045185c}"
- },
- {
- "name" : "profile1"
- },
- {
- "name" : "cmdFromUserSettings",
- "guid" : "{0caa0dad-35be-5f56-a8ff-afceeeaa6101}" // from defaults.json
- }
- ]
- })" };
-
- const auto settings0Json = VerifyParseSucceeded(settings0String);
-
- auto settings = winrt::make_self();
- settings->_ParseJsonString(DefaultJson, true);
- settings->LayerJson(settings->_defaultSettings);
- VERIFY_ARE_EQUAL(2u, settings->_profiles.Size());
- VERIFY_IS_TRUE(settings->_profiles.GetAt(0).HasGuid());
- VERIFY_IS_TRUE(settings->_profiles.GetAt(1).HasGuid());
- VERIFY_ARE_EQUAL(L"Windows PowerShell", settings->_profiles.GetAt(0).Name());
- VERIFY_ARE_EQUAL(L"Command Prompt", settings->_profiles.GetAt(1).Name());
-
- settings->_ParseJsonString(settings0String, false);
- settings->LayerJson(settings->_userSettings);
-
- VERIFY_ARE_EQUAL(4u, settings->_profiles.Size());
- VERIFY_IS_TRUE(settings->_profiles.GetAt(0).HasGuid());
- VERIFY_IS_TRUE(settings->_profiles.GetAt(1).HasGuid());
- VERIFY_IS_TRUE(settings->_profiles.GetAt(2).HasGuid());
- VERIFY_IS_FALSE(settings->_profiles.GetAt(3).HasGuid());
- VERIFY_ARE_EQUAL(L"Windows PowerShell", settings->_profiles.GetAt(0).Name());
- VERIFY_ARE_EQUAL(L"cmdFromUserSettings", settings->_profiles.GetAt(1).Name());
- VERIFY_ARE_EQUAL(L"profile0", settings->_profiles.GetAt(2).Name());
- VERIFY_ARE_EQUAL(L"profile1", settings->_profiles.GetAt(3).Name());
-
- settings->_ValidateSettings();
- VERIFY_ARE_EQUAL(0u, settings->_warnings.Size());
- VERIFY_ARE_EQUAL(4u, settings->_profiles.Size());
- VERIFY_IS_TRUE(settings->_profiles.GetAt(0).HasGuid());
- VERIFY_IS_TRUE(settings->_profiles.GetAt(1).HasGuid());
- VERIFY_IS_TRUE(settings->_profiles.GetAt(2).HasGuid());
- VERIFY_IS_TRUE(settings->_profiles.GetAt(3).HasGuid());
- VERIFY_ARE_EQUAL(L"profile0", settings->_profiles.GetAt(0).Name());
- VERIFY_ARE_EQUAL(L"profile1", settings->_profiles.GetAt(1).Name());
- VERIFY_ARE_EQUAL(L"cmdFromUserSettings", settings->_profiles.GetAt(2).Name());
- VERIFY_ARE_EQUAL(L"Windows PowerShell", settings->_profiles.GetAt(3).Name());
- }
-
- void SettingsTests::TestReorderingWithoutGuid()
- {
- Log::Comment(NoThrowString().Format(
- L"During the GH#2515 PR, this set of settings was found to cause an"
- L" exception, crashing the terminal. This test ensures that it doesn't."));
-
- Log::Comment(NoThrowString().Format(
- L"While similar to TestReorderWithNullGuids, there's something else"
- L" about this scenario specifically that causes a crash, when "
- L" TestReorderWithNullGuids did _not_."));
-
- const std::string settings0String{ R"(
- {
- "defaultProfile" : "{0caa0dad-35be-5f56-a8ff-afceeeaa6101}",
- "profiles": [
- {
- "guid" : "{0caa0dad-35be-5f56-a8ff-afceeeaa6101}",
- "acrylicOpacity" : 0.5,
- "closeOnExit" : true,
- "background" : "#8A00FF",
- "foreground" : "#F2F2F2",
- "commandline" : "cmd.exe",
- "cursorColor" : "#FFFFFF",
- "fontFace" : "Cascadia Code",
- "fontSize" : 10,
- "historySize" : 9001,
- "padding" : "20",
- "snapOnInput" : true,
- "startingDirectory" : "%USERPROFILE%",
- "useAcrylic" : true
- },
- {
- "name" : "ThisProfileShouldNotCrash",
- "tabTitle" : "Ubuntu",
- "acrylicOpacity" : 0.5,
- "background" : "#2C001E",
- "closeOnExit" : true,
- "colorScheme" : "Campbell",
- "commandline" : "wsl.exe",
- "cursorColor" : "#FFFFFF",
- "cursorShape" : "bar",
- "fontSize" : 10,
- "historySize" : 9001,
- "padding" : "0, 0, 0, 0",
- "snapOnInput" : true,
- "useAcrylic" : true
- },
- {
- // This is the same profile that would be generated by the WSL profile generator.
- "name" : "Ubuntu",
- "guid" : "{2C4DE342-38B7-51CF-B940-2309A097F518}",
- "acrylicOpacity" : 0.5,
- "background" : "#2C001E",
- "closeOnExit" : false,
- "cursorColor" : "#FFFFFF",
- "cursorShape" : "bar",
- "fontSize" : 10,
- "historySize" : 9001,
- "snapOnInput" : true,
- "useAcrylic" : true
- }
- ]
- })" };
-
- const auto settings0Json = VerifyParseSucceeded(settings0String);
-
- auto settings = winrt::make_self();
- settings->_ParseJsonString(DefaultJson, true);
- settings->LayerJson(settings->_defaultSettings);
- VERIFY_ARE_EQUAL(2u, settings->_profiles.Size());
- VERIFY_IS_TRUE(settings->_profiles.GetAt(0).HasGuid());
- VERIFY_IS_TRUE(settings->_profiles.GetAt(1).HasGuid());
- VERIFY_ARE_EQUAL(L"Windows PowerShell", settings->_profiles.GetAt(0).Name());
- VERIFY_ARE_EQUAL(L"Command Prompt", settings->_profiles.GetAt(1).Name());
-
- settings->_ParseJsonString(settings0String, false);
- settings->LayerJson(settings->_userSettings);
-
- VERIFY_ARE_EQUAL(4u, settings->_profiles.Size());
- VERIFY_IS_TRUE(settings->_profiles.GetAt(0).HasGuid());
- VERIFY_IS_TRUE(settings->_profiles.GetAt(1).HasGuid());
- VERIFY_IS_FALSE(settings->_profiles.GetAt(2).HasGuid());
- VERIFY_IS_TRUE(settings->_profiles.GetAt(3).HasGuid());
- VERIFY_ARE_EQUAL(L"Windows PowerShell", settings->_profiles.GetAt(0).Name());
- VERIFY_ARE_EQUAL(L"Command Prompt", settings->_profiles.GetAt(1).Name());
- VERIFY_ARE_EQUAL(L"ThisProfileShouldNotCrash", settings->_profiles.GetAt(2).Name());
- VERIFY_ARE_EQUAL(L"Ubuntu", settings->_profiles.GetAt(3).Name());
-
- settings->_ValidateSettings();
- VERIFY_ARE_EQUAL(0u, settings->_warnings.Size());
- VERIFY_ARE_EQUAL(4u, settings->_profiles.Size());
- VERIFY_IS_TRUE(settings->_profiles.GetAt(0).HasGuid());
- VERIFY_IS_TRUE(settings->_profiles.GetAt(1).HasGuid());
- VERIFY_IS_TRUE(settings->_profiles.GetAt(2).HasGuid());
- VERIFY_IS_TRUE(settings->_profiles.GetAt(3).HasGuid());
- VERIFY_ARE_EQUAL(L"Command Prompt", settings->_profiles.GetAt(0).Name());
- VERIFY_ARE_EQUAL(L"ThisProfileShouldNotCrash", settings->_profiles.GetAt(1).Name());
- VERIFY_ARE_EQUAL(L"Ubuntu", settings->_profiles.GetAt(2).Name());
- VERIFY_ARE_EQUAL(L"Windows PowerShell", settings->_profiles.GetAt(3).Name());
- }
-
- void SettingsTests::TestLayeringNameOnlyProfiles()
- {
- // This is a test discovered during GH#2782. When we add a name-only
- // profile, it should only layer with other name-only profiles with the
- // _same name_
-
- const std::string settings0String{ R"(
- {
- "defaultProfile" : "{00000000-0000-5f56-a8ff-afceeeaa6101}",
- "profiles": [
- {
- "guid" : "{00000000-0000-5f56-a8ff-afceeeaa6101}",
- "name" : "ThisProfileIsGood"
-
- },
- {
- "name" : "ThisProfileShouldNotLayer"
- },
- {
- "name" : "NeitherShouldThisOne"
- }
- ]
- })" };
-
- const auto settings0Json = VerifyParseSucceeded(settings0String);
-
- auto settings = winrt::make_self();
- settings->_ParseJsonString(DefaultJson, true);
- settings->LayerJson(settings->_defaultSettings);
- VERIFY_ARE_EQUAL(2u, settings->_profiles.Size());
- VERIFY_IS_TRUE(settings->_profiles.GetAt(0).HasGuid());
- VERIFY_IS_TRUE(settings->_profiles.GetAt(1).HasGuid());
- VERIFY_ARE_EQUAL(L"Windows PowerShell", settings->_profiles.GetAt(0).Name());
- VERIFY_ARE_EQUAL(L"Command Prompt", settings->_profiles.GetAt(1).Name());
-
- Log::Comment(NoThrowString().Format(
- L"Parse the user settings"));
- settings->_ParseJsonString(settings0String, false);
- settings->LayerJson(settings->_userSettings);
-
- VERIFY_ARE_EQUAL(5u, settings->_profiles.Size());
- VERIFY_IS_TRUE(settings->_profiles.GetAt(0).HasGuid());
- VERIFY_IS_TRUE(settings->_profiles.GetAt(1).HasGuid());
- VERIFY_IS_TRUE(settings->_profiles.GetAt(2).HasGuid());
- VERIFY_IS_FALSE(settings->_profiles.GetAt(3).HasGuid());
- VERIFY_IS_FALSE(settings->_profiles.GetAt(4).HasGuid());
- VERIFY_ARE_EQUAL(L"Windows PowerShell", settings->_profiles.GetAt(0).Name());
- VERIFY_ARE_EQUAL(L"Command Prompt", settings->_profiles.GetAt(1).Name());
- VERIFY_ARE_EQUAL(L"ThisProfileIsGood", settings->_profiles.GetAt(2).Name());
- VERIFY_ARE_EQUAL(L"ThisProfileShouldNotLayer", settings->_profiles.GetAt(3).Name());
- VERIFY_ARE_EQUAL(L"NeitherShouldThisOne", settings->_profiles.GetAt(4).Name());
- }
-
- void SettingsTests::TestExplodingNameOnlyProfiles()
- {
- // This is a test for GH#2782. When we add a name-only profile, we'll
- // generate a GUID for it. We should make sure that we don't re-append
- // that profile to the list of profiles.
-
- const std::string settings0String{ R"(
- {
- "defaultProfile" : "{00000000-0000-5f56-a8ff-afceeeaa6101}",
- "profiles": [
- {
- "guid" : "{00000000-0000-5f56-a8ff-afceeeaa6101}",
- "name" : "ThisProfileIsGood"
-
- },
- {
- "name" : "ThisProfileShouldNotDuplicate"
- },
- {
- "name" : "NeitherShouldThisOne"
- }
- ]
- })" };
-
- const auto settings0Json = VerifyParseSucceeded(settings0String);
-
- auto settings = winrt::make_self();
- settings->_ParseJsonString(DefaultJson, true);
- settings->LayerJson(settings->_defaultSettings);
- VERIFY_ARE_EQUAL(2u, settings->_profiles.Size());
- VERIFY_IS_TRUE(settings->_profiles.GetAt(0).HasGuid());
- VERIFY_IS_TRUE(settings->_profiles.GetAt(1).HasGuid());
- VERIFY_ARE_EQUAL(L"Windows PowerShell", settings->_profiles.GetAt(0).Name());
- VERIFY_ARE_EQUAL(L"Command Prompt", settings->_profiles.GetAt(1).Name());
-
- Log::Comment(NoThrowString().Format(
- L"Parse the user settings"));
- settings->_ParseJsonString(settings0String, false);
- settings->LayerJson(settings->_userSettings);
-
- VERIFY_ARE_EQUAL(5u, settings->_profiles.Size());
- VERIFY_IS_TRUE(settings->_profiles.GetAt(0).HasGuid());
- VERIFY_IS_TRUE(settings->_profiles.GetAt(1).HasGuid());
- VERIFY_IS_TRUE(settings->_profiles.GetAt(2).HasGuid());
- VERIFY_IS_FALSE(settings->_profiles.GetAt(3).HasGuid());
- VERIFY_IS_FALSE(settings->_profiles.GetAt(4).HasGuid());
- VERIFY_ARE_EQUAL(L"Windows PowerShell", settings->_profiles.GetAt(0).Name());
- VERIFY_ARE_EQUAL(L"Command Prompt", settings->_profiles.GetAt(1).Name());
- VERIFY_ARE_EQUAL(L"ThisProfileIsGood", settings->_profiles.GetAt(2).Name());
- VERIFY_ARE_EQUAL(L"ThisProfileShouldNotDuplicate", settings->_profiles.GetAt(3).Name());
- VERIFY_ARE_EQUAL(L"NeitherShouldThisOne", settings->_profiles.GetAt(4).Name());
-
- Log::Comment(NoThrowString().Format(
- L"Pretend like we're checking to append dynamic profiles to the "
- L"user's settings file. We absolutely _shouldn't_ be adding anything here."));
- bool const needToWriteFile = settings->_AppendDynamicProfilesToUserSettings();
- VERIFY_IS_FALSE(needToWriteFile);
- VERIFY_ARE_EQUAL(settings0String.size(), settings->_userSettingsString.size());
-
- Log::Comment(NoThrowString().Format(
- L"Re-parse the settings file. We should have the _same_ settings as before."));
- Log::Comment(NoThrowString().Format(
- L"Do this to a _new_ settings object, to make sure it turns out the same."));
- {
- auto settings2 = winrt::make_self();
- settings2->_ParseJsonString(DefaultJson, true);
- settings2->LayerJson(settings2->_defaultSettings);
- VERIFY_ARE_EQUAL(2u, settings2->_profiles.Size());
- // Initialize the second settings object from the first settings
- // object's settings string, the one that we synthesized.
- const auto firstSettingsString = settings->_userSettingsString;
- settings2->_ParseJsonString(firstSettingsString, false);
- settings2->LayerJson(settings2->_userSettings);
- VERIFY_ARE_EQUAL(5u, settings2->_profiles.Size());
- VERIFY_IS_TRUE(settings2->_profiles.GetAt(0).HasGuid());
- VERIFY_IS_TRUE(settings2->_profiles.GetAt(1).HasGuid());
- VERIFY_IS_TRUE(settings2->_profiles.GetAt(2).HasGuid());
- VERIFY_IS_FALSE(settings2->_profiles.GetAt(3).HasGuid());
- VERIFY_IS_FALSE(settings2->_profiles.GetAt(4).HasGuid());
- VERIFY_ARE_EQUAL(L"Windows PowerShell", settings2->_profiles.GetAt(0).Name());
- VERIFY_ARE_EQUAL(L"Command Prompt", settings2->_profiles.GetAt(1).Name());
- VERIFY_ARE_EQUAL(L"ThisProfileIsGood", settings2->_profiles.GetAt(2).Name());
- VERIFY_ARE_EQUAL(L"ThisProfileShouldNotDuplicate", settings2->_profiles.GetAt(3).Name());
- VERIFY_ARE_EQUAL(L"NeitherShouldThisOne", settings2->_profiles.GetAt(4).Name());
- }
-
- Log::Comment(NoThrowString().Format(
- L"Validate the settings. All the profiles we have should be valid."));
- settings->_ValidateSettings();
-
- VERIFY_ARE_EQUAL(5u, settings->_profiles.Size());
- VERIFY_IS_TRUE(settings->_profiles.GetAt(0).HasGuid());
- VERIFY_IS_TRUE(settings->_profiles.GetAt(1).HasGuid());
- VERIFY_IS_TRUE(settings->_profiles.GetAt(2).HasGuid());
- VERIFY_IS_TRUE(settings->_profiles.GetAt(3).HasGuid());
- VERIFY_IS_TRUE(settings->_profiles.GetAt(4).HasGuid());
- VERIFY_ARE_EQUAL(L"ThisProfileIsGood", settings->_profiles.GetAt(0).Name());
- VERIFY_ARE_EQUAL(L"ThisProfileShouldNotDuplicate", settings->_profiles.GetAt(1).Name());
- VERIFY_ARE_EQUAL(L"NeitherShouldThisOne", settings->_profiles.GetAt(2).Name());
- VERIFY_ARE_EQUAL(L"Windows PowerShell", settings->_profiles.GetAt(3).Name());
- VERIFY_ARE_EQUAL(L"Command Prompt", settings->_profiles.GetAt(4).Name());
- }
-
- void SettingsTests::TestHideAllProfiles()
- {
- const std::string settingsWithProfiles{ R"(
- {
- "profiles": [
- {
- "name" : "profile0",
- "hidden": false
- },
- {
- "name" : "profile1",
- "hidden": true
- }
- ]
- })" };
-
- const std::string settingsWithoutProfiles{ R"(
- {
- "profiles": [
- {
- "name" : "profile0",
- "hidden": true
- },
- {
- "name" : "profile1",
- "hidden": true
- }
- ]
- })" };
-
- VerifyParseSucceeded(settingsWithProfiles);
- VerifyParseSucceeded(settingsWithoutProfiles);
-
- {
- // Case 1: Good settings
- auto settings = winrt::make_self();
- settings->_ParseJsonString(settingsWithProfiles, false);
- settings->LayerJson(settings->_userSettings);
-
- settings->_RemoveHiddenProfiles();
- Log::Comment(NoThrowString().Format(
- L"settingsWithProfiles successfully parsed and validated"));
- VERIFY_ARE_EQUAL(1u, settings->_profiles.Size());
- }
- {
- // Case 2: Bad settings
- auto settings = winrt::make_self();
- settings->_ParseJsonString(settingsWithoutProfiles, false);
- settings->LayerJson(settings->_userSettings);
-
- bool caughtExpectedException = false;
- try
- {
- settings->_RemoveHiddenProfiles();
- }
- catch (const winrt::TerminalApp::implementation::SettingsException& ex)
- {
- VERIFY_IS_TRUE(ex.Error() == winrt::TerminalApp::SettingsLoadErrors::AllProfilesHidden);
- caughtExpectedException = true;
- }
- VERIFY_IS_TRUE(caughtExpectedException);
- }
- }
-
- void SettingsTests::TestInvalidColorSchemeName()
- {
- Log::Comment(NoThrowString().Format(
- L"Ensure that setting a profile's scheme to a non-existent scheme causes a warning."));
-
- const std::string settings0String{ R"(
- {
- "profiles": [
- {
- "name" : "profile0",
- "colorScheme": "schemeOne"
- },
- {
- "name" : "profile1",
- "colorScheme": "InvalidSchemeName"
- },
- {
- "name" : "profile2"
- // Will use the Profile default value, "Campbell"
- }
- ],
- "schemes": [
- {
- "name": "schemeOne",
- "foreground": "#111111"
- },
- {
- "name": "schemeTwo",
- "foreground": "#222222"
- }
- ]
- })" };
-
- VerifyParseSucceeded(settings0String);
-
- auto settings = winrt::make_self();
- settings->_ParseJsonString(settings0String, false);
- settings->LayerJson(settings->_userSettings);
-
- VERIFY_ARE_EQUAL(3u, settings->_profiles.Size());
- VERIFY_ARE_EQUAL(2u, settings->_globals->ColorSchemes().Size());
-
- VERIFY_ARE_EQUAL(L"schemeOne", settings->_profiles.GetAt(0).ColorSchemeName());
- VERIFY_ARE_EQUAL(L"InvalidSchemeName", settings->_profiles.GetAt(1).ColorSchemeName());
- VERIFY_ARE_EQUAL(L"Campbell", settings->_profiles.GetAt(2).ColorSchemeName());
-
- settings->_ValidateAllSchemesExist();
-
- VERIFY_ARE_EQUAL(1u, settings->_warnings.Size());
- VERIFY_ARE_EQUAL(winrt::TerminalApp::SettingsLoadWarnings::UnknownColorScheme, settings->_warnings.GetAt(0));
-
- VERIFY_ARE_EQUAL(3u, settings->_profiles.Size());
- VERIFY_ARE_EQUAL(2u, settings->_globals->ColorSchemes().Size());
-
- VERIFY_ARE_EQUAL(L"schemeOne", settings->_profiles.GetAt(0).ColorSchemeName());
- VERIFY_ARE_EQUAL(L"Campbell", settings->_profiles.GetAt(1).ColorSchemeName());
- VERIFY_ARE_EQUAL(L"Campbell", settings->_profiles.GetAt(2).ColorSchemeName());
- }
-
- void SettingsTests::TestHelperFunctions()
- {
- const std::string settings0String{ R"(
- {
- "defaultProfile" : "{2C4DE342-38B7-51CF-B940-2309A097F518}",
- "profiles": [
- {
- "name" : "profile0",
- "guid": "{6239a42c-5555-49a3-80bd-e8fdd045185c}"
- },
- {
- "name" : "profile1",
- "guid": "{6239a42c-6666-49a3-80bd-e8fdd045185c}"
- },
- {
- "name" : "ThisProfileShouldNotThrow"
- },
- {
- "name" : "Ubuntu",
- "guid" : "{2C4DE342-38B7-51CF-B940-2309A097F518}"
- }
- ]
- })" };
-
- auto name0{ L"profile0" };
- auto name1{ L"profile1" };
- auto name2{ L"Ubuntu" };
- auto name3{ L"ThisProfileShouldNotThrow" };
- auto badName{ L"DoesNotExist" };
-
- const winrt::guid guid0{ ::Microsoft::Console::Utils::GuidFromString(L"{6239a42c-5555-49a3-80bd-e8fdd045185c}") };
- const winrt::guid guid1{ ::Microsoft::Console::Utils::GuidFromString(L"{6239a42c-6666-49a3-80bd-e8fdd045185c}") };
- const winrt::guid guid2{ ::Microsoft::Console::Utils::GuidFromString(L"{2C4DE342-38B7-51CF-B940-2309A097F518}") };
- const winrt::guid fakeGuid{ ::Microsoft::Console::Utils::GuidFromString(L"{FFFFFFFF-FFFF-FFFF-FFFF-FFFFFFFFFFFF}") };
- const std::optional badGuid{};
-
- VerifyParseSucceeded(settings0String);
-
- auto settings = winrt::make_self