Skip to content

Commit d0f7b77

Browse files
committed
CoroutineHandleのテスト
1 parent 66c7f74 commit d0f7b77

File tree

3 files changed

+303
-0
lines changed

3 files changed

+303
-0
lines changed

Assets/UnityScreenNavigator/Runtime/Core/Modal/ModalContainer.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -255,6 +255,7 @@ public AsyncProcessHandle Push<TModal>(
255255
)
256256
where TModal : Modal
257257
{
258+
CoroutineManager.Instance.ThrowException = false;
258259
return CoroutineManager.Instance.Run(PushRoutine(typeof(TModal),
259260
resourceKey,
260261
playAnimation,
@@ -343,6 +344,8 @@ private IEnumerator PushRoutine(
343344
_transitionHandler.End();
344345
}
345346

347+
348+
346349
private IEnumerator PopRoutine(bool playAnimation, int popCount = 1)
347350
{
348351
Assert.IsTrue(popCount >= 1);
Lines changed: 289 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,289 @@
1+
using System;
2+
using System.Collections;
3+
using NUnit.Framework;
4+
using UnityScreenNavigator.Runtime.Foundation;
5+
6+
namespace UnityScreenNavigator.Tests.PlayMode.Foundation
7+
{
8+
internal sealed class CoroutineHandleTest
9+
{
10+
[Test]
11+
public void Constructor_初期化後_StatusがNotNullかつ未完了であること()
12+
{
13+
// Arrange
14+
var simpleRoutine = SimpleRoutine();
15+
16+
// Act
17+
var handle = new CoroutineHandle(simpleRoutine);
18+
19+
// Assert
20+
Assert.That(handle.Status, Is.Not.Null);
21+
Assert.That(handle.Status.IsCompleted, Is.False);
22+
Assert.That(handle.Status.IsFaulted, Is.False);
23+
Assert.That(handle.Status.Exception, Is.Null);
24+
}
25+
26+
[Test]
27+
public void Step_コルーチンが初回MoveNextで完了する場合_Completedを返しStatusが完了になること()
28+
{
29+
// Arrange
30+
// MoveNext() が false を返す IEnumerator (ステップがないため)
31+
var routine = SimpleRoutine();
32+
var handle = new CoroutineHandle(routine);
33+
34+
// Act
35+
var result = handle.Step();
36+
37+
// Assert
38+
Assert.That(result, Is.EqualTo(CoroutineStepResult.Completed));
39+
Assert.That(handle.Status.IsCompleted, Is.True);
40+
Assert.That(handle.Status.IsFaulted, Is.False);
41+
Assert.That(handle.Status.Exception, Is.Null);
42+
}
43+
44+
[Test]
45+
public void Step_コルーチンがnullをyieldする場合_Continueを返しStatusが未完了であること()
46+
{
47+
// Arrange
48+
var routine = SimpleRoutine(() => null);
49+
var handle = new CoroutineHandle(routine);
50+
51+
// Act
52+
var result = handle.Step();
53+
54+
// Assert
55+
Assert.That(result, Is.EqualTo(CoroutineStepResult.Continue));
56+
Assert.That(handle.Status.IsCompleted, Is.False);
57+
Assert.That(handle.Status.IsFaulted, Is.False);
58+
}
59+
60+
[Test]
61+
public void Step_コルーチンが未完了のAsyncStatusをyieldする場合_Continueを返しStatusが未完了であること()
62+
{
63+
// Arrange
64+
var awaitedStatus = new AsyncStatus();
65+
var routine = SimpleRoutine(() => awaitedStatus);
66+
var handle = new CoroutineHandle(routine);
67+
68+
// Act
69+
var result = handle.Step();
70+
71+
// Assert
72+
Assert.That(result, Is.EqualTo(CoroutineStepResult.Continue));
73+
Assert.That(handle.Status.IsCompleted, Is.False);
74+
Assert.That(handle.Status.IsFaulted, Is.False);
75+
}
76+
77+
[Test]
78+
public void Step_コルーチンが正常完了済みのAsyncStatusをyieldし次に完了する場合_Completedを返すこと()
79+
{
80+
// Arrange
81+
var awaitedStatus = new AsyncStatus();
82+
awaitedStatus.MarkCompleted(); // 事前に完了させておく
83+
// 最初に awaitedStatus を yield し、その直後にコルーチンが完了する (MoveNext が false を返す)
84+
var finalRoutine = SimpleRoutine(() => awaitedStatus);
85+
var handle = new CoroutineHandle(finalRoutine);
86+
87+
// Act
88+
// 1回目のStepでawaitedStatusを処理し、コルーチン内のwhile(true)ループにより
89+
// 即座に次の _routine.MoveNext() が試行され、それが false を返すため Completed になる。
90+
var result = handle.Step();
91+
92+
93+
// Assert
94+
Assert.That(result, Is.EqualTo(CoroutineStepResult.Completed), "完了したAsyncStatusを処理し、コルーチンも即座に完了する");
95+
Assert.That(handle.Status.IsCompleted, Is.True);
96+
Assert.That(handle.Status.IsFaulted, Is.False);
97+
}
98+
99+
[Test]
100+
public void Step_コルーチンが正常完了済みのAsyncStatusをyieldし次にnullをyieldする場合_Continueを返すこと()
101+
{
102+
// Arrange
103+
var awaitedStatus = new AsyncStatus();
104+
awaitedStatus.MarkCompleted();
105+
106+
// awaitedStatus を yield した後に、さらに null を yield するコルーチン
107+
var routine = SimpleRoutine(() => awaitedStatus, () => null);
108+
var handle = new CoroutineHandle(routine);
109+
110+
// Act
111+
// 最初のStepで awaitedStatus を処理し、内部ループで次の yield return null まで進み、そこで停止する
112+
var result = handle.Step();
113+
114+
// Assert
115+
Assert.That(result, Is.EqualTo(CoroutineStepResult.Continue));
116+
Assert.That(handle.Status.IsCompleted, Is.False);
117+
Assert.That(handle.Status.IsFaulted, Is.False);
118+
}
119+
120+
121+
[Test]
122+
public void Step_コルーチンが失敗済みのAsyncStatusをyieldする場合_Faultedを返しStatusが失敗になること()
123+
{
124+
// Arrange
125+
var awaitedStatus = new AsyncStatus();
126+
var awaitedException = new InvalidOperationException("Awaited task failed");
127+
awaitedStatus.MarkFaulted(awaitedException);
128+
129+
var routine = SimpleRoutine(() => awaitedStatus);
130+
var handle = new CoroutineHandle(routine);
131+
132+
// Act
133+
var result = handle.Step();
134+
135+
// Assert
136+
Assert.That(result, Is.EqualTo(CoroutineStepResult.Faulted));
137+
Assert.That(handle.Status.IsCompleted, Is.True);
138+
Assert.That(handle.Status.IsFaulted, Is.True);
139+
Assert.That(handle.Status.Exception, Is.EqualTo(awaitedException));
140+
}
141+
142+
[Test]
143+
public void Step_コルーチン実行中に例外が発生する場合_Faultedを返しStatusが失敗になること()
144+
{
145+
// Arrange
146+
var exceptionToThrow = new ArithmeticException("Coroutine calculation error");
147+
var routine = SimpleRoutine(() => throw exceptionToThrow);
148+
var handle = new CoroutineHandle(routine);
149+
150+
// Act
151+
// Step内で例外をキャッチし、適切に処理することをテスト
152+
var result = CoroutineStepResult.Continue; // 初期値
153+
Exception caughtInTest = null;
154+
try
155+
{
156+
// CoroutineHandle.Step() は MoveNext() を呼び出し、そこで例外が発生する。
157+
// Step() メソッド自体が例外をスローしないことを確認。
158+
result = handle.Step();
159+
}
160+
catch (Exception ex)
161+
{
162+
// このブロックが実行された場合、CoroutineHandle.Step() が例外を外にスローしたことになる。
163+
// これは期待される動作ではない。
164+
caughtInTest = ex;
165+
}
166+
167+
// Assert
168+
Assert.That(caughtInTest, Is.Null, "CoroutineHandle.Step() は例外を外部にスローすべきではない");
169+
Assert.That(result, Is.EqualTo(CoroutineStepResult.Faulted));
170+
Assert.That(handle.Status.IsCompleted, Is.True);
171+
Assert.That(handle.Status.IsFaulted, Is.True);
172+
Assert.That(handle.Status.Exception, Is.TypeOf<ArithmeticException>());
173+
Assert.That(handle.Status.Exception, Is.SameAs(exceptionToThrow));
174+
}
175+
176+
[Test]
177+
public void Step_既に完了しているコルーチンに対してStepを呼ぶ場合_Completedを返すこと()
178+
{
179+
// Arrange
180+
var routine = SimpleRoutine(); // すぐ完了するコルーチン
181+
var handle = new CoroutineHandle(routine);
182+
handle.Step(); // これで完了する
183+
184+
// Act
185+
var result = handle.Step(); // 再度Stepを呼ぶ
186+
187+
// Assert
188+
Assert.That(result, Is.EqualTo(CoroutineStepResult.Completed));
189+
Assert.That(handle.Status.IsCompleted, Is.True); // 状態は維持
190+
}
191+
192+
[Test]
193+
public void Step_既に失敗しているコルーチンに対してStepを呼ぶ場合_Faultedを返すこと()
194+
{
195+
// Arrange
196+
var exceptionToThrow = new AccessViolationException("Failed");
197+
var routine = SimpleRoutine(() => throw exceptionToThrow);
198+
var handle = new CoroutineHandle(routine);
199+
handle.Step();
200+
201+
// Act
202+
var result = handle.Step(); // 再度Stepを呼ぶ
203+
204+
// Assert
205+
Assert.That(result, Is.EqualTo(CoroutineStepResult.Faulted));
206+
Assert.That(handle.Status.IsFaulted, Is.True);
207+
Assert.That(handle.Status.IsCompleted, Is.True);
208+
}
209+
210+
211+
[Test]
212+
public void Step_コルーチンがAsyncStatus以外のオブジェクトをyieldする場合_Continueを返すこと()
213+
{
214+
// Arrange
215+
var routine = SimpleRoutine(() => 123); // int を yield する
216+
var handle = new CoroutineHandle(routine);
217+
218+
// Act
219+
var result = handle.Step();
220+
221+
// Assert
222+
Assert.That(result, Is.EqualTo(CoroutineStepResult.Continue));
223+
Assert.That(handle.Status.IsCompleted, Is.False);
224+
Assert.That(handle.Status.IsFaulted, Is.False);
225+
}
226+
227+
[Test]
228+
public void Step_複数ステップ後にコルーチンが完了する場合_正しくCompletedになること()
229+
{
230+
// Arrange
231+
var routine = SimpleRoutine(() => null, () => null, () => "step 3 then complete"); // 3回 yield して完了
232+
var handle = new CoroutineHandle(routine);
233+
234+
// Act & Assert
235+
// 1回目のStep
236+
var result1 = handle.Step();
237+
Assert.That(result1, Is.EqualTo(CoroutineStepResult.Continue), "Step 1 should continue");
238+
Assert.That(handle.Status.IsCompleted, Is.False, "Status after step 1 should not be completed");
239+
240+
// 2回目のStep
241+
var result2 = handle.Step();
242+
Assert.That(result2, Is.EqualTo(CoroutineStepResult.Continue), "Step 2 should continue");
243+
Assert.That(handle.Status.IsCompleted, Is.False, "Status after step 2 should not be completed");
244+
245+
// 3回目のStep (ここで最後の yield が行われる)
246+
var result3 = handle.Step();
247+
Assert.That(result3,
248+
Is.EqualTo(CoroutineStepResult.Continue),
249+
"Step 3 should continue as it yields 'step 3 then complete'");
250+
Assert.That(handle.Status.IsCompleted, Is.False, "Status after step 3 should not be completed");
251+
252+
// 4回目のStep (ここで MoveNext() が false を返し、コルーチンが完了する)
253+
var result4 = handle.Step();
254+
Assert.That(result4, Is.EqualTo(CoroutineStepResult.Completed), "Step 4 should complete the coroutine");
255+
Assert.That(handle.Status.IsCompleted, Is.True, "Status after step 4 should be completed");
256+
Assert.That(handle.Status.IsFaulted, Is.False);
257+
}
258+
259+
[Test]
260+
public void Step_完了済みAsyncStatusをyield後次のステップがnullの場合_Continueを返すこと()
261+
{
262+
// Arrange
263+
var completedAsyncStatus = new AsyncStatus();
264+
completedAsyncStatus.MarkCompleted();
265+
266+
var routine = SimpleRoutine(() => completedAsyncStatus, () => null);
267+
var handle = new CoroutineHandle(routine);
268+
269+
// Act
270+
// 最初のStep()呼び出し:
271+
// 1. _routine.MoveNext() -> true, _routine.Current is completedAsyncStatus
272+
// 2. awaited.IsCompleted is true, awaited.IsFaulted is false
273+
// 3. ループが継続し、再度 _routine.MoveNext() -> true, _routine.Current is null
274+
// 4. _routine.Current is not AsyncStatus -> CoroutineStepResult.Continue が返る
275+
var result = handle.Step();
276+
277+
// Assert
278+
Assert.That(result, Is.EqualTo(CoroutineStepResult.Continue));
279+
Assert.That(handle.Status.IsCompleted, Is.False);
280+
}
281+
282+
// Helper method to create a simple IEnumerator that yields specified values
283+
private static IEnumerator SimpleRoutine(params Func<object>[] steps)
284+
{
285+
foreach (var step in steps)
286+
yield return step.Invoke();
287+
}
288+
}
289+
}

Assets/UnityScreenNavigator/Tests/PlayMode/Foundation/CoroutineHandleTest.cs.meta

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

0 commit comments

Comments
 (0)