From c2c5a37ca70de423dd8360211f192c811d8314f9 Mon Sep 17 00:00:00 2001 From: Tig Date: Fri, 22 Nov 2024 11:03:02 -0700 Subject: [PATCH] Fixed CM bugs. Added unit tests. Trying to figure out why TryGet is not working properly --- .../Application/Application.Initialization.cs | 6 +- Terminal.Gui/Application/Application.Run.cs | 2 +- Terminal.Gui/Configuration/ConfigLocations.cs | 57 +++++++++ Terminal.Gui/Configuration/ConfigProperty.cs | 9 +- .../Configuration/ConfigurationManager.cs | 119 +++++++++--------- Terminal.Gui/Configuration/SettingsScope.cs | 7 +- Terminal.Gui/Configuration/ThemeManager.cs | 2 +- Terminal.Gui/Input/Key.cs | 15 ++- Terminal.Gui/Input/KeyBindings.cs | 12 +- UnitTests/Application/ApplicationTests.cs | 44 ++++++- UnitTests/Configuration/AppScopeTests.cs | 2 +- .../Configuration/ConfigurationMangerTests.cs | 104 ++++++++++----- .../Configuration/KeyJsonConverterTests.cs | 14 +++ UnitTests/Configuration/SettingsScopeTests.cs | 40 +++++- UnitTests/Configuration/ThemeScopeTests.cs | 8 +- UnitTests/Configuration/ThemeTests.cs | 4 +- UnitTests/Input/KeyBindingTests.cs | 13 ++ UnitTests/Input/KeyTests.cs | 4 + UnitTests/TestHelpers.cs | 4 +- UnitTests/UICatalog/ScenarioTests.cs | 16 +-- UnitTests/View/ViewTests.cs | 2 +- UnitTests/Views/ComboBoxTests.cs | 2 +- UnitTests/Views/MenuBarTests.cs | 4 +- UnitTests/Views/TabViewTests.cs | 2 +- UnitTests/Views/TableViewTests.cs | 18 +-- UnitTests/Views/TextViewTests.cs | 4 +- UnitTests/Views/TreeTableSourceTests.cs | 2 +- 27 files changed, 376 insertions(+), 140 deletions(-) create mode 100644 Terminal.Gui/Configuration/ConfigLocations.cs diff --git a/Terminal.Gui/Application/Application.Initialization.cs b/Terminal.Gui/Application/Application.Initialization.cs index 3d47aeb41..47c07a19f 100644 --- a/Terminal.Gui/Application/Application.Initialization.cs +++ b/Terminal.Gui/Application/Application.Initialization.cs @@ -86,12 +86,14 @@ public static partial class Application // Initialization (Init/Shutdown) // We're running unit tests. Disable loading config files other than default if (Locations == ConfigLocations.All) { - Locations = ConfigLocations.DefaultOnly; + Locations = ConfigLocations.Default; Reset (); } } } + AddApplicationKeyBindings (); + // Start the process of configuration management. // Note that we end up calling LoadConfigurationFromAllSources // multiple times. We need to do this because some settings are only @@ -106,8 +108,6 @@ public static partial class Application // Initialization (Init/Shutdown) } Apply (); - AddApplicationKeyBindings (); - // Ignore Configuration for ForceDriver if driverName is specified if (!string.IsNullOrEmpty (driverName)) { diff --git a/Terminal.Gui/Application/Application.Run.cs b/Terminal.Gui/Application/Application.Run.cs index 898fc935b..5c326e20c 100644 --- a/Terminal.Gui/Application/Application.Run.cs +++ b/Terminal.Gui/Application/Application.Run.cs @@ -16,7 +16,7 @@ public static partial class Application // Run (Begin, Run, End, Stop) get => _quitKey; set { - if (_quitKey != value) + //if (_quitKey != value) { ReplaceKey (_quitKey, value); _quitKey = value; diff --git a/Terminal.Gui/Configuration/ConfigLocations.cs b/Terminal.Gui/Configuration/ConfigLocations.cs new file mode 100644 index 000000000..cf84a068f --- /dev/null +++ b/Terminal.Gui/Configuration/ConfigLocations.cs @@ -0,0 +1,57 @@ +#nullable enable +namespace Terminal.Gui; + +/// +/// Describes the location of the configuration files. The constants can be combined (bitwise) to specify multiple +/// locations. The more significant the bit, the higher the priority meaning that the last location will override the +/// earlier ones. +/// + +[Flags] +public enum ConfigLocations +{ + /// No configuration will be loaded. + /// + /// Used for development and testing only. For Terminal,Gui to function properly, at least + /// should be set. + /// + None = 0, + + /// + /// Deafult configuration in Terminal.Gui.dll's resources (Terminal.Gui.Resources.config.json). + /// + Default = 0b_0000_0001, + + /// + /// Global settings in the current directory (e.g. ./.tui/config.json). + /// + GlobalCurrent = 0b_0000_0010, + + /// + /// Global settings in the home directory (e.g. ~/.tui/config.json). + /// + GlobalHome = 0b_0000_0100, + + /// + /// App resources (e.g. MyApp.Resources.config.json). + /// + AppResources = 0b_0000_1000, + + /// + /// App settings in the current directory (e.g. ./.tui/MyApp.config.json). + /// + AppCurrent = 0b_0001_0000, + + /// + /// App settings in the home directory (e.g. ~/.tui/MyApp.config.json). + /// + AppHome = 0b_0010_0000, + + /// + /// Settings in . + /// + Memory = 0b_0100_0000, + + /// This constant is a combination of all locations + All = 0b_1111_1111 +} diff --git a/Terminal.Gui/Configuration/ConfigProperty.cs b/Terminal.Gui/Configuration/ConfigProperty.cs index 0c4a41682..272c22d92 100644 --- a/Terminal.Gui/Configuration/ConfigProperty.cs +++ b/Terminal.Gui/Configuration/ConfigProperty.cs @@ -31,7 +31,7 @@ public class ConfigProperty /// public object? PropertyValue { get; set; } - /// Applies the to the property described by . + /// Applies the to the static property described by . /// public bool Apply () { @@ -94,6 +94,13 @@ public class ConfigProperty /// public object? RetrieveValue () { return PropertyValue = PropertyInfo!.GetValue (null); } + /// + /// Updates (using reflection) with + /// the value in . + /// + /// + /// + /// internal object? UpdateValueFrom (object source) { if (source is null) diff --git a/Terminal.Gui/Configuration/ConfigurationManager.cs b/Terminal.Gui/Configuration/ConfigurationManager.cs index cd5befa16..4735aa53a 100644 --- a/Terminal.Gui/Configuration/ConfigurationManager.cs +++ b/Terminal.Gui/Configuration/ConfigurationManager.cs @@ -24,7 +24,7 @@ namespace Terminal.Gui; /// /// /// Settings are defined in JSON format, according to this schema: -/// https://gui-cs.github.io/Terminal.GuiV2Docs/schemas/tui-config-schema.json +/// https://gui-cs.github.io/Terminal.GuiV2Docs/schemas/tui-config-schema.json /// /// /// Settings that will apply to all applications (global settings) reside in files named config.json. @@ -53,30 +53,6 @@ namespace Terminal.Gui; [ComponentGuarantees (ComponentGuaranteesOptions.None)] public static class ConfigurationManager { - /// - /// Describes the location of the configuration files. The constants can be combined (bitwise) to specify multiple - /// locations. - /// - [Flags] - public enum ConfigLocations - { - /// No configuration will be loaded. - /// - /// Used for development and testing only. For Terminal,Gui to function properly, at least - /// should be set. - /// - None = 0, - - /// - /// Global configuration in Terminal.Gui.dll's resources (Terminal.Gui.Resources.config.json) -- - /// Lowest Precedence. - /// - DefaultOnly, - - /// This constant is a combination of all locations - All = -1 - } - /// /// A dictionary of all properties in the Terminal.Gui project that are decorated with the /// attribute. The keys are the property names pre-pended with the @@ -201,6 +177,7 @@ public static class ConfigurationManager { // First start. Apply settings first. This ensures if a config sets Theme to something other than "Default", it gets used settings = Settings?.Apply () ?? false; + themes = !string.IsNullOrEmpty (ThemeManager.SelectedTheme) && (ThemeManager.Themes? [ThemeManager.SelectedTheme]?.Apply () ?? false); } @@ -210,6 +187,7 @@ public static class ConfigurationManager themes = ThemeManager.Themes? [ThemeManager.SelectedTheme]?.Apply () ?? false; settings = Settings?.Apply () ?? false; } + appSettings = AppSettings?.Apply () ?? false; } catch (JsonException e) @@ -243,14 +221,23 @@ public static class ConfigurationManager } /// - /// Loads all settings found in the various configuration storage locations to the - /// . Optionally, resets all settings attributed with + /// Gets or sets the in-memory config.json. See . + /// + public static string? Memory { get; set; } + + /// + /// Loads all settings found in the configuration storage locations (). Optionally, resets + /// all settings attributed with /// to the defaults. /// - /// Use to cause the loaded settings to be applied to the running application. + /// + /// + /// Use to cause the loaded settings to be applied to the running application. + /// + /// /// /// If the state of will be reset to the - /// defaults. + /// defaults (). /// [RequiresUnreferencedCode ("AOT")] [RequiresDynamicCode ("AOT")] @@ -263,8 +250,23 @@ public static class ConfigurationManager Reset (); } - // LibraryResources is always loaded by Reset - if (Locations == ConfigLocations.All) + // Deafult is always loaded by Reset, so only load it if reset is false + if (!reset && Locations.HasFlag (ConfigLocations.Default)) + { + Settings?.UpdateFromResource (typeof (ConfigurationManager).Assembly, $"Terminal.Gui.Resources.{_configFilename}"); + } + + if (Locations.HasFlag (ConfigLocations.GlobalCurrent)) + { + Settings?.Update ($"./.tui/{_configFilename}"); + } + + if (Locations.HasFlag (ConfigLocations.GlobalHome)) + { + Settings?.Update ($"~/.tui/{_configFilename}"); + } + + if (Locations.HasFlag (ConfigLocations.AppResources)) { string? embeddedStylesResourceName = Assembly.GetEntryAssembly () ? @@ -276,26 +278,22 @@ public static class ConfigurationManager embeddedStylesResourceName = _configFilename; } - Settings = Settings? + Settings?.UpdateFromResource (Assembly.GetEntryAssembly ()!, embeddedStylesResourceName!); + } - // Global current directory - .Update ($"./.tui/{_configFilename}") - ? + if (Locations.HasFlag (ConfigLocations.AppCurrent)) + { + Settings?.Update ($"./.tui/{AppName}.{_configFilename}"); + } - // Global home directory - .Update ($"~/.tui/{_configFilename}") - ? + if (Locations.HasFlag (ConfigLocations.AppHome)) + { + Settings?.Update ($"~/.tui/{AppName}.{_configFilename}"); + } - // App resources - .UpdateFromResource (Assembly.GetEntryAssembly ()!, embeddedStylesResourceName!) - ? - - // App current directory - .Update ($"./.tui/{AppName}.{_configFilename}") - ? - - // App home directory - .Update ($"~/.tui/{AppName}.{_configFilename}"); + if (Locations.HasFlag (ConfigLocations.Memory) && !string.IsNullOrEmpty(Memory)) + { + Settings?.Update (Memory, "ConfigurationManager.Memory"); } } @@ -314,12 +312,13 @@ public static class ConfigurationManager } /// - /// Called when the configuration has been updated from a configuration file. Invokes the + /// Called when the configuration has been updated from a configuration file or reset. Invokes the + /// /// event. /// public static void OnUpdated () { - Debug.WriteLine (@"ConfigurationManager.OnApplied()"); + Debug.WriteLine (@"ConfigurationManager.OnUpdated()"); Updated?.Invoke (null, new ()); } @@ -359,7 +358,7 @@ public static class ConfigurationManager AppSettings = new (); // To enable some unit tests, we only load from resources if the flag is set - if (Locations.HasFlag (ConfigLocations.DefaultOnly)) + if (Locations.HasFlag (ConfigLocations.Default)) { Settings.UpdateFromResource ( typeof (ConfigurationManager).Assembly, @@ -367,12 +366,14 @@ public static class ConfigurationManager ); } + OnUpdated (); + Apply (); ThemeManager.Themes? [ThemeManager.SelectedTheme]?.Apply (); AppSettings?.Apply (); } - /// Event fired when the configuration has been updated from a configuration source. application. + /// Event fired when the configuration has been updated from a configuration source or reset. public static event EventHandler? Updated; internal static void AddJsonError (string error) @@ -481,9 +482,9 @@ public static class ConfigurationManager } /// - /// Retrieves the hard coded default settings from the Terminal.Gui library implementation. Used in development of - /// the library to generate the default configuration file. Before calling Application.Init, make sure - /// is set to . + /// Retrieves the hard coded default settings (static properites) from the Terminal.Gui library implementation. Used in + /// development of + /// the library to generate the default configuration file. /// /// /// @@ -577,17 +578,13 @@ public static class ConfigurationManager scp.OmitClassName ? ConfigProperty.GetJsonPropertyName (p) : $"{p.DeclaringType?.Name}.{p.Name}", - new() { PropertyInfo = p, PropertyValue = null } + new () { PropertyInfo = p, PropertyValue = null } ); } else { throw new ( - $"Property { - p.Name - } in class { - p.DeclaringType?.Name - } is not static. All SerializableConfigurationProperty properties must be static." + $"Property {p.Name} in class {p.DeclaringType?.Name} is not static. All SerializableConfigurationProperty properties must be static." ); } } diff --git a/Terminal.Gui/Configuration/SettingsScope.cs b/Terminal.Gui/Configuration/SettingsScope.cs index 2ac4bf4c1..983d790a1 100644 --- a/Terminal.Gui/Configuration/SettingsScope.cs +++ b/Terminal.Gui/Configuration/SettingsScope.cs @@ -117,8 +117,13 @@ public class SettingsScope : Scope /// The source (filename/resource name) the Json document was read from. [RequiresUnreferencedCode ("AOT")] [RequiresDynamicCode ("AOT")] - public SettingsScope? Update (string json, string source) + public SettingsScope? Update (string? json, string source) { + //if (string.IsNullOrEmpty (json)) + //{ + // Debug.WriteLine ($"ConfigurationManager: Configuration file \"{source}\" is empty."); + // return this; + //} var stream = new MemoryStream (); var writer = new StreamWriter (stream); writer.Write (json); diff --git a/Terminal.Gui/Configuration/ThemeManager.cs b/Terminal.Gui/Configuration/ThemeManager.cs index b542c9f2c..86224c45c 100644 --- a/Terminal.Gui/Configuration/ThemeManager.cs +++ b/Terminal.Gui/Configuration/ThemeManager.cs @@ -148,7 +148,7 @@ public class ThemeManager : IDictionary internal static void Reset () { Debug.WriteLine ("Themes.Reset()"); - Colors.Reset (); + Colors.Reset (); Themes?.Clear (); SelectedTheme = string.Empty; } diff --git a/Terminal.Gui/Input/Key.cs b/Terminal.Gui/Input/Key.cs index 11f8d938e..204eda17a 100644 --- a/Terminal.Gui/Input/Key.cs +++ b/Terminal.Gui/Input/Key.cs @@ -393,24 +393,31 @@ public class Key : EventArgs, IEquatable public static implicit operator string (Key key) { return key.ToString (); } /// - public override bool Equals (object obj) { return obj is Key k && k.KeyCode == KeyCode && k.Handled == Handled; } + public override bool Equals (object obj) + { + if (obj is Key other) + { + return other._keyCode == _keyCode && other.Handled == Handled; + } + return false; + } bool IEquatable.Equals (Key other) { return Equals (other); } /// - public override int GetHashCode () { return (int)KeyCode; } + public override int GetHashCode () { return (int)_keyCode; } /// Compares two s for equality. /// /// /// - public static bool operator == (Key a, Key b) { return a?.KeyCode == b?.KeyCode; } + public static bool operator == (Key a, Key b) { return a!.Equals(b); } /// Compares two s for not equality. /// /// /// - public static bool operator != (Key a, Key b) { return a?.KeyCode != b?.KeyCode; } + public static bool operator != (Key a, Key b) { return !a!.Equals (b); } /// Compares two s for less-than. /// diff --git a/Terminal.Gui/Input/KeyBindings.cs b/Terminal.Gui/Input/KeyBindings.cs index e2f0ed8be..39bcc83af 100644 --- a/Terminal.Gui/Input/KeyBindings.cs +++ b/Terminal.Gui/Input/KeyBindings.cs @@ -388,15 +388,23 @@ public class KeyBindings /// if the Key is bound; otherwise . public bool TryGet (Key key, KeyBindingScope scope, out KeyBinding binding) { - binding = new (Array.Empty (), KeyBindingScope.Disabled, null); + if (!key.IsValid) + { + binding = new (Array.Empty (), KeyBindingScope.Disabled, null); + return false; + } - if (key.IsValid && Bindings.TryGetValue (key, out binding)) + if (Bindings.TryGetValue (key, out binding)) { if (scope.HasFlag (binding.Scope)) { return true; } } + else + { + binding = new (Array.Empty (), KeyBindingScope.Disabled, null); + } return false; } diff --git a/UnitTests/Application/ApplicationTests.cs b/UnitTests/Application/ApplicationTests.cs index 3428fcd15..9fe0f8ef1 100644 --- a/UnitTests/Application/ApplicationTests.cs +++ b/UnitTests/Application/ApplicationTests.cs @@ -1,4 +1,5 @@ using Xunit.Abstractions; +using static Terminal.Gui.ConfigurationManager; // Alias Console to MockConsole so we don't accidentally use Console @@ -10,7 +11,7 @@ public class ApplicationTests { _output = output; ConsoleDriver.RunningUnitTests = true; - ConfigurationManager.Locations = ConfigurationManager.ConfigLocations.None; + ConfigurationManager.Locations = ConfigLocations.Default; #if DEBUG_IDISPOSABLE View.Instances.Clear (); @@ -520,6 +521,47 @@ public class ApplicationTests Application.ResetState (); } + [Fact] + public void Init_KeyBindings_Set_To_Defaults () + { + // arrange + Locations = ConfigLocations.All; + ThrowOnJsonErrors = true; + + Application.QuitKey = Key.Q; + + Application.Init (new FakeDriver ()); + + Assert.Equal (Key.Esc, Application.QuitKey); + + Application.Shutdown (); + } + + [Fact] + public void Init_KeyBindings_Set_To_Custom () + { + // arrange + Locations = ConfigLocations.Memory; + ThrowOnJsonErrors = true; + + Memory = """ + + { + "Application.QuitKey": "Ctrl-Q" + } + """; + + Assert.Equal (Key.Esc, Application.QuitKey); + + // Act + Application.Init (new FakeDriver ()); + + Assert.Equal (Key.Q.WithCtrl, Application.QuitKey); + + Application.Shutdown (); + Locations = ConfigLocations.Default; + } + [Fact] [AutoInitShutdown (verifyShutdown: true)] public void Internal_Properties_Correct () diff --git a/UnitTests/Configuration/AppScopeTests.cs b/UnitTests/Configuration/AppScopeTests.cs index 059f724d2..d09e74f1d 100644 --- a/UnitTests/Configuration/AppScopeTests.cs +++ b/UnitTests/Configuration/AppScopeTests.cs @@ -15,7 +15,7 @@ public class AppScopeTests }; [Fact] - [AutoInitShutdown (configLocation: ConfigLocations.DefaultOnly)] + [AutoInitShutdown (configLocation: ConfigLocations.Default)] public void Apply_ShouldApplyUpdatedProperties () { Reset (); diff --git a/UnitTests/Configuration/ConfigurationMangerTests.cs b/UnitTests/Configuration/ConfigurationMangerTests.cs index 5f8e767c0..0b3d05601 100644 --- a/UnitTests/Configuration/ConfigurationMangerTests.cs +++ b/UnitTests/Configuration/ConfigurationMangerTests.cs @@ -21,7 +21,7 @@ public class ConfigurationManagerTests }; [Fact] - public void Apply_FiresApplied () + public void Apply_Raises_Applied () { Reset (); Applied += ConfigurationManager_Applied; @@ -147,45 +147,60 @@ public class ConfigurationManagerTests } [Fact] - public void Load_FiresUpdated () + public void Load_Raises_Updated () { - ConfigLocations savedLocations = Locations; Locations = ConfigLocations.All; Reset (); - - Settings! ["Application.QuitKey"].PropertyValue = Key.Q; - Settings ["Application.NextTabGroupKey"].PropertyValue = Key.F; - Settings ["Application.PrevTabGroupKey"].PropertyValue = Key.B; + Assert.Equal (Key.Esc, (((Key)Settings! ["Application.QuitKey"].PropertyValue)!).KeyCode); Updated += ConfigurationManager_Updated; var fired = false; - void ConfigurationManager_Updated (object sender, ConfigurationManagerEventArgs obj) + void ConfigurationManager_Updated (object? sender, ConfigurationManagerEventArgs obj) { fired = true; - - // assert - Assert.Equal (Key.Esc, (((Key)Settings! ["Application.QuitKey"].PropertyValue)!).KeyCode); - - Assert.Equal ( - KeyCode.F6, - (((Key)Settings ["Application.NextTabGroupKey"].PropertyValue)!).KeyCode - ); - - Assert.Equal ( - KeyCode.F6 | KeyCode.ShiftMask, - (((Key)Settings ["Application.PrevTabGroupKey"].PropertyValue)!).KeyCode - ); } - Load (true); + // Act + // Do NOT reset + Load (false); // assert Assert.True (fired); Updated -= ConfigurationManager_Updated; + + // clean up + Locations = ConfigLocations.Default; + Reset (); + } + + + [Fact] + public void Load_Loads_Custom_Json () + { + // arrange + Locations = ConfigLocations.All; + Reset (); + ThrowOnJsonErrors = true; + + Assert.Equal (Key.Esc, (Key)Settings! ["Application.QuitKey"].PropertyValue); + + // act + Memory = """ + + { + "Application.QuitKey": "Ctrl-Q" + } + """; + Load (false); + + // assert + Assert.Equal (Key.Q.WithCtrl, (Key)Settings ["Application.QuitKey"].PropertyValue); + + // clean up + Locations = ConfigLocations.Default; Reset (); - Locations = savedLocations; } [Fact] @@ -224,10 +239,40 @@ public class ConfigurationManagerTests //Assert.Equal ("AppSpecific", ConfigurationManager.Config.Settings.TestSetting); } + + [Fact] + public void Reset_Raises_Updated () + { + ConfigLocations savedLocations = Locations; + Locations = ConfigLocations.All; + Reset (); + + Settings! ["Application.QuitKey"].PropertyValue = Key.Q; + + Updated += ConfigurationManager_Updated; + var fired = false; + + void ConfigurationManager_Updated (object? sender, ConfigurationManagerEventArgs obj) + { + fired = true; + } + + // Act + Reset (); + + // assert + Assert.True (fired); + + Updated -= ConfigurationManager_Updated; + Reset (); + Locations = savedLocations; + } + + [Fact] public void Reset_and_ResetLoadWithLibraryResourcesOnly_are_same () { - Locations = ConfigLocations.DefaultOnly; + Locations = ConfigLocations.Default; // arrange Reset (); @@ -257,7 +302,7 @@ public class ConfigurationManagerTests Settings ["Application.PrevTabGroupKey"].PropertyValue = Key.B; Settings.Apply (); - Locations = ConfigLocations.DefaultOnly; + Locations = ConfigLocations.Default; // act Reset (); @@ -275,7 +320,7 @@ public class ConfigurationManagerTests [Fact] public void Reset_Resets () { - Locations = ConfigLocations.DefaultOnly; + Locations = ConfigLocations.Default; Reset (); Assert.NotEmpty (Themes!); Assert.Equal ("Default", Themes.Theme); @@ -433,7 +478,7 @@ public class ConfigurationManagerTests } [Fact] - [AutoInitShutdown (configLocation: ConfigLocations.DefaultOnly)] + [AutoInitShutdown (configLocation: ConfigLocations.Default)] public void TestConfigurationManagerInitDriver () { Assert.Equal ("Default", Themes!.Theme); @@ -469,7 +514,10 @@ public class ConfigurationManagerTests [Fact] [AutoInitShutdown (configLocation: ConfigLocations.None)] - public void TestConfigurationManagerInitDriver_NoLocations () { } + public void TestConfigurationManagerInitDriver_NoLocations () + { + // TODO: Write this test + } [Fact] public void TestConfigurationManagerInvalidJsonLogs () diff --git a/UnitTests/Configuration/KeyJsonConverterTests.cs b/UnitTests/Configuration/KeyJsonConverterTests.cs index de9a5553a..eba845feb 100644 --- a/UnitTests/Configuration/KeyJsonConverterTests.cs +++ b/UnitTests/Configuration/KeyJsonConverterTests.cs @@ -52,6 +52,20 @@ public class KeyJsonConverterTests Assert.Equal (expectedStringTo, deserializedKey.ToString ()); } + [Fact] + public void Deserialized_Key_Equals () + { + // Arrange + Key key = Key.Q.WithCtrl; + + // Act + string json = """Ctrl+Q"""; + Key deserializedKey = JsonSerializer.Deserialize (json, ConfigurationManager._serializerOptions); + + // Assert + Assert.Equal (key, deserializedKey); + + } [Fact] public void Separator_Property_Serializes_As_Glyph () { diff --git a/UnitTests/Configuration/SettingsScopeTests.cs b/UnitTests/Configuration/SettingsScopeTests.cs index d743b977f..746bfba6c 100644 --- a/UnitTests/Configuration/SettingsScopeTests.cs +++ b/UnitTests/Configuration/SettingsScopeTests.cs @@ -5,9 +5,39 @@ namespace Terminal.Gui.ConfigurationTests; public class SettingsScopeTests { [Fact] - [AutoInitShutdown (configLocation: ConfigLocations.DefaultOnly)] + public void Update_Overrides_Defaults () + { + // arrange + Locations = ConfigLocations.Default; + Load (true); + + Assert.Equal (Key.Esc, (Key)Settings ["Application.QuitKey"].PropertyValue); + + ThrowOnJsonErrors = true; + + // act + var json = """ + + { + "Application.QuitKey": "Ctrl-Q" + } + """; + + Settings!.Update (json, "test"); + + // assert + Assert.Equal (Key.Q.WithCtrl, (Key)Settings ["Application.QuitKey"].PropertyValue); + + // clean up + Locations = ConfigLocations.All; + } + + [Fact] public void Apply_ShouldApplyProperties () { + Locations = ConfigLocations.Default; + Reset(); + // arrange Assert.Equal (Key.Esc, (Key)Settings ["Application.QuitKey"].PropertyValue); @@ -18,7 +48,7 @@ public class SettingsScopeTests Assert.Equal ( Key.F6.WithShift, - (Key)Settings["Application.PrevTabGroupKey"].PropertyValue + (Key)Settings ["Application.PrevTabGroupKey"].PropertyValue ); // act @@ -32,6 +62,10 @@ public class SettingsScopeTests Assert.Equal (Key.Q, Application.QuitKey); Assert.Equal (Key.F, Application.NextTabGroupKey); Assert.Equal (Key.B, Application.PrevTabGroupKey); + + Locations = ConfigLocations.Default; + Reset (); + } [Fact] @@ -56,7 +90,7 @@ public class SettingsScopeTests public void GetHardCodedDefaults_ShouldSetProperties () { ConfigLocations savedLocations = Locations; - Locations = ConfigLocations.DefaultOnly; + Locations = ConfigLocations.Default; Reset (); Assert.Equal (5, ((Dictionary)Settings ["Themes"].PropertyValue).Count); diff --git a/UnitTests/Configuration/ThemeScopeTests.cs b/UnitTests/Configuration/ThemeScopeTests.cs index 64d13e0b4..28477f423 100644 --- a/UnitTests/Configuration/ThemeScopeTests.cs +++ b/UnitTests/Configuration/ThemeScopeTests.cs @@ -15,7 +15,7 @@ public class ThemeScopeTests }; [Fact] - [AutoInitShutdown (configLocation: ConfigLocations.DefaultOnly)] + [AutoInitShutdown (configLocation: ConfigLocations.Default)] public void AllThemesPresent () { Reset (); @@ -25,7 +25,7 @@ public class ThemeScopeTests } [Fact] - [AutoInitShutdown (configLocation: ConfigLocations.DefaultOnly)] + [AutoInitShutdown (configLocation: ConfigLocations.Default)] public void Apply_ShouldApplyUpdatedProperties () { Reset (); @@ -54,7 +54,7 @@ public class ThemeScopeTests } [Fact] - [AutoInitShutdown (configLocation: ConfigLocations.DefaultOnly)] + [AutoInitShutdown (configLocation: ConfigLocations.Default)] public void TestSerialize_RoundTrip () { Reset (); @@ -71,7 +71,7 @@ public class ThemeScopeTests } [Fact] - [AutoInitShutdown (configLocation: ConfigLocations.DefaultOnly)] + [AutoInitShutdown (configLocation: ConfigLocations.Default)] public void ThemeManager_ClassMethodsWork () { Reset (); diff --git a/UnitTests/Configuration/ThemeTests.cs b/UnitTests/Configuration/ThemeTests.cs index e7d023d10..70a1b393b 100644 --- a/UnitTests/Configuration/ThemeTests.cs +++ b/UnitTests/Configuration/ThemeTests.cs @@ -11,7 +11,7 @@ public class ThemeTests }; [Fact] - [AutoInitShutdown (configLocation: ConfigLocations.DefaultOnly)] + [AutoInitShutdown (configLocation: ConfigLocations.Default)] public void TestApply () { Reset (); @@ -33,7 +33,7 @@ public class ThemeTests } [Fact] - [AutoInitShutdown (configLocation: ConfigLocations.DefaultOnly)] + [AutoInitShutdown (configLocation: ConfigLocations.Default)] public void TestApply_UpdatesColors () { // Arrange diff --git a/UnitTests/Input/KeyBindingTests.cs b/UnitTests/Input/KeyBindingTests.cs index e5628da5a..af95eff47 100644 --- a/UnitTests/Input/KeyBindingTests.cs +++ b/UnitTests/Input/KeyBindingTests.cs @@ -331,6 +331,19 @@ public class KeyBindingTests } // TryGet + [Fact] + public void TryGet_Succeeds () + { + var keyBindings = new KeyBindings (); + keyBindings.Add (Key.Q.WithCtrl, KeyBindingScope.Application, Command.HotKey); + var key = new Key (Key.Q.WithCtrl); + bool result = keyBindings.TryGet (key, out KeyBinding _); + Assert.True (result);; + + result = keyBindings.Bindings.TryGetValue (key, out KeyBinding _); + Assert.True (result); + } + [Fact] public void TryGet_Unknown_ReturnsFalse () { diff --git a/UnitTests/Input/KeyTests.cs b/UnitTests/Input/KeyTests.cs index fa2695e5f..8493e09cb 100644 --- a/UnitTests/Input/KeyTests.cs +++ b/UnitTests/Input/KeyTests.cs @@ -532,6 +532,10 @@ public class KeyTests Key a = Key.A; Key b = Key.A; Assert.True (a.Equals (b)); + + b.Handled = true; + Assert.False (a.Equals (b)); + } [Fact] diff --git a/UnitTests/TestHelpers.cs b/UnitTests/TestHelpers.cs index 1b841ee65..3967d8b99 100644 --- a/UnitTests/TestHelpers.cs +++ b/UnitTests/TestHelpers.cs @@ -49,7 +49,7 @@ public class AutoInitShutdownAttribute : BeforeAfterTestAttribute bool useFakeClipboard = true, bool fakeClipboardAlwaysThrowsNotSupportedException = false, bool fakeClipboardIsSupportedAlwaysTrue = false, - ConfigLocations configLocation = ConfigLocations.None, + ConfigLocations configLocation = ConfigLocations.Default, // DefaultOnly is the default for tests bool verifyShutdown = false ) { @@ -110,7 +110,7 @@ public class AutoInitShutdownAttribute : BeforeAfterTestAttribute } // Reset to defaults - Locations = ConfigLocations.DefaultOnly; + Locations = ConfigLocations.Default; Reset (); // Enable subsequent tests that call Init to get all config files (the default). diff --git a/UnitTests/UICatalog/ScenarioTests.cs b/UnitTests/UICatalog/ScenarioTests.cs index 27cc5d661..aeac22357 100644 --- a/UnitTests/UICatalog/ScenarioTests.cs +++ b/UnitTests/UICatalog/ScenarioTests.cs @@ -31,8 +31,8 @@ public class ScenarioTests : TestsAllViews _timeoutLock = new (); // Disable any UIConfig settings - ConfigurationManager.ConfigLocations savedConfigLocations = ConfigurationManager.Locations; - ConfigurationManager.Locations = ConfigurationManager.ConfigLocations.DefaultOnly; + ConfigLocations savedConfigLocations = ConfigurationManager.Locations; + ConfigurationManager.Locations = ConfigLocations.Default; // If a previous test failed, this will ensure that the Application is in a clean state Application.ResetState (true); @@ -148,8 +148,8 @@ public class ScenarioTests : TestsAllViews _timeoutLock = new (); // Disable any UIConfig settings - ConfigurationManager.ConfigLocations savedConfigLocations = ConfigurationManager.Locations; - ConfigurationManager.Locations = ConfigurationManager.ConfigLocations.DefaultOnly; + ConfigLocations savedConfigLocations = ConfigurationManager.Locations; + ConfigurationManager.Locations = ConfigLocations.Default; // If a previous test failed, this will ensure that the Application is in a clean state Application.ResetState (true); @@ -305,8 +305,8 @@ public class ScenarioTests : TestsAllViews public void Run_All_Views_Tester_Scenario () { // Disable any UIConfig settings - ConfigurationManager.ConfigLocations savedConfigLocations = ConfigurationManager.Locations; - ConfigurationManager.Locations = ConfigurationManager.ConfigLocations.DefaultOnly; + ConfigLocations savedConfigLocations = ConfigurationManager.Locations; + ConfigurationManager.Locations = ConfigLocations.Default; Window _leftPane; ListView _classListView; @@ -764,8 +764,8 @@ public class ScenarioTests : TestsAllViews public void Run_Generic () { // Disable any UIConfig settings - ConfigurationManager.ConfigLocations savedConfigLocations = ConfigurationManager.Locations; - ConfigurationManager.Locations = ConfigurationManager.ConfigLocations.DefaultOnly; + ConfigLocations savedConfigLocations = ConfigurationManager.Locations; + ConfigurationManager.Locations = ConfigLocations.Default; ObservableCollection scenarios = Scenario.GetScenarios (); Assert.NotEmpty (scenarios); diff --git a/UnitTests/View/ViewTests.cs b/UnitTests/View/ViewTests.cs index 4bac57b60..c169013e9 100644 --- a/UnitTests/View/ViewTests.cs +++ b/UnitTests/View/ViewTests.cs @@ -283,7 +283,7 @@ public class ViewTests (ITestOutputHelper output) } [Theory] - [AutoInitShutdown (configLocation: ConfigurationManager.ConfigLocations.DefaultOnly)] + [AutoInitShutdown (configLocation: ConfigLocations.Default)] [InlineData (true)] [InlineData (false)] public void Clear_Does_Not_Spillover_Its_Parent (bool label) diff --git a/UnitTests/Views/ComboBoxTests.cs b/UnitTests/Views/ComboBoxTests.cs index ecc4a5cbc..839b3ece7 100644 --- a/UnitTests/Views/ComboBoxTests.cs +++ b/UnitTests/Views/ComboBoxTests.cs @@ -494,7 +494,7 @@ public class ComboBoxTests (ITestOutputHelper output) } [Fact] - [AutoInitShutdown (configLocation: ConfigurationManager.ConfigLocations.DefaultOnly)] + [AutoInitShutdown (configLocation: ConfigLocations.Default)] public void HideDropdownListOnClick_True_Highlight_Current_Item () { var selected = ""; diff --git a/UnitTests/Views/MenuBarTests.cs b/UnitTests/Views/MenuBarTests.cs index f3a49a66d..534ac5085 100644 --- a/UnitTests/Views/MenuBarTests.cs +++ b/UnitTests/Views/MenuBarTests.cs @@ -315,7 +315,7 @@ public class MenuBarTests (ITestOutputHelper output) } [Fact] - [AutoInitShutdown (configLocation: ConfigurationManager.ConfigLocations.DefaultOnly)] + [AutoInitShutdown (configLocation: ConfigLocations.Default)] public void Disabled_MenuBar_Is_Never_Opened () { Toplevel top = new (); @@ -341,7 +341,7 @@ public class MenuBarTests (ITestOutputHelper output) } [Fact (Skip = "#3798 Broke. Will fix in #2975")] - [AutoInitShutdown (configLocation: ConfigurationManager.ConfigLocations.DefaultOnly)] + [AutoInitShutdown (configLocation: ConfigLocations.Default)] public void Disabled_MenuItem_Is_Never_Selected () { var menu = new MenuBar diff --git a/UnitTests/Views/TabViewTests.cs b/UnitTests/Views/TabViewTests.cs index 3999142fa..9d38e1459 100644 --- a/UnitTests/Views/TabViewTests.cs +++ b/UnitTests/Views/TabViewTests.cs @@ -1347,7 +1347,7 @@ public class TabViewTests (ITestOutputHelper output) private void InitFakeDriver () { - ConfigurationManager.Locations = ConfigurationManager.ConfigLocations.DefaultOnly; + ConfigurationManager.Locations = ConfigLocations.DefaultOnly; ConfigurationManager.Reset (); var driver = new FakeDriver (); diff --git a/UnitTests/Views/TableViewTests.cs b/UnitTests/Views/TableViewTests.cs index dd099553f..6cceed034 100644 --- a/UnitTests/Views/TableViewTests.cs +++ b/UnitTests/Views/TableViewTests.cs @@ -54,7 +54,7 @@ public class TableViewTests (ITestOutputHelper output) } [Fact] - [AutoInitShutdown (configLocation: ConfigurationManager.ConfigLocations.DefaultOnly)] + [AutoInitShutdown (configLocation: ConfigLocations.Default)] public void CellEventsBackgroundFill () { var tv = new TableView { Width = 20, Height = 4 }; @@ -412,7 +412,7 @@ public class TableViewTests (ITestOutputHelper output) } [Fact] - [AutoInitShutdown (configLocation: ConfigurationManager.ConfigLocations.DefaultOnly)] + [AutoInitShutdown (configLocation: ConfigLocations.Default)] public void LongColumnTest () { var tableView = new TableView (); @@ -593,7 +593,7 @@ public class TableViewTests (ITestOutputHelper output) top.Dispose (); } - [AutoInitShutdown (configLocation: ConfigurationManager.ConfigLocations.DefaultOnly)] + [AutoInitShutdown (configLocation: ConfigLocations.Default)] [Fact] public void PageDown_ExcludesHeaders () { @@ -993,7 +993,7 @@ public class TableViewTests (ITestOutputHelper output) } [Fact] - [AutoInitShutdown (configLocation: ConfigurationManager.ConfigLocations.DefaultOnly)] + [AutoInitShutdown (configLocation: ConfigLocations.Default)] public void TableView_Activate () { string activatedValue = null; @@ -1033,7 +1033,7 @@ public class TableViewTests (ITestOutputHelper output) } [Theory] - [AutoInitShutdown (configLocation: ConfigurationManager.ConfigLocations.DefaultOnly)] + [AutoInitShutdown (configLocation: ConfigLocations.Default)] [InlineData (false)] [InlineData (true)] public void TableView_ColorsTest_ColorGetter (bool focused) @@ -1134,7 +1134,7 @@ public class TableViewTests (ITestOutputHelper output) } [Theory] - [AutoInitShutdown (configLocation: ConfigurationManager.ConfigLocations.DefaultOnly)] + [AutoInitShutdown (configLocation: ConfigLocations.Default)] [InlineData (false)] [InlineData (true)] public void TableView_ColorsTest_RowColorGetter (bool focused) @@ -1228,7 +1228,7 @@ public class TableViewTests (ITestOutputHelper output) } [Theory] - [AutoInitShutdown (configLocation: ConfigurationManager.ConfigLocations.DefaultOnly)] + [AutoInitShutdown (configLocation: ConfigLocations.Default)] [InlineData (false)] [InlineData (true)] public void TableView_ColorTests_FocusedOrNot (bool focused) @@ -1566,7 +1566,7 @@ public class TableViewTests (ITestOutputHelper output) } [Fact] - [AutoInitShutdown (configLocation: ConfigurationManager.ConfigLocations.DefaultOnly)] + [AutoInitShutdown (configLocation: ConfigLocations.Default)] public void Test_CollectionNavigator () { var tv = new TableView (); @@ -2572,7 +2572,7 @@ A B C [SetupFakeDriver] public void TestTableViewCheckboxes_ByObject () { - ConfigurationManager.Locations = ConfigurationManager.ConfigLocations.DefaultOnly; + ConfigurationManager.Locations = ConfigLocations.Default; ConfigurationManager.Reset(); TableView tv = GetPetTable (out EnumerableTableSource source); diff --git a/UnitTests/Views/TextViewTests.cs b/UnitTests/Views/TextViewTests.cs index ced1943fe..28e867c18 100644 --- a/UnitTests/Views/TextViewTests.cs +++ b/UnitTests/Views/TextViewTests.cs @@ -8525,7 +8525,7 @@ line. { public static string Txt = "TAB to jump between text fields."; - public TextViewTestsAutoInitShutdown () : base (configLocation: ConfigurationManager.ConfigLocations.DefaultOnly) { } + public TextViewTestsAutoInitShutdown () : base (configLocation: ConfigLocations.Default) { } public override void After (MethodInfo methodUnderTest) { @@ -8947,7 +8947,7 @@ line. ", } [Fact] - [AutoInitShutdown (configLocation: ConfigurationManager.ConfigLocations.DefaultOnly)] + [AutoInitShutdown (configLocation: ConfigLocations.Default)] public void Cell_LoadCells_InheritsPreviousAttribute () { List cells = []; diff --git a/UnitTests/Views/TreeTableSourceTests.cs b/UnitTests/Views/TreeTableSourceTests.cs index c22bfcc86..bf8945f61 100644 --- a/UnitTests/Views/TreeTableSourceTests.cs +++ b/UnitTests/Views/TreeTableSourceTests.cs @@ -155,7 +155,7 @@ public class TreeTableSourceTests : IDisposable } [Fact] - [AutoInitShutdown (configLocation:ConfigurationManager.ConfigLocations.DefaultOnly)] + [AutoInitShutdown (configLocation:ConfigLocations.Default)] public void TestTreeTableSource_CombinedWithCheckboxes () { Toplevel top = new ();