437 lines
13 KiB
C#
437 lines
13 KiB
C#
#if !(UNITY_4_5 || UNITY_4_6 || UNITY_4_7 || UNITY_5_0 || UNITY_5_1 || UNITY_5_2)
|
|
#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member
|
|
|
|
using UnityEngine;
|
|
using System;
|
|
using System.Collections;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.Text;
|
|
using UnityEngine.UI;
|
|
using UnityEngine.Scripting;
|
|
using UniRx;
|
|
using UniRx.Async;
|
|
using UnityEngine.SceneManagement;
|
|
#if CSHARP_7_OR_LATER || (UNITY_2018_3_OR_NEWER && (NET_STANDARD_2_0 || NET_4_6))
|
|
using System.Threading.Tasks;
|
|
#endif
|
|
using UnityEngine.Networking;
|
|
|
|
#if !UNITY_2019_3_OR_NEWER
|
|
using UnityEngine.Experimental.LowLevel;
|
|
#else
|
|
using UnityEngine.LowLevel;
|
|
#endif
|
|
|
|
#if !UNITY_WSA
|
|
using Unity.Jobs;
|
|
#endif
|
|
using Unity.Collections;
|
|
using System.Threading;
|
|
using NUnit.Framework;
|
|
using UnityEngine.TestTools;
|
|
using FluentAssertions;
|
|
|
|
namespace UniRx.AsyncTests
|
|
{
|
|
public class AsyncTest
|
|
{
|
|
#if CSHARP_7_OR_LATER || (UNITY_2018_3_OR_NEWER && (NET_STANDARD_2_0 || NET_4_6))
|
|
#if !UNITY_WSA
|
|
|
|
public struct MyJob : IJob
|
|
{
|
|
public int loopCount;
|
|
public NativeArray<int> inOut;
|
|
public int result;
|
|
|
|
public void Execute()
|
|
{
|
|
result = 0;
|
|
for (int i = 0; i < loopCount; i++)
|
|
{
|
|
result++;
|
|
}
|
|
inOut[0] = result;
|
|
}
|
|
}
|
|
|
|
[UnityTest]
|
|
public IEnumerator DelayAnd() => UniTask.ToCoroutine(async () =>
|
|
{
|
|
await UniTask.Yield(PlayerLoopTiming.PostLateUpdate);
|
|
|
|
var time = Time.realtimeSinceStartup;
|
|
|
|
Time.timeScale = 0.5f;
|
|
try
|
|
{
|
|
await UniTask.Delay(TimeSpan.FromSeconds(3));
|
|
|
|
var elapsed = Time.realtimeSinceStartup - time;
|
|
((int)Math.Round(TimeSpan.FromSeconds(elapsed).TotalSeconds, MidpointRounding.ToEven)).Should().Be(6);
|
|
}
|
|
finally
|
|
{
|
|
Time.timeScale = 1.0f;
|
|
}
|
|
});
|
|
|
|
[UnityTest]
|
|
public IEnumerator DelayIgnore() => UniTask.ToCoroutine(async () =>
|
|
{
|
|
var time = Time.realtimeSinceStartup;
|
|
|
|
Time.timeScale = 0.5f;
|
|
try
|
|
{
|
|
await UniTask.Delay(TimeSpan.FromSeconds(3), ignoreTimeScale: true);
|
|
|
|
var elapsed = Time.realtimeSinceStartup - time;
|
|
((int)Math.Round(TimeSpan.FromSeconds(elapsed).TotalSeconds, MidpointRounding.ToEven)).Should().Be(3);
|
|
}
|
|
finally
|
|
{
|
|
Time.timeScale = 1.0f;
|
|
}
|
|
});
|
|
|
|
[UnityTest]
|
|
public IEnumerator WhenAll() => UniTask.ToCoroutine(async () =>
|
|
{
|
|
var a = UniTask.FromResult(999);
|
|
var b = UniTask.Yield(PlayerLoopTiming.Update, CancellationToken.None).AsAsyncUnitUniTask();
|
|
var c = UniTask.DelayFrame(99);
|
|
|
|
var (a2, b2, c2) = await UniTask.WhenAll(a, b, c);
|
|
a2.Should().Be(999);
|
|
b2.Should().Be(AsyncUnit.Default);
|
|
c2.Should().Be(99);
|
|
});
|
|
|
|
[UnityTest]
|
|
public IEnumerator WhenAny() => UniTask.ToCoroutine(async () =>
|
|
{
|
|
var a = UniTask.FromResult(999);
|
|
var b = UniTask.Yield(PlayerLoopTiming.Update, CancellationToken.None).AsAsyncUnitUniTask();
|
|
var c = UniTask.DelayFrame(99);
|
|
|
|
var (win, a2, b2, c2) = await UniTask.WhenAny(a, b, c);
|
|
win.Should().Be(0);
|
|
a2.hasResult.Should().Be(true);
|
|
a2.result0.Should().Be(999);
|
|
b2.hasResult.Should().Be(false);
|
|
c2.hasResult.Should().Be(false);
|
|
});
|
|
|
|
[UnityTest]
|
|
public IEnumerator BothEnumeratorCheck() => UniTask.ToCoroutine(async () =>
|
|
{
|
|
await ToaruCoroutineEnumerator(); // wait 5 frame:)
|
|
await ToaruCoroutineEnumerator().ConfigureAwait(PlayerLoopTiming.PostLateUpdate);
|
|
});
|
|
|
|
[UnityTest]
|
|
public IEnumerator JobSystem() => UniTask.ToCoroutine(async () =>
|
|
{
|
|
var job = new MyJob() { loopCount = 999, inOut = new NativeArray<int>(1, Allocator.TempJob) };
|
|
JobHandle.ScheduleBatchedJobs();
|
|
await job.Schedule();
|
|
job.inOut[0].Should().Be(999);
|
|
job.inOut.Dispose();
|
|
});
|
|
|
|
class MyMyClass
|
|
{
|
|
public int MyProperty { get; set; }
|
|
}
|
|
|
|
[UnityTest]
|
|
public IEnumerator WaitUntil() => UniTask.ToCoroutine(async () =>
|
|
{
|
|
bool t = false;
|
|
|
|
UniTask.DelayFrame(10, PlayerLoopTiming.PostLateUpdate).ContinueWith(_ => t = true).Forget();
|
|
|
|
var startFrame = Time.frameCount;
|
|
await UniTask.WaitUntil(() => t, PlayerLoopTiming.EarlyUpdate);
|
|
|
|
var diff = Time.frameCount - startFrame;
|
|
diff.Should().Be(11);
|
|
});
|
|
|
|
[UnityTest]
|
|
public IEnumerator WaitWhile() => UniTask.ToCoroutine(async () =>
|
|
{
|
|
bool t = true;
|
|
|
|
UniTask.DelayFrame(10, PlayerLoopTiming.PostLateUpdate).ContinueWith(_ => t = false).Forget();
|
|
|
|
var startFrame = Time.frameCount;
|
|
await UniTask.WaitWhile(() => t, PlayerLoopTiming.EarlyUpdate);
|
|
|
|
var diff = Time.frameCount - startFrame;
|
|
diff.Should().Be(11);
|
|
});
|
|
|
|
[UnityTest]
|
|
public IEnumerator WaitUntilValueChanged() => UniTask.ToCoroutine(async () =>
|
|
{
|
|
var v = new MyMyClass { MyProperty = 99 };
|
|
|
|
UniTask.DelayFrame(10, PlayerLoopTiming.PostLateUpdate).ContinueWith(_ => v.MyProperty = 1000).Forget();
|
|
|
|
var startFrame = Time.frameCount;
|
|
await UniTask.WaitUntilValueChanged(v, x => x.MyProperty, PlayerLoopTiming.EarlyUpdate);
|
|
|
|
var diff = Time.frameCount - startFrame;
|
|
diff.Should().Be(11);
|
|
});
|
|
|
|
[UnityTest]
|
|
public IEnumerator SwitchTo() => UniTask.ToCoroutine(async () =>
|
|
{
|
|
await UniTask.Yield();
|
|
|
|
var currentThreadId = Thread.CurrentThread.ManagedThreadId;
|
|
|
|
|
|
|
|
await UniTask.SwitchToThreadPool();
|
|
//await UniTask.SwitchToThreadPool();
|
|
//await UniTask.SwitchToThreadPool();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
var switchedThreadId = Thread.CurrentThread.ManagedThreadId;
|
|
|
|
|
|
|
|
currentThreadId.Should().NotBe(switchedThreadId);
|
|
|
|
|
|
await UniTask.Yield();
|
|
|
|
var switchedThreadId2 = Thread.CurrentThread.ManagedThreadId;
|
|
|
|
currentThreadId.Should().Be(switchedThreadId2);
|
|
});
|
|
|
|
//[UnityTest]
|
|
//public IEnumerator ObservableConversion() => UniTask.ToCoroutine(async () =>
|
|
//{
|
|
// var v = await Observable.Range(1, 10).ToUniTask();
|
|
// v.Is(10);
|
|
|
|
// v = await Observable.Range(1, 10).ToUniTask(useFirstValue: true);
|
|
// v.Is(1);
|
|
|
|
// v = await UniTask.DelayFrame(10).ToObservable().ToTask();
|
|
// v.Is(10);
|
|
|
|
// v = await UniTask.FromResult(99).ToObservable();
|
|
// v.Is(99);
|
|
//});
|
|
|
|
//[UnityTest]
|
|
//public IEnumerator AwaitableReactiveProperty() => UniTask.ToCoroutine(async () =>
|
|
//{
|
|
// var rp1 = new ReactiveProperty<int>(99);
|
|
|
|
// UniTask.DelayFrame(100).ContinueWith(x => rp1.Value = x).Forget();
|
|
|
|
// await rp1;
|
|
|
|
// rp1.Value.Is(100);
|
|
|
|
// // var delay2 = UniTask.DelayFrame(10);
|
|
// // var (a, b ) = await UniTask.WhenAll(rp1.WaitUntilValueChangedAsync(), delay2);
|
|
|
|
//});
|
|
|
|
//[UnityTest]
|
|
//public IEnumerator AwaitableReactiveCommand() => UniTask.ToCoroutine(async () =>
|
|
//{
|
|
// var rc = new ReactiveCommand<int>();
|
|
|
|
// UniTask.DelayFrame(100).ContinueWith(x => rc.Execute(x)).Forget();
|
|
|
|
// var v = await rc;
|
|
|
|
// v.Is(100);
|
|
//});
|
|
|
|
[UnityTest]
|
|
public IEnumerator ExceptionlessCancellation() => UniTask.ToCoroutine(async () =>
|
|
{
|
|
var cts = new CancellationTokenSource();
|
|
|
|
UniTask.DelayFrame(10).ContinueWith(_ => cts.Cancel()).Forget();
|
|
|
|
var first = Time.frameCount;
|
|
var (canceled, value) = await UniTask.DelayFrame(100, cancellationToken: cts.Token).SuppressCancellationThrow();
|
|
|
|
(Time.frameCount - first).Should().Be(11); // 10 frame canceled
|
|
canceled.Should().Be(true);
|
|
});
|
|
|
|
[UnityTest]
|
|
public IEnumerator ExceptionCancellation() => UniTask.ToCoroutine(async () =>
|
|
{
|
|
var cts = new CancellationTokenSource();
|
|
|
|
UniTask.DelayFrame(10).ContinueWith(_ => cts.Cancel()).Forget();
|
|
|
|
bool occur = false;
|
|
try
|
|
{
|
|
var value = await UniTask.DelayFrame(100, cancellationToken: cts.Token);
|
|
}
|
|
catch (OperationCanceledException)
|
|
{
|
|
occur = true;
|
|
}
|
|
occur.Should().BeTrue();
|
|
});
|
|
|
|
IEnumerator ToaruCoroutineEnumerator()
|
|
{
|
|
yield return null;
|
|
yield return null;
|
|
yield return null;
|
|
yield return null;
|
|
yield return null;
|
|
}
|
|
|
|
[UnityTest]
|
|
public IEnumerator ExceptionUnobserved1() => UniTask.ToCoroutine(async () =>
|
|
{
|
|
bool calledEx = false;
|
|
Action<Exception> action = exx =>
|
|
{
|
|
calledEx = true;
|
|
exx.Message.Should().Be("MyException");
|
|
};
|
|
|
|
UniTaskScheduler.UnobservedTaskException += action;
|
|
|
|
var ex = InException1();
|
|
ex = default(UniTask);
|
|
|
|
await UniTask.DelayFrame(3);
|
|
|
|
GC.Collect();
|
|
GC.WaitForPendingFinalizers();
|
|
GC.Collect();
|
|
|
|
await UniTask.DelayFrame(1);
|
|
|
|
calledEx.Should().BeTrue();
|
|
|
|
UniTaskScheduler.UnobservedTaskException -= action;
|
|
});
|
|
|
|
[UnityTest]
|
|
public IEnumerator ExceptionUnobserved2() => UniTask.ToCoroutine(async () =>
|
|
{
|
|
bool calledEx = false;
|
|
Action<Exception> action = exx =>
|
|
{
|
|
calledEx = true;
|
|
exx.Message.Should().Be("MyException");
|
|
};
|
|
|
|
UniTaskScheduler.UnobservedTaskException += action;
|
|
|
|
var ex = InException2();
|
|
ex = default(UniTask<int>);
|
|
|
|
await UniTask.DelayFrame(3);
|
|
|
|
GC.Collect();
|
|
GC.WaitForPendingFinalizers();
|
|
GC.Collect();
|
|
|
|
await UniTask.DelayFrame(1);
|
|
|
|
calledEx.Should().BeTrue();
|
|
|
|
UniTaskScheduler.UnobservedTaskException -= action;
|
|
});
|
|
|
|
async UniTask InException1()
|
|
{
|
|
await UniTask.Yield();
|
|
throw new Exception("MyException");
|
|
}
|
|
|
|
async UniTask<int> InException2()
|
|
{
|
|
await UniTask.Yield();
|
|
throw new Exception("MyException");
|
|
}
|
|
|
|
[UnityTest]
|
|
public IEnumerator NestedEnumerator() => UniTask.ToCoroutine(async () =>
|
|
{
|
|
var time = Time.realtimeSinceStartup;
|
|
|
|
await ParentCoroutineEnumerator();
|
|
|
|
var elapsed = Time.realtimeSinceStartup - time;
|
|
((int)Math.Round(TimeSpan.FromSeconds(elapsed).TotalSeconds, MidpointRounding.ToEven)).Should().Be(3);
|
|
});
|
|
|
|
IEnumerator ParentCoroutineEnumerator()
|
|
{
|
|
yield return ChildCoroutineEnumerator();
|
|
}
|
|
|
|
IEnumerator ChildCoroutineEnumerator()
|
|
{
|
|
yield return new WaitForSeconds(3);
|
|
}
|
|
|
|
[UnityTest]
|
|
public IEnumerator ToObservable() => UniTask.ToCoroutine(async () =>
|
|
{
|
|
var completedTaskObserver = new ToObservableObserver<AsyncUnit>();
|
|
completedTaskObserver.OnNextCalled.Should().BeFalse();
|
|
completedTaskObserver.OnCompletedCalled.Should().BeFalse();
|
|
completedTaskObserver.OnErrorCalled.Should().BeFalse();
|
|
UniTask.CompletedTask.ToObservable().Subscribe(completedTaskObserver);
|
|
completedTaskObserver.OnNextCalled.Should().BeTrue();
|
|
completedTaskObserver.OnCompletedCalled.Should().BeTrue();
|
|
completedTaskObserver.OnErrorCalled.Should().BeFalse();
|
|
|
|
var delayFrameTaskObserver = new ToObservableObserver<int>();
|
|
UniTask.DelayFrame(1).ToObservable().Subscribe(delayFrameTaskObserver);
|
|
delayFrameTaskObserver.OnNextCalled.Should().BeFalse();
|
|
delayFrameTaskObserver.OnCompletedCalled.Should().BeFalse();
|
|
delayFrameTaskObserver.OnErrorCalled.Should().BeFalse();
|
|
await UniTask.DelayFrame(1);
|
|
delayFrameTaskObserver.OnNextCalled.Should().BeTrue();
|
|
delayFrameTaskObserver.OnCompletedCalled.Should().BeTrue();
|
|
delayFrameTaskObserver.OnErrorCalled.Should().BeFalse();
|
|
});
|
|
|
|
class ToObservableObserver<T> : IObserver<T>
|
|
{
|
|
public bool OnNextCalled { get; private set; }
|
|
public bool OnCompletedCalled { get; private set; }
|
|
public bool OnErrorCalled { get; private set; }
|
|
|
|
public void OnNext(T value) => OnNextCalled = true;
|
|
public void OnCompleted() => OnCompletedCalled = true;
|
|
public void OnError(Exception error) => OnErrorCalled = true;
|
|
}
|
|
|
|
#endif
|
|
#endif
|
|
}
|
|
}
|
|
|
|
#endif |