cleaned up tests and integrated them with ci

This commit is contained in:
Ell 2021-03-18 16:38:34 +01:00
parent c7378078ae
commit c26d0cbeb0
12 changed files with 190 additions and 270 deletions

3
.gitignore vendored
View File

@ -3,4 +3,5 @@ bin
obj obj
packages packages
*.user *.user
*.nupkg *.nupkg
TestResults

View File

@ -2,9 +2,9 @@
Microsoft Visual Studio Solution File, Format Version 12.00 Microsoft Visual Studio Solution File, Format Version 12.00
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Coroutine", "Coroutine\Coroutine.csproj", "{1657964D-2503-426A-8514-D020660BEE4D}" Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Coroutine", "Coroutine\Coroutine.csproj", "{1657964D-2503-426A-8514-D020660BEE4D}"
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Test", "Test\Test.csproj", "{8BE6B559-927D-47A6-8253-D7D809D337AF}" Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Example", "Example\Example.csproj", "{8BE6B559-927D-47A6-8253-D7D809D337AF}"
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CoroutineTests", "CoroutineTests\CoroutineTests.csproj", "{8E110BC2-38FD-404A-B5BD-02C771B0D1D5}" Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Tests", "Tests\Tests.csproj", "{8E110BC2-38FD-404A-B5BD-02C771B0D1D5}"
EndProject EndProject
Global Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution GlobalSection(SolutionConfigurationPlatforms) = preSolution

View File

