add PlayerLoopTiming.Last***

master
neuecc 2020-05-05 05:22:49 +09:00
parent 75f0bd26e7
commit 6e80295ec7
10 changed files with 598 additions and 119 deletions

View File

@ -169,21 +169,25 @@ Switch,
SaveSettings(settings); SaveSettings(settings);
} }
//[MenuItem("Test/Settings/BuildTarget/StandaloneLinux", validate = true, priority = 3)] #if !UNITY_2019_2_OR_NEWER
//static bool ValidateBuildTargetStandaloneLinux()
//{
// Menu.SetChecked("Test/Settings/BuildTarget/StandaloneLinux", LoadOrGetDefaultSettings().BuildTarget == BuildTarget.StandaloneLinux);
// return true;
//}
//[MenuItem("Test/Settings/BuildTarget/StandaloneLinux", validate = false, priority = 3)] [MenuItem("Test/Settings/BuildTarget/StandaloneLinux", validate = true, priority = 3)]
//static void BuildTargetStandaloneLinux() static bool ValidateBuildTargetStandaloneLinux()
//{ {
// var settings = LoadOrGetDefaultSettings(); Menu.SetChecked("Test/Settings/BuildTarget/StandaloneLinux", LoadOrGetDefaultSettings().BuildTarget == BuildTarget.StandaloneLinux);
// settings.UseCurrentBuildTarget = false; return true;
// settings.BuildTarget = BuildTarget.StandaloneLinux; }
// SaveSettings(settings);
//} [MenuItem("Test/Settings/BuildTarget/StandaloneLinux", validate = false, priority = 3)]
static void BuildTargetStandaloneLinux()
{
var settings = LoadOrGetDefaultSettings();
settings.UseCurrentBuildTarget = false;
settings.BuildTarget = BuildTarget.StandaloneLinux;
SaveSettings(settings);
}
#endif
[MenuItem("Test/Settings/BuildTarget/StandaloneLinux64", validate = true, priority = 4)] [MenuItem("Test/Settings/BuildTarget/StandaloneLinux64", validate = true, priority = 4)]
static bool ValidateBuildTargetStandaloneLinux64() static bool ValidateBuildTargetStandaloneLinux64()

View File

