ConfigurationMangerTests.cs 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933
  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. 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 Illustrate_DeepMemberWiseCopy_ ()
  148. //{
  149. // Assert.Equal (Key.Esc, Application.QuitKey);
  150. // var o = UpdateValueFrom (Application.QuitKey);
  151. // DeepMemberWiseCopy (Key.Q.WithCtrl, Application.QuitKey);
  152. // Assert.Equal (Key.Q.WithCtrl, Application.QuitKey);
  153. // Application.ResetState (true);
  154. //}
  155. [Fact]
  156. public void Load_Raises_Updated ()
  157. {
  158. Locations = ConfigLocations.All;
  159. Reset ();
  160. Assert.Equal (Key.Esc, (((Key)Settings! ["Application.QuitKey"].PropertyValue)!).KeyCode);
  161. Updated += ConfigurationManager_Updated;
  162. var fired = false;
  163. void ConfigurationManager_Updated (object? sender, ConfigurationManagerEventArgs obj)
  164. {
  165. fired = true;
  166. }
  167. // Act
  168. // Do NOT reset
  169. Load (false);
  170. // assert
  171. Assert.True (fired);
  172. Updated -= ConfigurationManager_Updated;
  173. // clean up
  174. Locations = ConfigLocations.Default;
  175. Reset ();
  176. }
  177. [Fact]
  178. public void Load_Loads_Custom_Json ()
  179. {
  180. // arrange
  181. Locations = ConfigLocations.All;
  182. Reset ();
  183. ThrowOnJsonErrors = true;
  184. Assert.Equal (Key.Esc, (Key)Settings! ["Application.QuitKey"].PropertyValue);
  185. // act
  186. Memory = """
  187. {
  188. "Application.QuitKey": "Ctrl-Q"
  189. }
  190. """;
  191. Load (false);
  192. // assert
  193. Assert.Equal (Key.Q.WithCtrl, (Key)Settings ["Application.QuitKey"].PropertyValue);
  194. // clean up
  195. Locations = ConfigLocations.Default;
  196. Reset ();
  197. }
  198. [Fact]
  199. [AutoInitShutdown]
  200. public void LoadConfigurationFromAllSources_ShouldLoadSettingsFromAllSources ()
  201. {
  202. //var _configFilename = "config.json";
  203. //// Arrange
  204. //// Create a mock of the configuration files in all sources
  205. //// Home directory
  206. //string homeDir = Path.Combine (Environment.GetFolderPath (Environment.SpecialFolder.UserProfile), ".tui");
  207. //if (!Directory.Exists (homeDir)) {
  208. // Directory.CreateDirectory (homeDir);
  209. //}
  210. //string globalConfigFile = Path.Combine (homeDir, _configFilename);
  211. //string appSpecificConfigFile = Path.Combine (homeDir, "appname.config.json");
  212. //File.WriteAllText (globalConfigFile, "{\"Settings\": {\"TestSetting\":\"Global\"}}");
  213. //File.WriteAllText (appSpecificConfigFile, "{\"Settings\": {\"TestSetting\":\"AppSpecific\"}}");
  214. //// App directory
  215. //string appDir = Directory.GetCurrentDirectory ();
  216. //string appDirGlobalConfigFile = Path.Combine (appDir, _configFilename);
  217. //string appDirAppSpecificConfigFile = Path.Combine (appDir, "appname.config.json");
  218. //File.WriteAllText (appDirGlobalConfigFile, "{\"Settings\": {\"TestSetting\":\"GlobalAppDir\"}}");
  219. //File.WriteAllText (appDirAppSpecificConfigFile, "{\"Settings\": {\"TestSetting\":\"AppSpecificAppDir\"}}");
  220. //// App resources
  221. //// ...
  222. //// Act
  223. //ConfigurationManager.Locations = ConfigurationManager.ConfigLocation.All;
  224. //ConfigurationManager.Load ();
  225. //// Assert
  226. //// Check that the settings from the highest precedence source are loaded
  227. //Assert.Equal ("AppSpecific", ConfigurationManager.Config.Settings.TestSetting);
  228. }
  229. [Fact]
  230. public void Reset_Raises_Updated ()
  231. {
  232. ConfigLocations savedLocations = Locations;
  233. Locations = ConfigLocations.All;
  234. Reset ();
  235. Settings! ["Application.QuitKey"].PropertyValue = Key.Q;
  236. Updated += ConfigurationManager_Updated;
  237. var fired = false;
  238. void ConfigurationManager_Updated (object? sender, ConfigurationManagerEventArgs obj)
  239. {
  240. fired = true;
  241. }
  242. // Act
  243. Reset ();
  244. // assert
  245. Assert.True (fired);
  246. Updated -= ConfigurationManager_Updated;
  247. Reset ();
  248. Locations = savedLocations;
  249. }
  250. [Fact]
  251. public void Reset_and_ResetLoadWithLibraryResourcesOnly_are_same ()
  252. {
  253. Locations = ConfigLocations.Default;
  254. // arrange
  255. Reset ();
  256. Settings! ["Application.QuitKey"].PropertyValue = Key.Q;
  257. Settings ["Application.NextTabGroupKey"].PropertyValue = Key.F;
  258. Settings ["Application.PrevTabGroupKey"].PropertyValue = Key.B;
  259. Settings.Apply ();
  260. // assert apply worked
  261. Assert.Equal (KeyCode.Q, Application.QuitKey.KeyCode);
  262. Assert.Equal (KeyCode.F, Application.NextTabGroupKey.KeyCode);
  263. Assert.Equal (KeyCode.B, Application.PrevTabGroupKey.KeyCode);
  264. //act
  265. Reset ();
  266. // assert
  267. Assert.NotEmpty (Themes!);
  268. Assert.Equal ("Default", Themes.Theme);
  269. Assert.Equal (Key.Esc, Application.QuitKey);
  270. Assert.Equal (Key.F6, Application.NextTabGroupKey);
  271. Assert.Equal (Key.F6.WithShift, Application.PrevTabGroupKey);
  272. // arrange
  273. Settings ["Application.QuitKey"].PropertyValue = Key.Q;
  274. Settings ["Application.NextTabGroupKey"].PropertyValue = Key.F;
  275. Settings ["Application.PrevTabGroupKey"].PropertyValue = Key.B;
  276. Settings.Apply ();
  277. Locations = ConfigLocations.Default;
  278. // act
  279. Reset ();
  280. Load ();
  281. // assert
  282. Assert.NotEmpty (Themes);
  283. Assert.Equal ("Default", Themes.Theme);
  284. Assert.Equal (KeyCode.Esc, Application.QuitKey.KeyCode);
  285. Assert.Equal (Key.F6, Application.NextTabGroupKey);
  286. Assert.Equal (Key.F6.WithShift, Application.PrevTabGroupKey);
  287. Reset ();
  288. }
  289. [Fact]
  290. public void Reset_Resets ()
  291. {
  292. Locations = ConfigLocations.Default;
  293. Reset ();
  294. Assert.NotEmpty (Themes!);
  295. Assert.Equal ("Default", Themes.Theme);
  296. }
  297. //[Fact ()]
  298. //public void LoadFromJsonTest ()
  299. //{
  300. // Assert.True (false, "This test needs an implementation");
  301. //}
  302. //[Fact ()]
  303. //public void ToJsonTest ()
  304. //{
  305. // Assert.True (false, "This test needs an implementation");
  306. //}
  307. //[Fact ()]
  308. //public void UpdateConfigurationTest ()
  309. //{
  310. // Assert.True (false, "This test needs an implementation");
  311. //}
  312. //[Fact ()]
  313. //public void UpdateConfigurationFromFileTest ()
  314. //{
  315. // Assert.True (false, "This test needs an implementation");
  316. //}
  317. //[Fact ()]
  318. //public void SaveHardCodedDefaultsTest ()
  319. //{
  320. // Assert.True (false, "This test needs an implementation");
  321. //}
  322. //[Fact ()]
  323. //public void LoadGlobalFromLibraryResourceTest ()
  324. //{
  325. // Assert.True (false, "This test needs an implementation");
  326. //}
  327. //[Fact ()]
  328. //public void LoadGlobalFromAppDirectoryTest ()
  329. //{
  330. // Assert.True (false, "This test needs an implementation");
  331. //}
  332. //[Fact ()]
  333. //public void LoadGlobalFromHomeDirectoryTest ()
  334. //{
  335. // Assert.True (false, "This test needs an implementation");
  336. //}
  337. //[Fact ()]
  338. //public void LoadAppFromAppResourcesTest ()
  339. //{
  340. // Assert.True (false, "This test needs an implementation");
  341. //}
  342. //[Fact ()]
  343. //public void LoadAppFromAppDirectoryTest ()
  344. //{
  345. // Assert.True (false, "This test needs an implementation");
  346. //}
  347. //[Fact ()]
  348. //public void LoadAppFromHomeDirectoryTest ()
  349. //{
  350. // Assert.True (false, "This test needs an implementation");
  351. //}
  352. //[Fact ()]
  353. //public void LoadTest ()
  354. //{
  355. // Assert.True (false, "This test needs an implementation");
  356. //}
  357. /// <summary>Save the `config.json` file; this can be used to update the file in `Terminal.Gui.Resources.config.json'.</summary>
  358. /// <remarks>
  359. /// IMPORTANT: For the file generated to be valid, this must be the ONLY test run. Config Properties are all
  360. /// static and thus can be overwritten by other tests.
  361. /// </remarks>
  362. [Fact]
  363. public void SaveDefaults ()
  364. {
  365. Initialize ();
  366. Reset ();
  367. // Get the hard coded settings
  368. GetHardCodedDefaults ();
  369. // Serialize to a JSON string
  370. string json = ToJson ();
  371. // Write the JSON string to the file
  372. File.WriteAllText ("config.json", json);
  373. }
  374. [Fact]
  375. public void TestConfigProperties ()
  376. {
  377. Locations = ConfigLocations.All;
  378. Reset ();
  379. Assert.NotEmpty (Settings!);
  380. // test that all ConfigProperties have our attribute
  381. Assert.All (
  382. Settings,
  383. item => Assert.NotEmpty (
  384. item.Value.PropertyInfo!.CustomAttributes.Where (
  385. a => a.AttributeType == typeof (SerializableConfigurationProperty)
  386. )
  387. )
  388. );
  389. #pragma warning disable xUnit2029
  390. Assert.Empty (
  391. Settings.Where (
  392. cp => cp.Value.PropertyInfo!.GetCustomAttribute (
  393. typeof (SerializableConfigurationProperty)
  394. )
  395. == null
  396. )
  397. );
  398. #pragma warning restore xUnit2029
  399. // Application is a static class
  400. PropertyInfo pi = typeof (Application).GetProperty ("QuitKey");
  401. Assert.Equal (pi, Settings ["Application.QuitKey"].PropertyInfo);
  402. // FrameView is not a static class and DefaultBorderStyle is Scope.Scheme
  403. pi = typeof (FrameView).GetProperty ("DefaultBorderStyle");
  404. Assert.False (Settings.ContainsKey ("FrameView.DefaultBorderStyle"));
  405. Assert.True (Themes! ["Default"].ContainsKey ("FrameView.DefaultBorderStyle"));
  406. Assert.Equal (pi, Themes! ["Default"] ["FrameView.DefaultBorderStyle"].PropertyInfo);
  407. }
  408. [Fact]
  409. public void TestConfigPropertyOmitClassName ()
  410. {
  411. ConfigLocations savedLocations = Locations;
  412. Locations = ConfigLocations.All;
  413. // Color.ColorSchemes is serialized as "ColorSchemes", not "Colors.ColorSchemes"
  414. PropertyInfo pi = typeof (Colors).GetProperty ("ColorSchemes");
  415. var scp = (SerializableConfigurationProperty)pi!.GetCustomAttribute (typeof (SerializableConfigurationProperty));
  416. Assert.True (scp!.Scope == typeof (ThemeScope));
  417. Assert.True (scp.OmitClassName);
  418. Reset ();
  419. Assert.Equal (pi, Themes! ["Default"] ["ColorSchemes"].PropertyInfo);
  420. Locations = savedLocations;
  421. }
  422. [Fact]
  423. [AutoInitShutdown (configLocation: ConfigLocations.Default)]
  424. public void TestConfigurationManagerInitDriver ()
  425. {
  426. Assert.Equal ("Default", Themes!.Theme);
  427. Assert.Equal (new Color (Color.White), Colors.ColorSchemes ["Base"]!.Normal.Foreground);
  428. Assert.Equal (new Color (Color.Blue), Colors.ColorSchemes ["Base"].Normal.Background);
  429. // Change Base
  430. Stream json = ToStream ();
  431. Settings!.Update (json, "TestConfigurationManagerInitDriver");
  432. Dictionary<string, ColorScheme> colorSchemes =
  433. (Dictionary<string, ColorScheme>)Themes [Themes.Theme] ["ColorSchemes"].PropertyValue;
  434. Assert.Equal (Colors.ColorSchemes ["Base"], colorSchemes! ["Base"]);
  435. Assert.Equal (Colors.ColorSchemes ["TopLevel"], colorSchemes ["TopLevel"]);
  436. Assert.Equal (Colors.ColorSchemes ["Error"], colorSchemes ["Error"]);
  437. Assert.Equal (Colors.ColorSchemes ["Dialog"], colorSchemes ["Dialog"]);
  438. Assert.Equal (Colors.ColorSchemes ["Menu"], colorSchemes ["Menu"]);
  439. Colors.ColorSchemes ["Base"] = colorSchemes ["Base"];
  440. Colors.ColorSchemes ["TopLevel"] = colorSchemes ["TopLevel"];
  441. Colors.ColorSchemes ["Error"] = colorSchemes ["Error"];
  442. Colors.ColorSchemes ["Dialog"] = colorSchemes ["Dialog"];
  443. Colors.ColorSchemes ["Menu"] = colorSchemes ["Menu"];
  444. Assert.Equal (colorSchemes ["Base"], Colors.ColorSchemes ["Base"]);
  445. Assert.Equal (colorSchemes ["TopLevel"], Colors.ColorSchemes ["TopLevel"]);
  446. Assert.Equal (colorSchemes ["Error"], Colors.ColorSchemes ["Error"]);
  447. Assert.Equal (colorSchemes ["Dialog"], Colors.ColorSchemes ["Dialog"]);
  448. Assert.Equal (colorSchemes ["Menu"], Colors.ColorSchemes ["Menu"]);
  449. }
  450. [Fact]
  451. [AutoInitShutdown (configLocation: ConfigLocations.None)]
  452. public void TestConfigurationManagerInitDriver_NoLocations ()
  453. {
  454. // TODO: Write this test
  455. }
  456. [Fact]
  457. public void TestConfigurationManagerInvalidJsonLogs ()
  458. {
  459. Application.Init (new FakeDriver ());
  460. ThrowOnJsonErrors = false;
  461. // "brown" is not a color
  462. var json = @"
  463. {
  464. ""Themes"" : [
  465. {
  466. ""Default"" : {
  467. ""ColorSchemes"": [
  468. {
  469. ""UserDefined"": {
  470. ""hotNormal"": {
  471. ""foreground"": ""brown"",
  472. ""background"": ""1234""
  473. }
  474. }
  475. }
  476. ]
  477. }
  478. }
  479. }
  480. }";
  481. Settings!.Update (json, "test");
  482. // AbNormal is not a ColorScheme attribute
  483. json = @"
  484. {
  485. ""Themes"" : [
  486. {
  487. ""Default"" : {
  488. ""ColorSchemes"": [
  489. {
  490. ""UserDefined"": {
  491. ""AbNormal"": {
  492. ""foreground"": ""green"",
  493. ""background"": ""black""
  494. }
  495. }
  496. }
  497. ]
  498. }
  499. }
  500. }
  501. }";
  502. Settings.Update (json, "test");
  503. // Modify hotNormal background only
  504. json = @"
  505. {
  506. ""Themes"" : [
  507. {
  508. ""Default"" : {
  509. ""ColorSchemes"": [
  510. {
  511. ""UserDefined"": {
  512. ""hotNormal"": {
  513. ""background"": ""cyan""
  514. }
  515. }
  516. }
  517. ]
  518. }
  519. }
  520. }
  521. }";
  522. Settings.Update (json, "test");
  523. Settings.Update ("{}}", "test");
  524. Assert.NotEqual (0, _jsonErrors.Length);
  525. Application.Shutdown ();
  526. ThrowOnJsonErrors = false;
  527. }
  528. [Fact]
  529. [AutoInitShutdown]
  530. public void TestConfigurationManagerInvalidJsonThrows ()
  531. {
  532. ThrowOnJsonErrors = true;
  533. // "yellow" is not a color
  534. var json = @"
  535. {
  536. ""Themes"" : [
  537. {
  538. ""Default"" : {
  539. ""ColorSchemes"": [
  540. {
  541. ""UserDefined"": {
  542. ""hotNormal"": {
  543. ""foreground"": ""brownish"",
  544. ""background"": ""1234""
  545. }
  546. }
  547. }
  548. ]
  549. }
  550. }
  551. ]
  552. }";
  553. var jsonException = Assert.Throws<JsonException> (() => Settings!.Update (json, "test"));
  554. Assert.Equal ("Unexpected color name: brownish.", jsonException.Message);
  555. // AbNormal is not a ColorScheme attribute
  556. json = @"
  557. {
  558. ""Themes"" : [
  559. {
  560. ""Default"" : {
  561. ""ColorSchemes"": [
  562. {
  563. ""UserDefined"": {
  564. ""AbNormal"": {
  565. ""foreground"": ""green"",
  566. ""background"": ""black""
  567. }
  568. }
  569. }
  570. ]
  571. }
  572. }
  573. ]
  574. }";
  575. jsonException = Assert.Throws<JsonException> (() => Settings!.Update (json, "test"));
  576. Assert.Equal ("Unrecognized ColorScheme Attribute name: AbNormal.", jsonException.Message);
  577. // Modify hotNormal background only
  578. json = @"
  579. {
  580. ""Themes"" : [
  581. {
  582. ""Default"" : {
  583. ""ColorSchemes"": [
  584. {
  585. ""UserDefined"": {
  586. ""hotNormal"": {
  587. ""background"": ""cyan""
  588. }
  589. }
  590. }
  591. ]
  592. }
  593. }
  594. ]
  595. }";
  596. jsonException = Assert.Throws<JsonException> (() => Settings!.Update (json, "test"));
  597. Assert.Equal ("Both Foreground and Background colors must be provided.", jsonException.Message);
  598. // Unknown property
  599. json = @"
  600. {
  601. ""Unknown"" : ""Not known""
  602. }";
  603. jsonException = Assert.Throws<JsonException> (() => Settings!.Update (json, "test"));
  604. Assert.StartsWith ("Unknown property", jsonException.Message);
  605. Assert.Equal (0, _jsonErrors.Length);
  606. ThrowOnJsonErrors = false;
  607. }
  608. [Fact]
  609. [AutoInitShutdown]
  610. public void TestConfigurationManagerToJson ()
  611. {
  612. Reset ();
  613. GetHardCodedDefaults ();
  614. Stream stream = ToStream ();
  615. Settings!.Update (stream, "TestConfigurationManagerToJson");
  616. }
  617. [Fact]
  618. public void TestConfigurationManagerUpdateFromJson ()
  619. {
  620. ConfigLocations savedLocations = Locations;
  621. Locations = ConfigLocations.All;
  622. // Arrange
  623. var json = @"
  624. {
  625. ""$schema"": ""https://gui-cs.github.io/Terminal.GuiV2Docs/schemas/tui-config-schema.json"",
  626. ""Application.QuitKey"": ""Alt-Z"",
  627. ""Theme"": ""Default"",
  628. ""Themes"": [
  629. {
  630. ""Default"": {
  631. ""ColorSchemes"": [
  632. {
  633. ""TopLevel"": {
  634. ""Normal"": {
  635. ""Foreground"": ""BrightGreen"",
  636. ""Background"": ""Black""
  637. },
  638. ""Focus"": {
  639. ""Foreground"": ""White"",
  640. ""Background"": ""Cyan""
  641. },
  642. ""HotNormal"": {
  643. ""Foreground"": ""Yellow"",
  644. ""Background"": ""Black""
  645. },
  646. ""HotFocus"": {
  647. ""Foreground"": ""Blue"",
  648. ""Background"": ""Cyan""
  649. },
  650. ""Disabled"": {
  651. ""Foreground"": ""DarkGray"",
  652. ""Background"": ""Black""
  653. }
  654. }
  655. },
  656. {
  657. ""Base"": {
  658. ""Normal"": {
  659. ""Foreground"": ""White"",
  660. ""Background"": ""Blue""
  661. },
  662. ""Focus"": {
  663. ""Foreground"": ""Black"",
  664. ""Background"": ""Gray""
  665. },
  666. ""HotNormal"": {
  667. ""Foreground"": ""BrightCyan"",
  668. ""Background"": ""Blue""
  669. },
  670. ""HotFocus"": {
  671. ""Foreground"": ""BrightBlue"",
  672. ""Background"": ""Gray""
  673. },
  674. ""Disabled"": {
  675. ""Foreground"": ""DarkGray"",
  676. ""Background"": ""Blue""
  677. }
  678. }
  679. },
  680. {
  681. ""Dialog"": {
  682. ""Normal"": {
  683. ""Foreground"": ""Black"",
  684. ""Background"": ""Gray""
  685. },
  686. ""Focus"": {
  687. ""Foreground"": ""White"",
  688. ""Background"": ""DarkGray""
  689. },
  690. ""HotNormal"": {
  691. ""Foreground"": ""Blue"",
  692. ""Background"": ""Gray""
  693. },
  694. ""HotFocus"": {
  695. ""Foreground"": ""BrightYellow"",
  696. ""Background"": ""DarkGray""
  697. },
  698. ""Disabled"": {
  699. ""Foreground"": ""Gray"",
  700. ""Background"": ""DarkGray""
  701. }
  702. }
  703. },
  704. {
  705. ""Menu"": {
  706. ""Normal"": {
  707. ""Foreground"": ""White"",
  708. ""Background"": ""DarkGray""
  709. },
  710. ""Focus"": {
  711. ""Foreground"": ""White"",
  712. ""Background"": ""Black""
  713. },
  714. ""HotNormal"": {
  715. ""Foreground"": ""BrightYellow"",
  716. ""Background"": ""DarkGray""
  717. },
  718. ""HotFocus"": {
  719. ""Foreground"": ""BrightYellow"",
  720. ""Background"": ""Black""
  721. },
  722. ""Disabled"": {
  723. ""Foreground"": ""Gray"",
  724. ""Background"": ""DarkGray""
  725. }
  726. }
  727. },
  728. {
  729. ""Error"": {
  730. ""Normal"": {
  731. ""Foreground"": ""Red"",
  732. ""Background"": ""White""
  733. },
  734. ""Focus"": {
  735. ""Foreground"": ""Black"",
  736. ""Background"": ""BrightRed""
  737. },
  738. ""HotNormal"": {
  739. ""Foreground"": ""Black"",
  740. ""Background"": ""White""
  741. },
  742. ""HotFocus"": {
  743. ""Foreground"": ""White"",
  744. ""Background"": ""BrightRed""
  745. },
  746. ""Disabled"": {
  747. ""Foreground"": ""DarkGray"",
  748. ""Background"": ""White""
  749. }
  750. }
  751. }
  752. ]
  753. }
  754. }
  755. ]
  756. }
  757. ";
  758. Reset ();
  759. ThrowOnJsonErrors = true;
  760. Settings!.Update (json, "TestConfigurationManagerUpdateFromJson");
  761. Assert.Equal (KeyCode.Esc, Application.QuitKey.KeyCode);
  762. Assert.Equal (KeyCode.Z | KeyCode.AltMask, ((Key)Settings ["Application.QuitKey"].PropertyValue)!.KeyCode);
  763. Assert.Equal ("Default", Themes!.Theme);
  764. Assert.Equal (new Color (Color.White), Colors.ColorSchemes ["Base"]!.Normal.Foreground);
  765. Assert.Equal (new Color (Color.Blue), Colors.ColorSchemes ["Base"].Normal.Background);
  766. Dictionary<string, ColorScheme> colorSchemes =
  767. (Dictionary<string, ColorScheme>)Themes.First ().Value ["ColorSchemes"].PropertyValue;
  768. Assert.Equal (new Color (Color.White), colorSchemes! ["Base"].Normal.Foreground);
  769. Assert.Equal (new Color (Color.Blue), colorSchemes ["Base"].Normal.Background);
  770. // Now re-apply
  771. Apply ();
  772. Assert.Equal (KeyCode.Z | KeyCode.AltMask, Application.QuitKey.KeyCode);
  773. Assert.Equal ("Default", Themes.Theme);
  774. Assert.Equal (new Color (Color.White), Colors.ColorSchemes ["Base"].Normal.Foreground);
  775. Assert.Equal (new Color (Color.Blue), Colors.ColorSchemes ["Base"].Normal.Background);
  776. Reset ();
  777. Locations = savedLocations;
  778. }
  779. [Fact]
  780. public void UseWithoutResetDoesNotThrow ()
  781. {
  782. Initialize ();
  783. _ = Settings;
  784. }
  785. }