@ -5,7 +5,7 @@ using System.Diagnostics;
namespace Coroutine { namespace Coroutine {
/// <summary> /// <summary>
/// A reference to a currently running coroutine. /// A reference to a currently running coroutine.
/// This is returned by <see cref="CoroutineHandler.Start(IEnumerator{Wait},string,int)"/>. /// This is returned by <see cref="CoroutineHandler.Start(System.Collections.Generic.IEnumerator{Coroutine.Wait},string,int)"/>.
/// </summary> /// </summary>
public class ActiveCoroutine : IComparable<ActiveCoroutine> { public class ActiveCoroutine : IComparable<ActiveCoroutine> {

View File

@ -1,20 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netcoreapp3.1</TargetFramework>
<IsPackable>false</IsPackable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.7.1" />
<PackageReference Include="MSTest.TestAdapter" Version="2.1.1" />
<PackageReference Include="MSTest.TestFramework" Version="2.1.1" />
<PackageReference Include="coverlet.collector" Version="1.3.0" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Coroutine\Coroutine.csproj" />
</ItemGroup>
</Project>

View File

@ -3,7 +3,7 @@ using System.Collections.Generic;
using System.Threading; using System.Threading;
using Coroutine; using Coroutine;
namespace Test { namespace Example {
internal static class Example { internal static class Example {
private static readonly Event TestEvent = new Event(); private static readonly Event TestEvent = new Event();
@ -18,10 +18,10 @@ namespace Test {
Console.WriteLine("Raising test event"); Console.WriteLine("Raising test event");
CoroutineHandler.RaiseEvent(TestEvent); CoroutineHandler.RaiseEvent(TestEvent);
}); });
CoroutineHandler.InvokeLater(new Wait(TestEvent), () => Console.WriteLine("Test event received")); CoroutineHandler.InvokeLater(new Wait(TestEvent), () => Console.WriteLine("Example event received"));
CoroutineHandler.InvokeLater(new Wait(TestEvent), () => Console.WriteLine("I am invoked after 'Test event received'"), priority: -5); CoroutineHandler.InvokeLater(new Wait(TestEvent), () => Console.WriteLine("I am invoked after 'Example event received'"), priority: -5);
CoroutineHandler.InvokeLater(new Wait(TestEvent), () => Console.WriteLine("I am invoked before 'Test event received'"), priority: 2); CoroutineHandler.InvokeLater(new Wait(TestEvent), () => Console.WriteLine("I am invoked before 'Example event received'"), priority: 2);
var lastTime = DateTime.Now; var lastTime = DateTime.Now;
while (true) { while (true) {

11
Example/Example.csproj Normal file
View File

@ -0,0 +1,11 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netcoreapp3.1</TargetFramework>
<OutputType>Exe</OutputType>
<IsPackable>false</IsPackable>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\Coroutine\Coroutine.csproj"/>
</ItemGroup>
</Project>

8
Jenkinsfile vendored
View File

@ -1,16 +1,18 @@
pipeline { pipeline {
agent any agent any
stages { stages {
stage('Build') { stage('Test') {
steps { steps {
sh 'dotnet build **/Coroutine.csproj' sh 'dotnet test --collect:"XPlat Code Coverage"'
nunit testResultsPattern: '**/TestResults.xml'
cobertura coberturaReportFile: '**/coverage.cobertura.xml'
} }
} }
stage('Pack') { stage('Pack') {
steps { steps {
sh 'find . -type f -name \\\'*.nupkg\\\' -delete' sh 'find . -type f -name \\\'*.nupkg\\\' -delete'
sh 'dotnet pack **/Coroutine.csproj --version-suffix ${BUILD_NUMBER}' sh 'dotnet pack --version-suffix ${BUILD_NUMBER}'
} }
} }

View File

@ -66,4 +66,4 @@ CoroutineHandler.RaiseEvent(TestEvent);
``` ```
## Additional Examples ## Additional Examples
For additional examples, take a look at the [Example class](https://github.com/Ellpeck/Coroutine/blob/master/Test/Example.cs). For additional examples, take a look at the [Example class](https://github.com/Ellpeck/Coroutine/blob/master/Example/Example.cs).

View File

@ -1,58 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{8BE6B559-927D-47A6-8253-D7D809D337AF}</ProjectGuid>
<OutputType>Exe</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>Test</RootNamespace>
<AssemblyName>Test</AssemblyName>
<TargetFrameworkVersion>v4.6.2</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Data" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="Example.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Coroutine\Coroutine.csproj">
<Project>{1657964d-2503-426a-8514-d020660bee4d}</Project>
<Name>Coroutine</Name>
</ProjectReference>
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
</Project>

View File

@ -1,19 +1,16 @@
using Coroutine; using System.Collections.Generic;
using Microsoft.VisualStudio.TestTools.UnitTesting; using Coroutine;
using System.Collections.Generic; using NUnit.Framework;
namespace CoroutineTests namespace Tests {
{ public class EventBasedCoroutineTests {
[TestClass]
public class EventBasedCoroutineTests [Test]
{ public void TestEventBasedCoroutine() {
[TestMethod] var counter = 0;
public void TestEventBasedCoroutine()
{
int counter = 0;
var myEvent = new Event(); var myEvent = new Event();
IEnumerator<Wait> OnEventTriggered()
{ IEnumerator<Wait> OnEventTriggered() {
counter++; counter++;
yield return new Wait(myEvent); yield return new Wait(myEvent);
counter++; counter++;
@ -30,5 +27,6 @@ namespace CoroutineTests
Assert.AreEqual(false, cr.WasCanceled, "Incorrect IsCanceled value."); Assert.AreEqual(false, cr.WasCanceled, "Incorrect IsCanceled value.");
Assert.AreEqual(cr.MoveNextCount, 2, "Incorrect MoveNextCount value."); Assert.AreEqual(cr.MoveNextCount, 2, "Incorrect MoveNextCount value.");
} }
} }
} }

19
Tests/Tests.csproj Normal file
View File

@ -0,0 +1,19 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netcoreapp3.1</TargetFramework>
<IsPackable>false</IsPackable>
<VSTestLogger>nunit</VSTestLogger>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="coverlet.collector" Version="3.0.3" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.9.1" />
<PackageReference Include="NUnit" Version="3.13.1" />
<PackageReference Include="NUnit3TestAdapter" Version="3.17.0" />
<PackageReference Include="NunitXml.TestLogger" Version="3.0.97" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Coroutine\Coroutine.csproj" />
</ItemGroup>
</Project>

View File

@ -1,20 +1,16 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Threading; using System.Threading;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Coroutine; using Coroutine;
using NUnit.Framework;
namespace Tests {
public class TimeBasedCoroutineTests {
namespace CoroutineTests [Test]
{ public void TestTimerBasedCoroutine() {
[TestClass] var counter = 0;
public class TimeBasedCoroutineTests
{ IEnumerator<Wait> OnTimeTickCodeExecuted() {
[TestMethod]
public void TestTimerBasedCoroutine()
{
int counter = 0;
IEnumerator<Wait> OnTimeTickCodeExecuted()
{
counter++; counter++;
yield return new Wait(0.1d); yield return new Wait(0.1d);
counter++; counter++;
@ -24,7 +20,7 @@ namespace CoroutineTests
Assert.AreEqual(1, counter, "instruction before yield is not executed."); Assert.AreEqual(1, counter, "instruction before yield is not executed.");
Assert.AreEqual(string.Empty, cr.Name, "Incorrect default name found"); Assert.AreEqual(string.Empty, cr.Name, "Incorrect default name found");
Assert.AreEqual(0, cr.Priority, "Default priority is not minimum"); Assert.AreEqual(0, cr.Priority, "Default priority is not minimum");
for (int i = 0; i < 5; i++) for (var i = 0; i < 5; i++)
this.SimulateTime(1); this.SimulateTime(1);
Assert.AreEqual(2, counter, "instruction after yield is not executed."); Assert.AreEqual(2, counter, "instruction after yield is not executed.");
Assert.AreEqual(true, cr.IsFinished, "Incorrect IsFinished value."); Assert.AreEqual(true, cr.IsFinished, "Incorrect IsFinished value.");
@ -32,159 +28,143 @@ namespace CoroutineTests
Assert.AreEqual(cr.MoveNextCount, 2, "Incorrect MoveNextCount value."); Assert.AreEqual(cr.MoveNextCount, 2, "Incorrect MoveNextCount value.");
} }
[TestMethod] [Test]
public void TestCoroutineReturningWeirdYields() public void TestCoroutineReturningWeirdYields() {
{ var counter = 0;
int counter = 0;
IEnumerator<Wait> OnTimeTickNeverReturnYield()
{
counter++; // 1
if (counter == 100) // condition that's expected to be false.
{
yield return new Wait(0.1d);
}
IEnumerator<Wait> OnTimeTickNeverReturnYield() {
counter++; // 1
// condition that's expected to be false
if (counter == 100)
yield return new Wait(0.1d);
counter++; // 2 counter++; // 2
} }
IEnumerator<Wait> OnTimeTickYieldBreak() IEnumerator<Wait> OnTimeTickYieldBreak() {
{
counter++; // 3 counter++; // 3
yield break; yield break;
counter++; // still 3
} }
var cr = new ActiveCoroutine[2]; var cr = new ActiveCoroutine[2];
cr[0] = CoroutineHandler.Start(OnTimeTickNeverReturnYield()); cr[0] = CoroutineHandler.Start(OnTimeTickNeverReturnYield());
cr[1] = CoroutineHandler.Start(OnTimeTickYieldBreak()); cr[1] = CoroutineHandler.Start(OnTimeTickYieldBreak());
for (int i = 0; i < 5; i++) for (var i = 0; i < 5; i++)
this.SimulateTime(1); this.SimulateTime(1);
Assert.AreEqual(3, counter, $"Incorrect counter value."); Assert.AreEqual(3, counter, "Incorrect counter value.");
for (int i = 0; i < cr.Length; i++) for (var i = 0; i < cr.Length; i++) {
{
Assert.AreEqual(true, cr[i].IsFinished, $"Incorrect IsFinished value on index {i}."); Assert.AreEqual(true, cr[i].IsFinished, $"Incorrect IsFinished value on index {i}.");
Assert.AreEqual(false, cr[i].WasCanceled, $"Incorrect IsCanceled value on index {i}"); Assert.AreEqual(false, cr[i].WasCanceled, $"Incorrect IsCanceled value on index {i}");
Assert.AreEqual(1, cr[i].MoveNextCount, $"Incorrect MoveNextCount value on index {i}"); Assert.AreEqual(1, cr[i].MoveNextCount, $"Incorrect MoveNextCount value on index {i}");
} }
} }
[TestMethod] [Test]
public void TestCoroutineReturningDefaultYield() public void TestCoroutineReturningDefaultYield() {
{ var counter = 0;
int counter = 0;
IEnumerator<Wait> OnTimeTickYieldDefault() IEnumerator<Wait> OnTimeTickYieldDefault() {
{
counter++; // 1 counter++; // 1
yield return default; yield return default;
counter++; // 2 counter++; // 2
} }
var cr = CoroutineHandler.Start(OnTimeTickYieldDefault()); var cr = CoroutineHandler.Start(OnTimeTickYieldDefault());
for (int i = 0; i < 5; i++) for (var i = 0; i < 5; i++)
this.SimulateTime(1); this.SimulateTime(1);
Assert.AreEqual(2, counter, $"Incorrect counter value."); Assert.AreEqual(2, counter, "Incorrect counter value.");
Assert.AreEqual(true, cr.IsFinished, $"Incorrect IsFinished value."); Assert.AreEqual(true, cr.IsFinished, "Incorrect IsFinished value.");
Assert.AreEqual(false, cr.WasCanceled, $"Incorrect IsCanceled value."); Assert.AreEqual(false, cr.WasCanceled, "Incorrect IsCanceled value.");
Assert.AreEqual(2, cr.MoveNextCount, $"Incorrect MoveNextCount value."); Assert.AreEqual(2, cr.MoveNextCount, "Incorrect MoveNextCount value.");
} }
[TestMethod] [Test]
public void TestInfiniteCoroutineNeverFinishesUnlessCanceled() public void TestInfiniteCoroutineNeverFinishesUnlessCanceled() {
{ var counter = 0;
int counter = 0;
IEnumerator<Wait> OnTimerTickInfinite() IEnumerator<Wait> OnTimerTickInfinite() {
{ while (true) {
while (true)
{
counter++; counter++;
yield return new Wait(1); yield return new Wait(1);
} }
} }
void setCounterToUnreachableValue(ActiveCoroutine coroutine) void SetCounterToUnreachableValue(ActiveCoroutine coroutine) {
{
counter = -100; counter = -100;
} }
var cr = CoroutineHandler.Start(OnTimerTickInfinite()); var cr = CoroutineHandler.Start(OnTimerTickInfinite());
cr.OnFinished += setCounterToUnreachableValue; cr.OnFinished += SetCounterToUnreachableValue;
for (int i = 0; i < 50; i++) for (var i = 0; i < 50; i++)
this.SimulateTime(1); this.SimulateTime(1);
Assert.AreEqual(51, counter, $"Incorrect counter value."); Assert.AreEqual(51, counter, "Incorrect counter value.");
Assert.AreEqual(false, cr.IsFinished, $"Incorrect IsFinished value."); Assert.AreEqual(false, cr.IsFinished, "Incorrect IsFinished value.");
Assert.AreEqual(false, cr.WasCanceled, $"Incorrect IsCanceled value."); Assert.AreEqual(false, cr.WasCanceled, "Incorrect IsCanceled value.");
Assert.AreEqual(51, cr.MoveNextCount, $"Incorrect MoveNextCount value."); Assert.AreEqual(51, cr.MoveNextCount, "Incorrect MoveNextCount value.");
cr.Cancel(); cr.Cancel();
Assert.AreEqual(true, cr.WasCanceled, $"Incorrect IsCanceled value after canceling."); Assert.AreEqual(true, cr.WasCanceled, "Incorrect IsCanceled value after canceling.");
Assert.AreEqual(-100, counter, $"OnFinished event not triggered when canceled."); Assert.AreEqual(-100, counter, "OnFinished event not triggered when canceled.");
Assert.AreEqual(51, cr.MoveNextCount, $"Incorrect MoveNextCount value."); Assert.AreEqual(51, cr.MoveNextCount, "Incorrect MoveNextCount value.");
Assert.AreEqual(true, cr.IsFinished, $"Incorrect IsFinished value."); Assert.AreEqual(true, cr.IsFinished, "Incorrect IsFinished value.");
} }
[TestMethod] [Test]
public void TestOnFinishedEventExecuted() public void TestOnFinishedEventExecuted() {
{ var counter = 0;
int counter = 0;
IEnumerator<Wait> OnTimeTick() IEnumerator<Wait> OnTimeTick() {
{
counter++; counter++;
yield return new Wait(0.1d); yield return new Wait(0.1d);
} }
void setCounterToUnreachableValue(ActiveCoroutine coroutine) void SetCounterToUnreachableValue(ActiveCoroutine coroutine) {
{
counter = -100; counter = -100;
} }
var cr = CoroutineHandler.Start(OnTimeTick()); var cr = CoroutineHandler.Start(OnTimeTick());
cr.OnFinished += setCounterToUnreachableValue; cr.OnFinished += SetCounterToUnreachableValue;
this.SimulateTime(50); this.SimulateTime(50);
Assert.AreEqual(-100, counter, $"Incorrect counter value."); Assert.AreEqual(-100, counter, "Incorrect counter value.");
} }
[TestMethod] [Test]
public void TestNestedCoroutine() public void TestNestedCoroutine() {
{ var counterAlwaysRunning = 0;
int counterAlwaysRunning = 0;
IEnumerator<Wait> AlwaysRunning() IEnumerator<Wait> AlwaysRunning() {
{ while (true) {
while (true)
{
yield return new Wait(1); yield return new Wait(1);
counterAlwaysRunning++; counterAlwaysRunning++;
} }
} }
int counterChild = 0; var counterChild = 0;
IEnumerator<Wait> Child()
{ IEnumerator<Wait> Child() {
yield return new Wait(1); yield return new Wait(1);
counterChild++; counterChild++;
} }
int counterParent = 0; var counterParent = 0;
IEnumerator<Wait> Parent()
{ IEnumerator<Wait> Parent() {
yield return new Wait(1); yield return new Wait(1);
counterParent++; counterParent++;
// OnFinish I will start child. // OnFinish I will start child.
} }
int counterGrandParent = 0; var counterGrandParent = 0;
IEnumerator<Wait> GrandParent()
{ IEnumerator<Wait> GrandParent() {
yield return new Wait(1); yield return new Wait(1);
counterGrandParent++; counterGrandParent++;
// Nested corotuine starting. // Nested corotuine starting.
var p = CoroutineHandler.Start(Parent()); var p = CoroutineHandler.Start(Parent());
// Nested corotuine starting in OnFinished. // Nested corotuine starting in OnFinished.
p.OnFinished += (ActiveCoroutine ac) => { CoroutineHandler.Start(Child()); }; p.OnFinished += ac => CoroutineHandler.Start(Child());
} }
CoroutineHandler.Start(AlwaysRunning()); CoroutineHandler.Start(AlwaysRunning());
@ -215,57 +195,50 @@ namespace CoroutineTests
Assert.AreEqual(1, counterChild, "Child counter is invalid at time 4."); Assert.AreEqual(1, counterChild, "Child counter is invalid at time 4.");
} }
[TestMethod] [Test]
public void TestPriority() public void TestPriority() {
{ var counterShouldExecuteBefore0 = 0;
int counterShouldExecuteBefore0 = 0;
IEnumerator<Wait> ShouldExecuteBefore0() IEnumerator<Wait> ShouldExecuteBefore0() {
{ while (true) {
while (true)
{
yield return new Wait(1); yield return new Wait(1);
counterShouldExecuteBefore0++; counterShouldExecuteBefore0++;
} }
} }
int counterShouldExecuteBefore1 = 0; var counterShouldExecuteBefore1 = 0;
IEnumerator<Wait> ShouldExecuteBefore1()
{ IEnumerator<Wait> ShouldExecuteBefore1() {
while (true) while (true) {
{
yield return new Wait(1); yield return new Wait(1);
counterShouldExecuteBefore1++; counterShouldExecuteBefore1++;
} }
} }
int counterShouldExecuteAfter = 0; var counterShouldExecuteAfter = 0;
IEnumerator<Wait> ShouldExecuteAfter()
{ IEnumerator<Wait> ShouldExecuteAfter() {
while (true) while (true) {
{
yield return new Wait(1); yield return new Wait(1);
if (counterShouldExecuteBefore0 == 1 && if (counterShouldExecuteBefore0 == 1 &&
counterShouldExecuteBefore1 == 1) counterShouldExecuteBefore1 == 1) {
{
counterShouldExecuteAfter++; counterShouldExecuteAfter++;
} }
} }
} }
int counterShouldExecuteFinally = 0; var counterShouldExecuteFinally = 0;
IEnumerator<Wait> ShouldExecuteFinally()
{ IEnumerator<Wait> ShouldExecuteFinally() {
while (true) while (true) {
{
yield return new Wait(1); yield return new Wait(1);
if (counterShouldExecuteAfter > 0) if (counterShouldExecuteAfter > 0) {
{
counterShouldExecuteFinally++; counterShouldExecuteFinally++;
} }
} }
} }
int highPriority = int.MaxValue; var highPriority = int.MaxValue;
CoroutineHandler.Start(ShouldExecuteBefore1(), priority: highPriority); CoroutineHandler.Start(ShouldExecuteBefore1(), priority: highPriority);
CoroutineHandler.Start(ShouldExecuteAfter()); CoroutineHandler.Start(ShouldExecuteAfter());
CoroutineHandler.Start(ShouldExecuteBefore0(), priority: highPriority); CoroutineHandler.Start(ShouldExecuteBefore0(), priority: highPriority);
@ -275,24 +248,21 @@ namespace CoroutineTests
Assert.AreEqual(1, counterShouldExecuteFinally, $"ShouldExecuteFinally counter {counterShouldExecuteFinally} is invalid."); Assert.AreEqual(1, counterShouldExecuteFinally, $"ShouldExecuteFinally counter {counterShouldExecuteFinally} is invalid.");
} }
[TestMethod] [Test]
public void TestTimeBasedCoroutineIsAccurate() public void TestTimeBasedCoroutineIsAccurate() {
{ var counter0 = 0;
int counter0 = 0;
IEnumerator<Wait> IncrementCounter0Ever10Seconds() IEnumerator<Wait> IncrementCounter0Ever10Seconds() {
{ while (true) {
while (true)
{
yield return new Wait(10); yield return new Wait(10);
counter0++; counter0++;
} }
} }
int counter1 = 0; var counter1 = 0;
IEnumerator<Wait> IncrementCounter1Every5Seconds()
{ IEnumerator<Wait> IncrementCounter1Every5Seconds() {
while (true) while (true) {
{
yield return new Wait(5); yield return new Wait(5);
counter1++; counter1++;
} }
@ -301,69 +271,66 @@ namespace CoroutineTests
CoroutineHandler.Start(IncrementCounter0Ever10Seconds()); CoroutineHandler.Start(IncrementCounter0Ever10Seconds());
CoroutineHandler.Start(IncrementCounter1Every5Seconds()); CoroutineHandler.Start(IncrementCounter1Every5Seconds());
this.SimulateTime(3); this.SimulateTime(3);
Assert.AreEqual(0, counter0, $"Incorrect counter0 value after 3 seconds."); Assert.AreEqual(0, counter0, "Incorrect counter0 value after 3 seconds.");
Assert.AreEqual(0, counter1, $"Incorrect counter1 value after 3 seconds."); Assert.AreEqual(0, counter1, "Incorrect counter1 value after 3 seconds.");
this.SimulateTime(3); this.SimulateTime(3);
Assert.AreEqual(0, counter0, $"Incorrect counter0 value after 6 seconds."); Assert.AreEqual(0, counter0, "Incorrect counter0 value after 6 seconds.");
Assert.AreEqual(1, counter1, $"Incorrect counter1 value after 6 seconds."); Assert.AreEqual(1, counter1, "Incorrect counter1 value after 6 seconds.");
// it's 5 over here because IncrementCounter1Every5Seconds // it's 5 over here because IncrementCounter1Every5Seconds
// increments 5 seconds after last yield. not 5 seconds since start. // increments 5 seconds after last yield. not 5 seconds since start.
// So the when we send 3 seconds in the last SimulateTime, // So the when we send 3 seconds in the last SimulateTime,
// the 3rd second was technically ignored. // the 3rd second was technically ignored.
this.SimulateTime(5); this.SimulateTime(5);
Assert.AreEqual(1, counter0, $"Incorrect counter0 value after 10 seconds."); Assert.AreEqual(1, counter0, "Incorrect counter0 value after 10 seconds.");
Assert.AreEqual(2, counter1, $"Incorrect counter1 value after next 5 seconds."); Assert.AreEqual(2, counter1, "Incorrect counter1 value after next 5 seconds.");
} }
[TestMethod] [Test]
public void InvokeLaterAndNameTest() public void InvokeLaterAndNameTest() {
{ var counter = 0;
int counter = 0;
var cr = CoroutineHandler.InvokeLater(new Wait(10), () => { var cr = CoroutineHandler.InvokeLater(new Wait(10), () => {
counter++; counter++;
}, "Bird"); }, "Bird");
this.SimulateTime(5); this.SimulateTime(5);
Assert.AreEqual(0, counter, $"Incorrect counter value after 5 seconds."); Assert.AreEqual(0, counter, "Incorrect counter value after 5 seconds.");
this.SimulateTime(5); this.SimulateTime(5);
Assert.AreEqual(1, counter, $"Incorrect counter value after 10 seconds."); Assert.AreEqual(1, counter, "Incorrect counter value after 10 seconds.");
Assert.AreEqual(true, cr.IsFinished, "Incorrect IsFinished value."); Assert.AreEqual(true, cr.IsFinished, "Incorrect IsFinished value.");
Assert.AreEqual(false, cr.WasCanceled, "Incorrect IsCanceled value."); Assert.AreEqual(false, cr.WasCanceled, "Incorrect IsCanceled value.");
Assert.AreEqual(cr.MoveNextCount, 2, "Incorrect MoveNextCount value."); Assert.AreEqual(cr.MoveNextCount, 2, "Incorrect MoveNextCount value.");
Assert.AreEqual(cr.Name, "Bird", "Incorrect name of the coroutine."); Assert.AreEqual(cr.Name, "Bird", "Incorrect name of the coroutine.");
} }
[TestMethod] [Test]
public void CoroutineStatsAre95PercentAccurate() public void CoroutineStatsAre95PercentAccurate() {
{ IEnumerator<Wait> CoroutineTakesMax500Ms() {
IEnumerator<Wait> CoroutineTakesMax500MS()
{
Thread.Sleep(200); Thread.Sleep(200);
yield return new Wait(10); yield return new Wait(10);
Thread.Sleep(500); Thread.Sleep(500);
} }
var cr = CoroutineHandler.Start(CoroutineTakesMax500MS()); var cr = CoroutineHandler.Start(CoroutineTakesMax500Ms());
for (int i = 0; i < 5; i++) for (var i = 0; i < 5; i++)
this.SimulateTime(50); this.SimulateTime(50);
int expected1 = 350; const int expected1 = 350;
float errorbar1 = (5 / 100f * expected1); const float errorbar1 = 5 / 100f * expected1;
bool gTA = cr.AverageMoveNextTime.Milliseconds > (expected1 - errorbar1); // 95% accuracy. var gTa = cr.AverageMoveNextTime.Milliseconds > expected1 - errorbar1; // 95% accuracy.
bool lTB = cr.AverageMoveNextTime.Milliseconds < (expected1 + errorbar1); // 95% accuracy. var lTb = cr.AverageMoveNextTime.Milliseconds < expected1 + errorbar1; // 95% accuracy.
Assert.IsTrue(gTA && lTB, $"Average Move Next Time {cr.AverageMoveNextTime.Milliseconds} is invalid."); Assert.IsTrue(gTa && lTb, $"Average Move Next Time {cr.AverageMoveNextTime.Milliseconds} is invalid.");
int expected2 = 500; const int expected2 = 500;
float errorbar2 = (5 / 100f * expected2); const float errorbar2 = 5 / 100f * expected2;
bool gTC = cr.MaxMoveNextTime.Milliseconds > (expected2 - errorbar2); // 95% accuracy. var gTc = cr.MaxMoveNextTime.Milliseconds > expected2 - errorbar2; // 95% accuracy.
bool lTD = cr.MaxMoveNextTime.Milliseconds < (expected2 + errorbar2); // 95% accuracy. var lTd = cr.MaxMoveNextTime.Milliseconds < expected2 + errorbar2; // 95% accuracy.
Assert.IsTrue(gTC && lTD, $"Maximum Move Next Time {cr.MaxMoveNextTime.Milliseconds} is invalid."); Assert.IsTrue(gTc && lTd, $"Maximum Move Next Time {cr.MaxMoveNextTime.Milliseconds} is invalid.");
} }
private void SimulateTime(double totalSeconds) private void SimulateTime(double totalSeconds) {
{
CoroutineHandler.Tick(totalSeconds); CoroutineHandler.Tick(totalSeconds);
} }
} }
} }