text: // 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());
          }
      }
  }
  