@ -1,4 +1,4 @@
#if UNITY_EDITOR #if UNITY_EDITOR
using RuntimeUnitTestToolkit; using RuntimeUnitTestToolkit;
using RuntimeUnitTestToolkit.Editor; using RuntimeUnitTestToolkit.Editor;
@ -118,7 +118,7 @@ public static partial class UnitTestBuilder
if (buildPath == null) if (buildPath == null)
{ {
buildPath = $"bin/UnitTest/{settings.BuildTarget}_{settings.ScriptBackend}/test" + (IsWindows(settings.BuildTarget) ? ".exe" : ""); buildPath = $"bin/UnitTest/{settings.BuildTarget}_{settings.ScriptBackend}/test" + GetExtensionForBuildTarget(settings.BuildTarget);
} }
var originalScene = SceneManager.GetActiveScene().path; var originalScene = SceneManager.GetActiveScene().path;
@ -136,6 +136,15 @@ public static partial class UnitTestBuilder
} }
} }
[MenuItem("Test/LoadUnitTestScene")]
public static void LoadUnitTestScene()
{
var scene = EditorSceneManager.NewScene(NewSceneSetup.EmptyScene, NewSceneMode.Single);
BuildUnitTestRunnerScene();
EditorSceneManager.MarkSceneDirty(scene);
}
static RuntimeUnitTestSettings LoadOrGetDefaultSettings() static RuntimeUnitTestSettings LoadOrGetDefaultSettings()
{ {
var key = SettingsKeyBase + Application.productName; var key = SettingsKeyBase + Application.productName;
@ -448,20 +457,42 @@ public static partial class UnitTestBuilder
} }
} }
static string GetExtensionForBuildTarget(BuildTarget buildTarget)
{
switch (buildTarget)
{
case BuildTarget.StandaloneWindows:
case BuildTarget.StandaloneWindows64:
case BuildTarget.WSAPlayer:
return ".exe";
case BuildTarget.StandaloneOSX:
return ".app";
case BuildTarget.Android:
return ".apk";
default:
return "";
}
}
static BuildTargetGroup ToBuildTargetGroup(BuildTarget buildTarget) static BuildTargetGroup ToBuildTargetGroup(BuildTarget buildTarget)
{ {
#pragma warning disable CS0618 #pragma warning disable CS0618
switch (buildTarget) switch (buildTarget)
{ {
#if UNITY_2017_3_OR_NEWER
case BuildTarget.StandaloneOSX: case BuildTarget.StandaloneOSX:
case (BuildTarget)3: #else
case BuildTarget.StandaloneOSXIntel: case BuildTarget.StandaloneOSXIntel:
case BuildTarget.StandaloneOSXIntel64: case BuildTarget.StandaloneOSXIntel64:
case BuildTarget.StandaloneOSXUniversal:
#endif // UNITY_2017_3_OR_NEWER
case BuildTarget.StandaloneWindows: case BuildTarget.StandaloneWindows:
case BuildTarget.StandaloneWindows64: case BuildTarget.StandaloneWindows64:
case BuildTarget.StandaloneLinux:
case BuildTarget.StandaloneLinux64: case BuildTarget.StandaloneLinux64:
#if !UNITY_2019_2_OR_NEWER
case BuildTarget.StandaloneLinux:
case BuildTarget.StandaloneLinuxUniversal: case BuildTarget.StandaloneLinuxUniversal:
#endif // !UNITY_2019_2_OR_NEWER
return BuildTargetGroup.Standalone; return BuildTargetGroup.Standalone;
case (BuildTarget)6: case (BuildTarget)6:
case (BuildTarget)7: case (BuildTarget)7:

View File

@ -14,7 +14,7 @@ namespace RuntimeUnitTestToolkit
public class UnitTestRunner : MonoBehaviour public class UnitTestRunner : MonoBehaviour
{ {
// object is IEnumerator or Func<IEnumerator> // object is IEnumerator or Func<IEnumerator>
Dictionary<string, List<KeyValuePair<string, object>>> tests = new Dictionary<string, List<KeyValuePair<string, object>>>(); Dictionary<string, List<TestKeyValuePair>> tests = new Dictionary<string, List<TestKeyValuePair>>();
List<Pair> additionalActionsOnFirst = new List<Pair>(); List<Pair> additionalActionsOnFirst = new List<Pair>();
@ -30,6 +30,7 @@ namespace RuntimeUnitTestToolkit
readonly Color normalColor = new Color(1f, 1f, 1f, 1f); // white readonly Color normalColor = new Color(1f, 1f, 1f, 1f); // white
bool allTestGreen = true; bool allTestGreen = true;
bool logClear = false;
void Start() void Start()
{ {
@ -37,7 +38,15 @@ namespace RuntimeUnitTestToolkit
{ {
UnityEngine.Application.logMessageReceived += (a, b, c) => UnityEngine.Application.logMessageReceived += (a, b, c) =>
{ {
logText.text += "[" + c + "]" + a + "\n"; if (a.Contains("Mesh can not have more than 65000 vertices"))
{
logClear = true;
}
else
{
AppendToGraphicText("[" + c + "]" + a + "\n");
WriteToConsole("[" + c + "]" + a);
}
}; };
// register all test types // register all test types
@ -133,13 +142,34 @@ namespace RuntimeUnitTestToolkit
{ {
foreach (var method in item.GetMethods()) foreach (var method in item.GetMethods())
{ {
var t1 = method.GetCustomAttribute<TestAttribute>(true); TestAttribute t1 = null;
try
{
t1 = method.GetCustomAttribute<TestAttribute>(true);
}
catch (Exception ex)
{
Debug.Log("TestAttribute Load Fail, Assembly:" + assembly.FullName);
Debug.LogException(ex);
goto NEXT_ASSEMBLY;
}
if (t1 != null) if (t1 != null)
{ {
yield return item; yield return item;
break; break;
} }
var t2 = method.GetCustomAttribute<UnityTestAttribute>(true);
UnityTestAttribute t2 = null;
try
{
t2 = method.GetCustomAttribute<UnityTestAttribute>(true);
}
catch (Exception ex)
{
Debug.Log("UnityTestAttribute Load Fail, Assembly:" + assembly.FullName);
Debug.LogException(ex);
goto NEXT_ASSEMBLY;
}
if (t2 != null) if (t2 != null)
{ {
yield return item; yield return item;
@ -147,31 +177,34 @@ namespace RuntimeUnitTestToolkit
} }
} }
} }
NEXT_ASSEMBLY:
continue;
} }
} }
public void AddTest(string group, string title, Action test) public void AddTest(string group, string title, Action test, List<Action> setups, List<Action> teardowns)
{ {
List<KeyValuePair<string, object>> list; List<TestKeyValuePair> list;
if (!tests.TryGetValue(group, out list)) if (!tests.TryGetValue(group, out list))
{ {
list = new List<KeyValuePair<string, object>>(); list = new List<TestKeyValuePair>();
tests[group] = list; tests[group] = list;
} }
list.Add(new KeyValuePair<string, object>(title, test)); list.Add(new TestKeyValuePair(title, test, setups, teardowns));
} }
public void AddAsyncTest(string group, string title, Func<IEnumerator> asyncTestCoroutine) public void AddAsyncTest(string group, string title, Func<IEnumerator> asyncTestCoroutine, List<Action> setups, List<Action> teardowns)
{ {
List<KeyValuePair<string, object>> list; List<TestKeyValuePair> list;
if (!tests.TryGetValue(group, out list)) if (!tests.TryGetValue(group, out list))
{ {
list = new List<KeyValuePair<string, object>>(); list = new List<TestKeyValuePair>();
tests[group] = list; tests[group] = list;
} }
list.Add(new KeyValuePair<string, object>(title, asyncTestCoroutine)); list.Add(new TestKeyValuePair(title, asyncTestCoroutine, setups, teardowns));
} }
public void AddCutomAction(string name, UnityAction action) public void AddCutomAction(string name, UnityAction action)
@ -193,6 +226,29 @@ namespace RuntimeUnitTestToolkit
var test = Activator.CreateInstance(testType); var test = Activator.CreateInstance(testType);
var methods = testType.GetMethods(System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.Public); var methods = testType.GetMethods(System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.Public);
List<Action> setups = new List<Action>();
List<Action> teardowns = new List<Action>();
foreach (var item in methods)
{
try
{
var setup = item.GetCustomAttribute<NUnit.Framework.SetUpAttribute>(true);
if (setup != null)
{
setups.Add((Action)Delegate.CreateDelegate(typeof(Action), test, item));
}
var teardown = item.GetCustomAttribute<NUnit.Framework.TearDownAttribute>(true);
if (teardown != null)
{
teardowns.Add((Action)Delegate.CreateDelegate(typeof(Action), test, item));
}
}
catch (Exception e)
{
UnityEngine.Debug.LogError(testType.Name + "." + item.Name + " failed to register setup/teardown method, exception: " + e.ToString());
}
}
foreach (var item in methods) foreach (var item in methods)
{ {
try try
@ -203,11 +259,34 @@ namespace RuntimeUnitTestToolkit
if (item.GetParameters().Length == 0 && item.ReturnType == typeof(IEnumerator)) if (item.GetParameters().Length == 0 && item.ReturnType == typeof(IEnumerator))
{ {
var factory = (Func<IEnumerator>)Delegate.CreateDelegate(typeof(Func<IEnumerator>), test, item); var factory = (Func<IEnumerator>)Delegate.CreateDelegate(typeof(Func<IEnumerator>), test, item);
AddAsyncTest(factory.Target.GetType().Name, factory.Method.Name, factory); AddAsyncTest(factory.Target.GetType().Name, factory.Method.Name, factory, setups, teardowns);
} }
else else
{ {
UnityEngine.Debug.Log(testType.Name + "." + item.Name + " currently does not supported in RuntumeUnitTestToolkit(multiple parameter or return type is invalid)."); var testData = GetTestData(item);
if (testData.Count != 0)
{
foreach (var item2 in testData)
{
Func<IEnumerator> factory;
if (item.IsGenericMethod)
{
var method2 = InferGenericType(item, item2);
factory = () => (IEnumerator)method2.Invoke(test, item2);
}
else
{
factory = () => (IEnumerator)item.Invoke(test, item2);
}
var name = item.Name + "(" + string.Join(", ", item2.Select(x => x?.ToString() ?? "null")) + ")";
name = name.Replace(Char.MinValue, ' ').Replace(Char.MaxValue, ' ').Replace("<", "[").Replace(">", "]");
AddAsyncTest(test.GetType().Name, name, factory, setups, teardowns);
}
}
else
{
UnityEngine.Debug.Log(testType.Name + "." + item.Name + " currently does not supported in RuntumeUnitTestToolkit(multiple parameter without TestCase or return type is invalid).");
}
} }
} }
@ -217,11 +296,34 @@ namespace RuntimeUnitTestToolkit
if (item.GetParameters().Length == 0 && item.ReturnType == typeof(void)) if (item.GetParameters().Length == 0 && item.ReturnType == typeof(void))
{ {
var invoke = (Action)Delegate.CreateDelegate(typeof(Action), test, item); var invoke = (Action)Delegate.CreateDelegate(typeof(Action), test, item);
AddTest(invoke.Target.GetType().Name, invoke.Method.Name, invoke); AddTest(invoke.Target.GetType().Name, invoke.Method.Name, invoke, setups, teardowns);
} }
else else
{ {
UnityEngine.Debug.Log(testType.Name + "." + item.Name + " currently does not supported in RuntumeUnitTestToolkit(multiple parameter or return type is invalid)."); var testData = GetTestData(item);
if (testData.Count != 0)
{
foreach (var item2 in testData)
{
Action invoke = null;
if (item.IsGenericMethod)
{
var method2 = InferGenericType(item, item2);
invoke = () => method2.Invoke(test, item2);
}
else
{
invoke = () => item.Invoke(test, item2);
}
var name = item.Name + "(" + string.Join(", ", item2.Select(x => x?.ToString() ?? "null")) + ")";
name = name.Replace(Char.MinValue, ' ').Replace(Char.MaxValue, ' ').Replace("<", "[").Replace(">", "]");
AddTest(test.GetType().Name, name, invoke, setups, teardowns);
}
}
else
{
UnityEngine.Debug.Log(testType.Name + "." + item.Name + " currently does not supported in RuntumeUnitTestToolkit(multiple parameter without TestCase or return type is invalid).");
}
} }
} }
} }
@ -237,6 +339,88 @@ namespace RuntimeUnitTestToolkit
} }
} }
List<object[]> GetTestData(MethodInfo methodInfo)
{
List<object[]> testCases = new List<object[]>();
var inlineData = methodInfo.GetCustomAttributes<NUnit.Framework.TestCaseAttribute>(true);
foreach (var item in inlineData)
{
testCases.Add(item.Arguments);
}
var sourceData = methodInfo.GetCustomAttributes<NUnit.Framework.TestCaseSourceAttribute>(true);
foreach (var item in sourceData)
{
var enumerator = GetTestCaseSource(methodInfo, item.SourceType, item.SourceName, item.MethodParams);
foreach (var item2 in enumerator)
{
var item3 = item2 as IEnumerable; // object[][]
if (item3 != null)
{
var l = new List<object>();
foreach (var item4 in item3)
{
l.Add(item4);
}
testCases.Add(l.ToArray());
}
}
}
return testCases;
}
IEnumerable GetTestCaseSource(MethodInfo method, Type sourceType, string sourceName, object[] methodParams)
{
Type type = sourceType ?? method.DeclaringType;
MemberInfo[] member = type.GetMember(sourceName, BindingFlags.FlattenHierarchy | BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static);
if (member.Length == 1)
{
MemberInfo memberInfo = member[0];
FieldInfo fieldInfo = memberInfo as FieldInfo;
if ((object)fieldInfo != null)
{
return (!fieldInfo.IsStatic) ? ReturnErrorAsParameter("The sourceName specified on a TestCaseSourceAttribute must refer to a static field, property or method.") : ((methodParams == null) ? ((IEnumerable)fieldInfo.GetValue(null)) : ReturnErrorAsParameter("You have specified a data source field but also given a set of parameters. Fields cannot take parameters, please revise the 3rd parameter passed to the TestCaseSourceAttribute and either remove it or specify a method."));
}
PropertyInfo propertyInfo = memberInfo as PropertyInfo;
if ((object)propertyInfo != null)
{
return (!propertyInfo.GetGetMethod(nonPublic: true).IsStatic) ? ReturnErrorAsParameter("The sourceName specified on a TestCaseSourceAttribute must refer to a static field, property or method.") : ((methodParams == null) ? ((IEnumerable)propertyInfo.GetValue(null, null)) : ReturnErrorAsParameter("You have specified a data source property but also given a set of parameters. Properties cannot take parameters, please revise the 3rd parameter passed to the TestCaseSource attribute and either remove it or specify a method."));
}
MethodInfo methodInfo = memberInfo as MethodInfo;
if ((object)methodInfo != null)
{
return (!methodInfo.IsStatic) ? ReturnErrorAsParameter("The sourceName specified on a TestCaseSourceAttribute must refer to a static field, property or method.") : ((methodParams == null || methodInfo.GetParameters().Length == methodParams.Length) ? ((IEnumerable)methodInfo.Invoke(null, methodParams)) : ReturnErrorAsParameter("You have given the wrong number of arguments to the method in the TestCaseSourceAttribute, please check the number of parameters passed in the object is correct in the 3rd parameter for the TestCaseSourceAttribute and this matches the number of parameters in the target method and try again."));
}
}
return null;
}
MethodInfo InferGenericType(MethodInfo methodInfo, object[] parameters)
{
var set = new HashSet<Type>();
List<Type> genericParameters = new List<Type>();
foreach (var item in methodInfo.GetParameters()
.Select((x, i) => new { x.ParameterType, i })
.Where(x => x.ParameterType.IsGenericParameter)
.OrderBy(x => x.ParameterType.GenericParameterPosition))
{
if (set.Add(item.ParameterType)) // DistinctBy
{
genericParameters.Add(parameters[item.i].GetType());
}
}
return methodInfo.MakeGenericMethod(genericParameters.ToArray());
}
IEnumerable ReturnErrorAsParameter(string name)
{
throw new Exception(name);
}
System.Collections.IEnumerator ScrollLogToEndNextFrame() System.Collections.IEnumerator ScrollLogToEndNextFrame()
{ {
yield return null; yield return null;
@ -244,7 +428,7 @@ namespace RuntimeUnitTestToolkit
logScrollBar.value = 0; logScrollBar.value = 0;
} }
IEnumerator RunTestInCoroutine(KeyValuePair<string, List<KeyValuePair<string, object>>> actionList) IEnumerator RunTestInCoroutine(KeyValuePair<string, List<TestKeyValuePair>> actionList)
{ {
Button self = null; Button self = null;
foreach (var btn in list.GetComponentsInChildren<Button>()) foreach (var btn in list.GetComponentsInChildren<Button>())
@ -259,77 +443,89 @@ namespace RuntimeUnitTestToolkit
var allGreen = true; var allGreen = true;
logText.text += "<color=yellow>" + actionList.Key + "</color>\n"; AppendToGraphicText("<color=yellow>" + actionList.Key + "</color>\n");
WriteToConsole("Begin Test Class: " + actionList.Key); WriteToConsole("Begin Test Class: " + actionList.Key);
yield return null; yield return null;
var totalExecutionTime = new List<double>(); var totalExecutionTime = new List<double>();
foreach (var item2 in actionList.Value) foreach (var item2 in actionList.Value)
{ {
// before start, cleanup // setup
GC.Collect(); try
GC.WaitForPendingFinalizers();
GC.Collect();
logText.text += "<color=teal>" + item2.Key + "</color>\n";
yield return null;
var v = item2.Value;
var methodStopwatch = System.Diagnostics.Stopwatch.StartNew();
Exception exception = null;
if (v is Action)
{ {
try foreach (var setup in item2.Setups)
{ {
((Action)v).Invoke(); setup();
} }
catch (Exception ex)
// before start, cleanup
GC.Collect();
GC.WaitForPendingFinalizers();
GC.Collect();
AppendToGraphicText("<color=teal>" + item2.Key + "</color>\n");
yield return null;
var v = item2.Value;
var methodStopwatch = System.Diagnostics.Stopwatch.StartNew();
Exception exception = null;
if (v is Action)
{ {
exception = ex; try
} {
} ((Action)v).Invoke();
else }
{ catch (Exception ex)
var coroutineFactory = (Func<IEnumerator>)v;
IEnumerator coroutine = null;
try
{
coroutine = coroutineFactory();
}
catch (Exception ex)
{
exception = ex;
}
if (exception == null)
{
yield return StartCoroutine(UnwrapEnumerator(coroutine, ex =>
{ {
exception = ex; exception = ex;
})); }
}
else
{
var coroutineFactory = (Func<IEnumerator>)v;
IEnumerator coroutine = null;
try
{
coroutine = coroutineFactory();
}
catch (Exception ex)
{
exception = ex;
}
if (exception == null)
{
yield return StartCoroutine(UnwrapEnumerator(coroutine, ex =>
{
exception = ex;
}));
}
}
methodStopwatch.Stop();
totalExecutionTime.Add(methodStopwatch.Elapsed.TotalMilliseconds);
if (exception == null)
{
AppendToGraphicText("OK, " + methodStopwatch.Elapsed.TotalMilliseconds.ToString("0.00") + "ms\n");
WriteToConsoleResult(item2.Key + ", " + methodStopwatch.Elapsed.TotalMilliseconds.ToString("0.00") + "ms", true);
}
else
{
AppendToGraphicText("<color=red>" + exception.ToString() + "</color>\n");
WriteToConsoleResult(item2.Key + ", " + exception.ToString(), false);
allGreen = false;
allTestGreen = false;
} }
} }
finally
methodStopwatch.Stop();
totalExecutionTime.Add(methodStopwatch.Elapsed.TotalMilliseconds);
if (exception == null)
{ {
logText.text += "OK, " + methodStopwatch.Elapsed.TotalMilliseconds.ToString("0.00") + "ms\n"; foreach (var teardown in item2.Teardowns)
WriteToConsoleResult(item2.Key + ", " + methodStopwatch.Elapsed.TotalMilliseconds.ToString("0.00") + "ms", true); {
} teardown();
else }
{
// found match line...
var line = string.Join("\n", exception.StackTrace.Split('\n').Where(x => x.Contains(actionList.Key) || x.Contains(item2.Key)).ToArray());
logText.text += "<color=red>" + exception.Message + "\n" + line + "</color>\n";
WriteToConsoleResult(item2.Key + ", " + exception.Message, false);
WriteToConsole(line);
allGreen = false;
allTestGreen = false;
} }
} }
logText.text += "[" + actionList.Key + "]" + totalExecutionTime.Sum().ToString("0.00") + "ms\n\n"; AppendToGraphicText("[" + actionList.Key + "]" + totalExecutionTime.Sum().ToString("0.00") + "ms\n\n");
foreach (var btn in list.GetComponentsInChildren<Button>()) btn.interactable = true; foreach (var btn in list.GetComponentsInChildren<Button>()) btn.interactable = true;
if (self != null) if (self != null)
{ {
@ -418,6 +614,27 @@ namespace RuntimeUnitTestToolkit
} }
} }
void AppendToGraphicText(string msg)
{
if (!Application.isBatchMode)
{
if (logClear)
{
logText.text = "";
logClear = false;
}
try
{
logText.text += msg;
}
catch
{
logClear = true;
}
}
}
static void WriteToConsoleResult(string msg, bool green) static void WriteToConsoleResult(string msg, bool green)
{ {
if (Application.isBatchMode) if (Application.isBatchMode)
@ -447,4 +664,21 @@ namespace RuntimeUnitTestToolkit
public UnityAction Action; public UnityAction Action;
} }
} }
public class TestKeyValuePair
{
public string Key;
/// <summary>IEnumerator or Func[IEnumerator]</summary>
public object Value;
public List<Action> Setups;
public List<Action> Teardowns;
public TestKeyValuePair(string key, object value, List<Action> setups, List<Action> teardowns)
{
this.Key = key;
this.Value = value;
this.Setups = setups;
this.Teardowns = teardowns;
}
}
} }

