`CascadiaSettings::UpdateColorSchemeReferences` had two bugs in it: 1. we would never check/update the base layer 2. we would explicitly set the color scheme on a profile referencing the old name This PR fixes both of those issues by checking/updating the base layer, and ensuring that we check if a profile has an explicit reference before updating it. Since the affected code is in TSM, I also created an automated local test. ## Validation Steps Performed Bug repro steps. Specifically tested [DHowett's scenario] too. Test added. Closes #9094 [DHowett's scenario]: https://github.com/microsoft/terminal/issues/9094#issuecomment-776412781
372 lines
17 KiB
C++
372 lines
17 KiB
C++
// Copyright (c) Microsoft Corporation.
|
|
// Licensed under the MIT license.
|
|
|
|
#include "pch.h"
|
|
|
|
#include "../TerminalSettingsModel/ColorScheme.h"
|
|
#include "../TerminalSettingsModel/CascadiaSettings.h"
|
|
#include "JsonTestClass.h"
|
|
|
|
using namespace Microsoft::Console;
|
|
using namespace winrt::Microsoft::Terminal::Settings::Model::implementation;
|
|
using namespace WEX::Logging;
|
|
using namespace WEX::TestExecution;
|
|
using namespace WEX::Common;
|
|
|
|
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 ColorSchemeTests : 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(ColorSchemeTests)
|
|
TEST_CLASS_PROPERTY(L"RunAs", L"UAP")
|
|
TEST_CLASS_PROPERTY(L"UAP:AppXManifest", L"TestHostAppXManifest.xml")
|
|
END_TEST_CLASS()
|
|
|
|
TEST_METHOD(CanLayerColorScheme);
|
|
TEST_METHOD(LayerColorSchemeProperties);
|
|
TEST_METHOD(LayerColorSchemesOnArray);
|
|
TEST_METHOD(UpdateSchemeReferences);
|
|
|
|
TEST_CLASS_SETUP(ClassSetup)
|
|
{
|
|
InitializeJsonReader();
|
|
return true;
|
|
}
|
|
};
|
|
|
|
void ColorSchemeTests::CanLayerColorScheme()
|
|
{
|
|
const std::string scheme0String{ R"({
|
|
"name": "scheme0",
|
|
"foreground": "#000000",
|
|
"background": "#010101"
|
|
})" };
|
|
const std::string scheme1String{ R"({
|
|
"name": "scheme1",
|
|
"foreground": "#020202",
|
|
"background": "#030303"
|
|
})" };
|
|
const std::string scheme2String{ R"({
|
|
"name": "scheme0",
|
|
"foreground": "#040404",
|
|
"background": "#050505"
|
|
})" };
|
|
const std::string scheme3String{ R"({
|
|
// "name": "scheme3",
|
|
"foreground": "#060606",
|
|
"background": "#070707"
|
|
})" };
|
|
|
|
const auto scheme0Json = VerifyParseSucceeded(scheme0String);
|
|
const auto scheme1Json = VerifyParseSucceeded(scheme1String);
|
|
const auto scheme2Json = VerifyParseSucceeded(scheme2String);
|
|
const auto scheme3Json = VerifyParseSucceeded(scheme3String);
|
|
|
|
const auto scheme0 = ColorScheme::FromJson(scheme0Json);
|
|
|
|
VERIFY_IS_TRUE(scheme0->ShouldBeLayered(scheme0Json));
|
|
VERIFY_IS_FALSE(scheme0->ShouldBeLayered(scheme1Json));
|
|
VERIFY_IS_TRUE(scheme0->ShouldBeLayered(scheme2Json));
|
|
VERIFY_IS_FALSE(scheme0->ShouldBeLayered(scheme3Json));
|
|
|
|
const auto scheme1 = ColorScheme::FromJson(scheme1Json);
|
|
|
|
VERIFY_IS_FALSE(scheme1->ShouldBeLayered(scheme0Json));
|
|
VERIFY_IS_TRUE(scheme1->ShouldBeLayered(scheme1Json));
|
|
VERIFY_IS_FALSE(scheme1->ShouldBeLayered(scheme2Json));
|
|
VERIFY_IS_FALSE(scheme1->ShouldBeLayered(scheme3Json));
|
|
|
|
const auto scheme3 = ColorScheme::FromJson(scheme3Json);
|
|
|
|
VERIFY_IS_FALSE(scheme3->ShouldBeLayered(scheme0Json));
|
|
VERIFY_IS_FALSE(scheme3->ShouldBeLayered(scheme1Json));
|
|
VERIFY_IS_FALSE(scheme3->ShouldBeLayered(scheme2Json));
|
|
VERIFY_IS_FALSE(scheme3->ShouldBeLayered(scheme3Json));
|
|
}
|
|
|
|
void ColorSchemeTests::LayerColorSchemeProperties()
|
|
{
|
|
const std::string scheme0String{ R"({
|
|
"name": "scheme0",
|
|
"foreground": "#000000",
|
|
"background": "#010101",
|
|
"selectionBackground": "#010100",
|
|
"cursorColor": "#010001",
|
|
"red": "#010000",
|
|
"green": "#000100",
|
|
"blue": "#000001"
|
|
})" };
|
|
const std::string scheme1String{ R"({
|
|
"name": "scheme1",
|
|
"foreground": "#020202",
|
|
"background": "#030303",
|
|
"selectionBackground": "#020200",
|
|
"cursorColor": "#040004",
|
|
"red": "#020000",
|
|
|
|
"blue": "#000002"
|
|
})" };
|
|
const std::string scheme2String{ R"({
|
|
"name": "scheme0",
|
|
"foreground": "#040404",
|
|
"background": "#050505",
|
|
"selectionBackground": "#030300",
|
|
"cursorColor": "#060006",
|
|
"red": "#030000",
|
|
"green": "#000300"
|
|
})" };
|
|
|
|
const auto scheme0Json = VerifyParseSucceeded(scheme0String);
|
|
const auto scheme1Json = VerifyParseSucceeded(scheme1String);
|
|
const auto scheme2Json = VerifyParseSucceeded(scheme2String);
|
|
|
|
auto scheme0 = ColorScheme::FromJson(scheme0Json);
|
|
VERIFY_ARE_EQUAL(L"scheme0", scheme0->_Name);
|
|
VERIFY_ARE_EQUAL(ARGB(0, 0, 0, 0), scheme0->_Foreground);
|
|
VERIFY_ARE_EQUAL(ARGB(0, 1, 1, 1), scheme0->_Background);
|
|
VERIFY_ARE_EQUAL(ARGB(0, 1, 1, 0), scheme0->_SelectionBackground);
|
|
VERIFY_ARE_EQUAL(ARGB(0, 1, 0, 1), scheme0->_CursorColor);
|
|
VERIFY_ARE_EQUAL(ARGB(0, 1, 0, 0), scheme0->_table[XTERM_RED_ATTR]);
|
|
VERIFY_ARE_EQUAL(ARGB(0, 0, 1, 0), scheme0->_table[XTERM_GREEN_ATTR]);
|
|
VERIFY_ARE_EQUAL(ARGB(0, 0, 0, 1), scheme0->_table[XTERM_BLUE_ATTR]);
|
|
|
|
Log::Comment(NoThrowString().Format(
|
|
L"Layering scheme1 on top of scheme0"));
|
|
scheme0->LayerJson(scheme1Json);
|
|
|
|
VERIFY_ARE_EQUAL(ARGB(0, 2, 2, 2), scheme0->_Foreground);
|
|
VERIFY_ARE_EQUAL(ARGB(0, 3, 3, 3), scheme0->_Background);
|
|
VERIFY_ARE_EQUAL(ARGB(0, 2, 2, 0), scheme0->_SelectionBackground);
|
|
VERIFY_ARE_EQUAL(ARGB(0, 4, 0, 4), scheme0->_CursorColor);
|
|
VERIFY_ARE_EQUAL(ARGB(0, 2, 0, 0), scheme0->_table[XTERM_RED_ATTR]);
|
|
VERIFY_ARE_EQUAL(ARGB(0, 0, 1, 0), scheme0->_table[XTERM_GREEN_ATTR]);
|
|
VERIFY_ARE_EQUAL(ARGB(0, 0, 0, 2), scheme0->_table[XTERM_BLUE_ATTR]);
|
|
|
|
Log::Comment(NoThrowString().Format(
|
|
L"Layering scheme2Json on top of (scheme0+scheme1)"));
|
|
scheme0->LayerJson(scheme2Json);
|
|
|
|
VERIFY_ARE_EQUAL(ARGB(0, 4, 4, 4), scheme0->_Foreground);
|
|
VERIFY_ARE_EQUAL(ARGB(0, 5, 5, 5), scheme0->_Background);
|
|
VERIFY_ARE_EQUAL(ARGB(0, 3, 3, 0), scheme0->_SelectionBackground);
|
|
VERIFY_ARE_EQUAL(ARGB(0, 6, 0, 6), scheme0->_CursorColor);
|
|
VERIFY_ARE_EQUAL(ARGB(0, 3, 0, 0), scheme0->_table[XTERM_RED_ATTR]);
|
|
VERIFY_ARE_EQUAL(ARGB(0, 0, 3, 0), scheme0->_table[XTERM_GREEN_ATTR]);
|
|
VERIFY_ARE_EQUAL(ARGB(0, 0, 0, 2), scheme0->_table[XTERM_BLUE_ATTR]);
|
|
}
|
|
|
|
void ColorSchemeTests::LayerColorSchemesOnArray()
|
|
{
|
|
const std::string scheme0String{ R"({
|
|
"name": "scheme0",
|
|
"foreground": "#000000",
|
|
"background": "#010101"
|
|
})" };
|
|
const std::string scheme1String{ R"({
|
|
"name": "scheme1",
|
|
"foreground": "#020202",
|
|
"background": "#030303"
|
|
})" };
|
|
const std::string scheme2String{ R"({
|
|
"name": "scheme0",
|
|
"foreground": "#040404",
|
|
"background": "#050505"
|
|
})" };
|
|
const std::string scheme3String{ R"({
|
|
// by not providing a name, the scheme will have the name ""
|
|
"foreground": "#060606",
|
|
"background": "#070707"
|
|
})" };
|
|
|
|
const auto scheme0Json = VerifyParseSucceeded(scheme0String);
|
|
const auto scheme1Json = VerifyParseSucceeded(scheme1String);
|
|
const auto scheme2Json = VerifyParseSucceeded(scheme2String);
|
|
const auto scheme3Json = VerifyParseSucceeded(scheme3String);
|
|
|
|
auto settings = winrt::make_self<CascadiaSettings>();
|
|
|
|
VERIFY_ARE_EQUAL(0u, settings->_globals->ColorSchemes().Size());
|
|
VERIFY_IS_NULL(settings->_FindMatchingColorScheme(scheme0Json));
|
|
VERIFY_IS_NULL(settings->_FindMatchingColorScheme(scheme1Json));
|
|
VERIFY_IS_NULL(settings->_FindMatchingColorScheme(scheme2Json));
|
|
VERIFY_IS_NULL(settings->_FindMatchingColorScheme(scheme3Json));
|
|
|
|
settings->_LayerOrCreateColorScheme(scheme0Json);
|
|
{
|
|
for (auto kv : settings->_globals->ColorSchemes())
|
|
{
|
|
Log::Comment(NoThrowString().Format(
|
|
L"kv:%s->%s", kv.Key().data(), kv.Value().Name().data()));
|
|
}
|
|
VERIFY_ARE_EQUAL(1u, settings->_globals->ColorSchemes().Size());
|
|
|
|
VERIFY_IS_TRUE(settings->_globals->ColorSchemes().HasKey(L"scheme0"));
|
|
auto scheme0Proj = settings->_globals->ColorSchemes().Lookup(L"scheme0");
|
|
auto scheme0 = winrt::get_self<ColorScheme>(scheme0Proj);
|
|
|
|
VERIFY_IS_NOT_NULL(settings->_FindMatchingColorScheme(scheme0Json));
|
|
VERIFY_IS_NULL(settings->_FindMatchingColorScheme(scheme1Json));
|
|
VERIFY_IS_NOT_NULL(settings->_FindMatchingColorScheme(scheme2Json));
|
|
VERIFY_IS_NULL(settings->_FindMatchingColorScheme(scheme3Json));
|
|
VERIFY_ARE_EQUAL(ARGB(0, 0, 0, 0), scheme0->_Foreground);
|
|
VERIFY_ARE_EQUAL(ARGB(0, 1, 1, 1), scheme0->_Background);
|
|
}
|
|
|
|
settings->_LayerOrCreateColorScheme(scheme1Json);
|
|
|
|
{
|
|
VERIFY_ARE_EQUAL(2u, settings->_globals->ColorSchemes().Size());
|
|
|
|
VERIFY_IS_TRUE(settings->_globals->ColorSchemes().HasKey(L"scheme0"));
|
|
auto scheme0Proj = settings->_globals->ColorSchemes().Lookup(L"scheme0");
|
|
auto scheme0 = winrt::get_self<ColorScheme>(scheme0Proj);
|
|
VERIFY_IS_TRUE(settings->_globals->ColorSchemes().HasKey(L"scheme1"));
|
|
auto scheme1Proj = settings->_globals->ColorSchemes().Lookup(L"scheme1");
|
|
auto scheme1 = winrt::get_self<ColorScheme>(scheme1Proj);
|
|
|
|
VERIFY_IS_NOT_NULL(settings->_FindMatchingColorScheme(scheme0Json));
|
|
VERIFY_IS_NOT_NULL(settings->_FindMatchingColorScheme(scheme1Json));
|
|
VERIFY_IS_NOT_NULL(settings->_FindMatchingColorScheme(scheme2Json));
|
|
VERIFY_IS_NULL(settings->_FindMatchingColorScheme(scheme3Json));
|
|
VERIFY_ARE_EQUAL(ARGB(0, 0, 0, 0), scheme0->_Foreground);
|
|
VERIFY_ARE_EQUAL(ARGB(0, 1, 1, 1), scheme0->_Background);
|
|
VERIFY_ARE_EQUAL(ARGB(0, 2, 2, 2), scheme1->_Foreground);
|
|
VERIFY_ARE_EQUAL(ARGB(0, 3, 3, 3), scheme1->_Background);
|
|
}
|
|
settings->_LayerOrCreateColorScheme(scheme2Json);
|
|
|
|
{
|
|
VERIFY_ARE_EQUAL(2u, settings->_globals->ColorSchemes().Size());
|
|
|
|
VERIFY_IS_TRUE(settings->_globals->ColorSchemes().HasKey(L"scheme0"));
|
|
auto scheme0Proj = settings->_globals->ColorSchemes().Lookup(L"scheme0");
|
|
auto scheme0 = winrt::get_self<ColorScheme>(scheme0Proj);
|
|
VERIFY_IS_TRUE(settings->_globals->ColorSchemes().HasKey(L"scheme1"));
|
|
auto scheme1Proj = settings->_globals->ColorSchemes().Lookup(L"scheme1");
|
|
auto scheme1 = winrt::get_self<ColorScheme>(scheme1Proj);
|
|
|
|
VERIFY_IS_NOT_NULL(settings->_FindMatchingColorScheme(scheme0Json));
|
|
VERIFY_IS_NOT_NULL(settings->_FindMatchingColorScheme(scheme1Json));
|
|
VERIFY_IS_NOT_NULL(settings->_FindMatchingColorScheme(scheme2Json));
|
|
VERIFY_IS_NULL(settings->_FindMatchingColorScheme(scheme3Json));
|
|
VERIFY_ARE_EQUAL(ARGB(0, 4, 4, 4), scheme0->_Foreground);
|
|
VERIFY_ARE_EQUAL(ARGB(0, 5, 5, 5), scheme0->_Background);
|
|
VERIFY_ARE_EQUAL(ARGB(0, 2, 2, 2), scheme1->_Foreground);
|
|
VERIFY_ARE_EQUAL(ARGB(0, 3, 3, 3), scheme1->_Background);
|
|
}
|
|
settings->_LayerOrCreateColorScheme(scheme3Json);
|
|
|
|
{
|
|
VERIFY_ARE_EQUAL(3u, settings->_globals->ColorSchemes().Size());
|
|
|
|
VERIFY_IS_TRUE(settings->_globals->ColorSchemes().HasKey(L"scheme0"));
|
|
auto scheme0Proj = settings->_globals->ColorSchemes().Lookup(L"scheme0");
|
|
auto scheme0 = winrt::get_self<ColorScheme>(scheme0Proj);
|
|
VERIFY_IS_TRUE(settings->_globals->ColorSchemes().HasKey(L"scheme1"));
|
|
auto scheme1Proj = settings->_globals->ColorSchemes().Lookup(L"scheme1");
|
|
auto scheme1 = winrt::get_self<ColorScheme>(scheme1Proj);
|
|
VERIFY_IS_TRUE(settings->_globals->ColorSchemes().HasKey(L""));
|
|
auto scheme2Proj = settings->_globals->ColorSchemes().Lookup(L"");
|
|
auto scheme2 = winrt::get_self<ColorScheme>(scheme2Proj);
|
|
|
|
VERIFY_IS_NOT_NULL(settings->_FindMatchingColorScheme(scheme0Json));
|
|
VERIFY_IS_NOT_NULL(settings->_FindMatchingColorScheme(scheme1Json));
|
|
VERIFY_IS_NOT_NULL(settings->_FindMatchingColorScheme(scheme2Json));
|
|
VERIFY_IS_NULL(settings->_FindMatchingColorScheme(scheme3Json));
|
|
VERIFY_ARE_EQUAL(ARGB(0, 4, 4, 4), scheme0->_Foreground);
|
|
VERIFY_ARE_EQUAL(ARGB(0, 5, 5, 5), scheme0->_Background);
|
|
VERIFY_ARE_EQUAL(ARGB(0, 2, 2, 2), scheme1->_Foreground);
|
|
VERIFY_ARE_EQUAL(ARGB(0, 3, 3, 3), scheme1->_Background);
|
|
VERIFY_ARE_EQUAL(ARGB(0, 6, 6, 6), scheme2->_Foreground);
|
|
VERIFY_ARE_EQUAL(ARGB(0, 7, 7, 7), scheme2->_Background);
|
|
}
|
|
}
|
|
|
|
void ColorSchemeTests::UpdateSchemeReferences()
|
|
{
|
|
const std::string settingsString{ R"json({
|
|
"defaultProfile": "Inherited reference",
|
|
"profiles": {
|
|
"defaults": {
|
|
"colorScheme": "Scheme 1"
|
|
},
|
|
"list": [
|
|
{
|
|
"name": "Explicit scheme reference",
|
|
"colorScheme": "Scheme 1"
|
|
},
|
|
{
|
|
"name": "Explicit reference; hidden",
|
|
"colorScheme": "Scheme 1",
|
|
"hidden": true
|
|
},
|
|
{
|
|
"name": "Inherited reference"
|
|
},
|
|
{
|
|
"name": "Different reference",
|
|
"colorScheme": "Scheme 2"
|
|
}
|
|
]
|
|
},
|
|
"schemes": [
|
|
{ "name": "Scheme 1" },
|
|
{ "name": "Scheme 2" },
|
|
{ "name": "Scheme 1 (renamed)" }
|
|
]
|
|
})json" };
|
|
|
|
auto settings{ winrt::make_self<CascadiaSettings>(false) };
|
|
settings->_ParseJsonString(settingsString, false);
|
|
settings->_ApplyDefaultsFromUserSettings();
|
|
settings->LayerJson(settings->_userSettings);
|
|
settings->_ValidateSettings();
|
|
|
|
// update all references to "Scheme 1"
|
|
const auto newName{ L"Scheme 1 (renamed)" };
|
|
settings->UpdateColorSchemeReferences(L"Scheme 1", newName);
|
|
|
|
// verify profile defaults
|
|
Log::Comment(L"Profile Defaults");
|
|
VERIFY_ARE_EQUAL(newName, settings->ProfileDefaults().ColorSchemeName());
|
|
VERIFY_IS_TRUE(settings->ProfileDefaults().HasColorSchemeName());
|
|
|
|
// verify all other profiles
|
|
const auto& profiles{ settings->AllProfiles() };
|
|
{
|
|
const auto& prof{ profiles.GetAt(0) };
|
|
Log::Comment(prof.Name().c_str());
|
|
VERIFY_ARE_EQUAL(newName, prof.ColorSchemeName());
|
|
VERIFY_IS_TRUE(prof.HasColorSchemeName());
|
|
}
|
|
{
|
|
const auto& prof{ profiles.GetAt(1) };
|
|
Log::Comment(prof.Name().c_str());
|
|
VERIFY_ARE_EQUAL(newName, prof.ColorSchemeName());
|
|
VERIFY_IS_TRUE(prof.HasColorSchemeName());
|
|
}
|
|
{
|
|
const auto& prof{ profiles.GetAt(2) };
|
|
Log::Comment(prof.Name().c_str());
|
|
VERIFY_ARE_EQUAL(newName, prof.ColorSchemeName());
|
|
VERIFY_IS_FALSE(prof.HasColorSchemeName());
|
|
}
|
|
{
|
|
const auto& prof{ profiles.GetAt(3) };
|
|
Log::Comment(prof.Name().c_str());
|
|
VERIFY_ARE_EQUAL(L"Scheme 2", prof.ColorSchemeName());
|
|
VERIFY_IS_TRUE(prof.HasColorSchemeName());
|
|
}
|
|
}
|
|
}
|