ConfigurationMangerTests.cs 26 KB

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