增加A2WToolBox工具集,增加Launch场景核LaunchPanel

This commit is contained in:
Wurui
2025-11-08 11:06:48 +08:00
parent 3e92e5684a
commit 3b43829e85
726 changed files with 87807 additions and 215 deletions

View File

@@ -0,0 +1,7 @@
using UnityEngine;
using System.Collections;
using MonsterLove.StateMachine;
public class ClassDerivedFromSuperClass : ClassWithBasicStates
{
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 56b834ac2387fd9428fa8e3d03e15af9
timeCreated: 1466594866
licenseType: Free
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,95 @@
using MonsterLove.StateMachine;
using UnityEngine;
using System.Collections;
public class ClassWithBasicStates : MonoBehaviour
{
public ClassWithBasicStatesTestHelper oneStats = new ClassWithBasicStatesTestHelper();
public ClassWithBasicStatesTestHelper twoStats = new ClassWithBasicStatesTestHelper();
public ClassWithBasicStatesTestHelper threeStats = new ClassWithBasicStatesTestHelper();
protected void One_Enter()
{
oneStats.enterCount++;
}
protected void One_Update()
{
oneStats.updateCount++;
}
protected void One_LateUpdate()
{
oneStats.lateUpdateCount++;
}
protected void One_Exit()
{
oneStats.exitCount++;
}
protected void One_Finally()
{
oneStats.finallyCount++;
}
protected void Two_Enter()
{
twoStats.enterCount++;
}
protected void Two_Update()
{
twoStats.updateCount++;
}
protected void Two_LateUpdate()
{
twoStats.lateUpdateCount++;
}
protected void Two_Exit()
{
twoStats.exitCount++;
}
protected void Two_Finally()
{
twoStats.finallyCount++;
}
protected void Three_Enter()
{
threeStats.enterCount++;
}
protected void Three_Update()
{
threeStats.updateCount++;
}
protected void Three_LateUpdate()
{
threeStats.lateUpdateCount++;
}
protected void Three_Exit()
{
threeStats.exitCount++;
}
protected void Three_Finally()
{
threeStats.finallyCount++;
}
}
[System.Serializable]
public class ClassWithBasicStatesTestHelper
{
public int enterCount;
public int updateCount;
public int lateUpdateCount;
public int exitCount;
public int finallyCount;
}

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: f41bf36ff667bf844808b5e9fa28af3f
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:

View File

@@ -0,0 +1,21 @@
{
"name": "MonsterLove.StateMachine.Tests.Runtime",
"references": [
"MonsterLove.StateMachine.Runtime",
"UnityEngine.TestRunner",
"UnityEditor.TestRunner"
],
"includePlatforms": [],
"excludePlatforms": [],
"allowUnsafeCode": false,
"overrideReferences": true,
"precompiledReferences": [
"nunit.framework.dll"
],
"autoReferenced": false,
"defineConstraints": [
"UNITY_INCLUDE_TESTS"
],
"versionDefines": [],
"noEngineReferences": false
}

View File

@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: f9fb370cdd6625f4fb8a0dec85124b0c
AssemblyDefinitionImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,199 @@
using System.Collections;
using MonsterLove.StateMachine;
using NUnit.Framework;
using UnityEngine;
using UnityEngine.TestTools;
namespace Tests
{
public class TestAsyncCustomDriver
{
public enum States
{
One,
Two,
Three,
Four,
}
private GameObject go;
private StateClass behaviour;
private StateMachine<States, StateDriverUnity> fsm;
[SetUp]
public void Init()
{
go = new GameObject();
behaviour = go.AddComponent<StateClass>();
fsm = new StateMachine<States, StateDriverUnity>(behaviour);
behaviour.fsm = fsm;
}
[TearDown]
public void Kill()
{
Object.Destroy(go);
}
[UnityTest]
public IEnumerator TestChange()
{
// /1
fsm.ChangeState(States.One);
yield return null;
Assert.AreEqual(0, behaviour.oneEnter);
Assert.AreEqual(0, behaviour.oneUpdate); //Enter still running, no update called
yield return null;
Assert.AreEqual(1, behaviour.oneEnter); //Enter now complete
Assert.AreEqual(0, behaviour.oneUpdate); //Update executes before co-routine, therefore update not run yet
yield return null;
Assert.AreEqual(1, behaviour.oneEnter);
Assert.AreEqual(1, behaviour.oneUpdate); //Update has first chance to run
}
private class StateClass : MonoBehaviour
{
public StateMachine<States, StateDriverUnity> fsm;
public int oneEnter;
public int oneUpdate;
public int oneExit;
public int oneFinally;
public int twoEnter;
public int twoUpdate;
public int twoExit;
public int twoFinally;
public int threeEnter;
public int threeUpdate;
public int threeExit;
public int threeFinally;
public int fourEnter;
public int fourUpdate;
public int fourExit;
public int fourFinally;
void Update()
{
fsm.Driver.Update.Invoke();
}
IEnumerator One_Enter()
{
Debug.LogFormat("State:{0} Frame:{1}", "One Enter Start", Time.frameCount);
yield return null;
yield return null;
Debug.LogFormat("State:{0} Frame:{1}", "One Enter End", Time.frameCount);
oneEnter++;
}
void One_Update()
{
Debug.LogFormat("State:{0} Frame:{1}", "One Update", Time.frameCount);
oneUpdate++;
}
IEnumerator One_Exit()
{
Debug.LogFormat("State:{0} Frame:{1}", "One Exit Start", Time.frameCount);
yield return null;
yield return null;
Debug.LogFormat("State:{0} Frame:{1}", "One Exit End", Time.frameCount);
oneExit++;
}
void One_Finally()
{
Debug.LogFormat("State:{0} Frame:{1}", "One Finally", Time.frameCount);
oneFinally++;
}
void Two_Enter()
{
Debug.LogFormat("State:{0} Frame:{1}", "Two Enter", Time.frameCount);
twoEnter++;
}
void Two_Update()
{
Debug.LogFormat("State:{0} Frame:{1}", "Two Update", Time.frameCount);
twoUpdate++;
}
void Two_Exit()
{
Debug.LogFormat("State:{0} Frame:{1}", "Two Exit", Time.frameCount);
twoExit++;
}
void Two_Finally()
{
Debug.LogFormat("State:{0} Frame:{1}", "Two Finally", Time.frameCount);
twoFinally++;
}
void Three_Enter()
{
Debug.LogFormat("State:{0} Frame:{1}", "Three Enter", Time.frameCount);
threeEnter++;
}
void Three_Update()
{
Debug.LogFormat("State:{0} Frame:{1}", "Three Update", Time.frameCount);
threeUpdate++;
}
void Three_Exit()
{
Debug.LogFormat("State:{0} Frame:{1}", "Three Exit", Time.frameCount);
threeExit++;
}
void Three_Finally()
{
Debug.LogFormat("State:{0} Frame:{1}", "Three Finally", Time.frameCount);
threeFinally++;
}
void Four_Enter()
{
Debug.LogFormat("State:{0} Frame:{1}", "Four Enter", Time.frameCount);
fourEnter++;
}
void Four_Update()
{
Debug.LogFormat("State:{0} Frame:{1}", "Four Update", Time.frameCount);
fourUpdate++;
}
void Four_Exit()
{
Debug.LogFormat("State:{0} Frame:{1}", "Four Exit", Time.frameCount);
fourExit++;
}
void Four_Finally()
{
Debug.LogFormat("State:{0} Frame:{1}", "Four Finally", Time.frameCount);
fourFinally++;
}
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 7b734601d42952c488c972b05398a234
timeCreated: 1567675903

View File

@@ -0,0 +1,286 @@
using System.Collections;
using MonsterLove.StateMachine;
using NUnit.Framework;
using UnityEngine;
using UnityEngine.TestTools;
namespace Tests
{
public class TestChangeAsyncOverwrite
{
public enum States
{
One,
Two,
Three,
Four,
}
private GameObject go;
private StateClass behaviour;
private StateMachine<States> fsm;
private float duration = 0.5f;
[SetUp]
public void Init()
{
go = new GameObject();
behaviour = go.AddComponent<StateClass>();
behaviour.duration = duration;
fsm = StateMachine<States>.Initialize(behaviour);
}
[TearDown]
public void Kill()
{
Object.Destroy(go);
}
[UnityTest]
public IEnumerator TestAsyncEnterExit()
{
// 1
fsm.ChangeState(States.One, StateTransition.Overwrite);
// 1*__/2
fsm.ChangeState(States.Two, StateTransition.Overwrite);
Assert.AreEqual(States.One, fsm.LastState);
Assert.AreEqual(States.Two, fsm.State);
Assert.AreEqual(States.Two, fsm.NextState);
yield return new WaitForSeconds(duration + 0.2f);
Assert.AreEqual(1, behaviour.oneEnter);
Assert.AreEqual(0, behaviour.oneUpdate);
Assert.AreEqual(0, behaviour.oneExit);
Assert.AreEqual(1, behaviour.oneFinally);
Assert.AreEqual(1, behaviour.twoEnter);
Assert.AreEqual(States.One, fsm.LastState);
Assert.AreEqual(States.Two, fsm.State);
Assert.AreEqual(States.Two, fsm.NextState);
}
[UnityTest]
public IEnumerator TestChangeDuringAsyncEnter()
{
// 1
fsm.ChangeState(States.One, StateTransition.Overwrite);
// 1\__/2
fsm.ChangeState(States.Two, StateTransition.Safe);
Assert.AreEqual(false, fsm.LastStateExists);
Assert.AreEqual(States.One, fsm.State);
Assert.AreEqual(States.Two, fsm.NextState);
yield return new WaitForSeconds(duration + duration * 0.5f);
Assert.AreEqual(1, behaviour.oneEnter);
Assert.AreEqual(0, behaviour.oneUpdate);
Assert.AreEqual(1, behaviour.oneExit);
Assert.AreEqual(1, behaviour.oneFinally);
Assert.AreEqual(0, behaviour.twoEnter);
Assert.AreEqual(0, behaviour.threeEnter);
Assert.AreEqual(States.One, fsm.LastState);
Assert.AreEqual(States.Two, fsm.State);
Assert.AreEqual(States.Two, fsm.NextState);
// 1\__*2__3
fsm.ChangeState(States.Three, StateTransition.Overwrite);
Assert.AreEqual(0, behaviour.twoEnter); //Intro never completes
Assert.AreEqual(1, behaviour.twoExit); //Single frame Exit still fires. Arguably more consistent that exit doesn't fire, instead relying on finally(), however this would be a breaking change
Assert.AreEqual(0, behaviour.twoUpdate);
Assert.AreEqual(1, behaviour.twoFinally);
Assert.AreEqual(1, behaviour.threeEnter);
Assert.AreEqual(States.Two, fsm.LastState);
Assert.AreEqual(States.Three, fsm.State);
Assert.AreEqual(States.Three, fsm.NextState);
}
[UnityTest]
public IEnumerator TestChangeDuringAsyncExit()
{
// 1
fsm.ChangeState(States.One, StateTransition.Overwrite);
// 1\__/2
fsm.ChangeState(States.Two, StateTransition.Safe);
Assert.AreEqual(false, fsm.LastStateExists);
Assert.AreEqual(States.One, fsm.State);
Assert.AreEqual(States.Two, fsm.NextState);
yield return new WaitForSeconds(duration * 0.5f);
Assert.AreEqual(1, behaviour.oneEnter);
Assert.AreEqual(0, behaviour.oneUpdate);
Assert.AreEqual(0, behaviour.oneExit);
Assert.AreEqual(0, behaviour.oneFinally);
Assert.AreEqual(0, behaviour.twoEnter);
Assert.AreEqual(false, fsm.LastStateExists);
Assert.AreEqual(States.One, fsm.State);
Assert.AreEqual(States.Two, fsm.NextState);
// 1*__/4
fsm.ChangeState(States.Four, StateTransition.Overwrite);
Assert.AreEqual(States.One, fsm.LastState);
Assert.AreEqual(States.Four, fsm.State);
Assert.AreEqual(States.Four, fsm.NextState);
yield return new WaitForSeconds(duration + 0.2f);
Assert.AreEqual(1, behaviour.oneEnter);
Assert.AreEqual(0, behaviour.oneUpdate);
Assert.AreEqual(0, behaviour.oneExit); //Cancelled - never completed
Assert.AreEqual(1, behaviour.oneFinally);
Assert.AreEqual(0, behaviour.twoEnter); //Never entered
Assert.AreEqual(1, behaviour.fourEnter);
Assert.AreEqual(States.One, fsm.LastState);
Assert.AreEqual(States.Four, fsm.State);
Assert.AreEqual(States.Four, fsm.NextState);
}
private class StateClass : MonoBehaviour
{
public float duration;
public int oneEnter;
public int oneUpdate;
public int oneExit;
public int oneFinally;
public int twoEnter;
public int twoUpdate;
public int twoExit;
public int twoFinally;
public int threeEnter;
public int threeUpdate;
public int threeExit;
public int threeFinally;
public int fourEnter;
public int fourUpdate;
public int fourExit;
public int fourFinally;
void One_Enter()
{
Debug.LogFormat("State:{0} Frame:{1}", "One Enter", Time.frameCount);
oneEnter++;
}
void One_Update()
{
Debug.LogFormat("State:{0} Frame:{1}", "One Update", Time.frameCount);
oneUpdate++;
}
IEnumerator One_Exit()
{
Debug.LogFormat("State:{0} Frame:{1}", "One Exit Start", Time.frameCount);
yield return new WaitForSeconds(duration);
Debug.LogFormat("State:{0} Frame:{1}", "One Exit End", Time.frameCount);
oneExit++;
}
void One_Finally()
{
Debug.LogFormat("State:{0} Frame:{1}", "One Finally", Time.frameCount);
oneFinally++;
}
IEnumerator Two_Enter()
{
Debug.LogFormat("State:{0} Frame:{1}", "Two Enter Start", Time.frameCount);
yield return new WaitForSeconds(duration);
Debug.LogFormat("State:{0} Frame:{1}", "Two Enter End", Time.frameCount);
twoEnter++;
}
void Two_Update()
{
Debug.LogFormat("State:{0} Frame:{1}", "Two Update", Time.frameCount);
twoUpdate++;
}
void Two_Exit()
{
Debug.LogFormat("State:{0} Frame:{1}", "Two Exit", Time.frameCount);
twoExit++;
}
void Two_Finally()
{
Debug.LogFormat("State:{0} Frame:{1}", "Two Finally", Time.frameCount);
twoFinally++;
}
void Three_Enter()
{
Debug.LogFormat("State:{0} Frame:{1}", "Three Enter", Time.frameCount);
threeEnter++;
}
void Three_Update()
{
Debug.LogFormat("State:{0} Frame:{1}", "Three Update", Time.frameCount);
threeUpdate++;
}
void Three_Exit()
{
Debug.LogFormat("State:{0} Frame:{1}", "Three Exit", Time.frameCount);
threeExit++;
}
void Three_Finally()
{
Debug.LogFormat("State:{0} Frame:{1}", "Three Finally", Time.frameCount);
threeFinally++;
}
IEnumerator Four_Enter()
{
Debug.LogFormat("State:{0} Frame:{1}", "Four Enter Start", Time.frameCount);
yield return new WaitForSeconds(duration);
Debug.LogFormat("State:{0} Frame:{1}", "Four Enter End", Time.frameCount);
fourEnter++;
}
void Four_Update()
{
Debug.LogFormat("State:{0} Frame:{1}", "Four Update", Time.frameCount);
fourUpdate++;
}
void Four_Exit()
{
Debug.LogFormat("State:{0} Frame:{1}", "Four Exit", Time.frameCount);
fourExit++;
}
void Four_Finally()
{
Debug.LogFormat("State:{0} Frame:{1}", "Four Finally", Time.frameCount);
fourFinally++;
}
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 1a082dc9366ca784087bde0dde49a5ce
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,302 @@
using System.Collections;
using MonsterLove.StateMachine;
using NUnit.Framework;
using UnityEngine;
using UnityEngine.TestTools;
namespace Tests
{
public class TestChangeAsyncSafe
{
public enum States
{
One,
Two,
Three,
Four,
}
private GameObject go;
private StateClass behaviour;
private StateMachine<States> fsm;
private float duration = 0.5f;
[SetUp]
public void Init()
{
go = new GameObject();
behaviour = go.AddComponent<StateClass>();
behaviour.duration = duration;
fsm = StateMachine<States>.Initialize(behaviour);
}
[TearDown]
public void Kill()
{
Object.Destroy(go);
}
[UnityTest]
public IEnumerator TestAsyncEnterExit()
{
// 1
fsm.ChangeState(States.One, StateTransition.Safe);
Assert.AreEqual(1, behaviour.oneEnter);
Assert.AreEqual(0, behaviour.oneExit);
Assert.AreEqual(0, behaviour.twoEnter);
// 1\__/2
fsm.ChangeState(States.Two, StateTransition.Safe);
Assert.Catch(() => { var state = fsm.LastState;});
Assert.AreEqual(States.One, fsm.State);
Assert.AreEqual(States.Two, fsm.NextState);
Assert.AreEqual(1, behaviour.oneEnter);
Assert.AreEqual(0, behaviour.oneExit);
Assert.AreEqual(0, behaviour.twoEnter);
yield return new WaitForSeconds(duration + duration + 0.2f);
Assert.AreEqual(States.One, fsm.LastState);
Assert.AreEqual(States.Two, fsm.State);
Assert.AreEqual(States.Two, fsm.NextState);
Assert.AreEqual(1, behaviour.oneEnter);
Assert.AreEqual(1, behaviour.oneExit);
Assert.AreEqual(1, behaviour.twoEnter);
}
[UnityTest]
public IEnumerator TestChangeDuringAsyncEnter()
{
// 3
fsm.ChangeState(States.Three, StateTransition.Safe);
// 3__/2
fsm.ChangeState(States.Two);
Assert.AreEqual(1, behaviour.threeExit);
Assert.AreEqual(0, behaviour.twoEnter);
Assert.AreEqual(States.Three, fsm.LastState);
Assert.AreEqual(States.Two, fsm.State);
Assert.AreEqual(States.Two, fsm.NextState);
yield return new WaitForSeconds(duration / 2f);
// 3__/2\__4 //In safe mode, once a state is entered, both enter and exit are allowed to finish
fsm.ChangeState(States.Four);
Assert.AreEqual(1, behaviour.threeExit);
Assert.AreEqual(0, behaviour.twoEnter);
Assert.AreEqual(0, behaviour.twoUpdate);
Assert.AreEqual(0, behaviour.twoExit);
Assert.AreEqual(0, behaviour.twoFinally);
Assert.AreEqual(0, behaviour.fourEnter);
Assert.AreEqual(States.Three, fsm.LastState);
Assert.AreEqual(States.Two, fsm.State);
Assert.AreEqual(States.Four, fsm.NextState);
yield return new WaitForSeconds(duration / 2f + duration + 0.2f);
Assert.AreEqual(1, behaviour.threeExit);
Assert.AreEqual(1, behaviour.twoEnter);
Assert.AreEqual(1, behaviour.twoUpdate); //Single frame update while changing from Enter To Exit Routines. Not sure this is desired behaviour (zero update frames is more consistent), but don't want to cause a breaking change
Assert.AreEqual(1, behaviour.twoExit);
Assert.AreEqual(1, behaviour.twoFinally);
Assert.AreEqual(1, behaviour.fourEnter);
Assert.AreEqual(States.Two, fsm.LastState);
Assert.AreEqual(States.Four, fsm.State);
Assert.AreEqual(States.Four, fsm.NextState);
}
[UnityTest]
public IEnumerator TestChangeDuringAsyncExit()
{
// 1
fsm.ChangeState(States.One, StateTransition.Safe);
// 1\__3
fsm.ChangeState(States.Three, StateTransition.Safe);
yield return new WaitForSeconds(duration / 2f);
Assert.AreEqual(0, behaviour.oneExit);
Assert.AreEqual(0, behaviour.threeEnter);
Assert.AreEqual(0, behaviour.threeExit);
Assert.AreEqual(0, behaviour.fourEnter);
Assert.Catch(() => { var state = fsm.LastState;});
Assert.AreEqual(States.One, fsm.State);
Assert.AreEqual(States.Three, fsm.NextState);
// 1\__4 //In safe mode, before state is entered, newer state will supersede queued state
fsm.ChangeState(States.Four);
Assert.AreEqual(0, behaviour.oneExit);
Assert.AreEqual(0, behaviour.threeEnter);
Assert.AreEqual(0, behaviour.threeExit);
Assert.AreEqual(0, behaviour.fourEnter);
Assert.Catch(() => { var state = fsm.LastState;});
Assert.AreEqual(States.One, fsm.State);
Assert.AreEqual(States.Four, fsm.NextState);
yield return new WaitForSeconds(duration / 2f + 0.2f);
Assert.AreEqual(1, behaviour.oneExit);
Assert.AreEqual(0, behaviour.threeEnter); //Three never runs
Assert.AreEqual(0, behaviour.threeExit);
Assert.AreEqual(1, behaviour.fourEnter);
Assert.AreEqual(States.One, fsm.LastState);
Assert.AreEqual(States.Four, fsm.State);
Assert.AreEqual(States.Four, fsm.NextState);
}
private class StateClass : MonoBehaviour
{
public float duration;
public int oneEnter;
public int oneUpdate;
public int oneExit;
public int oneFinally;
public int twoEnter;
public int twoUpdate;
public int twoExit;
public int twoFinally;
public int threeEnter;
public int threeUpdate;
public int threeExit;
public int threeFinally;
public int fourEnter;
public int fourUpdate;
public int fourExit;
public int fourFinally;
void One_Enter()
{
Debug.LogFormat("State:{0} Frame:{1}", "One Enter", Time.frameCount);
oneEnter++;
}
void One_Update()
{
Debug.LogFormat("State:{0} Frame:{1}", "One Update", Time.frameCount);
oneUpdate++;
}
IEnumerator One_Exit()
{
Debug.LogFormat("State:{0} Frame:{1}", "One Exit Start", Time.frameCount);
yield return new WaitForSeconds(duration);
Debug.LogFormat("State:{0} Frame:{1}", "One Exit End", Time.frameCount);
oneExit++;
}
void One_Finally()
{
Debug.LogFormat("State:{0} Frame:{1}", "One Finally", Time.frameCount);
oneFinally++;
}
IEnumerator Two_Enter()
{
Debug.LogFormat("State:{0} Frame:{1}", "Two Enter Start", Time.frameCount);
yield return new WaitForSeconds(duration);
Debug.LogFormat("State:{0} Frame:{1}", "Two Enter End", Time.frameCount);
twoEnter++;
}
void Two_Update()
{
Debug.LogFormat("State:{0} Frame:{1}", "Two Update", Time.frameCount);
twoUpdate++;
}
IEnumerator Two_Exit()
{
Debug.LogFormat("State:{0} Frame:{1}", "Two Exit Start", Time.frameCount);
twoExit++;
yield return new WaitForSeconds(duration);
Debug.LogFormat("State:{0} Frame:{1}", "Two Exit End", Time.frameCount);
}
void Two_Finally()
{
Debug.LogFormat("State:{0} Frame:{1}", "Two Finally", Time.frameCount);
twoFinally++;
}
void Three_Enter()
{
Debug.LogFormat("State:{0} Frame:{1}", "Three Enter", Time.frameCount);
threeEnter++;
}
void Three_Update()
{
Debug.LogFormat("State:{0} Frame:{1}", "Three Update", Time.frameCount);
threeUpdate++;
}
void Three_Exit()
{
Debug.LogFormat("State:{0} Frame:{1}", "Three Exit", Time.frameCount);
threeExit++;
}
void Three_Finally()
{
Debug.LogFormat("State:{0} Frame:{1}", "Three Finally", Time.frameCount);
threeFinally++;
}
void Four_Enter()
{
Debug.LogFormat("State:{0} Frame:{1}", "Four Enter", Time.frameCount);
fourEnter++;
}
void Four_Update()
{
Debug.LogFormat("State:{0} Frame:{1}", "Four Update", Time.frameCount);
fourUpdate++;
}
void Four_Exit()
{
Debug.LogFormat("State:{0} Frame:{1}", "Four Exit", Time.frameCount);
fourExit++;
}
void Four_Finally()
{
Debug.LogFormat("State:{0} Frame:{1}", "Four Finally", Time.frameCount);
fourFinally++;
}
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 6ba617b22bb510241b31b54b32315873
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,220 @@
using System;
using System.Collections;
using MonsterLove.StateMachine;
using NUnit.Framework;
using UnityEngine;
using UnityEngine.Analytics;
using UnityEngine.TestTools;
using Object = UnityEngine.Object;
namespace Tests
{
// TEST DESCRIPTION
//
// Coverage for the scenario where state transition is aborted based on a flag evaluated within transition Enter and Exit methods
public class TestChangeFromTransition
{
public enum States
{
One,
Two,
Three,
Four,
}
private GameObject go;
private StateClass behaviour;
private StateMachine<States> fsm;
[SetUp]
public void Init()
{
go = new GameObject();
behaviour = go.AddComponent<StateClass>();
fsm = StateMachine<States>.Initialize(behaviour);
behaviour.fsm = fsm;
}
[TearDown]
public void Kill()
{
Object.Destroy(go);
}
[Test]
public void TestChangeFromExit()
{
//TODO stack overflow is not the expected behaviour - also seems to be periodically crashing test suite. Disable for now
// // 1
// fsm.ChangeState(States.One);
//
//
//
// // 1-__3 //One_Exit contains change to 3
// Assert.Throws<StackOverflowException>(
// ()=> fsm.ChangeState(States.Two)
// );
//
//
//
// // Assert.AreEqual(1, behaviour.oneEnter);
// // Assert.AreEqual(0, behaviour.oneUpdate);
// // Assert.AreEqual(1, behaviour.oneExit);
// // Assert.AreEqual(1, behaviour.oneFinally);
// //
// // Assert.AreEqual(0, behaviour.twoEnter);
// // Assert.AreEqual(0, behaviour.twoUpdate);
// // Assert.AreEqual(0, behaviour.twoFinally);
// //
// // Assert.AreEqual(1, behaviour.threeEnter);
}
[Test]
public void TestChangeFromEnter()
{
fsm.ChangeState(States.Two);
// -4__3 //Four_Enter contains change to 3
fsm.ChangeState(States.Four);
Assert.AreEqual(1, behaviour.fourEnter); //This will complete after Exit and Finally. Not sure how to make this subtle side effect more obvious
Assert.AreEqual(0, behaviour.fourUpdate);
Assert.AreEqual(1, behaviour.fourExit);
Assert.AreEqual(1, behaviour.fourFinally);
Assert.AreEqual(1, behaviour.threeEnter);
Assert.AreEqual(States.Four, fsm.LastState);
Assert.AreEqual(States.Three, fsm.State);
Assert.AreEqual(States.Three, fsm.NextState);
}
private class StateClass : MonoBehaviour
{
public StateMachine<States> fsm;
public int oneEnter;
public int oneUpdate;
public int oneExit;
public int oneFinally;
public int twoEnter;
public int twoUpdate;
public int twoExit;
public int twoFinally;
public int threeEnter;
public int threeUpdate;
public int threeExit;
public int threeFinally;
public int fourEnter;
public int fourUpdate;
public int fourExit;
public int fourFinally;
void One_Enter()
{
Debug.LogFormat("State:{0} Frame:{1}", "One Enter", Time.frameCount);
oneEnter++;
}
void One_Update()
{
Debug.LogFormat("State:{0} Frame:{1}", "One Update", Time.frameCount);
oneUpdate++;
}
void One_Exit()
{
fsm.ChangeState(States.Three);
Debug.LogFormat("State:{0} Frame:{1}", "One Exit", Time.frameCount);
oneExit++;
}
void One_Finally()
{
Debug.LogFormat("State:{0} Frame:{1}", "One Finally", Time.frameCount);
oneFinally++;
}
void Two_Enter()
{
Debug.LogFormat("State:{0} Frame:{1}", "Two Enter", Time.frameCount);
twoEnter++;
}
void Two_Update()
{
Debug.LogFormat("State:{0} Frame:{1}", "Two Update", Time.frameCount);
twoUpdate++;
}
void Two_Exit()
{
Debug.LogFormat("State:{0} Frame:{1}", "Two Exit", Time.frameCount);
twoExit++;
}
void Two_Finally()
{
Debug.LogFormat("State:{0} Frame:{1}", "Two Finally", Time.frameCount);
twoFinally++;
}
void Three_Enter()
{
Debug.LogFormat("State:{0} Frame:{1}", "Three Enter", Time.frameCount);
threeEnter++;
}
void Three_Update()
{
Debug.LogFormat("State:{0} Frame:{1}", "Three Update", Time.frameCount);
threeUpdate++;
}
void Three_Exit()
{
Debug.LogFormat("State:{0} Frame:{1}", "Three Exit", Time.frameCount);
threeExit++;
}
void Three_Finally()
{
Debug.LogFormat("State:{0} Frame:{1}", "Three Finally", Time.frameCount);
threeFinally++;
}
void Four_Enter()
{
fsm.ChangeState(States.Three);
Debug.LogFormat("State:{0} Frame:{1}", "Four Enter", Time.frameCount);
fourEnter++;
}
void Four_Update()
{
Debug.LogFormat("State:{0} Frame:{1}", "Four Update", Time.frameCount);
fourUpdate++;
}
void Four_Exit()
{
Debug.LogFormat("State:{0} Frame:{1}", "Four Exit", Time.frameCount);
fourExit++;
}
void Four_Finally()
{
Debug.LogFormat("State:{0} Frame:{1}", "Four Finally", Time.frameCount);
fourFinally++;
}
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: edc9ab4afa17406b8cdfe574960c6177
timeCreated: 1567694365

View File

@@ -0,0 +1,213 @@
using System.Collections;
using MonsterLove.StateMachine;
using NUnit.Framework;
using UnityEngine;
using UnityEngine.TestTools;
namespace Tests
{
public class TestChangeState
{
public enum States
{
One,
Two,
Three,
Four,
}
private GameObject go;
private StateClass behaviour;
private StateMachine<States> fsm;
[SetUp]
public void Init()
{
go = new GameObject();
behaviour = go.AddComponent<StateClass>();
fsm = StateMachine<States>.Initialize(behaviour);
}
[TearDown]
public void Kill()
{
Object.Destroy(go);
}
[UnityTest]
public IEnumerator TestChange()
{
fsm.ChangeState(States.One);
Assert.Catch(()=>
{
var last = fsm.LastState;
});
Assert.AreEqual(States.One, fsm.State);
Assert.AreEqual(States.One, fsm.NextState);
yield return null;
fsm.ChangeState(States.Two);
Assert.AreEqual(1, behaviour.oneEnter);
Assert.AreEqual(1, behaviour.oneUpdate);
Assert.AreEqual(1, behaviour.oneExit);
Assert.AreEqual(1, behaviour.oneFinally);
Assert.AreEqual(1, behaviour.twoEnter);
Assert.AreEqual(0, behaviour.twoUpdate); //Only changed this frame, hasn't had a chance to update yet
Assert.AreEqual(States.One, fsm.LastState);
Assert.AreEqual(States.Two, fsm.State);
Assert.AreEqual(States.Two, fsm.NextState);
yield return null;
Assert.AreEqual(1, behaviour.twoUpdate); //First update runs a frame later
}
[UnityTest]
public IEnumerator TestChangeSameFrame()
{
fsm.ChangeState(States.One);
fsm.ChangeState(States.Two);
Assert.AreEqual(1, behaviour.oneEnter);
Assert.AreEqual(0, behaviour.oneUpdate); //Update never has chance to fire during same frame change
Assert.AreEqual(1, behaviour.oneExit);
Assert.AreEqual(1, behaviour.oneFinally);
Assert.AreEqual(1, behaviour.twoEnter);
Assert.AreEqual(0, behaviour.twoUpdate);
Assert.AreEqual(States.One, fsm.LastState);
Assert.AreEqual(States.Two, fsm.State);
Assert.AreEqual(States.Two, fsm.NextState);
yield return null;
Assert.AreEqual(0, behaviour.oneUpdate);
Assert.AreEqual(1, behaviour.twoUpdate); //First frame runs in state two
}
private class StateClass : MonoBehaviour
{
public int oneEnter;
public int oneUpdate;
public int oneExit;
public int oneFinally;
public int twoEnter;
public int twoUpdate;
public int twoExit;
public int twoFinally;
public int threeEnter;
public int threeUpdate;
public int threeExit;
public int threeFinally;
public int fourEnter;
public int fourUpdate;
public int fourExit;
public int fourFinally;
void One_Enter()
{
Debug.LogFormat("State:{0} Frame:{1}", "One Enter", Time.frameCount);
oneEnter++;
}
void One_Update()
{
Debug.LogFormat("State:{0} Frame:{1}", "One Update", Time.frameCount);
oneUpdate++;
}
void One_Exit()
{
Debug.LogFormat("State:{0} Frame:{1}", "One Exit", Time.frameCount);
oneExit++;
}
void One_Finally()
{
Debug.LogFormat("State:{0} Frame:{1}", "One Finally", Time.frameCount);
oneFinally++;
}
void Two_Enter()
{
Debug.LogFormat("State:{0} Frame:{1}", "Two Enter", Time.frameCount);
twoEnter++;
}
void Two_Update()
{
Debug.LogFormat("State:{0} Frame:{1}", "Two Update", Time.frameCount);
twoUpdate++;
}
void Two_Exit()
{
Debug.LogFormat("State:{0} Frame:{1}", "Two Exit", Time.frameCount);
twoExit++;
}
void Two_Finally()
{
Debug.LogFormat("State:{0} Frame:{1}", "Two Finally", Time.frameCount);
twoFinally++;
}
void Three_Enter()
{
Debug.LogFormat("State:{0} Frame:{1}", "Three Enter", Time.frameCount);
threeEnter++;
}
void Three_Update()
{
Debug.LogFormat("State:{0} Frame:{1}", "Three Update", Time.frameCount);
threeUpdate++;
}
void Three_Exit()
{
Debug.LogFormat("State:{0} Frame:{1}", "Three Exit", Time.frameCount);
threeExit++;
}
void Three_Finally()
{
Debug.LogFormat("State:{0} Frame:{1}", "Three Finally", Time.frameCount);
threeFinally++;
}
void Four_Enter()
{
Debug.LogFormat("State:{0} Frame:{1}", "Four Enter", Time.frameCount);
fourEnter++;
}
void Four_Update()
{
Debug.LogFormat("State:{0} Frame:{1}", "Four Update", Time.frameCount);
fourUpdate++;
}
void Four_Exit()
{
Debug.LogFormat("State:{0} Frame:{1}", "Four Exit", Time.frameCount);
fourExit++;
}
void Four_Finally()
{
Debug.LogFormat("State:{0} Frame:{1}", "Four Finally", Time.frameCount);
fourFinally++;
}
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 4306d2f2aa71459c9ea87a83001fd117
timeCreated: 1567675903

View File

@@ -0,0 +1,100 @@
using System.Collections;
using MonsterLove.StateMachine;
using NUnit.Framework;
using UnityEngine;
using UnityEngine.TestTools;
namespace Tests
{
public class TestMonoBehaviourUpdates
{
public enum States
{
One,
Two,
Three,
Four,
}
private GameObject go;
private StateClass behaviour;
private StateMachine<States> fsm;
[SetUp]
public void Init()
{
go = new GameObject();
behaviour = go.AddComponent<StateClass>();
fsm = StateMachine<States>.Initialize(behaviour);
}
[TearDown]
public void Kill()
{
Object.Destroy(go);
}
[UnityTest]
public IEnumerator TestUpdate()
{
fsm.ChangeState(States.One);
yield return null;
Assert.AreEqual(1, behaviour.oneEnter);
Assert.AreEqual(1, behaviour.oneUpdate);
Assert.AreEqual(1, behaviour.oneLateUpdate);
yield return new WaitForSeconds(Time.fixedDeltaTime);
Assert.GreaterOrEqual(behaviour.oneFixedUpdate, 1);
}
private class StateClass : MonoBehaviour
{
public int oneEnter;
public int oneUpdate;
public int oneFixedUpdate;
public int oneLateUpdate;
public int oneExit;
public int oneFinally;
void One_Enter()
{
Debug.LogFormat("State:{0} Frame:{1}", "One Enter", Time.frameCount);
oneEnter++;
}
void One_FixedUpdate()
{
Debug.LogFormat("State:{0} Frame:{1}", "One FixedUpdate", Time.frameCount);
oneFixedUpdate++;
}
void One_Update()
{
Debug.LogFormat("State:{0} Frame:{1}", "One Update", Time.frameCount);
oneUpdate++;
}
void One_LateUpdate()
{
Debug.LogFormat("State:{0} Frame:{1}", "One Late Update", Time.frameCount);
oneLateUpdate++;
}
void One_Exit()
{
Debug.LogFormat("State:{0} Frame:{1}", "One Exit", Time.frameCount);
oneExit++;
}
void One_Finally()
{
Debug.LogFormat("State:{0} Frame:{1}", "One Finally", Time.frameCount);
oneFinally++;
}
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 87d1cfcf5f33f2441b2b848c6053dbcf
timeCreated: 1567675903