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