Files
Terminal.Gui/Tests/UnitTests/Configuration/SettingsScopeTests.cs
Tig fdeaa8331b Fixes #4298 - Updates test namespaces (#4299)
* Refactored test namespaces.
Moved some tests that were in wrong project.
Code cleanup

* Parrallel -> Parallel
2025-10-20 14:14:38 -06:00

353 lines
12 KiB
C#

#nullable enable
using System.Collections.Concurrent;
using System.Collections.Frozen;
using System.Collections.Immutable;
using System.Text.Json;
using static Terminal.Gui.Configuration.ConfigurationManager;
namespace UnitTests.ConfigurationTests;
public class SettingsScopeTests
{
[Fact]
public void Load_Overrides_Defaults ()
{
// arrange
Enable (ConfigLocations.HardCoded);
Assert.Equal (Key.Esc, (Key)Settings! ["Application.QuitKey"].PropertyValue!);
ThrowOnJsonErrors = true;
// act
RuntimeConfig = """
{
"Application.QuitKey": "Ctrl-Q"
}
""";
Load (ConfigLocations.Runtime);
// assert
Assert.Equal (Key.Q.WithCtrl, (Key)Settings ["Application.QuitKey"].PropertyValue!);
// clean up
Disable (true);
}
[Fact]
public void Load_Dictionary_Property_Overrides_Defaults ()
{
// arrange
Enable (ConfigLocations.HardCoded);
ThrowOnJsonErrors = true;
ConfigProperty themesConfigProperty = Settings! ["Themes"];
ConcurrentDictionary<string, ThemeScope> dict = (themesConfigProperty.PropertyValue as ConcurrentDictionary<string, ThemeScope>)!;
Assert.NotNull (dict);
Assert.Single (dict);
Assert.NotEmpty (((ConcurrentDictionary<string, ThemeScope>)themesConfigProperty.PropertyValue!)!);
ThemeScope scope = dict [ThemeManager.DEFAULT_THEME_NAME];
Assert.NotNull (scope);
Assert.Equal (MouseState.In | MouseState.Pressed | MouseState.PressedOutside, scope ["Button.DefaultHighlightStates"].PropertyValue);
RuntimeConfig = """
{
"Themes": [
{
"Default":
{
"Button.DefaultHighlightStates": "None"
}
},
{
"NewTheme":
{
"Button.DefaultHighlightStates": "In"
}
}
]
}
""";
Load (ConfigLocations.Runtime);
// assert
Assert.Equal (2, ThemeManager.Themes!.Count);
Assert.Equal (MouseState.None, (MouseState)ThemeManager.GetCurrentTheme () ["Button.DefaultHighlightStates"].PropertyValue!);
Assert.Equal (MouseState.In, (MouseState)ThemeManager.Themes ["NewTheme"] ["Button.DefaultHighlightStates"].PropertyValue!);
RuntimeConfig = """
{
"Themes": [
{
"Default":
{
"Button.DefaultHighlightStates": "Pressed"
}
}
]
}
""";
Load (ConfigLocations.Runtime);
// assert
Assert.Equal (2, ThemeManager.Themes.Count);
Assert.Equal (MouseState.Pressed, (MouseState)ThemeManager.Themes! [ThemeManager.DEFAULT_THEME_NAME] ["Button.DefaultHighlightStates"].PropertyValue!);
Assert.Equal (MouseState.In, (MouseState)ThemeManager.Themes! ["NewTheme"] ["Button.DefaultHighlightStates"].PropertyValue!);
// clean up
Disable (true);
}
[Fact]
public void Apply_ShouldApplyProperties ()
{
Enable (ConfigLocations.HardCoded);
Load (ConfigLocations.LibraryResources);
// arrange
Assert.Equal (Key.Esc, (Key)Settings! ["Application.QuitKey"].PropertyValue!);
Assert.Equal (
Key.F6,
(Key)Settings ["Application.NextTabGroupKey"].PropertyValue!
);
Assert.Equal (
Key.F6.WithShift,
(Key)Settings ["Application.PrevTabGroupKey"].PropertyValue!
);
// act
Settings ["Application.QuitKey"].PropertyValue = Key.Q;
Settings ["Application.NextTabGroupKey"].PropertyValue = Key.F;
Settings ["Application.PrevTabGroupKey"].PropertyValue = Key.B;
Settings.Apply ();
// assert
Assert.Equal (Key.Q, Application.QuitKey);
Assert.Equal (Key.F, Application.NextTabGroupKey);
Assert.Equal (Key.B, Application.PrevTabGroupKey);
Disable (true);
}
[Fact]
public void CopyUpdatedPropertiesFrom_ShouldCopyChangedPropertiesOnly ()
{
Enable (ConfigLocations.HardCoded);
Settings! ["Application.QuitKey"].PropertyValue = Key.End;
var updatedSettings = new SettingsScope ();
updatedSettings.LoadHardCodedDefaults ();
// Don't set Quitkey
updatedSettings ["Application.QuitKey"].HasValue = false;
updatedSettings ["Application.QuitKey"].PropertyValue = null;
updatedSettings ["Application.NextTabGroupKey"].PropertyValue = Key.F;
updatedSettings ["Application.PrevTabGroupKey"].PropertyValue = Key.B;
Settings.UpdateFrom (updatedSettings);
Assert.Equal (KeyCode.End, ((Key)Settings ["Application.QuitKey"].PropertyValue!).KeyCode);
Assert.Equal (KeyCode.F, ((Key)updatedSettings ["Application.NextTabGroupKey"].PropertyValue!).KeyCode);
Assert.Equal (KeyCode.B, ((Key)updatedSettings ["Application.PrevTabGroupKey"].PropertyValue!).KeyCode);
Disable (true);
}
[Fact]
public void ResetToHardCodedDefaults_Resets_Config_And_Applies ()
{
try
{
Enable (ConfigLocations.HardCoded);
Load (ConfigLocations.LibraryResources);
Assert.True (Settings! ["Application.QuitKey"].PropertyValue is Key);
Assert.Equal (Key.Esc, Settings ["Application.QuitKey"].PropertyValue as Key);
Settings ["Application.QuitKey"].PropertyValue = Key.Q;
Apply ();
Assert.Equal (Key.Q, Application.QuitKey);
// Act
ResetToHardCodedDefaults ();
Assert.Equal (Key.Esc, Settings ["Application.QuitKey"].PropertyValue as Key);
Assert.Equal (Key.Esc, Application.QuitKey);
}
finally
{
Disable (true);
}
}
[Fact]
public void Themes_Property_Exists ()
{
var settingsScope = new SettingsScope ();
Assert.NotEmpty (settingsScope);
// Themes exists, but is not initialized
Assert.Null (settingsScope ["Themes"].PropertyValue);
//settingsScope.UpdateToCurrentValues ();
//Assert.NotEmpty (settingsScope);
}
[Fact]
public void LoadHardCodedDefaults_Resets ()
{
// Arrange
Assert.Equal (Key.Esc, Application.QuitKey);
var settingsScope = new SettingsScope ();
settingsScope.LoadHardCodedDefaults ();
// Act
settingsScope ["Application.QuitKey"].PropertyValue = Key.Q;
settingsScope.Apply ();
Assert.Equal (Key.Q, Application.QuitKey);
settingsScope.LoadHardCodedDefaults ();
settingsScope.Apply ();
// Assert
Assert.Equal (Key.Esc, Application.QuitKey);
Disable (true);
}
private class ConfigPropertyMock
{
public object? PropertyValue { get; init; }
public bool Immutable { get; init; }
}
private class SettingsScopeMock : Dictionary<string, ConfigPropertyMock>
{
public string? Theme { get; set; }
}
[Fact]
public void SettingsScopeMockWithKey_CreatesDeepCopy ()
{
SettingsScopeMock? source = new ()
{
Theme = "Dark",
["KeyBinding"] = new () { PropertyValue = new Key (KeyCode.A) { Handled = true } },
["Counts"] = new () { PropertyValue = new Dictionary<string, int> { { "X", 1 } } }
};
SettingsScopeMock? result = DeepCloner.DeepClone (source);
Assert.NotNull (result);
Assert.NotSame (source, result);
Assert.Equal (source.Theme, result!.Theme);
Assert.NotSame (source ["KeyBinding"], result ["KeyBinding"]);
Assert.NotSame (source ["Counts"], result ["Counts"]);
ConfigPropertyMock clonedKeyProp = result ["KeyBinding"];
var clonedKey = (Key)clonedKeyProp.PropertyValue!;
Assert.NotSame (source ["KeyBinding"].PropertyValue, clonedKey);
Assert.Equal (((Key)source ["KeyBinding"].PropertyValue!).KeyCode, clonedKey.KeyCode);
Assert.Equal (((Key)source ["KeyBinding"].PropertyValue!).Handled, clonedKey.Handled);
Assert.Equal ((Dictionary<string, int>)source ["Counts"].PropertyValue!, (Dictionary<string, int>)result ["Counts"].PropertyValue!);
// Modify result, ensure source unchanged
result.Theme = "Light";
clonedKey.Handled = false;
((Dictionary<string, int>)result ["Counts"].PropertyValue!).Add ("Y", 2);
Assert.Equal ("Dark", source.Theme);
Assert.True (((Key)source ["KeyBinding"].PropertyValue!).Handled);
Assert.Single ((Dictionary<string, int>)source ["Counts"].PropertyValue!);
Disable (true);
}
[Fact /*(Skip = "This test randomly fails due to a concurrent change to something. Needs to be moved to non-parallel tests.")*/]
public void ThemeScopeList_WithThemes_ClonesSuccessfully ()
{
// Arrange: Create a ThemeScope and verify a property exists
var defaultThemeScope = new ThemeScope ();
defaultThemeScope.LoadHardCodedDefaults ();
Assert.True (defaultThemeScope.ContainsKey ("Button.DefaultHighlightStates"));
var darkThemeScope = new ThemeScope ();
darkThemeScope.LoadHardCodedDefaults ();
Assert.True (darkThemeScope.ContainsKey ("Button.DefaultHighlightStates"));
// Create a Themes list with two themes
List<Dictionary<string, ThemeScope>> themesList =
[
new () { { "Default", defaultThemeScope } },
new () { { "Dark", darkThemeScope } }
];
// Create a SettingsScope and set the Themes property
var settingsScope = new SettingsScope ();
settingsScope.LoadHardCodedDefaults ();
Assert.True (settingsScope.ContainsKey ("Themes"));
settingsScope ["Themes"].PropertyValue = themesList;
// Act
SettingsScope? result = DeepCloner.DeepClone (settingsScope);
// Assert
Assert.NotNull (result);
Assert.IsType<SettingsScope> (result);
var resultScope = result;
Assert.True (resultScope.ContainsKey ("Themes"));
Assert.NotNull (resultScope ["Themes"].PropertyValue);
List<Dictionary<string, ThemeScope>> clonedThemes = (List<Dictionary<string, ThemeScope>>)resultScope ["Themes"].PropertyValue!;
Assert.Equal (2, clonedThemes.Count);
Disable (true);
}
[Fact]
public void Empty_SettingsScope_ClonesSuccessfully ()
{
// Arrange: Create a SettingsScope
var settingsScope = new SettingsScope ();
Assert.True (settingsScope.ContainsKey ("Themes"));
// Act
SettingsScope? result = DeepCloner.DeepClone (settingsScope);
// Assert
Assert.NotNull (result);
Assert.IsType<SettingsScope> (result);
Assert.True (result.ContainsKey ("Themes"));
Disable (true);
}
[Fact]
public void SettingsScope_With_Themes_Set_ClonesSuccessfully ()
{
// Arrange: Create a SettingsScope
var settingsScope = new SettingsScope ();
Assert.True (settingsScope.ContainsKey ("Themes"));
settingsScope ["Themes"].PropertyValue = new List<Dictionary<string, ThemeScope>>
{
new () { { "Default", new () } },
new () { { "Dark", new () } }
};
// Act
SettingsScope? result = DeepCloner.DeepClone (settingsScope);
// Assert
Assert.NotNull (result);
Assert.IsType<SettingsScope> (result);
Assert.True (result.ContainsKey ("Themes"));
Assert.NotNull (result ["Themes"].PropertyValue);
Disable (true);
}
}