| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418 |
- 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"": [
- {
- ""Runnable"": {
- ""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"": [
- {
- ""Runnable"": {
- ""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);
- }
- }
- [ConfigurationProperty (Scope = typeof (CMTestsScope))]
- public static bool? TestProperty { get; set; }
- private class CMTestsScope : Scope<CMTestsScope>
- {
- }
- [Fact]
- public void GetConfigPropertiesByScope_Gets ()
- {
- var props = GetUninitializedConfigPropertiesByScope ("CMTestsScope");
- Assert.NotNull (props);
- Assert.NotEmpty (props);
- }
- }
|