DeepClonerTests.cs 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641
  1. #nullable enable
  2. using System.Collections.Concurrent;
  3. using System.Collections.Immutable;
  4. using System.Diagnostics;
  5. using System.Text;
  6. namespace UnitTests_Parallelizable.ConfigurationTests;
  7. /// <summary>
  8. /// Unit tests for the <see cref="DeepCloner"/> class, ensuring robust deep cloning for
  9. /// Terminal.Gui's configuration system.
  10. /// </summary>
  11. public class DeepClonerTests
  12. {
  13. // Test classes for complex scenarios
  14. private class SimpleValueType
  15. {
  16. public int Number { get; set; }
  17. public bool Flag { get; init; }
  18. }
  19. private class SimpleReferenceType
  20. {
  21. public string? Name { get; set; }
  22. public int Count { get; set; }
  23. public override bool Equals (object? obj) { return obj is SimpleReferenceType other && Name == other.Name && Count == other.Count; }
  24. // ReSharper disable twice NonReadonlyMemberInGetHashCode
  25. public override int GetHashCode () { return HashCode.Combine (Name, Count); }
  26. }
  27. private class CollectionContainer
  28. {
  29. public List<string>? Strings { get; init; }
  30. public Dictionary<string, int>? Counts { get; init; }
  31. public int []? Numbers { get; init; }
  32. }
  33. private class NestedObject
  34. {
  35. public SimpleReferenceType? Inner { get; init; }
  36. public List<SimpleValueType>? Values { get; init; }
  37. }
  38. private class CircularReference
  39. {
  40. public CircularReference? Self { get; set; }
  41. public string? Name { get; set; }
  42. }
  43. private class ConfigPropertyMock
  44. {
  45. public object? PropertyValue { get; init; }
  46. public bool Immutable { get; init; }
  47. }
  48. private class ComplexKey
  49. {
  50. public int Id { get; init; }
  51. public override bool Equals (object? obj) { return obj is ComplexKey key && Id == key.Id; }
  52. public override int GetHashCode () { return Id.GetHashCode (); }
  53. }
  54. private class KeyEqualityComparer : IEqualityComparer<Key>
  55. {
  56. public bool Equals (Key? x, Key? y) { return x?.KeyCode == y?.KeyCode; }
  57. public int GetHashCode (Key obj) { return obj.KeyCode.GetHashCode (); }
  58. }
  59. // Fundamentals
  60. [Fact]
  61. public void Null_ReturnsNull ()
  62. {
  63. object? source = null;
  64. object? result = DeepCloner.DeepClone (source);
  65. Assert.Null (result);
  66. }
  67. [Fact]
  68. public void SimpleValueType_ReturnsEqualValue ()
  69. {
  70. var source = 42;
  71. int result = DeepCloner.DeepClone (source);
  72. Assert.Equal (source, result);
  73. }
  74. [Fact]
  75. public void String_ReturnsSameString ()
  76. {
  77. var source = "Hello";
  78. string? result = DeepCloner.DeepClone (source);
  79. Assert.Equal (source, result);
  80. Assert.Same (source, result); // Strings are immutable
  81. }
  82. [Fact]
  83. public void Rune_ReturnsEqualRune ()
  84. {
  85. Rune source = new ('A');
  86. Rune result = DeepCloner.DeepClone (source);
  87. Assert.Equal (source, result);
  88. }
  89. [Fact]
  90. public void Key_CreatesDeepCopy ()
  91. {
  92. Key? source = new (KeyCode.A);
  93. source.Handled = true;
  94. Key? result = DeepCloner.DeepClone (source);
  95. Assert.NotNull (result);
  96. Assert.NotSame (source, result);
  97. Assert.Equal (source.KeyCode, result.KeyCode);
  98. Assert.Equal (source.Handled, result.Handled);
  99. // Modify result, ensure source unchanged
  100. result.Handled = false;
  101. Assert.True (source.Handled);
  102. }
  103. [Fact]
  104. public void Enum_ReturnsEqualEnum ()
  105. {
  106. var source = DayOfWeek.Monday;
  107. DayOfWeek result = DeepCloner.DeepClone (source);
  108. Assert.Equal (source, result);
  109. }
  110. [Fact]
  111. public void Boolean_ReturnsEqualValue ()
  112. {
  113. var source = true;
  114. bool result = DeepCloner.DeepClone (source);
  115. Assert.Equal (source, result);
  116. source = false;
  117. result = DeepCloner.DeepClone (source);
  118. Assert.Equal (source, result);
  119. }
  120. [Fact]
  121. public void Attribute_ReturnsEqualValue ()
  122. {
  123. var source = new Attribute (Color.Black);
  124. Attribute result = DeepCloner.DeepClone (source);
  125. Assert.Equal (source, result);
  126. source = new (Color.White);
  127. result = DeepCloner.DeepClone (source);
  128. Assert.Equal (source, result);
  129. }
  130. [Fact]
  131. public void Scheme_Normal_Set_ReturnsEqualValue ()
  132. {
  133. var source = new Scheme (new Scheme (new Attribute (Color.Red, Color.Green, TextStyle.Bold)));
  134. Scheme? result = DeepCloner.DeepClone (source);
  135. Assert.Equal (source, result);
  136. source = new Scheme (new Scheme ());
  137. result = DeepCloner.DeepClone (source);
  138. Assert.Equal (source, result);
  139. }
  140. [Fact]
  141. public void Scheme_All_Set_ReturnsEqualValue ()
  142. {
  143. Scheme? source = new ()
  144. {
  145. Normal = new ("LightGray", "RaisinBlack", TextStyle.None),
  146. Focus = new ("White", "DarkGray", TextStyle.None),
  147. HotNormal = new ("Silver", "RaisinBlack", TextStyle.Underline),
  148. Disabled = new ("DarkGray", "RaisinBlack", TextStyle.Faint),
  149. HotFocus = new ("White", "Green", TextStyle.Underline),
  150. Active = new ("White", "Charcoal", TextStyle.Bold),
  151. HotActive = new ("White", "Charcoal", TextStyle.Underline | TextStyle.Bold),
  152. Highlight = new ("White", "Onyx", TextStyle.None),
  153. Editable = new ("LightYellow", "RaisinBlack", TextStyle.None),
  154. ReadOnly = new ("Gray", "RaisinBlack", TextStyle.Italic)
  155. };
  156. Scheme? result = DeepCloner.DeepClone (source);
  157. Assert.True (source.TryGetExplicitlySetAttributeForRole (VisualRole.Normal, out _));
  158. Assert.True (source.TryGetExplicitlySetAttributeForRole (VisualRole.Active, out _));
  159. Assert.True (source.TryGetExplicitlySetAttributeForRole (VisualRole.HotNormal, out _));
  160. Assert.True (source.TryGetExplicitlySetAttributeForRole (VisualRole.Focus, out _));
  161. Assert.True (source.TryGetExplicitlySetAttributeForRole (VisualRole.HotFocus, out _));
  162. Assert.True (source.TryGetExplicitlySetAttributeForRole (VisualRole.Active, out _));
  163. Assert.True (source.TryGetExplicitlySetAttributeForRole (VisualRole.HotActive, out _));
  164. Assert.True (source.TryGetExplicitlySetAttributeForRole (VisualRole.Highlight, out _));
  165. Assert.True (source.TryGetExplicitlySetAttributeForRole (VisualRole.Editable, out _));
  166. Assert.True (source.TryGetExplicitlySetAttributeForRole (VisualRole.ReadOnly, out _));
  167. Assert.True (source.TryGetExplicitlySetAttributeForRole (VisualRole.Disabled, out _));
  168. Assert.Equal (source, result);
  169. source = new Scheme (new Scheme ());
  170. result = DeepCloner.DeepClone (source);
  171. Assert.Equal (source, result);
  172. }
  173. // Simple Reference Types
  174. [Fact]
  175. public void SimpleReferenceType_CreatesDeepCopy ()
  176. {
  177. SimpleReferenceType? source = new () { Name = "Test", Count = 10 };
  178. SimpleReferenceType? result = DeepCloner.DeepClone (source);
  179. Assert.NotNull (result);
  180. Assert.NotSame (source, result);
  181. Assert.Equal (source.Name, result!.Name);
  182. Assert.Equal (source.Count, result.Count);
  183. Assert.True (source.Equals (result)); // Verify Equals method
  184. Assert.Equal (source.GetHashCode (), result.GetHashCode ()); // Verify GetHashCode
  185. // Modify result, ensure source unchanged
  186. result.Name = "Modified";
  187. result.Count = 20;
  188. Assert.Equal ("Test", source.Name);
  189. Assert.Equal (10, source.Count);
  190. }
  191. // Collections
  192. [Fact]
  193. public void List_CreatesDeepCopy ()
  194. {
  195. List<string>? source = new () { "One", "Two" };
  196. List<string>? result = DeepCloner.DeepClone (source);
  197. Assert.NotNull (result);
  198. Assert.NotSame (source, result);
  199. Assert.Equal (source, result);
  200. // Modify result, ensure source unchanged
  201. result!.Add ("Three");
  202. Assert.Equal (2, source.Count);
  203. Assert.Equal (3, result.Count);
  204. }
  205. [Fact]
  206. public void Dictionary_CreatesDeepCopy ()
  207. {
  208. Dictionary<string, int>? source = new () { { "A", 1 }, { "B", 2 } };
  209. Dictionary<string, int>? result = DeepCloner.DeepClone (source);
  210. Assert.NotNull (result);
  211. Assert.NotSame (source, result);
  212. Assert.Equal (source, result);
  213. // Modify result, ensure source unchanged
  214. result! ["C"] = 3;
  215. Assert.Equal (2, source.Count);
  216. Assert.Equal (3, result.Count);
  217. }
  218. [Fact]
  219. public void Dictionary_CreatesDeepCopy_Including_Comparer_Options ()
  220. {
  221. Dictionary<string, int>? source = new (StringComparer.InvariantCultureIgnoreCase) { { "A", 1 }, { "B", 2 } };
  222. Dictionary<string, int>? result = DeepCloner.DeepClone (source);
  223. Assert.NotNull (result);
  224. Assert.NotSame (source, result);
  225. Assert.Equal (source, result);
  226. Assert.Equal (source.Comparer, result.Comparer);
  227. // Modify result, ensure source unchanged
  228. result! ["C"] = 3;
  229. Assert.Equal (2, source.Count);
  230. Assert.Equal (3, result.Count);
  231. Assert.Contains ("A", result);
  232. Assert.Contains ("a", result);
  233. }
  234. [Fact]
  235. public void Dictionary_CreatesDeepCopy_WithCapacity ()
  236. {
  237. // Arrange: Create a dictionary with a specific capacity
  238. Dictionary<string, int> source = new (100) // Set initial capacity to 100
  239. {
  240. { "Key1", 1 },
  241. { "Key2", 2 }
  242. };
  243. // Act: Clone the dictionary
  244. Dictionary<string, int>? result = DeepCloner.DeepClone (source);
  245. // Assert: Verify the dictionary was cloned correctly
  246. Assert.NotNull (result);
  247. Assert.NotSame (source, result);
  248. Assert.Equal (source, result); // Verify key-value pairs are cloned
  249. // Verify that the capacity is preserved (if supported)
  250. Assert.True (result.Count <= result.EnsureCapacity (0)); // EnsureCapacity(0) returns the current capacity
  251. Assert.True (source.Count <= source.EnsureCapacity (0)); // EnsureCapacity(0) returns the current capacity
  252. }
  253. [Fact]
  254. public void ConcurrentDictionary_CreatesDeepCopy ()
  255. {
  256. ConcurrentDictionary<string, int>? source = new (new Dictionary<string, int> () { { "A", 1 }, { "B", 2 } });
  257. ConcurrentDictionary<string, int>? result = DeepCloner.DeepClone (source);
  258. Assert.NotNull (result);
  259. Assert.NotSame (source, result);
  260. Assert.Equal (source, result);
  261. // Modify result, ensure source unchanged
  262. result! ["C"] = 3;
  263. Assert.Equal (2, source.Count);
  264. Assert.Equal (3, result.Count);
  265. }
  266. [Fact]
  267. public void Array_CreatesDeepCopy ()
  268. {
  269. int []? source = { 1, 2, 3 };
  270. int []? result = DeepCloner.DeepClone (source);
  271. Assert.NotNull (result);
  272. Assert.NotSame (source, result);
  273. Assert.Equal (source, result);
  274. // Modify result, ensure source unchanged
  275. result! [0] = 99;
  276. Assert.Equal (1, source [0]);
  277. Assert.Equal (99, result [0]);
  278. }
  279. [Fact]
  280. public void ImmutableList_ThrowsNotSupported ()
  281. {
  282. ImmutableList<string> source = ImmutableList.Create ("One", "Two");
  283. Assert.Throws<NotSupportedException> (() => DeepCloner.DeepClone (source));
  284. }
  285. [Fact]
  286. public void ImmutableDictionary_ThrowsNotSupported ()
  287. {
  288. ImmutableDictionary<string, int> source = ImmutableDictionary.Create<string, int> ().Add ("A", 1);
  289. Assert.Throws<NotSupportedException> (() => DeepCloner.DeepClone (source));
  290. }
  291. [Fact]
  292. public void Dictionary_SourceAddsItem_ClonesCorrectly ()
  293. {
  294. Dictionary<string, Attribute>? source = new ()
  295. {
  296. { "Disabled", new (Color.White) },
  297. { "Normal", new (Color.Blue) }
  298. };
  299. Dictionary<string, Attribute>? result = DeepCloner.DeepClone (source);
  300. Assert.NotNull (result);
  301. Assert.NotSame (source, result);
  302. Assert.Equal (2, result.Count);
  303. Assert.Equal ((Attribute)source ["Disabled"], (Attribute)result ["Disabled"]);
  304. Assert.Equal (source ["Normal"], result ["Normal"]);
  305. }
  306. [Fact]
  307. public void Dictionary_SourceUpdatesOneItem_ClonesCorrectly ()
  308. {
  309. Dictionary<string, Attribute>? source = new () { { "Disabled", new (Color.White) } };
  310. Dictionary<string, Attribute>? result = DeepCloner.DeepClone (source);
  311. Assert.NotNull (result);
  312. Assert.NotSame (source, result);
  313. Assert.Single (result);
  314. Assert.Equal (source ["Disabled"], result ["Disabled"]);
  315. }
  316. [Fact]
  317. public void Dictionary_WithComplexKeys_ClonesCorrectly ()
  318. {
  319. Dictionary<ComplexKey, string>? source = new ()
  320. {
  321. { new() { Id = 1 }, "Value1" }
  322. };
  323. Dictionary<ComplexKey, string>? result = DeepCloner.DeepClone (source);
  324. Assert.NotNull (result);
  325. Assert.NotSame (source, result);
  326. Assert.Equal (source.Keys.First ().Id, result.Keys.First ().Id);
  327. Assert.Equal (source.Values.First (), result.Values.First ());
  328. }
  329. [Fact]
  330. public void Dictionary_WithCustomKeyComparer_ClonesCorrectly ()
  331. {
  332. Dictionary<Key, string> source = new (new KeyEqualityComparer ())
  333. {
  334. { new (KeyCode.Esc), "Esc" }
  335. };
  336. Dictionary<Key, string> result = DeepCloner.DeepClone (source)!;
  337. Assert.NotNull (result);
  338. Assert.NotSame (source, result);
  339. Assert.Single (result);
  340. Assert.True (result.ContainsKey (new (KeyCode.Esc)));
  341. Assert.Equal ("Esc", result [new (KeyCode.Esc)]);
  342. // Modify result, ensure source unchanged
  343. result [new (KeyCode.Q)] = "Q";
  344. Assert.False (source.ContainsKey (new (KeyCode.Q)));
  345. }
  346. // Nested Objects
  347. [Fact]
  348. public void CollectionContainer_CreatesDeepCopy ()
  349. {
  350. CollectionContainer? source = new ()
  351. {
  352. Strings = ["A", "B"],
  353. Counts = new () { { "X", 1 }, { "Y", 2 } },
  354. Numbers = [10, 20]
  355. };
  356. CollectionContainer? result = DeepCloner.DeepClone (source);
  357. Assert.NotNull (result);
  358. Assert.NotSame (source, result);
  359. Assert.NotSame (source.Strings, result!.Strings);
  360. Assert.NotSame (source.Counts, result.Counts);
  361. Assert.NotSame (source.Numbers, result.Numbers);
  362. Assert.Equal (source.Strings, result.Strings);
  363. Assert.Equal (source.Counts, result.Counts);
  364. Assert.Equal (source.Numbers, result.Numbers);
  365. // Modify result, ensure source unchanged
  366. result.Strings!.Add ("C");
  367. result.Counts! ["Z"] = 3;
  368. result.Numbers! [0] = 99;
  369. Assert.Equal (2, source.Strings.Count);
  370. Assert.Equal (2, source.Counts.Count);
  371. Assert.Equal (10, source.Numbers [0]);
  372. }
  373. [Fact]
  374. public void NestedObject_CreatesDeepCopy ()
  375. {
  376. NestedObject? source = new ()
  377. {
  378. Inner = new () { Name = "Inner", Count = 5 },
  379. Values = new ()
  380. {
  381. new() { Number = 1, Flag = true },
  382. new() { Number = 2, Flag = false }
  383. }
  384. };
  385. NestedObject? result = DeepCloner.DeepClone (source);
  386. Assert.NotNull (result);
  387. Assert.NotSame (source, result);
  388. Assert.NotSame (source.Inner, result!.Inner);
  389. Assert.NotSame (source.Values, result.Values);
  390. Assert.Equal (source.Inner!.Name, result.Inner!.Name);
  391. Assert.Equal (source.Inner.Count, result.Inner.Count);
  392. Assert.Equal (source.Values! [0].Number, result.Values! [0].Number);
  393. Assert.Equal (source.Values [0].Flag, result.Values [0].Flag);
  394. // Modify result, ensure source unchanged
  395. result.Inner.Name = "Modified";
  396. result.Values [0].Number = 99;
  397. Assert.Equal ("Inner", source.Inner.Name);
  398. Assert.Equal (1, source.Values [0].Number);
  399. }
  400. // Circular References
  401. [Fact]
  402. public void CircularReference_HandlesCorrectly ()
  403. {
  404. CircularReference? source = new () { Name = "Cycle" };
  405. source.Self = source; // Create circular reference
  406. CircularReference? result = DeepCloner.DeepClone (source);
  407. Assert.NotNull (result);
  408. Assert.NotSame (source, result);
  409. Assert.Equal (source.Name, result!.Name);
  410. Assert.NotNull (result.Self);
  411. Assert.Same (result, result.Self); // Circular reference preserved
  412. Assert.NotSame (source.Self, result.Self);
  413. // Modify result, ensure source unchanged
  414. result.Name = "Modified";
  415. Assert.Equal ("Cycle", source.Name);
  416. }
  417. // Terminal.Gui-Specific Types
  418. [Fact]
  419. public void ConfigPropertyMock_CreatesDeepCopy ()
  420. {
  421. ConfigPropertyMock? source = new ()
  422. {
  423. PropertyValue = new List<string> { "Red", "Blue" },
  424. Immutable = true
  425. };
  426. ConfigPropertyMock? result = DeepCloner.DeepClone (source);
  427. Assert.NotNull (result);
  428. Assert.NotSame (source, result);
  429. Assert.NotSame (source.PropertyValue, result!.PropertyValue);
  430. Assert.Equal ((List<string>)source.PropertyValue, (List<string>)result.PropertyValue!);
  431. Assert.Equal (source.Immutable, result.Immutable);
  432. // Modify result, ensure source unchanged
  433. ((List<string>)result.PropertyValue!).Add ("Green");
  434. Assert.Equal (2, ((List<string>)source.PropertyValue).Count);
  435. }
  436. [Fact]
  437. public void ConfigProperty_CreatesDeepCopy ()
  438. {
  439. ConfigProperty? source = ConfigProperty.CreateImmutableWithAttributeInfo (CM.GetHardCodedConfigPropertyCache ()! ["Application.QuitKey"].PropertyInfo!);
  440. source.Immutable = false;
  441. source.PropertyValue = Key.A;
  442. ConfigProperty? result = DeepCloner.DeepClone (source);
  443. Assert.NotNull (result);
  444. Assert.NotNull (result.PropertyInfo);
  445. Assert.NotSame (source, result);
  446. Assert.NotSame (source.PropertyValue, result!.PropertyValue);
  447. // PropertyInfo is effectively a simple type
  448. Assert.Same (source.PropertyInfo, result!.PropertyInfo);
  449. Assert.Equal (source.Immutable, result.Immutable);
  450. }
  451. [Fact]
  452. public void LargeObject_PerformsWithinLimit ()
  453. {
  454. List<int> source = new (Enumerable.Range (1, 10000));
  455. var stopwatch = Stopwatch.StartNew ();
  456. List<int> result = DeepCloner.DeepClone (source)!;
  457. stopwatch.Stop ();
  458. Assert.Equal (source, result);
  459. Assert.True (stopwatch.ElapsedMilliseconds < 1000); // Ensure it completes within 1 second
  460. }
  461. [Fact]
  462. public void CloneDictionary_ShouldClone_NormalDictionary ()
  463. {
  464. // Arrange: A supported generic dictionary
  465. var original = new Dictionary<string, int>
  466. {
  467. ["one"] = 1,
  468. ["two"] = 2,
  469. ["three"] = 3
  470. };
  471. // Act
  472. var cloned = DeepCloner.DeepClone (original);
  473. // Assert
  474. Assert.NotNull (cloned);
  475. Assert.NotSame (original, cloned); // must be a new instance
  476. Assert.Equal (original, cloned); // must have same contents
  477. Assert.Equal (original.Count, cloned.Count);
  478. Assert.Equal (original ["one"], cloned ["one"]);
  479. Assert.Equal (original ["two"], cloned ["two"]);
  480. Assert.Equal (original ["three"], cloned ["three"]);
  481. }
  482. [Fact]
  483. public void CloneDictionary_ShouldClone_ConcurrentDictionary ()
  484. {
  485. // Arrange
  486. var original = new ConcurrentDictionary<string, string>
  487. {
  488. ["a"] = "alpha",
  489. ["b"] = "beta"
  490. };
  491. // Act
  492. var cloned = DeepCloner.DeepClone (original);
  493. // Assert
  494. Assert.NotSame (original, cloned);
  495. Assert.Equal (original, cloned);
  496. }
  497. [Fact]
  498. public void CloneDictionary_Empty_Dictionary_ShouldWork ()
  499. {
  500. // Arrange
  501. var original = new Dictionary<int, string> ();
  502. // Act
  503. var cloned = DeepCloner.DeepClone (original);
  504. // Assert
  505. Assert.NotSame (original, cloned);
  506. Assert.Empty (cloned!);
  507. }
  508. [Fact]
  509. public void CloneDictionary_Empty_ConcurrentDictionary_ShouldWork ()
  510. {
  511. // Arrange
  512. var original = new ConcurrentDictionary<int, string> ();
  513. // Act
  514. var cloned = DeepCloner.DeepClone (original);
  515. // Assert
  516. Assert.NotSame (original, cloned);
  517. Assert.Empty (cloned!);
  518. }
  519. [Fact]
  520. public void CloneDictionary_With_Unsupported_Dictionary_Throws ()
  521. {
  522. // Arrange: A generic dictionary type (SortedDictionary for example)
  523. var unsupportedDict = new SortedDictionary<int, string>
  524. {
  525. { 1, "A" },
  526. { 2, "B" }
  527. };
  528. // Act & Assert: DeepCloner should throw
  529. Assert.ThrowsAny<InvalidOperationException> (() =>
  530. {
  531. // This should throw, because DeepCloner does not support SortedDictionary
  532. _ = DeepCloner.DeepClone (unsupportedDict);
  533. });
  534. }
  535. }