ThemeScopeTests.cs 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231
  1. #nullable enable
  2. using System.Collections.Concurrent;
  3. using System.Collections.Frozen;
  4. using System.Collections.Immutable;
  5. using System.Text.Json;
  6. using static Terminal.Gui.Configuration.ConfigurationManager;
  7. namespace UnitTests.ConfigurationTests;
  8. public class ThemeScopeTests
  9. {
  10. [Fact]
  11. public void Load_AllThemesPresent ()
  12. {
  13. Enable (ConfigLocations.HardCoded);
  14. Load (ConfigLocations.All);
  15. Assert.True (ThemeManager.Themes!.ContainsKey ("Default"));
  16. Assert.True (ThemeManager.Themes.ContainsKey ("Dark"));
  17. Assert.True (ThemeManager.Themes.ContainsKey ("Light"));
  18. Disable (true);
  19. }
  20. [Fact]
  21. public void Apply_ShouldApplyUpdatedProperties ()
  22. {
  23. Enable (ConfigLocations.HardCoded);
  24. Assert.NotEmpty (ThemeManager.Themes!);
  25. Alignment savedButtonAlignment = Dialog.DefaultButtonAlignment;
  26. Alignment newButtonAlignment = Alignment.Center != savedButtonAlignment ? Alignment.Center : Alignment.Start;
  27. ThemeManager.GetCurrentTheme () ["Dialog.DefaultButtonAlignment"].PropertyValue = newButtonAlignment;
  28. LineStyle savedBorderStyle = Dialog.DefaultBorderStyle;
  29. var newBorderStyle = LineStyle.HeavyDotted;
  30. ThemeManager.GetCurrentTheme () ["Dialog.DefaultBorderStyle"].PropertyValue = newBorderStyle;
  31. ThemeManager.Themes! [ThemeManager.Theme]!.Apply ();
  32. Assert.Equal (newButtonAlignment, Dialog.DefaultButtonAlignment);
  33. Assert.Equal (newBorderStyle, Dialog.DefaultBorderStyle);
  34. // Replace with the savedValue to avoid failures on other unit tests that rely on the default value
  35. ThemeManager.GetCurrentTheme () ["Dialog.DefaultButtonAlignment"].PropertyValue = savedButtonAlignment;
  36. ThemeManager.GetCurrentTheme () ["Dialog.DefaultBorderStyle"].PropertyValue = savedBorderStyle;
  37. ThemeManager.GetCurrentTheme ().Apply ();
  38. Assert.Equal (savedButtonAlignment, Dialog.DefaultButtonAlignment);
  39. Assert.Equal (savedBorderStyle, Dialog.DefaultBorderStyle);
  40. Disable (true);
  41. }
  42. [Fact]
  43. public void UpdateToHardCodedDefaults_Resets_Config_Does_Not_Apply ()
  44. {
  45. Enable (ConfigLocations.HardCoded);
  46. Load (ConfigLocations.LibraryResources);
  47. Assert.Equal ("Default", ThemeManager.Theme);
  48. ThemeManager.Theme = "Dark";
  49. Assert.Equal ("Dark", ThemeManager.Theme);
  50. Apply ();
  51. Assert.Equal ("Dark", ThemeManager.Theme);
  52. // Act
  53. ThemeManager.LoadHardCodedDefaults ();
  54. Assert.Equal ("Default", ThemeManager.Theme);
  55. Disable (true);
  56. }
  57. [Fact]
  58. public void Serialize_Themes_RoundTrip ()
  59. {
  60. Enable (ConfigLocations.HardCoded);
  61. IDictionary<string, ThemeScope> initial = ThemeManager.Themes!;
  62. string serialized = JsonSerializer.Serialize (ThemeManager.Themes, SerializerContext.Options);
  63. ConcurrentDictionary<string, ThemeScope>? deserialized =
  64. JsonSerializer.Deserialize<ConcurrentDictionary<string, ThemeScope>> (serialized, SerializerContext.Options);
  65. Assert.NotEqual (initial, deserialized);
  66. Assert.Equal (deserialized!.Count, initial!.Count);
  67. Disable (true);
  68. }
  69. [Fact]
  70. public void DeSerialize_Themes_UpdateFrom_Updates ()
  71. {
  72. Enable (ConfigLocations.HardCoded);
  73. IDictionary<string, ThemeScope> initial = ThemeManager.Themes!;
  74. string serialized = """
  75. {
  76. "Default": {
  77. "Button.DefaultShadow": "None"
  78. }
  79. }
  80. """;
  81. ConcurrentDictionary<string, ThemeScope>? deserialized =
  82. JsonSerializer.Deserialize<ConcurrentDictionary<string, ThemeScope>> (serialized, SerializerContext.Options);
  83. ShadowStyle initialShadowStyle = (ShadowStyle)(initial! ["Default"] ["Button.DefaultShadow"].PropertyValue!);
  84. Assert.Equal (ShadowStyle.Opaque, initialShadowStyle);
  85. ShadowStyle deserializedShadowStyle = (ShadowStyle)(deserialized! ["Default"] ["Button.DefaultShadow"].PropertyValue!);
  86. Assert.Equal (ShadowStyle.None, deserializedShadowStyle);
  87. initial ["Default"].UpdateFrom (deserialized ["Default"]);
  88. initialShadowStyle = (ShadowStyle)(initial! ["Default"] ["Button.DefaultShadow"].PropertyValue!);
  89. Assert.Equal (ShadowStyle.None, initialShadowStyle);
  90. Assert.Equal(ShadowStyle.Opaque, Button.DefaultShadow);
  91. initial ["Default"].Apply ();
  92. Assert.Equal (ShadowStyle.None, Button.DefaultShadow);
  93. Disable (true);
  94. Assert.Equal (ShadowStyle.Opaque, Button.DefaultShadow);
  95. }
  96. [Fact]
  97. public void Serialize_New_RoundTrip ()
  98. {
  99. Enable (ConfigLocations.HardCoded);
  100. var theme = new ThemeScope ();
  101. theme.LoadHardCodedDefaults ();
  102. theme ["Dialog.DefaultButtonAlignment"].PropertyValue = Alignment.End;
  103. string json = JsonSerializer.Serialize (theme, SerializerContext.Options);
  104. var deserialized = JsonSerializer.Deserialize<ThemeScope> (json, SerializerContext.Options);
  105. Assert.Equal (
  106. Alignment.End,
  107. (Alignment)deserialized! ["Dialog.DefaultButtonAlignment"].PropertyValue!
  108. );
  109. Disable (true);
  110. }
  111. [Fact (Skip = "Temp work arounds for #4288 prevent corruption.")]
  112. public void UpdateFrom_Corrupts_Schemes_HardCodeDefaults ()
  113. {
  114. // BUGBUG: ThemeScope is broken and needs to be fixed to not have the hard coded schemes get overwritten.
  115. // BUGBUG: This test demonstrates the problem.
  116. // BUGBUG: See https://github.com/gui-cs/Terminal.Gui/issues/4288
  117. // Create a test theme
  118. var json = """
  119. {
  120. "Schemes": [
  121. {
  122. "Base": {
  123. "Normal": {
  124. "Foreground": "White",
  125. "Background": "Blue"
  126. }
  127. }
  128. }
  129. ]
  130. }
  131. """;
  132. //var json = """
  133. // {
  134. // "Themes": [
  135. // {
  136. // "Default": {
  137. // "Schemes": [
  138. // {
  139. // "Base": {
  140. // "Normal": {
  141. // "Foreground": "White",
  142. // "Background": "Blue"
  143. // }
  144. // }
  145. // }
  146. // ]
  147. // }
  148. // }
  149. // ]
  150. // }
  151. // """;
  152. try
  153. {
  154. Assert.False (IsEnabled);
  155. ThrowOnJsonErrors = true;
  156. // Enable (ConfigLocations.HardCoded);
  157. //ResetToCurrentValues ();
  158. // Capture dynamically created hardCoded hard-coded scheme colors
  159. ImmutableSortedDictionary<string, Scheme> hardCodedSchemes = SchemeManager.GetHardCodedSchemes ()!;
  160. Color hardCodedBaseNormalFg = hardCodedSchemes ["Base"].Normal.Foreground;
  161. Assert.Equal (new Color (StandardColor.LightBlue).ToString (), hardCodedBaseNormalFg.ToString ());
  162. // Capture hard-coded scheme colors via cache
  163. Dictionary<string, Scheme>? hardCodedSchemesViaCache =
  164. GetHardCodedConfigPropertiesByScope ("ThemeScope")!.ToFrozenDictionary () ["Schemes"].PropertyValue as Dictionary<string, Scheme>;
  165. Assert.Equal (hardCodedBaseNormalFg.ToString (), hardCodedSchemesViaCache! ["Base"].Normal.Foreground.ToString ());
  166. // (ConfigLocations.HardCoded);
  167. // Capture current scheme
  168. Dictionary<string, Scheme> currentSchemes = SchemeManager.GetSchemes ()!;
  169. Color currentBaseNormalFg = currentSchemes ["Base"].Normal.Foreground;
  170. Assert.Equal (hardCodedBaseNormalFg.ToString (), currentBaseNormalFg.ToString ());
  171. //ConfigurationManager.SourcesManager?.Load (Settings, json, "UpdateFromJson", ConfigLocations.Runtime);
  172. ThemeScope scope = (JsonSerializer.Deserialize (json, typeof (ThemeScope), SerializerContext.Options) as ThemeScope)!;
  173. ThemeScope defaultTheme = ThemeManager.Themes! ["Default"]!;
  174. Dictionary<string, Scheme?> schemesScope = (defaultTheme ["Schemes"].PropertyValue as Dictionary<string, Scheme?>)!;
  175. defaultTheme ["Schemes"].UpdateFrom (scope ["Schemes"].PropertyValue!);
  176. defaultTheme.UpdateFrom (scope);
  177. Assert.Equal (Color.White.ToString (), hardCodedSchemesViaCache! ["Base"].Normal.Foreground.ToString ());
  178. }
  179. finally
  180. {
  181. ResetToHardCodedDefaults ();
  182. }
  183. }
  184. }