Skip to content

Commit 01b3b10

Browse files
committed
テストを追加
1 parent d0f7b77 commit 01b3b10

File tree

9 files changed

+634
-8
lines changed

9 files changed

+634
-8
lines changed

Assets/UnityScreenNavigator/Tests/PlayMode/Foundation/CoroutineSystem.meta

Lines changed: 3 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 378 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,378 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Threading.Tasks;
4+
using NUnit.Framework;
5+
using UnityScreenNavigator.Runtime.Foundation;
6+
7+
namespace UnityScreenNavigator.Tests.PlayMode.Foundation.CoroutineSystem
8+
{
9+
internal sealed class AsyncStatusTest
10+
{
11+
[Test]
12+
public void Constructor_初期状態_IsCompletedFalse_IsFaultedFalse_ExceptionNull_AllExceptionsEmpty()
13+
{
14+
// Arrange & Act
15+
var status = new AsyncStatus();
16+
17+
// Assert
18+
Assert.That(status.IsCompleted, Is.False);
19+
Assert.That(status.IsFaulted, Is.False);
20+
Assert.That(status.Exception, Is.Null);
21+
Assert.That(status.AllExceptions, Is.Not.Null.And.Empty);
22+
}
23+
24+
[Test]
25+
public void MarkCompleted_未完了の時_IsCompletedがTrueになること()
26+
{
27+
// Arrange
28+
var status = new AsyncStatus();
29+
30+
// Act
31+
status.MarkCompleted();
32+
33+
// Assert
34+
Assert.That(status.IsCompleted, Is.True);
35+
Assert.That(status.IsFaulted, Is.False); // 念のため確認
36+
}
37+
38+
[Test]
39+
public void MarkCompleted_既に完了している時_何も変わらないこと()
40+
{
41+
// Arrange
42+
var status = new AsyncStatus();
43+
status.MarkCompleted(); // 最初に完了させる
44+
45+
// Act
46+
status.MarkCompleted(); // 再度呼び出し
47+
48+
// Assert
49+
Assert.That(status.IsCompleted, Is.True);
50+
Assert.That(status.IsFaulted, Is.False);
51+
}
52+
53+
[Test]
54+
public void MarkFaulted_単一例外で未完了の時_IsCompletedTrue_IsFaultedTrue_Exception設定_AllExceptionsに設定()
55+
{
56+
// Arrange
57+
var status = new AsyncStatus();
58+
var exception = new InvalidOperationException("Test exception");
59+
60+
// Act
61+
status.MarkFaulted(exception);
62+
63+
// Assert
64+
Assert.That(status.IsCompleted, Is.True);
65+
Assert.That(status.IsFaulted, Is.True);
66+
Assert.That(status.Exception, Is.SameAs(exception));
67+
Assert.That(status.AllExceptions, Is.Not.Null);
68+
Assert.That(status.AllExceptions.Count, Is.EqualTo(1));
69+
Assert.That(status.AllExceptions[0], Is.SameAs(exception));
70+
}
71+
72+
[Test]
73+
public void MarkFaulted_単一例外で既に完了している時_何も変わらないこと()
74+
{
75+
// Arrange
76+
var status = new AsyncStatus();
77+
var initialException = new ArgumentNullException("Initial");
78+
status.MarkFaulted(initialException); // 最初に失敗させる
79+
80+
var subsequentException = new InvalidOperationException("Subsequent");
81+
82+
// Act
83+
status.MarkFaulted(subsequentException); // 完了後に再度呼び出し
84+
85+
// Assert
86+
Assert.That(status.IsCompleted, Is.True);
87+
Assert.That(status.IsFaulted, Is.True);
88+
Assert.That(status.Exception, Is.SameAs(initialException), "最初の例外が保持されるべき");
89+
Assert.That(status.AllExceptions.Count, Is.EqualTo(1), "例外リストの数は変わらないべき");
90+
Assert.That(status.AllExceptions[0], Is.SameAs(initialException));
91+
}
92+
93+
[Test]
94+
public void MarkFaulted_単一例外で正常完了している時_何も変わらないこと()
95+
{
96+
// Arrange
97+
var status = new AsyncStatus();
98+
status.MarkCompleted(); // 最初に正常完了させる
99+
100+
var subsequentException = new InvalidOperationException("Subsequent");
101+
102+
// Act
103+
status.MarkFaulted(subsequentException); // 完了後にFaultedを呼び出し
104+
105+
// Assert
106+
Assert.That(status.IsCompleted, Is.True);
107+
Assert.That(status.IsFaulted, Is.False, "正常完了後はFaultedにならない");
108+
Assert.That(status.Exception, Is.Null);
109+
Assert.That(status.AllExceptions, Is.Empty);
110+
}
111+
112+
[Test]
113+
public void MarkFaulted_複数例外リストで未完了の時_IsCompletedTrue_IsFaultedTrue_Exceptionは最初の例外_AllExceptionsに全設定()
114+
{
115+
// Arrange
116+
var status = new AsyncStatus();
117+
var ex1 = new InvalidOperationException("Ex1");
118+
var ex2 = new ArgumentException("Ex2");
119+
var exceptions = new List<Exception> { ex1, ex2 };
120+
121+
// Act
122+
status.MarkFaulted(exceptions);
123+
124+
// Assert
125+
Assert.That(status.IsCompleted, Is.True);
126+
Assert.That(status.IsFaulted, Is.True);
127+
Assert.That(status.Exception, Is.SameAs(ex1), "最初の例外がExceptionプロパティに設定される");
128+
Assert.That(status.AllExceptions, Is.Not.Null);
129+
Assert.That(status.AllExceptions.Count, Is.EqualTo(2));
130+
Assert.That(status.AllExceptions.Contains(ex1), Is.True);
131+
Assert.That(status.AllExceptions.Contains(ex2), Is.True);
132+
}
133+
134+
[Test]
135+
public void MarkFaulted_空の複数例外リストで未完了の時_IsCompletedTrue_IsFaultedFalse_ExceptionNull()
136+
{
137+
// Arrange
138+
var status = new AsyncStatus();
139+
var exceptions = new List<Exception>(); // 空のリスト
140+
141+
// Act
142+
status.MarkFaulted(exceptions);
143+
144+
// Assert
145+
Assert.That(status.IsCompleted, Is.True, "IsCompleted は true になる");
146+
Assert.That(status.IsFaulted, Is.False, "空の例外リストでは IsFaulted は false");
147+
Assert.That(status.Exception, Is.Null, "Exception は null");
148+
Assert.That(status.AllExceptions, Is.Empty, "AllExceptions は空");
149+
}
150+
151+
152+
[Test]
153+
public void MarkFaulted_複数例外リストで既に完了している時_何も変わらないこと()
154+
{
155+
// Arrange
156+
var status = new AsyncStatus();
157+
var initialException = new ApplicationException("Initial");
158+
status.MarkFaulted(initialException); // 最初に失敗させる
159+
160+
var ex1 = new InvalidOperationException("Ex1");
161+
var ex2 = new ArgumentException("Ex2");
162+
var subsequentExceptions = new List<Exception> { ex1, ex2 };
163+
164+
// Act
165+
status.MarkFaulted(subsequentExceptions); // 完了後に再度呼び出し
166+
167+
// Assert
168+
Assert.That(status.IsCompleted, Is.True);
169+
Assert.That(status.IsFaulted, Is.True);
170+
Assert.That(status.Exception, Is.SameAs(initialException));
171+
Assert.That(status.AllExceptions.Count, Is.EqualTo(1));
172+
Assert.That(status.AllExceptions[0], Is.SameAs(initialException));
173+
}
174+
175+
[Test]
176+
public void MarkFaulted_複数例外リストで正常完了している時_何も変わらないこと()
177+
{
178+
// Arrange
179+
var status = new AsyncStatus();
180+
status.MarkCompleted(); // 最初に正常完了させる
181+
182+
var ex1 = new InvalidOperationException("Ex1");
183+
var subsequentExceptions = new List<Exception> { ex1 };
184+
185+
// Act
186+
status.MarkFaulted(subsequentExceptions);
187+
188+
// Assert
189+
Assert.That(status.IsCompleted, Is.True);
190+
Assert.That(status.IsFaulted, Is.False);
191+
Assert.That(status.Exception, Is.Null);
192+
Assert.That(status.AllExceptions, Is.Empty);
193+
}
194+
195+
196+
[Test]
197+
public void IsFaulted_例外がない場合_Falseを返すこと()
198+
{
199+
// Arrange
200+
var status = new AsyncStatus();
201+
202+
// Act & Assert
203+
Assert.That(status.IsFaulted, Is.False);
204+
status.MarkCompleted(); // 正常完了しても Faulted ではない
205+
Assert.That(status.IsFaulted, Is.False);
206+
}
207+
208+
[Test]
209+
public void IsFaulted_例外がある場合_Trueを返すこと()
210+
{
211+
// Arrange
212+
var status = new AsyncStatus();
213+
status.MarkFaulted(new Exception("Test"));
214+
215+
// Act & Assert
216+
Assert.That(status.IsFaulted, Is.True);
217+
}
218+
219+
[Test]
220+
public void Wait_未完了の時_IsCompletedがFalseの間nullを返し続けること()
221+
{
222+
// Arrange
223+
var status = new AsyncStatus();
224+
var waiter = status.Wait();
225+
var stepCount = 0;
226+
227+
// Act & Assert
228+
// 最初の数ステップは IsCompleted が false なので null を返すはず
229+
Assert.That(waiter.MoveNext(), Is.True, "MoveNext 1 should be true");
230+
Assert.That(waiter.Current, Is.Null, "Current 1 should be null");
231+
stepCount++;
232+
233+
Assert.That(waiter.MoveNext(), Is.True, "MoveNext 2 should be true");
234+
Assert.That(waiter.Current, Is.Null, "Current 2 should be null");
235+
stepCount++;
236+
237+
// 途中で完了させる
238+
status.MarkCompleted();
239+
240+
Assert.That(waiter.MoveNext(), Is.False, "MoveNext after completion should be false");
241+
Assert.That(stepCount, Is.EqualTo(2), "Specified steps should have occurred before completion");
242+
}
243+
244+
[Test]
245+
public void Wait_最初から完了済みの時_すぐに終了すること()
246+
{
247+
// Arrange
248+
var status = new AsyncStatus();
249+
status.MarkCompleted();
250+
var waiter = status.Wait();
251+
252+
// Act & Assert
253+
Assert.That(waiter.MoveNext(), Is.False); // IsCompleted なのですぐに false
254+
}
255+
256+
[Test]
257+
public void Wait_最初から失敗済みの時_すぐに終了すること()
258+
{
259+
// Arrange
260+
var status = new AsyncStatus();
261+
status.MarkFaulted(new Exception("fail")); // IsCompleted も true になる
262+
var waiter = status.Wait();
263+
264+
// Act & Assert
265+
Assert.That(waiter.MoveNext(), Is.False);
266+
}
267+
268+
// Createメソッドのテストは非同期処理の性質上、少し複雑になります。
269+
// MonitorAsyncがasync voidであるため、その完了を直接待つのが難しいです。
270+
// テストでは、Taskが完了するか例外をスローするのを待ってからStatusを検証します。
271+
// async voidメソッドのテストは通常、同期コンテキストのカスタマイズや、
272+
// 副作用(この場合はStatusの更新)をポーリングすることで行われます。
273+
274+
[Test]
275+
public async Task Create_Taskが正常に完了する場合_Statusが完了になること()
276+
{
277+
// Arrange
278+
var tcs = new TaskCompletionSource<bool>();
279+
Func<Task> asyncFunc = () => tcs.Task;
280+
281+
// Act
282+
var status = AsyncStatus.Create(asyncFunc);
283+
284+
// Assert
285+
Assert.That(status.IsCompleted, Is.False, "Task開始直後は未完了");
286+
287+
tcs.SetResult(true); // Taskを完了させる
288+
289+
// async void の MonitorAsync が完了するのを少し待つ
290+
// より堅牢なテストのためには、ポーリングやカスタム同期コンテキストが必要になる場合があります。
291+
// ここでは簡略化のため、Task.Delayを使用します。
292+
await Task.Delay(100); // MonitorAsync内のawaitとMarkCompletedが実行されるのに十分な時間
293+
294+
Assert.That(status.IsCompleted, Is.True, "Task完了後、Statusは完了になるべき");
295+
Assert.That(status.IsFaulted, Is.False);
296+
}
297+
298+
[Test]
299+
public async Task Create_Taskが例外をスローする場合_Statusが失敗になること()
300+
{
301+
// Arrange
302+
var tcs = new TaskCompletionSource<bool>();
303+
var testException = new InvalidOperationException("Async task failed");
304+
Func<Task> asyncFunc = () =>
305+
{
306+
tcs.SetException(testException);
307+
return tcs.Task;
308+
};
309+
// 代わりに Task.FromException を使うこともできます
310+
// Func<Task> asyncFunc = () => Task.FromException(testException);
311+
312+
313+
// Act
314+
var status = AsyncStatus.Create(asyncFunc);
315+
316+
// Assert
317+
Assert.That(status.IsCompleted, Is.False, "Task開始直後は未完了");
318+
319+
// Taskが例外で完了するのを待つ (Create内では捕捉される)
320+
Exception? caughtInTest = null;
321+
try
322+
{
323+
await asyncFunc(); // これ自体は例外を再スローする
324+
}
325+
catch (Exception ex)
326+
{
327+
caughtInTest = ex; // Createに渡したasyncFuncがスローした例外をキャッチ
328+
}
329+
330+
Assert.That(caughtInTest, Is.SameAs(testException), "asyncFuncは指定した例外をスローするべき");
331+
332+
333+
// async void の MonitorAsync が完了するのを少し待つ
334+
await Task.Delay(100);
335+
336+
Assert.That(status.IsCompleted, Is.True, "Task失敗後、Statusは完了になるべき");
337+
Assert.That(status.IsFaulted, Is.True, "Task失敗後、StatusはFaultedになるべき");
338+
Assert.That(status.Exception, Is.SameAs(testException));
339+
Assert.That(status.AllExceptions.Contains(testException), Is.True);
340+
}
341+
342+
[Test]
343+
public async Task Create_Taskが既に完了している場合_Statusが即座に完了に近い状態になること()
344+
{
345+
// Arrange
346+
Func<Task> asyncFunc = () => Task.CompletedTask;
347+
348+
// Act
349+
var status = AsyncStatus.Create(asyncFunc);
350+
351+
// async void の MonitorAsync が完了するのを少し待つ
352+
await Task.Delay(50); // 通常は非常に速いはず
353+
354+
// Assert
355+
Assert.That(status.IsCompleted, Is.True);
356+
Assert.That(status.IsFaulted, Is.False);
357+
}
358+
359+
[Test]
360+
public async Task Create_Taskが既に失敗している場合_Statusが即座に失敗に近い状態になること()
361+
{
362+
// Arrange
363+
var testException = new OperationCanceledException("Cancelled");
364+
Func<Task> asyncFunc = () => Task.FromException(testException);
365+
366+
// Act
367+
var status = AsyncStatus.Create(asyncFunc);
368+
369+
// async void の MonitorAsync が完了するのを少し待つ
370+
await Task.Delay(50);
371+
372+
// Assert
373+
Assert.That(status.IsCompleted, Is.True);
374+
Assert.That(status.IsFaulted, Is.True);
375+
Assert.That(status.Exception, Is.SameAs(testException));
376+
}
377+
}
378+
}

Assets/UnityScreenNavigator/Tests/PlayMode/Foundation/CoroutineSystem/AsyncStatusTest.cs.meta

Lines changed: 3 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Assets/UnityScreenNavigator/Tests/PlayMode/Foundation/CoroutineHandleTest.cs renamed to Assets/UnityScreenNavigator/Tests/PlayMode/Foundation/CoroutineSystem/CoroutineHandleTest.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
using NUnit.Framework;
44
using UnityScreenNavigator.Runtime.Foundation;
55

6-
namespace UnityScreenNavigator.Tests.PlayMode.Foundation
6+
namespace UnityScreenNavigator.Tests.PlayMode.Foundation.CoroutineSystem
77
{
88
internal sealed class CoroutineHandleTest
99
{

Assets/UnityScreenNavigator/Tests/PlayMode/Foundation/CoroutineHandleTest.cs.meta renamed to Assets/UnityScreenNavigator/Tests/PlayMode/Foundation/CoroutineSystem/CoroutineHandleTest.cs.meta

File renamed without changes.

0 commit comments

Comments
 (0)