View File

@ -1,7 +1,7 @@
{ {
"name": "jp.cysharp.runtimeunittesttoolkit", "name": "com.cysharp.runtimeunittesttoolkit",
"displayName": "RuntimeUnitTestToolkit", "displayName": "RuntimeUnitTestToolkit",
"version": "2.0.0", "version": "2.3.0",
"unity": "2018.3", "unity": "2018.3",
"description": "CLI/GUI Frontend of Unity Test Runner to test on any platform.", "description": "CLI/GUI Frontend of Unity Test Runner to test on any platform.",
"keywords": ["test"], "keywords": ["test"],

View File

@ -22,6 +22,17 @@ public class SandboxMain : MonoBehaviour
void Start() void Start()
{ {
var playerLoop = UnityEngine.LowLevel.PlayerLoop.GetCurrentPlayerLoop();
ShowPlayerLoop.DumpPlayerLoop("Current", playerLoop);
//for (int i = 0; i < 14; i++)
//{
// TimingDump((PlayerLoopTiming)i).Forget();
//}
//StartCoroutine(CoroutineDump("yield WaitForEndOfFrame", new WaitForEndOfFrame()));
//StartCoroutine(CoroutineDump("yield WaitForFixedUpdate", new WaitForFixedUpdate()));
//StartCoroutine(CoroutineDump("yield null", null));
// ----- // -----
@ -45,6 +56,40 @@ public class SandboxMain : MonoBehaviour
}); });
} }
async UniTask TimingDump(PlayerLoopTiming timing)
{
while (true)
{
await UniTask.Yield(timing);
Debug.Log("PlayerLoopTiming." + timing);
}
}
IEnumerator CoroutineDump(string msg, YieldInstruction waitObj)
{
while (true)
{
yield return waitObj;
Debug.Log(msg);
}
}
//private void Update()
//{
// Debug.Log("Update");
//}
//private void LateUpdate()
//{
// Debug.Log("LateUpdate");
//}
//private void FixedUpdate()
//{
// Debug.Log("FixedUpdate");
//}
private void Application_logMessageReceived(string condition, string stackTrace, LogType type) private void Application_logMessageReceived(string condition, string stackTrace, LogType type)
{ {
text.text += "\n" + condition; text.text += "\n" + condition;
@ -79,9 +124,33 @@ public class SandboxMain : MonoBehaviour
} }
} }
/*
PlayerLoopTiming.Initialization
PlayerLoopTiming.LastInitialization
PlayerLoopTiming.EarlyUpdate
PlayerLoopTiming.LastEarlyUpdate
PlayerLoopTiming.PreUpdate
PlayerLoopTiming.LastPreUpdate
PlayerLoopTiming.Update
Update
yield null
yield WaitForSeconds
yield WWW
yield StartCoroutine
PlayerLoopTiming.LastUpdate
PlayerLoopTiming.PreLateUpdate
LateUpdate
PlayerLoopTiming.LastPreLateUpdate
PlayerLoopTiming.PostLateUpdate
PlayerLoopTiming.LastPostLateUpdate
yield WaitForEndOfFrame
// --- Physics Loop
PlayerLoopTiming.FixedUpdate
FixedUpdate
yield WaitForFixedUpdate
PlayerLoopTiming.LastFixedUpdate
*/
@ -114,13 +183,17 @@ public class SandboxMain : MonoBehaviour
public class ShowPlayerLoop public class ShowPlayerLoop
{ {
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)] [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.SubsystemRegistration)]
static void Init() static void Init()
{ {
var playerLoop = UnityEngine.LowLevel.PlayerLoop.GetDefaultPlayerLoop(); var playerLoop = UnityEngine.LowLevel.PlayerLoop.GetDefaultPlayerLoop();
DumpPlayerLoop("Default", playerLoop);
}
public static void DumpPlayerLoop(string which, UnityEngine.LowLevel.PlayerLoopSystem playerLoop)
{
var sb = new StringBuilder(); var sb = new StringBuilder();
sb.AppendLine("Default Playerloop List"); sb.AppendLine($"{which} PlayerLoop List");
foreach (var header in playerLoop.subSystemList) foreach (var header in playerLoop.subSystemList)
{ {
sb.AppendFormat("------{0}------", header.type.Name); sb.AppendFormat("------{0}------", header.type.Name);
@ -129,6 +202,11 @@ public class ShowPlayerLoop
{ {
sb.AppendFormat("{0}.{1}", header.type.Name, subSystem.type.Name); sb.AppendFormat("{0}.{1}", header.type.Name, subSystem.type.Name);
sb.AppendLine(); sb.AppendLine();
if (subSystem.subSystemList != null)
{
UnityEngine.Debug.LogWarning("More Subsystem:" + subSystem.subSystemList.Length);
}
} }
} }

View File

@ -29,6 +29,16 @@ namespace UniRx.Async
public struct UniTaskLoopRunnerPreLateUpdate { }; public struct UniTaskLoopRunnerPreLateUpdate { };
public struct UniTaskLoopRunnerPostLateUpdate { }; public struct UniTaskLoopRunnerPostLateUpdate { };
// Last
public struct UniTaskLoopRunnerLastInitialization { };
public struct UniTaskLoopRunnerLastEarlyUpdate { };
public struct UniTaskLoopRunnerLastFixedUpdate { };
public struct UniTaskLoopRunnerLastPreUpdate { };
public struct UniTaskLoopRunnerLastUpdate { };
public struct UniTaskLoopRunnerLastPreLateUpdate { };
public struct UniTaskLoopRunnerLastPostLateUpdate { };
// Yield // Yield
public struct UniTaskLoopRunnerYieldInitialization { }; public struct UniTaskLoopRunnerYieldInitialization { };
@ -38,17 +48,40 @@ namespace UniRx.Async
public struct UniTaskLoopRunnerYieldUpdate { }; public struct UniTaskLoopRunnerYieldUpdate { };
public struct UniTaskLoopRunnerYieldPreLateUpdate { }; public struct UniTaskLoopRunnerYieldPreLateUpdate { };
public struct UniTaskLoopRunnerYieldPostLateUpdate { }; public struct UniTaskLoopRunnerYieldPostLateUpdate { };
// Yield Last
public struct UniTaskLoopRunnerLastYieldInitialization { };
public struct UniTaskLoopRunnerLastYieldEarlyUpdate { };
public struct UniTaskLoopRunnerLastYieldFixedUpdate { };
public struct UniTaskLoopRunnerLastYieldPreUpdate { };
public struct UniTaskLoopRunnerLastYieldUpdate { };
public struct UniTaskLoopRunnerLastYieldPreLateUpdate { };
public struct UniTaskLoopRunnerLastYieldPostLateUpdate { };
} }
public enum PlayerLoopTiming public enum PlayerLoopTiming
{ {
Initialization = 0, Initialization = 0,
EarlyUpdate = 1, LastInitialization = 1,
FixedUpdate = 2,
PreUpdate = 3, EarlyUpdate = 2,
Update = 4, LastEarlyUpdate = 3,
PreLateUpdate = 5,
PostLateUpdate = 6 FixedUpdate = 4,
LastFixedUpdate = 5,
PreUpdate = 6,
LastPreUpdate = 7,
Update = 8,
LastUpdate = 9,
PreLateUpdate = 10,
LastPreLateUpdate = 11,
PostLateUpdate = 12,
LastPostLateUpdate = 13
} }
public interface IPlayerLoopItem public interface IPlayerLoopItem
@ -66,19 +99,36 @@ namespace UniRx.Async
static ContinuationQueue[] yielders; static ContinuationQueue[] yielders;
static PlayerLoopRunner[] runners; static PlayerLoopRunner[] runners;
static PlayerLoopSystem[] InsertRunner(PlayerLoopSystem loopSystem, Type loopRunnerYieldType, static PlayerLoopSystem[] InsertRunner(PlayerLoopSystem loopSystem,
ContinuationQueue cq, Type loopRunnerType, PlayerLoopRunner runner) Type loopRunnerYieldType, ContinuationQueue cq, Type lastLoopRunnerYieldType, ContinuationQueue lastCq,
Type loopRunnerType, PlayerLoopRunner runner, Type lastLoopRunnerType, PlayerLoopRunner lastRunner)
{ {
#if UNITY_EDITOR #if UNITY_EDITOR
EditorApplication.playModeStateChanged += (state) => EditorApplication.playModeStateChanged += (state) =>
{ {
if (state == PlayModeStateChange.EnteredEditMode || if (state == PlayModeStateChange.EnteredEditMode || state == PlayModeStateChange.EnteredPlayMode)
state == PlayModeStateChange.EnteredPlayMode) return; {
return;
}
if (runner != null) if (runner != null)
{
runner.Clear(); runner.Clear();
}
if (lastRunner != null)
{
lastRunner.Clear();
}
if (cq != null) if (cq != null)
{
cq.Clear(); cq.Clear();
}
if (lastCq != null)
{
lastCq.Clear();
}
}; };
#endif #endif
@ -88,18 +138,37 @@ namespace UniRx.Async
updateDelegate = cq.Run updateDelegate = cq.Run
}; };
var lastYieldLoop = new PlayerLoopSystem
{
type = lastLoopRunnerYieldType,
updateDelegate = lastCq.Run
};
var runnerLoop = new PlayerLoopSystem var runnerLoop = new PlayerLoopSystem
{ {
type = loopRunnerType, type = loopRunnerType,
updateDelegate = runner.Run updateDelegate = runner.Run
}; };
var source = loopSystem.subSystemList // Remove items from previous initializations. var lastRunnerLoop = new PlayerLoopSystem
.Where(ls => ls.type != loopRunnerYieldType && ls.type != loopRunnerType).ToArray(); {
var dest = new PlayerLoopSystem[source.Length + 2]; type = lastLoopRunnerType,
updateDelegate = lastRunner.Run
};
// Remove items from previous initializations.
var source = loopSystem.subSystemList
.Where(ls => ls.type != loopRunnerYieldType && ls.type != loopRunnerType && ls.type != lastLoopRunnerYieldType && ls.type != lastLoopRunnerType)
.ToArray();
var dest = new PlayerLoopSystem[source.Length + 4];
Array.Copy(source, 0, dest, 2, source.Length); Array.Copy(source, 0, dest, 2, source.Length);
dest[0] = yieldLoop; dest[0] = yieldLoop;
dest[1] = runnerLoop; dest[1] = runnerLoop;
dest[dest.Length - 2] = lastYieldLoop;
dest[dest.Length - 1] = lastRunnerLoop;
return dest; return dest;
} }
@ -142,7 +211,6 @@ namespace UniRx.Async
EditorApplication.update += ForceEditorPlayerLoopUpdate; EditorApplication.update += ForceEditorPlayerLoopUpdate;
} }
private static void ForceEditorPlayerLoopUpdate() private static void ForceEditorPlayerLoopUpdate()
{ {
if (EditorApplication.isPlayingOrWillChangePlaymode || EditorApplication.isCompiling || if (EditorApplication.isPlayingOrWillChangePlaymode || EditorApplication.isCompiling ||
@ -160,18 +228,46 @@ namespace UniRx.Async
public static void Initialize(ref PlayerLoopSystem playerLoop) public static void Initialize(ref PlayerLoopSystem playerLoop)
{ {
yielders = new ContinuationQueue[7]; yielders = new ContinuationQueue[14];
runners = new PlayerLoopRunner[7]; runners = new PlayerLoopRunner[14];
var copyList = playerLoop.subSystemList.ToArray(); var copyList = playerLoop.subSystemList.ToArray();
copyList[0].subSystemList = InsertRunner(copyList[0], typeof(UniTaskLoopRunners.UniTaskLoopRunnerYieldInitialization), yielders[0] = new ContinuationQueue(), typeof(UniTaskLoopRunners.UniTaskLoopRunnerInitialization), runners[0] = new PlayerLoopRunner()); // Initialization
copyList[1].subSystemList = InsertRunner(copyList[1], typeof(UniTaskLoopRunners.UniTaskLoopRunnerYieldEarlyUpdate), yielders[1] = new ContinuationQueue(), typeof(UniTaskLoopRunners.UniTaskLoopRunnerEarlyUpdate), runners[1] = new PlayerLoopRunner()); copyList[0].subSystemList = InsertRunner(copyList[0], typeof(UniTaskLoopRunners.UniTaskLoopRunnerYieldInitialization), yielders[0] = new ContinuationQueue(),
copyList[2].subSystemList = InsertRunner(copyList[2], typeof(UniTaskLoopRunners.UniTaskLoopRunnerYieldFixedUpdate), yielders[2] = new ContinuationQueue(), typeof(UniTaskLoopRunners.UniTaskLoopRunnerFixedUpdate), runners[2] = new PlayerLoopRunner()); typeof(UniTaskLoopRunners.UniTaskLoopRunnerLastYieldInitialization), yielders[1] = new ContinuationQueue(),
copyList[3].subSystemList = InsertRunner(copyList[3], typeof(UniTaskLoopRunners.UniTaskLoopRunnerYieldPreUpdate), yielders[3] = new ContinuationQueue(), typeof(UniTaskLoopRunners.UniTaskLoopRunnerPreUpdate), runners[3] = new PlayerLoopRunner()); typeof(UniTaskLoopRunners.UniTaskLoopRunnerInitialization), runners[1] = new PlayerLoopRunner(),
copyList[4].subSystemList = InsertRunner(copyList[4], typeof(UniTaskLoopRunners.UniTaskLoopRunnerYieldUpdate), yielders[4] = new ContinuationQueue(), typeof(UniTaskLoopRunners.UniTaskLoopRunnerUpdate), runners[4] = new PlayerLoopRunner()); typeof(UniTaskLoopRunners.UniTaskLoopRunnerLastInitialization), runners[1] = new PlayerLoopRunner());
copyList[5].subSystemList = InsertRunner(copyList[5], typeof(UniTaskLoopRunners.UniTaskLoopRunnerYieldPreLateUpdate), yielders[5] = new ContinuationQueue(), typeof(UniTaskLoopRunners.UniTaskLoopRunnerPreLateUpdate), runners[5] = new PlayerLoopRunner()); // EarlyUpdate
copyList[6].subSystemList = InsertRunner(copyList[6], typeof(UniTaskLoopRunners.UniTaskLoopRunnerYieldPostLateUpdate), yielders[6] = new ContinuationQueue(), typeof(UniTaskLoopRunners.UniTaskLoopRunnerPostLateUpdate), runners[6] = new PlayerLoopRunner()); copyList[1].subSystemList = InsertRunner(copyList[1], typeof(UniTaskLoopRunners.UniTaskLoopRunnerYieldEarlyUpdate), yielders[2] = new ContinuationQueue(),
typeof(UniTaskLoopRunners.UniTaskLoopRunnerLastYieldEarlyUpdate), yielders[3] = new ContinuationQueue(),
typeof(UniTaskLoopRunners.UniTaskLoopRunnerEarlyUpdate), runners[2] = new PlayerLoopRunner(),
typeof(UniTaskLoopRunners.UniTaskLoopRunnerLastEarlyUpdate), runners[3] = new PlayerLoopRunner());
// FixedUpdate
copyList[2].subSystemList = InsertRunner(copyList[2], typeof(UniTaskLoopRunners.UniTaskLoopRunnerYieldFixedUpdate), yielders[4] = new ContinuationQueue(),
typeof(UniTaskLoopRunners.UniTaskLoopRunnerLastYieldFixedUpdate), yielders[5] = new ContinuationQueue(),
typeof(UniTaskLoopRunners.UniTaskLoopRunnerFixedUpdate), runners[4] = new PlayerLoopRunner(),
typeof(UniTaskLoopRunners.UniTaskLoopRunnerLastFixedUpdate), runners[5] = new PlayerLoopRunner());
// PreUpdate
copyList[3].subSystemList = InsertRunner(copyList[3], typeof(UniTaskLoopRunners.UniTaskLoopRunnerYieldPreUpdate), yielders[6] = new ContinuationQueue(),
typeof(UniTaskLoopRunners.UniTaskLoopRunnerLastYieldPreUpdate), yielders[7] = new ContinuationQueue(),
typeof(UniTaskLoopRunners.UniTaskLoopRunnerPreUpdate), runners[6] = new PlayerLoopRunner(),
typeof(UniTaskLoopRunners.UniTaskLoopRunnerLastPreUpdate), runners[7] = new PlayerLoopRunner());
// Update
copyList[4].subSystemList = InsertRunner(copyList[4], typeof(UniTaskLoopRunners.UniTaskLoopRunnerYieldUpdate), yielders[8] = new ContinuationQueue(),
typeof(UniTaskLoopRunners.UniTaskLoopRunnerLastYieldUpdate), yielders[9] = new ContinuationQueue(),
typeof(UniTaskLoopRunners.UniTaskLoopRunnerUpdate), runners[8] = new PlayerLoopRunner(),
typeof(UniTaskLoopRunners.UniTaskLoopRunnerLastUpdate), runners[9] = new PlayerLoopRunner());
// PreLateUpdate
copyList[5].subSystemList = InsertRunner(copyList[5], typeof(UniTaskLoopRunners.UniTaskLoopRunnerYieldPreLateUpdate), yielders[10] = new ContinuationQueue(),
typeof(UniTaskLoopRunners.UniTaskLoopRunnerLastYieldPreLateUpdate), yielders[11] = new ContinuationQueue(),
typeof(UniTaskLoopRunners.UniTaskLoopRunnerPreLateUpdate), runners[10] = new PlayerLoopRunner(),
typeof(UniTaskLoopRunners.UniTaskLoopRunnerLastPreLateUpdate), runners[11] = new PlayerLoopRunner());
// PostLateUpdate
copyList[6].subSystemList = InsertRunner(copyList[6], typeof(UniTaskLoopRunners.UniTaskLoopRunnerYieldPostLateUpdate), yielders[12] = new ContinuationQueue(),
typeof(UniTaskLoopRunners.UniTaskLoopRunnerLastYieldPostLateUpdate), yielders[13] = new ContinuationQueue(),
typeof(UniTaskLoopRunners.UniTaskLoopRunnerPostLateUpdate), runners[12] = new PlayerLoopRunner(),
typeof(UniTaskLoopRunners.UniTaskLoopRunnerLastPostLateUpdate), runners[13] = new PlayerLoopRunner());
playerLoop.subSystemList = copyList; playerLoop.subSystemList = copyList;
PlayerLoop.SetPlayerLoop(playerLoop); PlayerLoop.SetPlayerLoop(playerLoop);

View File

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

View File

@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 3ca26d0cd9373354c8cd147490f32c8e
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

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

View File

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