A game framework written with osu! in mind.
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;
5using System.Collections.Generic;
6using System.Linq;
7using System.Threading;
8using System.Threading.Tasks;
9using NUnit.Framework;
10using osu.Framework.Allocation;
11using osu.Framework.Logging;
12
13namespace osu.Framework.Tests.Threading
14{
15 [TestFixture]
16 public class AsyncDisposalQueueTest
17 {
18 [Test]
19 public void TestManyAsyncDisposal()
20 {
21 var objects = new List<DisposableObject>();
22 for (int i = 0; i < 10000; i++)
23 objects.Add(new DisposableObject());
24
25 objects.ForEach(AsyncDisposalQueue.Enqueue);
26
27 int attempts = 1000;
28
29 while (!objects.All(o => o.IsDisposed))
30 {
31 if (attempts-- == 0)
32 Assert.Fail("Expected all objects to dispose.");
33 Thread.Sleep(10);
34 }
35
36 Logger.Log(objects.Select(d => d.TaskId).Distinct().Count().ToString());
37
38 // It's very unlikely for this to fail by chance due to the number of objects being disposed and computational time requirement of task scheduling
39 Assert.That(objects.Select(d => d.TaskId).Distinct().Count(), Is.LessThan(objects.Count));
40 }
41
42 [Test]
43 public void TestManyAsyncDisposalUsingWait()
44 {
45 var objects = new List<DisposableObject>();
46 for (int i = 0; i < 10000; i++)
47 objects.Add(new DisposableObject());
48
49 objects.ForEach(AsyncDisposalQueue.Enqueue);
50
51 AsyncDisposalQueue.WaitForEmpty();
52
53 Assert.That(objects.All(o => o.IsDisposed));
54 }
55
56 [Test]
57 public void TestNestedAsyncDisposal()
58 {
59 var objects = new List<NestedDisposableObject>();
60 for (int i = 0; i < 10000; i++)
61 objects.Add(new NestedDisposableObject());
62
63 objects.ForEach(AsyncDisposalQueue.Enqueue);
64
65 int attempts = 1000;
66
67 while (!objects.All(o => o.IsDisposed && o.Nested?.IsDisposed == true))
68 {
69 if (attempts-- == 0)
70 Assert.Fail("Expected all objects to dispose.");
71 Thread.Sleep(10);
72 }
73 }
74
75 private class NestedDisposableObject : DisposableObject
76 {
77 public DisposableObject Nested;
78
79 public override void Dispose()
80 {
81 base.Dispose();
82 AsyncDisposalQueue.Enqueue(Nested = new DisposableObject());
83 }
84 }
85
86 private class DisposableObject : IDisposable
87 {
88 public int? TaskId { get; private set; }
89
90 public bool IsDisposed { get; private set; }
91
92 public virtual void Dispose()
93 {
94 TaskId = Task.CurrentId;
95 IsDisposed = true;
96 }
97 }
98 }
99}