| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402 |
- using System.Collections.Frozen;
- using System.Collections.Immutable;
- using System.Diagnostics;
- using System.Reflection;
- using System.Text;
- using System.Text.Json;
- using Xunit.Abstractions;
- using static Terminal.Gui.Configuration.ConfigurationManager;
- using File = System.IO.File;
- #pragma warning disable IDE1006
- namespace UnitTests.ConfigurationTests;
- public class ConfigurationManagerTests (ITestOutputHelper output)
- {
- [Fact]
- public void ModuleInitializer_Was_Called ()
- {
- Assert.False (IsEnabled);
- Assert.True (IsInitialized ());
- }
- [Fact]
- public void Initialize_Throws_If_Called_Explicitly ()
- {
- Assert.False (IsEnabled);
- Assert.Throws<InvalidOperationException> (Initialize);
- }
- [Fact]
- public void HardCodedDefaultCache_Properties_Are_Copies ()
- {
- Assert.False (IsEnabled);
- Enable (ConfigLocations.HardCoded);
- Assert.Equal (Key.Esc, Application.QuitKey);
- ConfigProperty fromSettings = Settings! ["Application.QuitKey"];
- FrozenDictionary<string, ConfigProperty> initialCache = GetHardCodedConfigPropertyCache ();
- Assert.NotNull (initialCache);
- ConfigProperty fromCache = initialCache ["Application.QuitKey"];
- // Assert
- Assert.NotEqual (fromCache, fromSettings);
- Disable (true);
- }
- [Fact]
- public void GetHardCodedDefaultCache_Always_Returns_Same_Ref ()
- {
- // It's important it always returns the same cache ref, so no copies are made
- // Otherwise it's a big performance hit
- Assert.False (IsEnabled);
- try
- {
- FrozenDictionary<string, ConfigProperty> initialCache = GetHardCodedConfigPropertyCache ();
- FrozenDictionary<string, ConfigProperty> cache = GetHardCodedConfigPropertyCache ();
- Assert.Equal (initialCache, cache);
- }
- finally
- {
- Disable (true);
- }
- }
- [Fact]
- public void HardCodedDefaultCache_Properties_Are_Immutable ()
- {
- Assert.False (IsEnabled);
- try
- {
- Enable (ConfigLocations.HardCoded);
- Assert.Equal (Key.Esc, Application.QuitKey);
- FrozenDictionary<string, ConfigProperty> initialCache = GetHardCodedConfigPropertyCache ();
- Assert.NotNull (initialCache);
- Assert.Equal (Key.Esc, (Key)initialCache ["Application.QuitKey"].PropertyValue);
- // Act
- Settings! ["Application.QuitKey"].PropertyValue = Key.Q;
- Assert.Equal (Key.Q, (Key)Settings ["Application.QuitKey"].PropertyValue);
- Settings ["Application.QuitKey"].Apply ();
- Assert.Equal (Key.Q, Application.QuitKey);
- Application.QuitKey = Key.K;
- // Assert
- FrozenDictionary<string, ConfigProperty> cache = GetHardCodedConfigPropertyCache ();
- Assert.True (initialCache ["Application.QuitKey"].Immutable);
- Assert.Equal (Key.Esc, (Key)initialCache ["Application.QuitKey"].PropertyValue);
- }
- finally
- {
- Disable (true);
- Application.ResetState (true);
- }
- }
- [Fact]
- public void Disable_Settings_Is_NotNull ()
- {
- Assert.False (IsEnabled);
- Disable ();
- Assert.NotNull (Settings);
- }
- [Fact]
- public void Disable_With_ResetToHardCodedDefaults_True_Works_When_Disabled ()
- {
- Assert.False (IsEnabled);
- Disable (true);
- }
- [Fact]
- public void Enable_Settings_Is_Valid ()
- {
- Assert.False (IsEnabled);
- Enable (ConfigLocations.HardCoded);
- Assert.NotNull (Settings);
- Disable (true);
- }
- [Fact]
- public void Enable_HardCoded_Resets_Schemes_After_Runtime_Config ()
- {
- Assert.False (IsEnabled);
- try
- {
- // Arrange: Start from hard-coded defaults and capture baseline scheme values.
- Enable (ConfigLocations.HardCoded);
- Dictionary<string, Scheme> schemes = SchemeManager.GetSchemes ();
- Assert.NotNull (schemes);
- Assert.NotEmpty (schemes);
- Color baselineFg = schemes ["Base"].Normal.Foreground;
- Color baselineBg = schemes ["Base"].Normal.Background;
- // Sanity: defaults should be stable
- Assert.NotEqual (default (Color), baselineFg);
- Assert.NotEqual (default (Color), baselineBg);
- // Act: Override the Base scheme via runtime JSON and apply
- ThrowOnJsonErrors = true;
- RuntimeConfig = """
- {
- "Themes": [
- {
- "Default": {
- "Schemes": [
- {
- "Base": {
- "Normal": {
- "Foreground": "Black",
- "Background": "Gray"
- }
- }
- }
- ]
- }
- }
- ]
- }
- """;
- Load (ConfigLocations.Runtime);
- Apply ();
- // Verify override took effect
- Dictionary<string, Scheme> overridden = SchemeManager.GetSchemes ();
- Assert.Equal (Color.Black, overridden ["Base"].Normal.Foreground);
- Assert.Equal (Color.Gray, overridden ["Base"].Normal.Background);
- // Now simulate "CM.Enable(true)" semantics: re-enable with HardCoded to reset
- Disable ();
- Enable (ConfigLocations.HardCoded);
- // Assert: schemes are reset to the original hard-coded baseline
- Dictionary<string, Scheme> reset = SchemeManager.GetSchemes ();
- Assert.Equal (baselineFg, reset ["Base"].Normal.Foreground);
- Assert.Equal (baselineBg, reset ["Base"].Normal.Background);
- }
- finally
- {
- Disable (true);
- Application.ResetState (true);
- }
- }
- [Fact]
- public void Enable_HardCoded_Resets_Theme_Dictionary_And_Selection ()
- {
- Assert.False (IsEnabled);
- try
- {
- // Arrange: Enable defaults
- Enable (ConfigLocations.HardCoded);
- Assert.Equal (ThemeManager.DEFAULT_THEME_NAME, ThemeManager.Theme);
- Assert.Single (ThemeManager.Themes!);
- Assert.True (ThemeManager.Themes.ContainsKey (ThemeManager.DEFAULT_THEME_NAME));
- // Act: Load a runtime config that introduces a custom theme and selects it
- ThrowOnJsonErrors = true;
- RuntimeConfig = """
- {
- "Theme": "Custom",
- "Themes": [
- {
- "Custom": {
- "Schemes": [
- {
- "Base": {
- "Normal": {
- "Foreground": "Yellow",
- "Background": "Black"
- }
- }
- }
- ]
- }
- }
- ]
- }
- """;
- // Capture dynamically created hardCoded hard-coded scheme colors
- ImmutableSortedDictionary<string, Scheme> hardCodedSchemes = SchemeManager.GetHardCodedSchemes ()!;
- Color hardCodedBaseNormalFg = hardCodedSchemes ["Base"].Normal.Foreground;
- Assert.Equal (new Color (StandardColor.LightBlue).ToString (), hardCodedBaseNormalFg.ToString ());
- Load (ConfigLocations.Runtime);
- Apply ();
- // Verify the runtime selection took effect
- Assert.Equal ("Custom", ThemeManager.Theme);
- // Now simulate "CM.Enable(true)" semantics: re-enable with HardCoded to reset
- Disable ();
- Enable (ConfigLocations.HardCoded);
- // Assert: selection and dictionary have been reset to hard-coded defaults
- Assert.Equal (ThemeManager.DEFAULT_THEME_NAME, ThemeManager.Theme);
- Assert.Single (ThemeManager.Themes!);
- Assert.True (ThemeManager.Themes.ContainsKey (ThemeManager.DEFAULT_THEME_NAME));
- // Also assert the Base scheme is back to defaults (sanity check)
- Scheme baseScheme = SchemeManager.GetSchemes () ["Base"];
- Assert.Equal (hardCodedBaseNormalFg.ToString (), SchemeManager.GetSchemes () ["Base"]!.Normal.Foreground.ToString ());
- }
- finally
- {
- Disable (true);
- Application.ResetState (true);
- }
- }
- [Fact]
- public void Apply_Applies_Theme ()
- {
- Assert.False (IsEnabled);
- Enable (ConfigLocations.HardCoded);
- var theme = new ThemeScope ();
- theme.LoadHardCodedDefaults ();
- Assert.NotEmpty (theme);
- Assert.True (ThemeManager.Themes!.TryAdd ("testTheme", theme));
- Assert.Equal (2, ThemeManager.Themes.Count);
- Assert.Equal (LineStyle.Rounded, FrameView.DefaultBorderStyle);
- theme ["FrameView.DefaultBorderStyle"].PropertyValue = LineStyle.Double;
- ThemeManager.Theme = "testTheme";
- Apply ();
- Assert.Equal (LineStyle.Double, FrameView.DefaultBorderStyle);
- Disable (true);
- }
- [Fact]
- public void Apply_Raises_Applied ()
- {
- Assert.False (IsEnabled);
- Enable (ConfigLocations.HardCoded);
- Applied += ConfigurationManagerApplied;
- var fired = false;
- void ConfigurationManagerApplied (object sender, ConfigurationManagerEventArgs obj)
- {
- fired = true;
- // assert
- Assert.Equal (KeyCode.Q, Application.QuitKey.KeyCode);
- Assert.Equal (KeyCode.F, Application.NextTabGroupKey.KeyCode);
- Assert.Equal (KeyCode.B, Application.PrevTabGroupKey.KeyCode);
- }
- // act
- Settings! ["Application.QuitKey"].PropertyValue = Key.Q;
- Settings ["Application.NextTabGroupKey"].PropertyValue = Key.F;
- Settings ["Application.PrevTabGroupKey"].PropertyValue = Key.B;
- Apply ();
- // assert
- Assert.True (fired);
- Applied -= ConfigurationManagerApplied;
- Disable (true);
- Application.ResetState (true);
- }
- [Fact]
- public void Load_Raises_Updated ()
- {
- Assert.False (IsEnabled);
- var fired = false;
- Enable (ConfigLocations.HardCoded);
- ThrowOnJsonErrors = true;
- Assert.Equal (Key.Esc, ((Key)Settings! ["Application.QuitKey"].PropertyValue)!.KeyCode);
- Updated += ConfigurationManagerUpdated;
- // Act
- // Only select locations under test control
- Load (ConfigLocations.LibraryResources | ConfigLocations.AppResources | ConfigLocations.Runtime);
- // assert
- Assert.True (fired);
- // clean up
- Updated -= ConfigurationManagerUpdated;
- Disable (true);
- Application.ResetState (true);
- return;
- void ConfigurationManagerUpdated (object sender, ConfigurationManagerEventArgs obj) { fired = true; }
- }
- [Fact]
- public void Load_And_Apply_Performance_Check ()
- {
- Assert.False (IsEnabled);
- Enable (ConfigLocations.HardCoded);
- try
- {
- // Start stopwatch
- var stopwatch = new Stopwatch ();
- stopwatch.Start ();
- // Act
- Load (ConfigLocations.All);
- Apply ();
- // Stop stopwatch
- stopwatch.Stop ();
- // Assert
- output.WriteLine ($"Load took {stopwatch.ElapsedMilliseconds} ms");
- // Ensure load time is reasonable (adjust threshold as needed)
- Assert.True (
- stopwatch.ElapsedMilliseconds < 1000,
- $"Loading configuration took {stopwatch.ElapsedMilliseconds}ms, which exceeds reasonable threshold");
- }
- finally
- {
- Disable (true);
- Application.ResetState (true);
- }
- }
- [Fact]
- public void Load_Loads_Custom_Json ()
- {
- Assert.False (IsEnabled);
- try
- {
- Enable (ConfigLocations.HardCoded);
- ThrowOnJsonErrors = true;
- Assert.Equal (Key.Esc, (Key)Settings! ["Application.QuitKey"].PropertyValue);
- // act
- RuntimeConfig = """
- {
- "Application.QuitKey": "Ctrl-Q"
- }
- """;
- Load (ConfigLocations.Runtime);
- // assert
- Assert.Equal (Key.Q.WithCtrl, (Key)Settings ["Application.QuitKey"].PropertyValue);
- }
- finally
- {
- // clean up
- Disable (true);
- Application.ResetState (true);
- }
- }
- [Fact (Skip = "Events disabled")]
- public void ResetToCurrentValues_Raises_Updated ()
- {
- Assert.False (IsEnabled);
- var fired = false;
- try
- {
- Enable (ConfigLocations.HardCoded);
- Settings! ["Application.QuitKey"].PropertyValue = Key.Q;
- Updated += ConfigurationManagerUpdated;
- // Act
- UpdateToCurrentValues ();
- // assert
- Assert.True (fired);
- }
- finally
- {
- Updated -= ConfigurationManagerUpdated;
- Disable (true);
- Application.ResetState (true);
- }
- return;
- void ConfigurationManagerUpdated (object sender, ConfigurationManagerEventArgs obj) { fired = true; }
- }
- [Fact]
- public void ResetToHardCodedDefaults_and_Load_LibraryResourcesOnly_are_same ()
- {
- Assert.False (IsEnabled);
- try
- {
- // arrange
- Enable (ConfigLocations.HardCoded);
- Settings! ["Application.QuitKey"].PropertyValue = Key.Q;
- Settings ["Application.NextTabGroupKey"].PropertyValue = Key.F;
- Settings ["Application.PrevTabGroupKey"].PropertyValue = Key.B;
- Settings.Apply ();
- // assert apply worked
- Assert.Equal (KeyCode.Q, Application.QuitKey.KeyCode);
- Assert.Equal (KeyCode.F, Application.NextTabGroupKey.KeyCode);
- Assert.Equal (KeyCode.B, Application.PrevTabGroupKey.KeyCode);
- //act
- ResetToHardCodedDefaults ();
- // assert
- Assert.NotEmpty (ThemeManager.Themes!);
- Assert.Equal ("Default", ThemeManager.Theme);
- Assert.Equal (Key.Esc, Application.QuitKey);
- Assert.Equal (Key.F6, Application.NextTabGroupKey);
- Assert.Equal (Key.F6.WithShift, Application.PrevTabGroupKey);
- // arrange
- Settings ["Application.QuitKey"].PropertyValue = Key.Q;
- Settings ["Application.NextTabGroupKey"].PropertyValue = Key.F;
- Settings ["Application.PrevTabGroupKey"].PropertyValue = Key.B;
- Settings.Apply ();
- // act
- Load (ConfigLocations.LibraryResources);
- Apply ();
- // assert
- Assert.NotEmpty (ThemeManager.Themes);
- Assert.Equal ("Default", ThemeManager.Theme);
- Assert.Equal (KeyCode.Esc, Application.QuitKey.KeyCode);
- Assert.Equal (Key.F6, Application.NextTabGroupKey);
- Assert.Equal (Key.F6.WithShift, Application.PrevTabGroupKey);
- }
- finally
- {
- Disable (true);
- Application.ResetState (true);
- }
- }
- [Fact]
- public void ResetToHardCodedDefaults_Resets ()
- {
- Assert.False (IsEnabled);
- try
- {
- Enable (ConfigLocations.HardCoded);
- // Capture dynamically created hardCoded hard-coded scheme colors
- ImmutableSortedDictionary<string, Scheme> hardCodedSchemesViaSchemeManager = SchemeManager.GetHardCodedSchemes ()!;
- Dictionary<string, Scheme> hardCodedSchemes =
- GetHardCodedConfigPropertiesByScope ("ThemeScope")!.ToFrozenDictionary () ["Schemes"].PropertyValue as Dictionary<string, Scheme>;
- Color hardCodedBaseNormalFg = hardCodedSchemesViaSchemeManager ["Base"].Normal.Foreground;
- Assert.Equal (new Color (StandardColor.LightBlue).ToString (), hardCodedBaseNormalFg.ToString ());
- // Capture current scheme colors
- Dictionary<string, Scheme> currentSchemes = SchemeManager.GetSchemes ()!;
- Color currentBaseNormalFg = currentSchemes ["Base"].Normal.Foreground;
- Assert.Equal (hardCodedBaseNormalFg.ToString (), currentBaseNormalFg.ToString ());
- // Arrange
- var json = @"
- {
- ""$schema"": ""https://gui-cs.github.io/Terminal.Gui/schemas/tui-config-schema.json"",
- ""Application.QuitKey"": ""Alt-Z"",
- ""Theme"": ""Default"",
- ""Themes"": [
- {
- ""Default"": {
- ""MessageBox.DefaultButtonAlignment"": ""End"",
- ""Schemes"": [
- {
- ""TopLevel"": {
- ""Normal"": {
- ""Foreground"": ""BrightGreen"",
- ""Background"": ""Black""
- },
- ""Focus"": {
- ""Foreground"": ""White"",
- ""Background"": ""Cyan""
- },
- ""HotNormal"": {
- ""Foreground"": ""Yellow"",
- ""Background"": ""Black""
- },
- ""HotFocus"": {
- ""Foreground"": ""Blue"",
- ""Background"": ""Cyan""
- },
- ""Disabled"": {
- ""Foreground"": ""DarkGray"",
- ""Background"": ""Black""
- }
- }
- },
- {
- ""Base"": {
- ""Normal"": {
- ""Foreground"": ""White"",
- ""Background"": ""Blue""
- },
- ""Focus"": {
- ""Foreground"": ""Black"",
- ""Background"": ""Gray""
- },
- ""HotNormal"": {
- ""Foreground"": ""BrightCyan"",
- ""Background"": ""Blue""
- },
- ""HotFocus"": {
- ""Foreground"": ""BrightBlue"",
- ""Background"": ""Gray""
- },
- ""Disabled"": {
- ""Foreground"": ""DarkGray"",
- ""Background"": ""Blue""
- }
- }
- },
- {
- ""Dialog"": {
- ""Normal"": {
- ""Foreground"": ""Black"",
- ""Background"": ""Gray""
- },
- ""Focus"": {
- ""Foreground"": ""White"",
- ""Background"": ""DarkGray""
- },
- ""HotNormal"": {
- ""Foreground"": ""Blue"",
- ""Background"": ""Gray""
- },
- ""HotFocus"": {
- ""Foreground"": ""BrightYellow"",
- ""Background"": ""DarkGray""
- },
- ""Disabled"": {
- ""Foreground"": ""Gray"",
- ""Background"": ""DarkGray""
- }
- }
- },
- {
- ""Menu"": {
- ""Normal"": {
- ""Foreground"": ""White"",
- ""Background"": ""DarkGray""
- },
- ""Focus"": {
- ""Foreground"": ""White"",
- ""Background"": ""Black""
- },
- ""HotNormal"": {
- ""Foreground"": ""BrightYellow"",
- ""Background"": ""DarkGray""
- },
- ""HotFocus"": {
- ""Foreground"": ""BrightYellow"",
- ""Background"": ""Black""
- },
- ""Disabled"": {
- ""Foreground"": ""Gray"",
- ""Background"": ""DarkGray""
- }
- }
- },
- {
- ""Error"": {
- ""Normal"": {
- ""Foreground"": ""Red"",
- ""Background"": ""White""
- },
- ""Focus"": {
- ""Foreground"": ""Black"",
- ""Background"": ""BrightRed""
- },
- ""HotNormal"": {
- ""Foreground"": ""Black"",
- ""Background"": ""White""
- },
- ""HotFocus"": {
- ""Foreground"": ""White"",
- ""Background"": ""BrightRed""
- },
- ""Disabled"": {
- ""Foreground"": ""DarkGray"",
- ""Background"": ""White""
- }
- }
- }
- ]
- }
- }
- ]
- }
- ";
- // ResetToCurrentValues ();
- ThrowOnJsonErrors = true;
- ConfigurationManager.SourcesManager?.Load (Settings, json, "UpdateFromJson", ConfigLocations.Runtime);
- Assert.Equal ("Default", ThemeManager.Theme);
- Assert.Equal (KeyCode.Esc, Application.QuitKey.KeyCode);
- Assert.Equal (KeyCode.Z | KeyCode.AltMask, ((Key)Settings! ["Application.QuitKey"].PropertyValue)!.KeyCode);
- Assert.Equal (Alignment.Center, MessageBox.DefaultButtonAlignment);
- // Get current scheme colors again
- currentSchemes = SchemeManager.GetSchemes ()!;
- currentBaseNormalFg = currentSchemes ["Base"].Normal.Foreground;
- Assert.Equal (Color.White.ToString (), currentBaseNormalFg.ToString ());
- // Now Apply
- Apply ();
- Assert.Equal ("Default", ThemeManager.Theme);
- Assert.Equal (KeyCode.Z | KeyCode.AltMask, Application.QuitKey.KeyCode);
- Assert.Equal (Alignment.End, MessageBox.DefaultButtonAlignment);
- Assert.Equal (Color.White.ToString (), currentBaseNormalFg.ToString ());
- // Reset
- ResetToHardCodedDefaults ();
- hardCodedSchemes =
- GetHardCodedConfigPropertiesByScope ("ThemeScope")!.ToFrozenDictionary () ["Schemes"].PropertyValue as Dictionary<string, Scheme>;
- hardCodedBaseNormalFg = hardCodedSchemes! ["Base"].Normal.Foreground;
- Assert.Equal (new Color (StandardColor.LightBlue).ToString (), hardCodedBaseNormalFg.ToString ());
- FrozenDictionary<string, ConfigProperty> hardCodedCache = GetHardCodedConfigPropertyCache ()!;
- Assert.Equal (hardCodedCache ["Theme"].PropertyValue, ThemeManager.Theme);
- Assert.Equal (hardCodedCache ["Application.QuitKey"].PropertyValue, Application.QuitKey);
- // Themes
- Assert.Equal (hardCodedCache ["MessageBox.DefaultButtonAlignment"].PropertyValue, MessageBox.DefaultButtonAlignment);
- Assert.Equal (GetHardCodedConfigPropertyCache ()! ["MessageBox.DefaultButtonAlignment"].PropertyValue, MessageBox.DefaultButtonAlignment);
- // Schemes
- currentSchemes = SchemeManager.GetSchemes ()!;
- currentBaseNormalFg = currentSchemes ["Base"].Normal.Foreground;
- Assert.Equal (hardCodedBaseNormalFg.ToString (), currentBaseNormalFg.ToString ());
- Scheme baseScheme = SchemeManager.GetScheme ("Base");
- Attribute attr = baseScheme.Normal;
- // Use ToString so Assert.Equal shows the actual vs expected values on failure
- Assert.Equal (hardCodedBaseNormalFg.ToString (), attr.Foreground.ToString ());
- }
- finally
- {
- output.WriteLine ("Disabling CM to clean up.");
- Disable (true);
- }
- }
- [Fact (Skip = "ResetToCurrentValues corrupts hard coded cache")]
- public void ResetToCurrentValues_Enabled_Resets ()
- {
- Assert.False (IsEnabled);
- try
- {
- // Act
- Enable (ConfigLocations.HardCoded);
- Application.QuitKey = Key.A;
- UpdateToCurrentValues ();
- Assert.Equal (Key.A, (Key)Settings! ["Application.QuitKey"].PropertyValue);
- Assert.NotNull (Settings);
- Assert.NotNull (AppSettings);
- Assert.NotNull (ThemeManager.Themes);
- // Default Theme should be "Default"
- Assert.Single (ThemeManager.Themes);
- Assert.Equal (ThemeManager.DEFAULT_THEME_NAME, ThemeManager.Theme);
- }
- finally
- {
- Disable (true);
- }
- }
- [Fact]
- public void ConfigurationManager_DefaultPrecedence_IsRespected ()
- {
- Assert.False (IsEnabled);
- try
- {
- // arrange
- Enable (ConfigLocations.HardCoded);
- ThrowOnJsonErrors = true;
- // Setup multiple configurations with the same setting
- // with different precedence levels
- RuntimeConfig = """
- {
- "Application.QuitKey": "Alt+Q"
- }
- """;
- var defaultConfig = """
- {
- "Application.QuitKey": "Ctrl+X"
- }
- """;
- // Update default config first (lower precedence)
- ConfigurationManager.SourcesManager?.Load (Settings, defaultConfig, "default-test", ConfigLocations.LibraryResources);
- // Then load runtime config, which should override default
- Load (ConfigLocations.Runtime);
- // Assert - the runtime config should win due to precedence
- Assert.Equal (Key.Q.WithAlt, (Key)Settings! ["Application.QuitKey"].PropertyValue);
- }
- finally
- {
- Disable (true);
- }
- }
- /// <summary>Save the `config.json` file; this can be used to update the file in `Terminal.Gui.Resources.config.json'.</summary>
- /// <remarks>
- /// IMPORTANT: For the file generated to be valid, this must be the ONLY test run. Config Properties are all
- /// static and thus can be overwritten by other tests.
- /// </remarks>
- [Fact]
- public void Save_HardCodedDefaults_To_config_json ()
- {
- Assert.False (IsEnabled);
- try
- {
- Enable (ConfigLocations.HardCoded);
- // Get the hard coded settings
- ResetToHardCodedDefaults ();
- // Serialize to a JSON string
- string json = ConfigurationManager.SourcesManager?.ToJson (Settings);
- // Write the JSON string to the file
- File.WriteAllText ("hard_coded_defaults_config.json", json);
- // Verify the file was created
- Assert.True (File.Exists ("hard_coded_defaults_config.json"), "Failed to create config.json file");
- }
- finally
- {
- Disable (true);
- }
- }
- /// <summary>Save the `config.json` file; this can be used to update the file in `Terminal.Gui.Resources.config.json'.</summary>
- /// <remarks>
- /// IMPORTANT: For the file generated to be valid, this must be the ONLY test run. Config Properties are all
- /// static and thus can be overwritten by other tests.
- /// </remarks>
- [Fact]
- public void Save_Library_Defaults_To_config_json ()
- {
- Assert.False (IsEnabled);
- try
- {
- Enable (ConfigLocations.LibraryResources);
- // Serialize to a JSON string
- string json = ConfigurationManager.SourcesManager?.ToJson (Settings);
- // Write the JSON string to the file
- File.WriteAllText ("library_defaults_config.json", json);
- // Verify the file was created
- Assert.True (File.Exists ("library_defaults_config.json"), "Failed to create config.json file");
- }
- finally
- {
- Disable (true);
- }
- }
- [Fact]
- public void TestConfigProperties ()
- {
- Assert.False (IsEnabled);
- try
- {
- Enable (ConfigLocations.HardCoded);
- Assert.NotEmpty (Settings!);
- // test that all ConfigProperties have our attribute
- Assert.All (
- Settings,
- item => Assert.Contains (
- item.Value.PropertyInfo!.CustomAttributes,
- a => a.AttributeType
- == typeof (ConfigurationPropertyAttribute)
- ));
- #pragma warning disable xUnit2030
- Assert.DoesNotContain (
- Settings,
- cp => cp.Value.PropertyInfo!.GetCustomAttribute (
- typeof (ConfigurationPropertyAttribute)
- )
- == null
- );
- #pragma warning restore xUnit2030
- // Application is a static class
- PropertyInfo pi = typeof (Application).GetProperty ("QuitKey");
- Assert.Equal (pi, Settings ["Application.QuitKey"].PropertyInfo);
- // FrameView is not a static class and DefaultBorderStyle is Scope.Scheme
- pi = typeof (FrameView).GetProperty ("DefaultBorderStyle");
- Assert.False (Settings.ContainsKey ("FrameView.DefaultBorderStyle"));
- Assert.True (ThemeManager.GetCurrentTheme ().ContainsKey ("FrameView.DefaultBorderStyle"));
- Assert.Equal (pi, ThemeManager.GetCurrentTheme () ["FrameView.DefaultBorderStyle"].PropertyInfo);
- }
- finally
- {
- Disable (true);
- }
- }
- [Fact]
- public void Load_And_Apply_HardCoded ()
- {
- Assert.False (IsEnabled);
- try
- {
- // Spot check by setting some of the config properties
- Application.QuitKey = Key.X.WithCtrl;
- FileDialog.MaxSearchResults = 1;
- Enable (ConfigLocations.HardCoded);
- Load (ConfigLocations.HardCoded);
- // Spot check
- Assert.Equal (Key.Esc, Settings ["Application.QuitKey"].PropertyValue as Key);
- Assert.Equal (10000, (int)Settings ["FileDialog.MaxSearchResults"].PropertyValue!);
- Assert.Single (ThemeManager.Themes!);
- Assert.Equal ("Default", ThemeManager.Theme);
- Assert.NotEmpty (ThemeManager.Themes [ThemeManager.Theme]);
- // Verify schemes are properly initialized
- Assert.NotNull (SchemeManager.GetSchemes ());
- Assert.NotEmpty (SchemeManager.GetSchemes ());
- // Verify "Base" has correct values
- //Assert.Equal (Color.White, SchemeManager.GetSchemes () ["Base"]!.Normal.Foreground);
- //Assert.Equal (Color.Blue, SchemeManager.GetSchemes () ["Base"].Normal.Background);
- Apply ();
- Assert.Equal (Key.Esc, Application.QuitKey);
- Assert.Equal (10000, FileDialog.MaxSearchResults);
- }
- finally
- {
- Disable (true);
- }
- }
- [Fact]
- public void Load_And_Apply_LibraryResources ()
- {
- Assert.False (IsEnabled);
- try
- {
- // Spot check by setting some of the config properties
- Application.QuitKey = Key.X.WithCtrl;
- FileDialog.MaxSearchResults = 1;
- Enable (ConfigLocations.HardCoded);
- Load (ConfigLocations.LibraryResources);
- // Spot check
- Assert.Equal (Key.Esc, Settings! ["Application.QuitKey"].PropertyValue as Key);
- Assert.Equal (10000, (int)Settings ["FileDialog.MaxSearchResults"].PropertyValue!);
- Assert.NotEmpty (ThemeManager.Themes!);
- Assert.Equal ("Default", ThemeManager.Theme);
- Assert.NotEmpty (ThemeManager.Themes [ThemeManager.Theme]);
- // Verify schemes are properly initialized
- Assert.NotNull (SchemeManager.GetSchemes ());
- Assert.NotEmpty (SchemeManager.GetSchemes ());
- // This is too fragile as the default scheme may change
- // Verify "Base" has correct values
- //Assert.Equal (Color.White, SchemeManager.Schemes ["Base"]!.Normal.Foreground);
- //Assert.Equal (Color.Blue, SchemeManager.Schemes ["Base"].Normal.Background);
- Apply ();
- Assert.Equal (Key.Esc, Application.QuitKey);
- Assert.Equal (10000, FileDialog.MaxSearchResults);
- }
- finally
- {
- Disable (true);
- }
- }
- [Fact]
- public void Load_And_Apply_RuntimeConfig ()
- {
- Assert.False (IsEnabled);
- try
- {
- // Spot check by setting some of the config properties
- Application.QuitKey = Key.X.WithCtrl;
- FileDialog.MaxSearchResults = 1;
- Glyphs.Apple = new ('z');
- ThrowOnJsonErrors = true;
- Enable (ConfigLocations.HardCoded);
- RuntimeConfig = """
- {
- "Application.QuitKey": "Alt-Q",
- "FileDialog.MaxSearchResults":9,
- "Themes" : [
- {
- "Default" : {
- "Glyphs.Apple": "a"
- }
- }
- ]
- }
- """;
- Load (ConfigLocations.Runtime);
- Assert.Equal (Key.Q.WithAlt, Settings! ["Application.QuitKey"].PropertyValue as Key);
- Assert.Equal (9, (int)Settings ["FileDialog.MaxSearchResults"].PropertyValue!);
- Assert.Equal (new Rune ('a'), ThemeManager.GetCurrentTheme () ["Glyphs.Apple"].PropertyValue);
- Apply ();
- Assert.Equal (Key.Q.WithAlt, Application.QuitKey);
- Assert.Equal (9, FileDialog.MaxSearchResults);
- Assert.Equal (new ('a'), Glyphs.Apple);
- }
- finally
- {
- Disable (true);
- }
- }
- [Fact]
- public void InvalidJsonLogs ()
- {
- Assert.False (IsEnabled);
- Enable (ConfigLocations.HardCoded);
- ThrowOnJsonErrors = false;
- // "brown" is not a color
- var json = @"
- {
- ""Themes"" : [
- {
- ""Default"" : {
- ""Schemes"": [
- {
- ""UserDefined"": {
- ""hotNormal"": {
- ""foreground"": ""brown"",
- ""background"": ""1234""
- }
- }
- }
- ]
- }
- }
- }
- }";
- ConfigurationManager.SourcesManager?.Load (Settings, json, "test", ConfigLocations.Runtime);
- // AbNormal is not a Scheme attribute
- json = @"
- {
- ""Themes"" : [
- {
- ""Default"" : {
- ""Schemes"": [
- {
- ""UserDefined"": {
- ""AbNormal"": {
- ""foreground"": ""green"",
- ""background"": ""black""
- }
- }
- }
- ]
- }
- }
- }
- }";
- ConfigurationManager.SourcesManager?.Load (Settings, json, "test", ConfigLocations.Runtime);
- // Modify hotNormal background only
- json = @"
- {
- ""Themes"" : [
- {
- ""Default"" : {
- ""Schemes"": [
- {
- ""UserDefined"": {
- ""hotNormal"": {
- ""background"": ""cyan""
- }
- }
- }
- ]
- }
- }
- }
- }";
- ConfigurationManager.SourcesManager?.Load (Settings, json, "test", ConfigLocations.Runtime);
- ConfigurationManager.SourcesManager?.Load (Settings, "{}}", "test", ConfigLocations.Runtime);
- Assert.NotEqual (0, _jsonErrors.Length);
- ThrowOnJsonErrors = false;
- Disable (true);
- }
- [Fact]
- public void InvalidJsonThrows ()
- {
- Assert.False (IsEnabled);
- Enable (ConfigLocations.HardCoded);
- ThrowOnJsonErrors = true;
- // "yellow" is not a color
- var json = @"
- {
- ""Themes"" : [
- {
- ""Default"" : {
- ""Schemes"": [
- {
- ""UserDefined"": {
- ""hotNormal"": {
- ""foreground"": ""brownish"",
- ""background"": ""1234""
- }
- }
- }
- ]
- }
- }
- ]
- }";
- var jsonException = Assert.Throws<JsonException> (() => ConfigurationManager.SourcesManager?.Load (Settings, json, "test", ConfigLocations.Runtime));
- Assert.StartsWith ("foreground: \"\"brownish\"\"", jsonException.Message);
- // AbNormal is not a Scheme attribute
- json = @"
- {
- ""Themes"" : [
- {
- ""Default"" : {
- ""Schemes"": [
- {
- ""UserDefined"": {
- ""AbNormal"": {
- ""foreground"": ""green"",
- ""background"": ""black""
- }
- }
- }
- ]
- }
- }
- ]
- }";
- jsonException = Assert.Throws<JsonException> (() => ConfigurationManager.SourcesManager?.Load (Settings, json, "test", ConfigLocations.Runtime));
- Assert.StartsWith ("AbNormal:", jsonException.Message);
- // Modify hotNormal background only
- json = @"
- {
- ""Themes"" : [
- {
- ""Default"" : {
- ""Schemes"": [
- {
- ""UserDefined"": {
- ""hotNormal"": {
- ""background"": ""cyan""
- }
- }
- }
- ]
- }
- }
- ]
- }";
- jsonException = Assert.Throws<JsonException> (() => ConfigurationManager.SourcesManager?.Load (Settings, json, "test", ConfigLocations.Runtime));
- Assert.StartsWith ("background:", jsonException.Message);
- // Unknown property
- json = @"
- {
- ""Unknown"" : ""Not known""
- }";
- jsonException = Assert.Throws<JsonException> (() => ConfigurationManager.SourcesManager?.Load (Settings, json, "test", ConfigLocations.Runtime));
- Assert.StartsWith ("Unknown:", jsonException.Message);
- Assert.Equal (0, _jsonErrors.Length);
- ThrowOnJsonErrors = false;
- Disable (true);
- }
- [Fact]
- public void SourcesManager_Load_FromJson_Loads ()
- {
- Assert.False (IsEnabled);
- try
- {
- Enable (ConfigLocations.HardCoded);
- // Arrange
- var json = @"
- {
- ""$schema"": ""https://gui-cs.github.io/Terminal.Gui/schemas/tui-config-schema.json"",
- ""Application.QuitKey"": ""Alt-Z"",
- ""Theme"": ""Default"",
- ""Themes"": [
- {
- ""Default"": {
- ""MessageBox.DefaultButtonAlignment"": ""End"",
- ""Schemes"": [
- {
- ""TopLevel"": {
- ""Normal"": {
- ""Foreground"": ""BrightGreen"",
- ""Background"": ""Black""
- },
- ""Focus"": {
- ""Foreground"": ""White"",
- ""Background"": ""Cyan""
- },
- ""HotNormal"": {
- ""Foreground"": ""Yellow"",
- ""Background"": ""Black""
- },
- ""HotFocus"": {
- ""Foreground"": ""Blue"",
- ""Background"": ""Cyan""
- },
- ""Disabled"": {
- ""Foreground"": ""DarkGray"",
- ""Background"": ""Black""
- }
- }
- },
- {
- ""Base"": {
- ""Normal"": {
- ""Foreground"": ""White"",
- ""Background"": ""Blue""
- },
- ""Focus"": {
- ""Foreground"": ""Black"",
- ""Background"": ""Gray""
- },
- ""HotNormal"": {
- ""Foreground"": ""BrightCyan"",
- ""Background"": ""Blue""
- },
- ""HotFocus"": {
- ""Foreground"": ""BrightBlue"",
- ""Background"": ""Gray""
- },
- ""Disabled"": {
- ""Foreground"": ""DarkGray"",
- ""Background"": ""Blue""
- }
- }
- },
- {
- ""Dialog"": {
- ""Normal"": {
- ""Foreground"": ""Black"",
- ""Background"": ""Gray""
- },
- ""Focus"": {
- ""Foreground"": ""White"",
- ""Background"": ""DarkGray""
- },
- ""HotNormal"": {
- ""Foreground"": ""Blue"",
- ""Background"": ""Gray""
- },
- ""HotFocus"": {
- ""Foreground"": ""BrightYellow"",
- ""Background"": ""DarkGray""
- },
- ""Disabled"": {
- ""Foreground"": ""Gray"",
- ""Background"": ""DarkGray""
- }
- }
- },
- {
- ""Menu"": {
- ""Normal"": {
- ""Foreground"": ""White"",
- ""Background"": ""DarkGray""
- },
- ""Focus"": {
- ""Foreground"": ""White"",
- ""Background"": ""Black""
- },
- ""HotNormal"": {
- ""Foreground"": ""BrightYellow"",
- ""Background"": ""DarkGray""
- },
- ""HotFocus"": {
- ""Foreground"": ""BrightYellow"",
- ""Background"": ""Black""
- },
- ""Disabled"": {
- ""Foreground"": ""Gray"",
- ""Background"": ""DarkGray""
- }
- }
- },
- {
- ""Error"": {
- ""Normal"": {
- ""Foreground"": ""Red"",
- ""Background"": ""White""
- },
- ""Focus"": {
- ""Foreground"": ""Black"",
- ""Background"": ""BrightRed""
- },
- ""HotNormal"": {
- ""Foreground"": ""Black"",
- ""Background"": ""White""
- },
- ""HotFocus"": {
- ""Foreground"": ""White"",
- ""Background"": ""BrightRed""
- },
- ""Disabled"": {
- ""Foreground"": ""DarkGray"",
- ""Background"": ""White""
- }
- }
- }
- ]
- }
- }
- ]
- }
- ";
- //ResetToCurrentValues ();
- ThrowOnJsonErrors = true;
- ConfigurationManager.SourcesManager?.Load (Settings, json, "UpdateFromJson", ConfigLocations.Runtime);
- Assert.Equal ("Default", ThemeManager.Theme);
- Assert.Equal (KeyCode.Esc, Application.QuitKey.KeyCode);
- Assert.Equal (KeyCode.Z | KeyCode.AltMask, ((Key)Settings! ["Application.QuitKey"].PropertyValue)!.KeyCode);
- Assert.Equal (Alignment.Center, MessageBox.DefaultButtonAlignment);
- // Now Apply
- Apply ();
- Assert.Equal ("Default", ThemeManager.Theme);
- Assert.Equal (KeyCode.Z | KeyCode.AltMask, Application.QuitKey.KeyCode);
- Assert.Equal (Alignment.End, MessageBox.DefaultButtonAlignment);
- Assert.Equal (Color.White, SchemeManager.GetSchemes ()! ["Base"].Normal.Foreground);
- Assert.Equal (Color.Blue, SchemeManager.GetSchemes ()! ["Base"].Normal.Background);
- }
- finally
- {
- output.WriteLine ("Disabling CM to clean up.");
- Disable (true);
- }
- }
- }
|