SchemeManagerTests.cs 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489
  1. #nullable enable
  2. using System.Collections.Concurrent;
  3. using System.Collections.Immutable;
  4. using System.Text.Json;
  5. using static Terminal.Gui.Configuration.ConfigurationManager;
  6. namespace Terminal.Gui.ConfigurationTests;
  7. public class SchemeManagerTests
  8. {
  9. [Fact]
  10. public void GetSchemes_Not_Enabled_Gets_Schemes ()
  11. {
  12. Disable (true);
  13. Dictionary<string, Scheme?>? schemes = SchemeManager.GetSchemesForCurrentTheme ();
  14. Assert.NotNull (schemes);
  15. Assert.NotNull (schemes ["Base"]);
  16. Assert.True (schemes!.ContainsKey ("Base"));
  17. Assert.True (schemes.ContainsKey ("base"));
  18. Assert.Equal (SchemeManager.GetSchemes (), schemes);
  19. }
  20. [Fact]
  21. public void GetSchemes_Enabled_Gets_Current ()
  22. {
  23. Enable (ConfigLocations.HardCoded);
  24. Dictionary<string, Scheme?>? schemes = SchemeManager.GetSchemesForCurrentTheme ();
  25. Assert.NotNull (schemes);
  26. Assert.NotNull (schemes ["Base"]);
  27. Assert.True (schemes!.ContainsKey ("Base"));
  28. Assert.True (schemes.ContainsKey ("base"));
  29. Assert.Equal (SchemeManager.GetSchemes (), schemes);
  30. Disable (true);
  31. }
  32. [Fact]
  33. public void GetSchemes_Get_Schemes_After_Load ()
  34. {
  35. Enable (ConfigLocations.HardCoded);
  36. Load (ConfigLocations.All);
  37. Apply ();
  38. Assert.Equal (SchemeManager.GetSchemes (), SchemeManager.GetSchemesForCurrentTheme ());
  39. }
  40. [Fact]
  41. public void GetHardCodedSchemes_Gets_HardCoded_Theme_Schemes ()
  42. {
  43. ImmutableSortedDictionary<string, Scheme?>? hardCoded = SchemeManager.GetHardCodedSchemes ();
  44. Assert.Equal (Scheme.GetHardCodedSchemes (), actual: hardCoded!);
  45. }
  46. [Fact]
  47. public void Not_Case_Sensitive_Disabled ()
  48. {
  49. Assert.False (IsEnabled);
  50. Dictionary<string, Scheme?>? current = SchemeManager.GetSchemesForCurrentTheme ();
  51. Assert.NotNull (current);
  52. Assert.True (current!.ContainsKey ("Base"));
  53. Assert.True (current.ContainsKey ("base"));
  54. }
  55. [Fact]
  56. public void Not_Case_Sensitive_Enabled ()
  57. {
  58. Assert.False (IsEnabled);
  59. Enable (ConfigLocations.HardCoded);
  60. Assert.True (SchemeManager.GetSchemesForCurrentTheme ()!.ContainsKey ("Base"));
  61. Assert.True (SchemeManager.GetSchemesForCurrentTheme ()!.ContainsKey ("base"));
  62. ResetToHardCodedDefaults ();
  63. Dictionary<string, Scheme?>? current = SchemeManager.GetSchemesForCurrentTheme ();
  64. Assert.NotNull (current);
  65. Assert.True (current!.ContainsKey ("Base"));
  66. Assert.True (current.ContainsKey ("base"));
  67. Disable (true);
  68. }
  69. [Fact]
  70. public void Load_Adds ()
  71. {
  72. // arrange
  73. Enable (ConfigLocations.HardCoded);
  74. var theme = new ThemeScope ();
  75. theme.LoadHardCodedDefaults ();
  76. Assert.NotEmpty (theme);
  77. Assert.Equal (5, SchemeManager.GetSchemes ().Count);
  78. theme ["Schemes"].PropertyValue = SchemeManager.GetSchemes ();
  79. Dictionary<string, Scheme> schemes = (Dictionary<string, Scheme>)theme ["Schemes"].PropertyValue!;
  80. Assert.Equal (SchemeManager.GetSchemes ().Count, schemes.Count);
  81. var newTheme = new ThemeScope ();
  82. newTheme.LoadHardCodedDefaults ();
  83. var scheme = new Scheme
  84. {
  85. // note: Scheme's can't be partial; default for each attribute
  86. // is always White/Black
  87. Normal = new (Color.Red, Color.Green),
  88. Focus = new (Color.Cyan, Color.BrightCyan),
  89. HotNormal = new (Color.Yellow, Color.BrightYellow),
  90. HotFocus = new (Color.Green, Color.BrightGreen),
  91. Disabled = new (Color.Gray, Color.DarkGray)
  92. };
  93. newTheme ["Schemes"].PropertyValue = SchemeManager.GetSchemesForCurrentTheme ();
  94. Assert.Equal (5, SchemeManager.GetSchemes ().Count);
  95. // add a new Scheme to the newTheme
  96. ((Dictionary<string, Scheme>)theme ["Schemes"].PropertyValue!) ["Test"] = scheme;
  97. schemes = (Dictionary<string, Scheme>)theme ["Schemes"].PropertyValue!;
  98. Assert.Equal (SchemeManager.GetSchemes ().Count, schemes.Count);
  99. // Act
  100. theme.UpdateFrom (newTheme);
  101. // Assert
  102. schemes = (Dictionary<string, Scheme>)theme ["Schemes"].PropertyValue!;
  103. Assert.Equal (schemes ["Test"].Normal, scheme.Normal);
  104. Assert.Equal (schemes ["Test"].Focus, scheme.Focus);
  105. Disable (true);
  106. }
  107. [Fact]
  108. public void Load_Changes ()
  109. {
  110. // arrange
  111. Enable (ConfigLocations.HardCoded);
  112. var theme = new ThemeScope ();
  113. theme.LoadHardCodedDefaults ();
  114. Assert.NotEmpty (theme);
  115. var scheme = new Scheme
  116. {
  117. // note: Scheme's can't be partial; default for each attribute
  118. // is always White/Black
  119. Normal = new (Color.Red, Color.Green),
  120. Focus = new (Color.Cyan, Color.BrightCyan),
  121. HotNormal = new (Color.Yellow, Color.BrightYellow),
  122. HotFocus = new (Color.Green, Color.BrightGreen),
  123. Disabled = new (Color.Gray, Color.DarkGray)
  124. };
  125. theme ["Schemes"].PropertyValue = SchemeManager.GetSchemesForCurrentTheme ();
  126. ((Dictionary<string, Scheme>)theme ["Schemes"].PropertyValue!)! ["Test"] = scheme;
  127. Dictionary<string, Scheme>? schemes = (Dictionary<string, Scheme>)theme ["Schemes"].PropertyValue!;
  128. Assert.Equal (scheme.Normal, schemes ["Test"].Normal);
  129. Assert.Equal (scheme.Focus, schemes ["Test"].Focus);
  130. // Change just Normal
  131. var newTheme = new ThemeScope ();
  132. newTheme.LoadHardCodedDefaults ();
  133. var newScheme = new Scheme
  134. {
  135. Normal = new (Color.Blue, Color.BrightBlue),
  136. Focus = scheme.Focus,
  137. HotNormal = scheme.HotNormal,
  138. HotFocus = scheme.HotFocus,
  139. Disabled = scheme.Disabled
  140. };
  141. newTheme ["Schemes"].PropertyValue = SchemeManager.GetSchemesForCurrentTheme ();
  142. ((Dictionary<string, Scheme>)newTheme ["Schemes"].PropertyValue!)! ["Test"] = newScheme;
  143. // Act
  144. theme.UpdateFrom (newTheme);
  145. // Assert
  146. schemes = (Dictionary<string, Scheme>)theme ["Schemes"].PropertyValue!;
  147. // Normal should have changed
  148. Assert.Equal (new (Color.Blue, Color.BrightBlue), schemes ["Test"].Normal);
  149. Assert.Equal (Color.BrightBlue, schemes ["Test"].Normal.Background);
  150. Assert.Equal (Color.Cyan, schemes ["Test"].Focus.Foreground);
  151. Assert.Equal (Color.BrightCyan, schemes ["Test"].Focus.Background);
  152. Disable (true);
  153. }
  154. [Fact (Skip = "TODO: This should throw an exception")]
  155. public void Load_Null_Scheme_Throws ()
  156. {
  157. try
  158. {
  159. Enable (ConfigLocations.HardCoded);
  160. ThrowOnJsonErrors = true;
  161. // Create a test theme
  162. RuntimeConfig = """
  163. {
  164. "Theme": "TestTheme",
  165. "Themes": [
  166. {
  167. "TestTheme": {
  168. }
  169. }
  170. ]
  171. }
  172. """;
  173. // Load the test theme
  174. // TODO: This should throw an exception!
  175. Assert.Throws< JsonException > (() => Load (ConfigLocations.Runtime));
  176. Assert.Contains ("TestTheme", ThemeManager.Themes!);
  177. Assert.Equal ("TestTheme", ThemeManager.Theme);
  178. Assert.Throws<System.Collections.Generic.KeyNotFoundException> (SchemeManager.GetSchemes);
  179. // Now reset everything and reload
  180. ResetToCurrentValues ();
  181. // Verify we're back to default
  182. Assert.Equal ("Default", ThemeManager.Theme);
  183. }
  184. finally
  185. {
  186. Disable (true);
  187. }
  188. }
  189. [Fact]
  190. public void Load_Empty_Scheme_Throws ()
  191. {
  192. try
  193. {
  194. Enable (ConfigLocations.HardCoded);
  195. ThrowOnJsonErrors = true;
  196. // Create a test theme
  197. RuntimeConfig = """
  198. {
  199. "Theme": "TestTheme",
  200. "Themes": [
  201. {
  202. "TestTheme": {
  203. "Schemes": []
  204. }
  205. }
  206. ]
  207. }
  208. """;
  209. // Load the test theme
  210. Load (ConfigLocations.Runtime);
  211. Assert.Equal ("TestTheme", ThemeManager.Theme);
  212. // Now reset everything and reload
  213. ResetToCurrentValues ();
  214. // Verify we're back to default
  215. Assert.Equal ("Default", ThemeManager.Theme);
  216. }
  217. finally
  218. {
  219. Disable (true);
  220. }
  221. }
  222. [Fact]
  223. public void Load_Custom_Scheme_Loads ()
  224. {
  225. try
  226. {
  227. Enable (ConfigLocations.HardCoded);
  228. ThrowOnJsonErrors = true;
  229. // Create a test theme
  230. RuntimeConfig = """
  231. {
  232. "Theme": "TestTheme",
  233. "Themes": [
  234. {
  235. "TestTheme": {
  236. "Schemes": [
  237. {
  238. "TopLevel": {
  239. "Normal": {
  240. "Foreground": "AntiqueWhite",
  241. "Background": "DimGray"
  242. },
  243. "Focus": {
  244. "Foreground": "White",
  245. "Background": "DarkGray"
  246. },
  247. "HotNormal": {
  248. "Foreground": "Wheat",
  249. "Background": "DarkGray",
  250. "Style": "Underline"
  251. },
  252. "HotFocus": {
  253. "Foreground": "LightYellow",
  254. "Background": "DimGray",
  255. "Style": "Underline"
  256. },
  257. "Disabled": {
  258. "Foreground": "Black",
  259. "Background": "DimGray"
  260. }
  261. }
  262. },
  263. {
  264. "Base": {
  265. "Normal": {
  266. "Foreground": "White",
  267. "Background": "Blue"
  268. },
  269. "Focus": {
  270. "Foreground": "DarkBlue",
  271. "Background": "LightGray"
  272. },
  273. "HotNormal": {
  274. "Foreground": "BrightCyan",
  275. "Background": "Blue"
  276. },
  277. "HotFocus": {
  278. "Foreground": "BrightBlue",
  279. "Background": "LightGray"
  280. },
  281. "Disabled": {
  282. "Foreground": "DarkGray",
  283. "Background": "Blue"
  284. }
  285. }
  286. },
  287. {
  288. "Dialog": {
  289. "Normal": {
  290. "Foreground": "Black",
  291. "Background": "LightGray"
  292. },
  293. "Focus": {
  294. "Foreground": "DarkGray",
  295. "Background": "LightGray"
  296. },
  297. "HotNormal": {
  298. "Foreground": "Blue",
  299. "Background": "LightGray"
  300. },
  301. "HotFocus": {
  302. "Foreground": "BrightBlue",
  303. "Background": "LightGray"
  304. },
  305. "Disabled": {
  306. "Foreground": "Gray",
  307. "Background": "DarkGray"
  308. }
  309. }
  310. },
  311. {
  312. "Menu": {
  313. "Normal": {
  314. "Foreground": "White",
  315. "Background": "DarkBlue",
  316. "Style": "Bold"
  317. },
  318. "Focus": {
  319. "Foreground": "White",
  320. "Background": "DarkBlue",
  321. "Style": "Bold,Reverse"
  322. },
  323. "HotNormal": {
  324. "Foreground": "BrightYellow",
  325. "Background": "DarkBlue",
  326. "Style": "Bold,Underline"
  327. },
  328. "HotFocus": {
  329. "Foreground": "Blue",
  330. "Background": "White",
  331. "Style": "Bold,Underline"
  332. },
  333. "Disabled": {
  334. "Foreground": "Gray",
  335. "Background": "DarkGray",
  336. "Style": "Faint"
  337. }
  338. }
  339. },
  340. {
  341. "Error": {
  342. "Normal": {
  343. "Foreground": "Red",
  344. "Background": "Pink"
  345. },
  346. "Focus": {
  347. "Foreground": "White",
  348. "Background": "BrightRed"
  349. },
  350. "HotNormal": {
  351. "Foreground": "Black",
  352. "Background": "Pink"
  353. },
  354. "HotFocus": {
  355. "Foreground": "Pink",
  356. "Background": "BrightRed"
  357. },
  358. "Disabled": {
  359. "Foreground": "DarkGray",
  360. "Background": "White"
  361. }
  362. }
  363. }
  364. ]
  365. }
  366. }
  367. ]
  368. }
  369. """;
  370. // Load the test theme
  371. Load (ConfigLocations.Runtime);
  372. Assert.Equal ("TestTheme", ThemeManager.Theme);
  373. TextStyle style = SchemeManager.GetSchemesForCurrentTheme () ["Menu"]!.Normal.Style;
  374. Assert.Equal (TextStyle.Bold, style);
  375. // Now reset everything and reload
  376. ResetToCurrentValues ();
  377. // Verify we're back to default
  378. Assert.Equal ("Default", ThemeManager.Theme);
  379. }
  380. finally
  381. {
  382. Disable (true);
  383. }
  384. }
  385. [Fact (Skip = "WIP")]
  386. public void Apply_UpdatesSchemes ()
  387. {
  388. Enable (ConfigLocations.HardCoded);
  389. Assert.False (SchemeManager.GetSchemes ()!.ContainsKey ("test"));
  390. Assert.Equal (5, SchemeManager.GetSchemes ().Count); // base, toplevel, menu, error, dialog
  391. var theme = new ThemeScope ();
  392. Assert.NotEmpty (theme);
  393. ThemeManager.Themes!.TryAdd ("testTheme", theme);
  394. var scheme = new Scheme { Normal = new (Color.Red, Color.Green) };
  395. theme ["Schemes"].PropertyValue = new Dictionary<string, Scheme> (StringComparer.InvariantCultureIgnoreCase) { { "test", scheme } };
  396. Assert.Equal (
  397. new (Color.Red),
  398. ((Dictionary<string, Scheme>)theme ["Schemes"].PropertyValue!) ["test"].Normal.Foreground
  399. );
  400. Assert.Equal (
  401. new (Color.Green),
  402. ((Dictionary<string, Scheme>)theme ["Schemes"].PropertyValue!) ["test"].Normal.Background
  403. );
  404. // Act
  405. ThemeManager.Theme = "testTheme";
  406. ThemeManager.Themes! [ThemeManager.Theme]!.Apply ();
  407. Assert.Equal (5, SchemeManager.GetSchemes ().Count); // base, toplevel, menu, error, dialog
  408. // Assert
  409. Scheme updatedScheme = SchemeManager.GetSchemes () ["test"]!;
  410. Assert.Equal (new (Color.Red), updatedScheme.Normal.Foreground);
  411. Assert.Equal (new (Color.Green), updatedScheme.Normal.Background);
  412. // remove test Scheme from Colors to avoid failures on others unit tests with Scheme
  413. SchemeManager.GetSchemes ().Remove ("test");
  414. Assert.Equal (5, SchemeManager.GetSchemes ().Count);
  415. Disable (true);
  416. }
  417. }