ConfigurationMangerTests.cs 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942
  1. using System.Diagnostics;
  2. using System.Reflection;
  3. using System.Text.Json;
  4. using Xunit.Abstractions;
  5. using static Terminal.Gui.ConfigurationManager;
  6. #pragma warning disable IDE1006
  7. namespace Terminal.Gui.ConfigurationTests;
  8. public class ConfigurationManagerTests
  9. {
  10. private readonly ITestOutputHelper _output;
  11. public ConfigurationManagerTests (ITestOutputHelper output)
  12. {
  13. _output = output;
  14. }
  15. public static readonly JsonSerializerOptions _jsonOptions = new ()
  16. {
  17. Converters = { new AttributeJsonConverter (), new ColorJsonConverter () }
  18. };
  19. [Fact]
  20. public void Apply_Raises_Applied ()
  21. {
  22. Reset ();
  23. Applied += ConfigurationManager_Applied;
  24. var fired = false;
  25. void ConfigurationManager_Applied (object sender, ConfigurationManagerEventArgs obj)
  26. {
  27. fired = true;
  28. // assert
  29. Assert.Equal (KeyCode.Q, Application.QuitKey.KeyCode);
  30. Assert.Equal (KeyCode.F, Application.NextTabGroupKey.KeyCode);
  31. Assert.Equal (KeyCode.B, Application.PrevTabGroupKey.KeyCode);
  32. }
  33. // act
  34. Settings! ["Application.QuitKey"].PropertyValue = Key.Q;
  35. Settings ["Application.NextTabGroupKey"].PropertyValue = Key.F;
  36. Settings ["Application.PrevTabGroupKey"].PropertyValue = Key.B;
  37. Apply ();
  38. // assert
  39. Assert.True (fired);
  40. Applied -= ConfigurationManager_Applied;
  41. Reset ();
  42. }
  43. [Fact]
  44. public void DeepMemberWiseCopyTest ()
  45. {
  46. // Value types
  47. var stringDest = "Destination";
  48. var stringSrc = "Source";
  49. object stringCopy = DeepMemberWiseCopy (stringSrc, stringDest);
  50. Assert.Equal (stringSrc, stringCopy);
  51. stringDest = "Destination";
  52. stringSrc = "Destination";
  53. stringCopy = DeepMemberWiseCopy (stringSrc, stringDest);
  54. Assert.Equal (stringSrc, stringCopy);
  55. stringDest = "Destination";
  56. stringSrc = null;
  57. stringCopy = DeepMemberWiseCopy (stringSrc, stringDest);
  58. Assert.Equal (stringSrc, stringCopy);
  59. stringDest = "Destination";
  60. stringSrc = string.Empty;
  61. stringCopy = DeepMemberWiseCopy (stringSrc, stringDest);
  62. Assert.Equal (stringSrc, stringCopy);
  63. var boolDest = true;
  64. var boolSrc = false;
  65. object boolCopy = DeepMemberWiseCopy (boolSrc, boolDest);
  66. Assert.Equal (boolSrc, boolCopy);
  67. boolDest = false;
  68. boolSrc = true;
  69. boolCopy = DeepMemberWiseCopy (boolSrc, boolDest);
  70. Assert.Equal (boolSrc, boolCopy);
  71. boolDest = true;
  72. boolSrc = true;
  73. boolCopy = DeepMemberWiseCopy (boolSrc, boolDest);
  74. Assert.Equal (boolSrc, boolCopy);
  75. boolDest = false;
  76. boolSrc = false;
  77. boolCopy = DeepMemberWiseCopy (boolSrc, boolDest);
  78. Assert.Equal (boolSrc, boolCopy);
  79. // Structs
  80. var attrDest = new Attribute (Color.Black);
  81. var attrSrc = new Attribute (Color.White);
  82. object attrCopy = DeepMemberWiseCopy (attrSrc, attrDest);
  83. Assert.Equal (attrSrc, attrCopy);
  84. // Classes
  85. var colorschemeDest = new ColorScheme { Disabled = new Attribute (Color.Black) };
  86. var colorschemeSrc = new ColorScheme { Disabled = new Attribute (Color.White) };
  87. object colorschemeCopy = DeepMemberWiseCopy (colorschemeSrc, colorschemeDest);
  88. Assert.Equal (colorschemeSrc, colorschemeCopy);
  89. // Dictionaries
  90. Dictionary<string, Attribute> dictDest = new () { { "Disabled", new Attribute (Color.Black) } };
  91. Dictionary<string, Attribute> dictSrc = new () { { "Disabled", new Attribute (Color.White) } };
  92. Dictionary<string, Attribute> dictCopy = (Dictionary<string, Attribute>)DeepMemberWiseCopy (dictSrc, dictDest);
  93. Assert.Equal (dictSrc, dictCopy);
  94. dictDest = new Dictionary<string, Attribute> { { "Disabled", new Attribute (Color.Black) } };
  95. dictSrc = new Dictionary<string, Attribute>
  96. {
  97. { "Disabled", new Attribute (Color.White) }, { "Normal", new Attribute (Color.Blue) }
  98. };
  99. dictCopy = (Dictionary<string, Attribute>)DeepMemberWiseCopy (dictSrc, dictDest);
  100. Assert.Equal (dictSrc, dictCopy);
  101. // src adds an item
  102. dictDest = new Dictionary<string, Attribute> { { "Disabled", new Attribute (Color.Black) } };
  103. dictSrc = new Dictionary<string, Attribute>
  104. {
  105. { "Disabled", new Attribute (Color.White) }, { "Normal", new Attribute (Color.Blue) }
  106. };
  107. dictCopy = (Dictionary<string, Attribute>)DeepMemberWiseCopy (dictSrc, dictDest);
  108. Assert.Equal (2, dictCopy!.Count);
  109. Assert.Equal (dictSrc ["Disabled"], dictCopy ["Disabled"]);
  110. Assert.Equal (dictSrc ["Normal"], dictCopy ["Normal"]);
  111. // src updates only one item
  112. dictDest = new Dictionary<string, Attribute>
  113. {
  114. { "Disabled", new Attribute (Color.Black) }, { "Normal", new Attribute (Color.White) }
  115. };
  116. dictSrc = new Dictionary<string, Attribute> { { "Disabled", new Attribute (Color.White) } };
  117. dictCopy = (Dictionary<string, Attribute>)DeepMemberWiseCopy (dictSrc, dictDest);
  118. Assert.Equal (2, dictCopy!.Count);
  119. Assert.Equal (dictSrc ["Disabled"], dictCopy ["Disabled"]);
  120. Assert.Equal (dictDest ["Normal"], dictCopy ["Normal"]);
  121. }
  122. public class DeepCopyTest ()
  123. {
  124. public static Key key = Key.Esc;
  125. }
  126. [Fact]
  127. public void Illustrate_DeepMemberWiseCopy_Breaks_Dictionary ()
  128. {
  129. Assert.Equal (Key.Esc, DeepCopyTest.key);
  130. Dictionary<Key, string> dict = new Dictionary<Key, string> (new KeyEqualityComparer ());
  131. dict.Add (new (DeepCopyTest.key), "Esc");
  132. Assert.Contains (Key.Esc, dict);
  133. DeepCopyTest.key = (Key)DeepMemberWiseCopy (Key.Q.WithCtrl, DeepCopyTest.key);
  134. Assert.Equal (Key.Q.WithCtrl, DeepCopyTest.key);
  135. Assert.Equal (Key.Esc, dict.Keys.ToArray () [0]);
  136. var eq = new KeyEqualityComparer ();
  137. Assert.True (eq.Equals (Key.Q.WithCtrl, DeepCopyTest.key));
  138. Assert.Equal (Key.Q.WithCtrl.GetHashCode (), DeepCopyTest.key.GetHashCode ());
  139. Assert.Equal (eq.GetHashCode (Key.Q.WithCtrl), eq.GetHashCode (DeepCopyTest.key));
  140. Assert.Equal (Key.Q.WithCtrl.GetHashCode (), eq.GetHashCode (DeepCopyTest.key));
  141. Assert.True (dict.ContainsKey (Key.Esc));
  142. dict.Remove (Key.Esc);
  143. dict.Add (new (DeepCopyTest.key), "Ctrl+Q");
  144. Assert.True (dict.ContainsKey (Key.Q.WithCtrl));
  145. }
  146. [Fact]
  147. public void Load_Raises_Updated ()
  148. {
  149. ThrowOnJsonErrors = true;
  150. Locations = ConfigLocations.All;
  151. Reset ();
  152. Assert.Equal (Key.Esc, (((Key)Settings! ["Application.QuitKey"].PropertyValue)!).KeyCode);
  153. Updated += ConfigurationManager_Updated;
  154. var fired = false;
  155. void ConfigurationManager_Updated (object sender, ConfigurationManagerEventArgs obj)
  156. {
  157. fired = true;
  158. }
  159. // Act
  160. // Reset to cause load to raise event
  161. Load (true);
  162. // assert
  163. Assert.True (fired);
  164. Updated -= ConfigurationManager_Updated;
  165. // clean up
  166. Locations = ConfigLocations.Default;
  167. Reset ();
  168. }
  169. [Fact]
  170. public void Load_Performance_Check ()
  171. {
  172. Locations = ConfigLocations.All;
  173. Reset ();
  174. // Start stopwatch
  175. Stopwatch stopwatch = new Stopwatch ();
  176. stopwatch.Start ();
  177. // Act
  178. Load (true);
  179. Apply();
  180. // Stop stopwatch
  181. stopwatch.Stop ();
  182. // Assert
  183. _output.WriteLine ($"Load took {stopwatch.ElapsedMilliseconds} ms");
  184. }
  185. [Fact]
  186. public void Load_Loads_Custom_Json ()
  187. {
  188. // arrange
  189. Locations = ConfigLocations.All;
  190. Reset ();
  191. ThrowOnJsonErrors = true;
  192. Assert.Equal (Key.Esc, (Key)Settings! ["Application.QuitKey"].PropertyValue);
  193. // act
  194. RuntimeConfig = """
  195. {
  196. "Application.QuitKey": "Ctrl-Q"
  197. }
  198. """;
  199. Load (false);
  200. // assert
  201. Assert.Equal (Key.Q.WithCtrl, (Key)Settings ["Application.QuitKey"].PropertyValue);
  202. // clean up
  203. Locations = ConfigLocations.Default;
  204. Reset ();
  205. }
  206. //[Fact]
  207. //[AutoInitShutdown]
  208. //public void LoadConfigurationFromAllSources_ShouldLoadSettingsFromAllSources ()
  209. //{
  210. // //var _configFilename = "config.json";
  211. // //// Arrange
  212. // //// Create a mock of the configuration files in all sources
  213. // //// Home directory
  214. // //string homeDir = Path.Combine (Environment.GetFolderPath (Environment.SpecialFolder.UserProfile), ".tui");
  215. // //if (!Directory.Exists (homeDir)) {
  216. // // Directory.CreateDirectory (homeDir);
  217. // //}
  218. // //string globalConfigFile = Path.Combine (homeDir, _configFilename);
  219. // //string appSpecificConfigFile = Path.Combine (homeDir, "appname.config.json");
  220. // //File.WriteAllText (globalConfigFile, "{\"Settings\": {\"TestSetting\":\"Global\"}}");
  221. // //File.WriteAllText (appSpecificConfigFile, "{\"Settings\": {\"TestSetting\":\"AppSpecific\"}}");
  222. // //// App directory
  223. // //string appDir = Directory.GetCurrentDirectory ();
  224. // //string appDirGlobalConfigFile = Path.Combine (appDir, _configFilename);
  225. // //string appDirAppSpecificConfigFile = Path.Combine (appDir, "appname.config.json");
  226. // //File.WriteAllText (appDirGlobalConfigFile, "{\"Settings\": {\"TestSetting\":\"GlobalAppDir\"}}");
  227. // //File.WriteAllText (appDirAppSpecificConfigFile, "{\"Settings\": {\"TestSetting\":\"AppSpecificAppDir\"}}");
  228. // //// App resources
  229. // //// ...
  230. // //// Act
  231. // //ConfigurationManager.Locations = ConfigurationManager.ConfigLocation.All;
  232. // //ConfigurationManager.Load ();
  233. // //// Assert
  234. // //// Check that the settings from the highest precedence source are loaded
  235. // //Assert.Equal ("AppSpecific", ConfigurationManager.Config.Settings.TestSetting);
  236. //}
  237. [Fact]
  238. public void Reset_Raises_Updated ()
  239. {
  240. ConfigLocations savedLocations = Locations;
  241. Locations = ConfigLocations.All;
  242. Reset ();
  243. Settings! ["Application.QuitKey"].PropertyValue = Key.Q;
  244. Updated += ConfigurationManager_Updated;
  245. var fired = false;
  246. void ConfigurationManager_Updated (object sender, ConfigurationManagerEventArgs obj)
  247. {
  248. fired = true;
  249. }
  250. // Act
  251. Reset ();
  252. // assert
  253. Assert.True (fired);
  254. Updated -= ConfigurationManager_Updated;
  255. Reset ();
  256. Locations = savedLocations;
  257. }
  258. [Fact]
  259. public void Reset_and_ResetLoadWithLibraryResourcesOnly_are_same ()
  260. {
  261. Locations = ConfigLocations.Default;
  262. // arrange
  263. Reset ();
  264. Settings! ["Application.QuitKey"].PropertyValue = Key.Q;
  265. Settings ["Application.NextTabGroupKey"].PropertyValue = Key.F;
  266. Settings ["Application.PrevTabGroupKey"].PropertyValue = Key.B;
  267. Settings.Apply ();
  268. // assert apply worked
  269. Assert.Equal (KeyCode.Q, Application.QuitKey.KeyCode);
  270. Assert.Equal (KeyCode.F, Application.NextTabGroupKey.KeyCode);
  271. Assert.Equal (KeyCode.B, Application.PrevTabGroupKey.KeyCode);
  272. //act
  273. Reset ();
  274. // assert
  275. Assert.NotEmpty (Themes!);
  276. Assert.Equal ("Default", Themes.Theme);
  277. Assert.Equal (Key.Esc, Application.QuitKey);
  278. Assert.Equal (Key.F6, Application.NextTabGroupKey);
  279. Assert.Equal (Key.F6.WithShift, Application.PrevTabGroupKey);
  280. // arrange
  281. Settings ["Application.QuitKey"].PropertyValue = Key.Q;
  282. Settings ["Application.NextTabGroupKey"].PropertyValue = Key.F;
  283. Settings ["Application.PrevTabGroupKey"].PropertyValue = Key.B;
  284. Settings.Apply ();
  285. Locations = ConfigLocations.Default;
  286. // act
  287. Reset ();
  288. Load ();
  289. // assert
  290. Assert.NotEmpty (Themes);
  291. Assert.Equal ("Default", Themes.Theme);
  292. Assert.Equal (KeyCode.Esc, Application.QuitKey.KeyCode);
  293. Assert.Equal (Key.F6, Application.NextTabGroupKey);
  294. Assert.Equal (Key.F6.WithShift, Application.PrevTabGroupKey);
  295. Reset ();
  296. }
  297. [Fact]
  298. public void Reset_Resets ()
  299. {
  300. Locations = ConfigLocations.Default;
  301. Reset ();
  302. Assert.NotEmpty (Themes!);
  303. Assert.Equal ("Default", Themes.Theme);
  304. }
  305. //[Fact ()]
  306. //public void LoadFromJsonTest ()
  307. //{
  308. // Assert.True (false, "This test needs an implementation");
  309. //}
  310. //[Fact ()]
  311. //public void ToJsonTest ()
  312. //{
  313. // Assert.True (false, "This test needs an implementation");
  314. //}
  315. //[Fact ()]
  316. //public void UpdateConfigurationTest ()
  317. //{
  318. // Assert.True (false, "This test needs an implementation");
  319. //}
  320. //[Fact ()]
  321. //public void UpdateConfigurationFromFileTest ()
  322. //{
  323. // Assert.True (false, "This test needs an implementation");
  324. //}
  325. //[Fact ()]
  326. //public void SaveHardCodedDefaultsTest ()
  327. //{
  328. // Assert.True (false, "This test needs an implementation");
  329. //}
  330. //[Fact ()]
  331. //public void LoadGlobalFromLibraryResourceTest ()
  332. //{
  333. // Assert.True (false, "This test needs an implementation");
  334. //}
  335. //[Fact ()]
  336. //public void LoadGlobalFromAppDirectoryTest ()
  337. //{
  338. // Assert.True (false, "This test needs an implementation");
  339. //}
  340. //[Fact ()]
  341. //public void LoadGlobalFromHomeDirectoryTest ()
  342. //{
  343. // Assert.True (false, "This test needs an implementation");
  344. //}
  345. //[Fact ()]
  346. //public void LoadAppFromAppResourcesTest ()
  347. //{
  348. // Assert.True (false, "This test needs an implementation");
  349. //}
  350. //[Fact ()]
  351. //public void LoadAppFromAppDirectoryTest ()
  352. //{
  353. // Assert.True (false, "This test needs an implementation");
  354. //}
  355. //[Fact ()]
  356. //public void LoadAppFromHomeDirectoryTest ()
  357. //{
  358. // Assert.True (false, "This test needs an implementation");
  359. //}
  360. //[Fact ()]
  361. //public void LoadTest ()
  362. //{
  363. // Assert.True (false, "This test needs an implementation");
  364. //}
  365. /// <summary>Save the `config.json` file; this can be used to update the file in `Terminal.Gui.Resources.config.json'.</summary>
  366. /// <remarks>
  367. /// IMPORTANT: For the file generated to be valid, this must be the ONLY test run. Config Properties are all
  368. /// static and thus can be overwritten by other tests.
  369. /// </remarks>
  370. [Fact]
  371. public void SaveDefaults ()
  372. {
  373. Initialize ();
  374. Reset ();
  375. // Get the hard coded settings
  376. GetHardCodedDefaults ();
  377. // Serialize to a JSON string
  378. string json = ToJson ();
  379. // Write the JSON string to the file
  380. File.WriteAllText ("config.json", json);
  381. }
  382. [Fact]
  383. public void TestConfigProperties ()
  384. {
  385. Locations = ConfigLocations.All;
  386. Reset ();
  387. Assert.NotEmpty (Settings!);
  388. // test that all ConfigProperties have our attribute
  389. Assert.All (
  390. Settings,
  391. item => Assert.NotEmpty (
  392. item.Value.PropertyInfo!.CustomAttributes.Where (
  393. a => a.AttributeType == typeof (SerializableConfigurationProperty)
  394. )
  395. )
  396. );
  397. #pragma warning disable xUnit2029
  398. Assert.Empty (
  399. Settings.Where (
  400. cp => cp.Value.PropertyInfo!.GetCustomAttribute (
  401. typeof (SerializableConfigurationProperty)
  402. )
  403. == null
  404. )
  405. );
  406. #pragma warning restore xUnit2029
  407. // Application is a static class
  408. PropertyInfo pi = typeof (Application).GetProperty ("QuitKey");
  409. Assert.Equal (pi, Settings ["Application.QuitKey"].PropertyInfo);
  410. // FrameView is not a static class and DefaultBorderStyle is Scope.Scheme
  411. pi = typeof (FrameView).GetProperty ("DefaultBorderStyle");
  412. Assert.False (Settings.ContainsKey ("FrameView.DefaultBorderStyle"));
  413. Assert.True (Themes! ["Default"].ContainsKey ("FrameView.DefaultBorderStyle"));
  414. Assert.Equal (pi, Themes! ["Default"] ["FrameView.DefaultBorderStyle"].PropertyInfo);
  415. }
  416. [Fact]
  417. public void TestConfigPropertyOmitClassName ()
  418. {
  419. ConfigLocations savedLocations = Locations;
  420. Locations = ConfigLocations.All;
  421. // Color.ColorSchemes is serialized as "ColorSchemes", not "Colors.ColorSchemes"
  422. PropertyInfo pi = typeof (Colors).GetProperty ("ColorSchemes");
  423. var scp = (SerializableConfigurationProperty)pi!.GetCustomAttribute (typeof (SerializableConfigurationProperty));
  424. Assert.True (scp!.Scope == typeof (ThemeScope));
  425. Assert.True (scp.OmitClassName);
  426. Reset ();
  427. Assert.Equal (pi, Themes! ["Default"] ["ColorSchemes"].PropertyInfo);
  428. Locations = savedLocations;
  429. }
  430. [Fact]
  431. [AutoInitShutdown (configLocation: ConfigLocations.Default)]
  432. public void TestConfigurationManagerInitDriver ()
  433. {
  434. Assert.Equal ("Default", Themes!.Theme);
  435. Assert.Equal (new Color (Color.White), Colors.ColorSchemes ["Base"]!.Normal.Foreground);
  436. Assert.Equal (new Color (Color.Blue), Colors.ColorSchemes ["Base"].Normal.Background);
  437. // Change Base
  438. Stream json = ToStream ();
  439. Settings!.Update (json, "TestConfigurationManagerInitDriver", ConfigLocations.Runtime);
  440. Dictionary<string, ColorScheme> colorSchemes =
  441. (Dictionary<string, ColorScheme>)Themes [Themes.Theme] ["ColorSchemes"].PropertyValue;
  442. Assert.Equal (Colors.ColorSchemes ["Base"], colorSchemes! ["Base"]);
  443. Assert.Equal (Colors.ColorSchemes ["TopLevel"], colorSchemes ["TopLevel"]);
  444. Assert.Equal (Colors.ColorSchemes ["Error"], colorSchemes ["Error"]);
  445. Assert.Equal (Colors.ColorSchemes ["Dialog"], colorSchemes ["Dialog"]);
  446. Assert.Equal (Colors.ColorSchemes ["Menu"], colorSchemes ["Menu"]);
  447. Colors.ColorSchemes ["Base"] = colorSchemes ["Base"];
  448. Colors.ColorSchemes ["TopLevel"] = colorSchemes ["TopLevel"];
  449. Colors.ColorSchemes ["Error"] = colorSchemes ["Error"];
  450. Colors.ColorSchemes ["Dialog"] = colorSchemes ["Dialog"];
  451. Colors.ColorSchemes ["Menu"] = colorSchemes ["Menu"];
  452. Assert.Equal (colorSchemes ["Base"], Colors.ColorSchemes ["Base"]);
  453. Assert.Equal (colorSchemes ["TopLevel"], Colors.ColorSchemes ["TopLevel"]);
  454. Assert.Equal (colorSchemes ["Error"], Colors.ColorSchemes ["Error"]);
  455. Assert.Equal (colorSchemes ["Dialog"], Colors.ColorSchemes ["Dialog"]);
  456. Assert.Equal (colorSchemes ["Menu"], Colors.ColorSchemes ["Menu"]);
  457. }
  458. [Fact]
  459. [AutoInitShutdown (configLocation: ConfigLocations.None)]
  460. public void TestConfigurationManagerInitDriver_NoLocations ()
  461. {
  462. // TODO: Write this test
  463. }
  464. [Fact]
  465. public void TestConfigurationManagerInvalidJsonLogs ()
  466. {
  467. Application.Init (new FakeDriver ());
  468. ThrowOnJsonErrors = false;
  469. // "brown" is not a color
  470. var json = @"
  471. {
  472. ""Themes"" : [
  473. {
  474. ""Default"" : {
  475. ""ColorSchemes"": [
  476. {
  477. ""UserDefined"": {
  478. ""hotNormal"": {
  479. ""foreground"": ""brown"",
  480. ""background"": ""1234""
  481. }
  482. }
  483. }
  484. ]
  485. }
  486. }
  487. }
  488. }";
  489. Settings!.Update (json, "test", ConfigLocations.Runtime);
  490. // AbNormal is not a ColorScheme attribute
  491. json = @"
  492. {
  493. ""Themes"" : [
  494. {
  495. ""Default"" : {
  496. ""ColorSchemes"": [
  497. {
  498. ""UserDefined"": {
  499. ""AbNormal"": {
  500. ""foreground"": ""green"",
  501. ""background"": ""black""
  502. }
  503. }
  504. }
  505. ]
  506. }
  507. }
  508. }
  509. }";
  510. Settings.Update (json, "test", ConfigLocations.Runtime);
  511. // Modify hotNormal background only
  512. json = @"
  513. {
  514. ""Themes"" : [
  515. {
  516. ""Default"" : {
  517. ""ColorSchemes"": [
  518. {
  519. ""UserDefined"": {
  520. ""hotNormal"": {
  521. ""background"": ""cyan""
  522. }
  523. }
  524. }
  525. ]
  526. }
  527. }
  528. }
  529. }";
  530. Settings.Update (json, "test", ConfigLocations.Runtime);
  531. Settings.Update ("{}}", "test", ConfigLocations.Runtime);
  532. Assert.NotEqual (0, _jsonErrors.Length);
  533. Application.Shutdown ();
  534. ThrowOnJsonErrors = false;
  535. }
  536. [Fact]
  537. [AutoInitShutdown]
  538. public void TestConfigurationManagerInvalidJsonThrows ()
  539. {
  540. ThrowOnJsonErrors = true;
  541. // "yellow" is not a color
  542. var json = @"
  543. {
  544. ""Themes"" : [
  545. {
  546. ""Default"" : {
  547. ""ColorSchemes"": [
  548. {
  549. ""UserDefined"": {
  550. ""hotNormal"": {
  551. ""foreground"": ""brownish"",
  552. ""background"": ""1234""
  553. }
  554. }
  555. }
  556. ]
  557. }
  558. }
  559. ]
  560. }";
  561. var jsonException = Assert.Throws<JsonException> (() => Settings!.Update (json, "test", ConfigLocations.Runtime));
  562. Assert.Equal ("Unexpected color name: brownish.", jsonException.Message);
  563. // AbNormal is not a ColorScheme attribute
  564. json = @"
  565. {
  566. ""Themes"" : [
  567. {
  568. ""Default"" : {
  569. ""ColorSchemes"": [
  570. {
  571. ""UserDefined"": {
  572. ""AbNormal"": {
  573. ""foreground"": ""green"",
  574. ""background"": ""black""
  575. }
  576. }
  577. }
  578. ]
  579. }
  580. }
  581. ]
  582. }";
  583. jsonException = Assert.Throws<JsonException> (() => Settings!.Update (json, "test", ConfigLocations.Runtime));
  584. Assert.Equal ("Unrecognized ColorScheme Attribute name: AbNormal.", jsonException.Message);
  585. // Modify hotNormal background only
  586. json = @"
  587. {
  588. ""Themes"" : [
  589. {
  590. ""Default"" : {
  591. ""ColorSchemes"": [
  592. {
  593. ""UserDefined"": {
  594. ""hotNormal"": {
  595. ""background"": ""cyan""
  596. }
  597. }
  598. }
  599. ]
  600. }
  601. }
  602. ]
  603. }";
  604. jsonException = Assert.Throws<JsonException> (() => Settings!.Update (json, "test", ConfigLocations.Runtime));
  605. Assert.Equal ("Both Foreground and Background colors must be provided.", jsonException.Message);
  606. // Unknown property
  607. json = @"
  608. {
  609. ""Unknown"" : ""Not known""
  610. }";
  611. jsonException = Assert.Throws<JsonException> (() => Settings!.Update (json, "test", ConfigLocations.Runtime));
  612. Assert.StartsWith ("Unknown property", jsonException.Message);
  613. Assert.Equal (0, _jsonErrors.Length);
  614. ThrowOnJsonErrors = false;
  615. }
  616. [Fact]
  617. [AutoInitShutdown]
  618. public void TestConfigurationManagerToJson ()
  619. {
  620. Reset ();
  621. GetHardCodedDefaults ();
  622. Stream stream = ToStream ();
  623. Settings!.Update (stream, "TestConfigurationManagerToJson", ConfigLocations.Runtime);
  624. }
  625. [Fact]
  626. public void TestConfigurationManagerUpdateFromJson ()
  627. {
  628. ConfigLocations savedLocations = Locations;
  629. Locations = ConfigLocations.All;
  630. // Arrange
  631. var json = @"
  632. {
  633. ""$schema"": ""https://gui-cs.github.io/Terminal.GuiV2Docs/schemas/tui-config-schema.json"",
  634. ""Application.QuitKey"": ""Alt-Z"",
  635. ""Theme"": ""Default"",
  636. ""Themes"": [
  637. {
  638. ""Default"": {
  639. ""ColorSchemes"": [
  640. {
  641. ""TopLevel"": {
  642. ""Normal"": {
  643. ""Foreground"": ""BrightGreen"",
  644. ""Background"": ""Black""
  645. },
  646. ""Focus"": {
  647. ""Foreground"": ""White"",
  648. ""Background"": ""Cyan""
  649. },
  650. ""HotNormal"": {
  651. ""Foreground"": ""Yellow"",
  652. ""Background"": ""Black""
  653. },
  654. ""HotFocus"": {
  655. ""Foreground"": ""Blue"",
  656. ""Background"": ""Cyan""
  657. },
  658. ""Disabled"": {
  659. ""Foreground"": ""DarkGray"",
  660. ""Background"": ""Black""
  661. }
  662. }
  663. },
  664. {
  665. ""Base"": {
  666. ""Normal"": {
  667. ""Foreground"": ""White"",
  668. ""Background"": ""Blue""
  669. },
  670. ""Focus"": {
  671. ""Foreground"": ""Black"",
  672. ""Background"": ""Gray""
  673. },
  674. ""HotNormal"": {
  675. ""Foreground"": ""BrightCyan"",
  676. ""Background"": ""Blue""
  677. },
  678. ""HotFocus"": {
  679. ""Foreground"": ""BrightBlue"",
  680. ""Background"": ""Gray""
  681. },
  682. ""Disabled"": {
  683. ""Foreground"": ""DarkGray"",
  684. ""Background"": ""Blue""
  685. }
  686. }
  687. },
  688. {
  689. ""Dialog"": {
  690. ""Normal"": {
  691. ""Foreground"": ""Black"",
  692. ""Background"": ""Gray""
  693. },
  694. ""Focus"": {
  695. ""Foreground"": ""White"",
  696. ""Background"": ""DarkGray""
  697. },
  698. ""HotNormal"": {
  699. ""Foreground"": ""Blue"",
  700. ""Background"": ""Gray""
  701. },
  702. ""HotFocus"": {
  703. ""Foreground"": ""BrightYellow"",
  704. ""Background"": ""DarkGray""
  705. },
  706. ""Disabled"": {
  707. ""Foreground"": ""Gray"",
  708. ""Background"": ""DarkGray""
  709. }
  710. }
  711. },
  712. {
  713. ""Menu"": {
  714. ""Normal"": {
  715. ""Foreground"": ""White"",
  716. ""Background"": ""DarkGray""
  717. },
  718. ""Focus"": {
  719. ""Foreground"": ""White"",
  720. ""Background"": ""Black""
  721. },
  722. ""HotNormal"": {
  723. ""Foreground"": ""BrightYellow"",
  724. ""Background"": ""DarkGray""
  725. },
  726. ""HotFocus"": {
  727. ""Foreground"": ""BrightYellow"",
  728. ""Background"": ""Black""
  729. },
  730. ""Disabled"": {
  731. ""Foreground"": ""Gray"",
  732. ""Background"": ""DarkGray""
  733. }
  734. }
  735. },
  736. {
  737. ""Error"": {
  738. ""Normal"": {
  739. ""Foreground"": ""Red"",
  740. ""Background"": ""White""
  741. },
  742. ""Focus"": {
  743. ""Foreground"": ""Black"",
  744. ""Background"": ""BrightRed""
  745. },
  746. ""HotNormal"": {
  747. ""Foreground"": ""Black"",
  748. ""Background"": ""White""
  749. },
  750. ""HotFocus"": {
  751. ""Foreground"": ""White"",
  752. ""Background"": ""BrightRed""
  753. },
  754. ""Disabled"": {
  755. ""Foreground"": ""DarkGray"",
  756. ""Background"": ""White""
  757. }
  758. }
  759. }
  760. ]
  761. }
  762. }
  763. ]
  764. }
  765. ";
  766. Reset ();
  767. ThrowOnJsonErrors = true;
  768. Settings!.Update (json, "TestConfigurationManagerUpdateFromJson", ConfigLocations.Runtime);
  769. Assert.Equal (KeyCode.Esc, Application.QuitKey.KeyCode);
  770. Assert.Equal (KeyCode.Z | KeyCode.AltMask, ((Key)Settings ["Application.QuitKey"].PropertyValue)!.KeyCode);
  771. Assert.Equal ("Default", Themes!.Theme);
  772. Assert.Equal (new Color (Color.White), Colors.ColorSchemes ["Base"]!.Normal.Foreground);
  773. Assert.Equal (new Color (Color.Blue), Colors.ColorSchemes ["Base"].Normal.Background);
  774. Dictionary<string, ColorScheme> colorSchemes =
  775. (Dictionary<string, ColorScheme>)Themes.First ().Value ["ColorSchemes"].PropertyValue;
  776. Assert.Equal (new Color (Color.White), colorSchemes! ["Base"].Normal.Foreground);
  777. Assert.Equal (new Color (Color.Blue), colorSchemes ["Base"].Normal.Background);
  778. // Now re-apply
  779. Apply ();
  780. Assert.Equal (KeyCode.Z | KeyCode.AltMask, Application.QuitKey.KeyCode);
  781. Assert.Equal ("Default", Themes.Theme);
  782. Assert.Equal (new Color (Color.White), Colors.ColorSchemes ["Base"].Normal.Foreground);
  783. Assert.Equal (new Color (Color.Blue), Colors.ColorSchemes ["Base"].Normal.Background);
  784. Reset ();
  785. Locations = savedLocations;
  786. }
  787. [Fact]
  788. public void UseWithoutResetDoesNotThrow ()
  789. {
  790. Initialize ();
  791. _ = Settings;
  792. }
  793. }