A game framework written with osu! in mind.
at master 117 lines 3.7 kB view raw
1// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence. 2// See the LICENCE file in the repository root for full licence text. 3 4using System.Threading; 5using System.Threading.Tasks; 6using NUnit.Framework; 7using osu.Framework.Allocation; 8using osu.Framework.Graphics.Containers; 9using osu.Framework.Platform; 10using osu.Framework.Testing; 11 12namespace osu.Framework.Tests.Platform 13{ 14 [TestFixture] 15 public class ComponentAsyncDisposalTest 16 { 17 private TestTestGame game; 18 private HeadlessGameHost host; 19 20 private const int timeout = 10000; 21 22 /// <summary> 23 /// Ensure that if a component is on the async disposal queue, the game will wait for the queue to empty before disposing itself. 24 /// While we generally don't dispose games in normal execution, this may be used in tests, and can cause unwanted exceptions in (cancelled) load 25 /// methods if not ordered correctly. 26 /// </summary> 27 [Test] 28 public void TestChildDisposedBeforeGame() 29 { 30 var gameCreated = new ManualResetEventSlim(); 31 32 var task = Task.Run(() => 33 { 34 using (host = new TestRunHeadlessGameHost(@"host", false)) 35 { 36 game = new TestTestGame(); 37 gameCreated.Set(); 38 host.Run(game); 39 } 40 }); 41 42 Assert.IsTrue(gameCreated.Wait(timeout)); 43 Assert.IsTrue(game.BecameAlive.Wait(timeout)); 44 45 var container = new DisposableContainer(); 46 47 game.Schedule(() => game.Add(container)); 48 49 Assert.IsTrue(container.BecameAlive.Wait(timeout)); 50 51 game.Schedule(() => 52 { 53 game.ClearInternal(false); 54 game.DisposeChildAsync(container); 55 }); 56 57 game.Exit(); 58 59 Assert.IsTrue(task.Wait(timeout)); 60 61 game.Dispose(); 62 63 Assert.IsTrue(container.DisposedSuccessfully.Wait(timeout)); 64 } 65 66 private class DisposableContainer : Container 67 { 68 [Resolved] 69 private TestTestGame game { get; set; } 70 71 public readonly ManualResetEventSlim BecameAlive = new ManualResetEventSlim(); 72 73 public readonly ManualResetEventSlim DisposedSuccessfully = new ManualResetEventSlim(); 74 75 protected override void LoadComplete() 76 { 77 BecameAlive.Set(); 78 } 79 80 protected override void Dispose(bool isDisposing) 81 { 82 game.DisposalStarted.Wait(timeout); 83 84 // make sure we take some time to dispose (forcing Game to wait on the async queue). 85 Thread.Sleep(100); 86 87 // we want to ensure that game is still alive pending our disposal. 88 if (!game.IsDisposed) 89 DisposedSuccessfully.Set(); 90 91 base.Dispose(isDisposing); 92 } 93 } 94 95 [Cached] 96 private class TestTestGame : TestGame 97 { 98 public readonly ManualResetEventSlim BecameAlive = new ManualResetEventSlim(); 99 100 public readonly ManualResetEventSlim DisposalStarted = new ManualResetEventSlim(); 101 102 public readonly ManualResetEventSlim DisposalCompleted = new ManualResetEventSlim(); 103 104 protected override void LoadComplete() 105 { 106 BecameAlive.Set(); 107 } 108 109 protected override void Dispose(bool isDisposing) 110 { 111 DisposalStarted.Set(); 112 base.Dispose(isDisposing); 113 DisposalCompleted.Set(); 114 } 115 } 116 } 117}