ViewDisposalTest.cs 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112
  1. using System.Reflection;
  2. using Xunit.Abstractions;
  3. namespace Terminal.Gui.ViewsTests;
  4. public class ViewDisposalTest (ITestOutputHelper output)
  5. {
  6. #nullable enable
  7. private readonly Dictionary<Type, object? []?> _special_params = new ();
  8. #nullable restore
  9. [Fact]
  10. [AutoInitShutdown]
  11. public void TestViewsDisposeCorrectly ()
  12. {
  13. WeakReference reference = DoTest ();
  14. for (var i = 0; i < 10 && reference.IsAlive; i++)
  15. {
  16. GC.Collect ();
  17. GC.WaitForPendingFinalizers ();
  18. }
  19. #if DEBUG_IDISPOSABLE
  20. if (reference.IsAlive)
  21. {
  22. Assert.True (((View)reference.Target).WasDisposed);
  23. Assert.Fail ($"Some Views didnt get Garbage Collected: {((View)reference.Target).Subviews}");
  24. }
  25. #endif
  26. }
  27. private WeakReference DoTest ()
  28. {
  29. GetSpecialParams ();
  30. var container = new View () { Id = "container" };
  31. Toplevel top = new () { Id = "top" };
  32. List<Type> views = GetViews ();
  33. foreach (Type view in views)
  34. {
  35. View instance;
  36. //Create instance of view and add to container
  37. if (_special_params.TryGetValue (view, out object [] param))
  38. {
  39. instance = (View)Activator.CreateInstance (view, param);
  40. }
  41. else
  42. {
  43. instance = (View)Activator.CreateInstance (view);
  44. }
  45. Assert.NotNull (instance);
  46. instance.Id = $"{view.Name}";
  47. container.Add (instance);
  48. output.WriteLine ($"Added instance of {view}!");
  49. }
  50. top.Add (container);
  51. // make sure the application is doing to the views whatever its supposed to do to the views
  52. for (var i = 0; i < 100; i++)
  53. {
  54. Application.LayoutAndDraw ();
  55. }
  56. top.Remove (container);
  57. WeakReference reference = new (container, true);
  58. container.Dispose ();
  59. return reference;
  60. }
  61. private void GetSpecialParams ()
  62. {
  63. _special_params.Clear ();
  64. //special_params.Add (typeof (LineView), new object [] { Orientation.Horizontal });
  65. }
  66. // TODO: Consoldate this with same fn that's in AllViewsTester, ScenarioTests etc...
  67. /// <summary>Get all types derived from <see cref="View"/> using reflection</summary>
  68. /// <returns></returns>
  69. private List<Type> GetViews ()
  70. {
  71. List<Type> valid = new ();
  72. // Filter all types that can be instantiated, are public, arent generic, aren't the view type itself, but derive from view
  73. foreach (Type type in Assembly.GetAssembly (typeof (View))
  74. .GetTypes ()
  75. .Where (
  76. T =>
  77. { //body of anonymous check function
  78. return !T.IsAbstract
  79. && T.IsPublic
  80. && T.IsClass
  81. && T.IsAssignableTo (typeof (View))
  82. && !T.IsGenericType
  83. && !(T == typeof (View));
  84. }
  85. )) //end of body of anonymous check function
  86. { //body of the foreach loop
  87. output.WriteLine ($"Found Type {type.Name}");
  88. Assert.DoesNotContain (type, valid);
  89. Assert.True (type.IsAssignableTo (typeof (IDisposable))); // Just to be safe
  90. valid.Add (type);
  91. output.WriteLine (" -Added!");
  92. } //end body of foreach loop
  93. return valid;
  94. }
  95. }