Initial Commit

This commit is contained in:
Sebastian Cabrera 2021-08-02 05:44:37 -04:00
parent 53eb92e9af
commit 270ab7d11f
15341 changed files with 700234 additions and 0 deletions

View file

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 5d7f0d6acfced954682a89e7002c04d9
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,186 @@
using System;
using System.Collections.Generic;
using System.Linq;
using NUnit.Framework;
using NUnit.Framework.Interfaces;
using NUnit.Framework.Internal;
using UnityEditor.SceneManagement;
using UnityEngine;
using UnityEngine.TestTools.TestRunner;
namespace UnityEditor.TestTools.TestRunner
{
internal class EditModeRunnerCallback : ScriptableObject, ITestRunnerListener
{
private EditModeLauncherContextSettings m_Settings;
public SceneSetup[] previousSceneSetup;
public EditModeRunner runner;
private bool m_Canceled;
private ITest m_CurrentTest;
private int m_TotalTests;
[SerializeField]
private List<string> m_PendingTests;
[SerializeField]
private string m_LastCountedTestName;
[SerializeField]
private bool m_RunRestarted;
public void OnDestroy()
{
CleanUp();
}
public void RunStarted(ITest testsToRun)
{
Setup();
if (m_PendingTests == null)
{
m_PendingTests = GetTestsExpectedToRun(testsToRun, runner.GetFilter());
m_TotalTests = m_PendingTests.Count;
}
}
public void OnEnable()
{
if (m_RunRestarted)
{
Setup();
}
}
private void Setup()
{
m_Settings = new EditModeLauncherContextSettings();
Application.logMessageReceivedThreaded += LogReceived;
EditorApplication.playModeStateChanged += WaitForExitPlaymode;
EditorApplication.update += DisplayProgressBar;
AssemblyReloadEvents.beforeAssemblyReload += BeforeAssemblyReload;
}
private void BeforeAssemblyReload()
{
if (m_CurrentTest != null)
{
m_LastCountedTestName = m_CurrentTest.FullName;
m_RunRestarted = true;
}
}
private void DisplayProgressBar()
{
if (m_CurrentTest == null)
return;
if (!m_Canceled && EditorUtility.DisplayCancelableProgressBar("Test Runner", "Running test " + m_CurrentTest.Name, Math.Min(1.0f, (float)(m_TotalTests - m_PendingTests.Count) / m_TotalTests)))
{
EditorApplication.update -= DisplayProgressBar;
m_Canceled = true;
EditorUtility.ClearProgressBar();
runner.OnRunCancel();
}
}
private static void LogReceived(string message, string stacktrace, LogType type)
{
if (TestContext.Out != null)
TestContext.Out.WriteLine(message);
}
private static void WaitForExitPlaymode(PlayModeStateChange state)
{
if (state == PlayModeStateChange.EnteredEditMode)
{
EditorApplication.playModeStateChanged -= WaitForExitPlaymode;
//because logMessage is reset on Enter EditMode
//we remove and add the callback
//because Unity
Application.logMessageReceivedThreaded -= LogReceived;
Application.logMessageReceivedThreaded += LogReceived;
}
}
public void RunFinished(ITestResult result)
{
if (previousSceneSetup != null && previousSceneSetup.Length > 0)
{
try
{
EditorSceneManager.RestoreSceneManagerSetup(previousSceneSetup);
}
catch (ArgumentException e)
{
Debug.LogWarning(e.Message);
}
}
else
{
foreach (var obj in FindObjectsOfType<GameObject>())
{
if (obj != null && obj.transform.parent != null && (obj.transform.parent.hideFlags & HideFlags.DontSaveInEditor) == HideFlags.DontSaveInEditor && obj.transform.parent.gameObject != null)
{
DestroyImmediate(obj.transform.parent.gameObject);
}
}
EditorSceneManager.NewScene(NewSceneSetup.DefaultGameObjects, NewSceneMode.Single);
}
CleanUp();
}
private void CleanUp()
{
m_CurrentTest = null;
EditorUtility.ClearProgressBar();
if (m_Settings != null)
{
m_Settings.Dispose();
}
Application.logMessageReceivedThreaded -= LogReceived;
EditorApplication.update -= DisplayProgressBar;
}
public void TestStarted(ITest test)
{
if (test.IsSuite || !(test is TestMethod))
{
return;
}
m_CurrentTest = test;
if (m_RunRestarted)
{
if (test.FullName == m_LastCountedTestName)
m_RunRestarted = false;
}
}
public void TestFinished(ITestResult result)
{
if (result.Test is TestMethod)
{
m_PendingTests.Remove(result.Test.FullName);
}
}
private static List<string> GetTestsExpectedToRun(ITest test, ITestFilter filter)
{
var expectedTests = new List<string>();
if (filter.Pass(test))
{
if (test.IsSuite)
{
expectedTests.AddRange(test.Tests.SelectMany(subTest => GetTestsExpectedToRun(subTest, filter)));
}
else
{
expectedTests.Add(test.FullName);
}
}
return expectedTests;
}
}
}

View file

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

View file

@ -0,0 +1,86 @@
using UnityEditor.TestTools.TestRunner.Api;
using UnityEditor.TestTools.TestRunner.CommandLineTest;
using UnityEditor.TestTools.TestRunner.GUI;
using UnityEngine;
namespace UnityEditor.TestTools.TestRunner
{
internal class RerunCallback : ScriptableObject, ICallbacks
{
public static bool useMockRunFilter = false;
public static UITestRunnerFilter mockRunFilter = null;
public void RunFinished(ITestResultAdaptor result)
{
if (RerunCallbackData.instance.runFilters == null || RerunCallbackData.instance.runFilters.Length == 0)
RerunCallbackData.instance.runFilters = new[] {new UITestRunnerFilter()};
var runFilter = RerunCallbackData.instance.runFilters[0];
if (useMockRunFilter)
{
runFilter = mockRunFilter;
}
runFilter.testRepetitions--;
if (runFilter.testRepetitions <= 0 || result.TestStatus != TestStatus.Passed)
{
ExitCallbacks.preventExit = false;
return;
}
ExitCallbacks.preventExit = true;
if (EditorApplication.isPlaying)
{
EditorApplication.playModeStateChanged += WaitForExitPlaymode;
return;
}
if (!useMockRunFilter)
{
ExecuteTestRunnerAPI();
}
}
private static void WaitForExitPlaymode(PlayModeStateChange state)
{
if (state == PlayModeStateChange.EnteredEditMode)
{
ExecuteTestRunnerAPI();
}
}
private static void ExecuteTestRunnerAPI()
{
var runFilter = RerunCallbackData.instance.runFilters[0];
var testMode = RerunCallbackData.instance.testMode;
var testRunnerApi = ScriptableObject.CreateInstance<TestRunnerApi>();
testRunnerApi.Execute(new Api.ExecutionSettings()
{
filters = new[]
{
new Filter()
{
categoryNames = runFilter.categoryNames,
groupNames = runFilter.groupNames,
testMode = testMode,
testNames = runFilter.testNames
}
}
});
}
public void TestStarted(ITestAdaptor test)
{
}
public void TestFinished(ITestResultAdaptor result)
{
}
public void RunStarted(ITestAdaptor testsToRun)
{
}
}
}

View file

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

View file

@ -0,0 +1,15 @@
using UnityEditor.TestTools.TestRunner.Api;
using UnityEditor.TestTools.TestRunner.GUI;
using UnityEngine;
namespace UnityEditor.TestTools.TestRunner
{
internal class RerunCallbackData : ScriptableSingleton<RerunCallbackData>
{
[SerializeField]
internal UITestRunnerFilter[] runFilters;
[SerializeField]
internal TestMode testMode;
}
}

View file

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

View file

@ -0,0 +1,17 @@
using UnityEngine;
using UnityEditor.TestTools.TestRunner.Api;
namespace UnityEditor.TestTools.TestRunner
{
[InitializeOnLoad]
static class RerunCallbackInitializer
{
static RerunCallbackInitializer()
{
var testRunnerApi = ScriptableObject.CreateInstance<TestRunnerApi>();
var rerunCallback = ScriptableObject.CreateInstance<RerunCallback>();
testRunnerApi.RegisterCallbacks<RerunCallback>(rerunCallback);
}
}
}

View file

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

View file

@ -0,0 +1,37 @@
using NUnit.Framework.Interfaces;
using UnityEngine;
using UnityEngine.TestTools.TestRunner;
namespace UnityEditor.TestTools.TestRunner
{
internal class TestRunnerCallback : ScriptableObject, ITestRunnerListener
{
public void RunStarted(ITest testsToRun)
{
EditorApplication.playModeStateChanged += OnPlayModeStateChanged;
}
private void OnPlayModeStateChanged(PlayModeStateChange state)
{
if (state == PlayModeStateChange.ExitingPlayMode)
{
EditorApplication.playModeStateChanged -= OnPlayModeStateChanged;
//We need to make sure we don't block NUnit thread in case we exit PlayMode earlier
PlaymodeTestsController.TryCleanup();
}
}
public void RunFinished(ITestResult testResults)
{
EditorApplication.isPlaying = false;
}
public void TestStarted(ITest testName)
{
}
public void TestFinished(ITestResult test)
{
}
}
}

View file

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

View file

@ -0,0 +1,59 @@
using System.Linq;
using TestRunner.Callbacks;
using UnityEditor.TestTools.TestRunner.Api;
namespace UnityEditor.TestTools.TestRunner.GUI
{
internal class WindowResultUpdater : ICallbacks, ITestTreeRebuildCallbacks
{
public WindowResultUpdater()
{
var cachedResults = WindowResultUpdaterDataHolder.instance.CachedResults;
var testList = TestRunnerWindow.s_Instance.m_SelectedTestTypes;
foreach (var result in cachedResults)
{
testList.UpdateResult(result);
}
cachedResults.Clear();
}
public void RunStarted(ITestAdaptor testsToRun)
{
}
public void RunFinished(ITestResultAdaptor testResults)
{
if (TestRunnerWindow.s_Instance != null)
{
TestRunnerWindow.s_Instance.RebuildUIFilter();
}
}
public void TestStarted(ITestAdaptor testName)
{
}
public void TestFinished(ITestResultAdaptor test)
{
var result = new TestRunnerResult(test);
if (TestRunnerWindow.s_Instance == null)
{
WindowResultUpdaterDataHolder.instance.CachedResults.Add(result);
return;
}
TestRunnerWindow.s_Instance.m_SelectedTestTypes.UpdateResult(result);
}
public void TestTreeRebuild(ITestAdaptor test)
{
if (TestRunnerWindow.s_Instance == null)
{
return;
}
TestRunnerWindow.s_Instance.m_SelectedTestTypes.UpdateTestTree(test);
}
}
}

View file

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

View file

@ -0,0 +1,11 @@
using System.Collections.Generic;
using UnityEditor;
using UnityEditor.TestTools.TestRunner.GUI;
namespace TestRunner.Callbacks
{
internal class WindowResultUpdaterDataHolder : ScriptableSingleton<WindowResultUpdaterDataHolder>
{
public List<TestRunnerResult> CachedResults = new List<TestRunnerResult>();
}
}

View file

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

View file

@ -0,0 +1,32 @@
using System.Collections;
using System.Reflection;
using UnityEngine.TestTools;
namespace UnityEditor.TestTools.TestRunner
{
internal class EditModePcHelper : TestCommandPcHelper
{
public override void SetEnumeratorPC(IEnumerator enumerator, int pc)
{
GetPCFieldInfo(enumerator).SetValue(enumerator, pc);
}
public override int GetEnumeratorPC(IEnumerator enumerator)
{
if (enumerator == null)
{
return 0;
}
return (int)GetPCFieldInfo(enumerator).GetValue(enumerator);
}
private FieldInfo GetPCFieldInfo(IEnumerator enumerator)
{
var field = enumerator.GetType().GetField("$PC", BindingFlags.NonPublic | BindingFlags.Instance);
if (field == null) // Roslyn
field = enumerator.GetType().GetField("<>1__state", BindingFlags.NonPublic | BindingFlags.Instance);
return field;
}
}
}

View file

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

View file

@ -0,0 +1,447 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using NUnit.Framework.Interfaces;
using NUnit.Framework.Internal;
using NUnit.Framework.Internal.Filters;
using UnityEngine;
using UnityEngine.TestTools.NUnitExtensions;
using UnityEngine.TestTools.TestRunner;
using UnityEngine.TestTools;
using UnityEngine.TestTools.TestRunner.GUI;
using UnityEditor.Callbacks;
using UnityEditor.TestTools.TestRunner.Api;
using UnityEngine.TestRunner.NUnitExtensions;
using UnityEngine.TestRunner.NUnitExtensions.Runner;
namespace UnityEditor.TestTools.TestRunner
{
internal interface IUnityTestAssemblyRunnerFactory
{
IUnityTestAssemblyRunner Create(TestPlatform testPlatform, WorkItemFactory factory);
}
internal class UnityTestAssemblyRunnerFactory : IUnityTestAssemblyRunnerFactory
{
public IUnityTestAssemblyRunner Create(TestPlatform testPlatform, WorkItemFactory factory)
{
return new UnityTestAssemblyRunner(new UnityTestAssemblyBuilder(), factory);
}
}
[Serializable]
internal class EditModeRunner : ScriptableObject, IDisposable
{
[SerializeField]
private Filter[] m_Filters;
//The counter from the IEnumerator object
[SerializeField]
private int m_CurrentPC;
[SerializeField]
private bool m_ExecuteOnEnable;
[SerializeField]
private List<string> m_AlreadyStartedTests;
[SerializeField]
private List<TestResultSerializer> m_ExecutedTests;
[SerializeField]
private List<ScriptableObject> m_CallbackObjects = new List<ScriptableObject>();
[SerializeField]
private TestStartedEvent m_TestStartedEvent = new TestStartedEvent();
[SerializeField]
private TestFinishedEvent m_TestFinishedEvent = new TestFinishedEvent();
[SerializeField]
private RunStartedEvent m_RunStartedEvent = new RunStartedEvent();
[SerializeField]
private RunFinishedEvent m_RunFinishedEvent = new RunFinishedEvent();
[SerializeField]
private TestRunnerStateSerializer m_TestRunnerStateSerializer = new TestRunnerStateSerializer();
[SerializeField]
private bool m_RunningTests;
[SerializeField]
private TestPlatform m_TestPlatform;
[SerializeField]
private object m_CurrentYieldObject;
[SerializeField]
private BeforeAfterTestCommandState m_SetUpTearDownState;
[SerializeField]
private BeforeAfterTestCommandState m_OuterUnityTestActionState;
[SerializeField]
private EnumerableTestState m_EnumerableTestState;
[SerializeField]
public bool RunFinished = false;
public bool RunningSynchronously { get; private set; }
internal IUnityTestAssemblyRunner m_Runner;
private ConstructDelegator m_ConstructDelegator;
private IEnumerator m_RunStep;
public IUnityTestAssemblyRunnerFactory UnityTestAssemblyRunnerFactory { get; set; }
public void Init(Filter[] filters, TestPlatform platform, bool runningSynchronously)
{
m_Filters = filters;
m_TestPlatform = platform;
m_AlreadyStartedTests = new List<string>();
m_ExecutedTests = new List<TestResultSerializer>();
RunningSynchronously = runningSynchronously;
InitRunner();
}
private void InitRunner()
{
//We give the EditMode platform here so we dont suddenly create Playmode work items in the test Runner.
m_Runner = (UnityTestAssemblyRunnerFactory ?? new UnityTestAssemblyRunnerFactory()).Create(TestPlatform.EditMode, new EditmodeWorkItemFactory());
var testAssemblyProvider = new EditorLoadedTestAssemblyProvider(new EditorCompilationInterfaceProxy(), new EditorAssembliesProxy());
var assemblies = testAssemblyProvider.GetAssembliesGroupedByType(m_TestPlatform).Select(x => x.Assembly).ToArray();
var loadedTests = m_Runner.Load(assemblies, TestPlatform.EditMode,
UnityTestAssemblyBuilder.GetNUnitTestBuilderSettings(m_TestPlatform));
loadedTests.ParseForNameDuplicates();
CallbacksDelegator.instance.TestTreeRebuild(loadedTests);
hideFlags |= HideFlags.DontSave;
EnumerableSetUpTearDownCommand.ActivePcHelper = new EditModePcHelper();
OuterUnityTestActionCommand.ActivePcHelper = new EditModePcHelper();
}
public void OnEnable()
{
if (m_ExecuteOnEnable)
{
InitRunner();
m_ExecuteOnEnable = false;
foreach (var callback in m_CallbackObjects)
{
AddListeners(callback as ITestRunnerListener);
}
m_ConstructDelegator = new ConstructDelegator(m_TestRunnerStateSerializer);
EnumeratorStepHelper.SetEnumeratorPC(m_CurrentPC);
UnityWorkItemDataHolder.alreadyExecutedTests = m_ExecutedTests.Select(x => x.uniqueName).ToList();
UnityWorkItemDataHolder.alreadyStartedTests = m_AlreadyStartedTests;
Run();
}
}
public void TestStartedEvent(ITest test)
{
m_AlreadyStartedTests.Add(test.GetUniqueName());
}
public void TestFinishedEvent(ITestResult testResult)
{
m_AlreadyStartedTests.Remove(testResult.Test.GetUniqueName());
m_ExecutedTests.Add(TestResultSerializer.MakeFromTestResult(testResult));
}
public void Run()
{
EditModeTestCallbacks.RestoringTestContext += OnRestoringTest;
var context = m_Runner.GetCurrentContext();
if (m_SetUpTearDownState == null)
{
m_SetUpTearDownState = CreateInstance<BeforeAfterTestCommandState>();
}
context.SetUpTearDownState = m_SetUpTearDownState;
if (m_OuterUnityTestActionState == null)
{
m_OuterUnityTestActionState = CreateInstance<BeforeAfterTestCommandState>();
}
context.OuterUnityTestActionState = m_OuterUnityTestActionState;
if (m_EnumerableTestState == null)
{
m_EnumerableTestState = CreateInstance<EnumerableTestState>();
}
context.EnumerableTestState = m_EnumerableTestState;
if (!m_RunningTests)
{
m_RunStartedEvent.Invoke(m_Runner.LoadedTest);
}
if (m_ConstructDelegator == null)
m_ConstructDelegator = new ConstructDelegator(m_TestRunnerStateSerializer);
Reflect.ConstructorCallWrapper = m_ConstructDelegator.Delegate;
m_TestStartedEvent.AddListener(TestStartedEvent);
m_TestFinishedEvent.AddListener(TestFinishedEvent);
AssemblyReloadEvents.beforeAssemblyReload += OnBeforeAssemblyReload;
RunningTests = true;
EditorApplication.LockReloadAssemblies();
var testListenerWrapper = new TestListenerWrapper(m_TestStartedEvent, m_TestFinishedEvent);
m_RunStep = m_Runner.Run(testListenerWrapper, GetFilter()).GetEnumerator();
m_RunningTests = true;
if (!RunningSynchronously)
EditorApplication.update += TestConsumer;
}
public void CompleteSynchronously()
{
while (!m_Runner.IsTestComplete)
TestConsumer();
}
private void OnBeforeAssemblyReload()
{
EditorApplication.update -= TestConsumer;
if (m_ExecuteOnEnable)
{
AssemblyReloadEvents.beforeAssemblyReload -= OnBeforeAssemblyReload;
return;
}
if (m_Runner != null && m_Runner.TopLevelWorkItem != null)
m_Runner.TopLevelWorkItem.ResultedInDomainReload = true;
if (RunningTests)
{
Debug.LogError("TestRunner: Unexpected assembly reload happened while running tests");
EditorUtility.ClearProgressBar();
if (m_Runner.GetCurrentContext() != null && m_Runner.GetCurrentContext().CurrentResult != null)
{
m_Runner.GetCurrentContext().CurrentResult.SetResult(ResultState.Cancelled, "Unexpected assembly reload happened");
}
OnRunCancel();
}
}
private bool RunningTests;
private Stack<IEnumerator> StepStack = new Stack<IEnumerator>();
private bool MoveNextAndUpdateYieldObject()
{
var result = m_RunStep.MoveNext();
if (result)
{
m_CurrentYieldObject = m_RunStep.Current;
while (m_CurrentYieldObject is IEnumerator) // going deeper
{
var currentEnumerator = (IEnumerator)m_CurrentYieldObject;
// go deeper and add parent to stack
StepStack.Push(m_RunStep);
m_RunStep = currentEnumerator;
m_CurrentYieldObject = m_RunStep.Current;
}
if (StepStack.Count > 0 && m_CurrentYieldObject != null) // not null and not IEnumerator, nested
{
Debug.LogError("EditMode test can only yield null, but not <" + m_CurrentYieldObject.GetType().Name + ">");
}
return true;
}
if (StepStack.Count == 0) // done
return false;
m_RunStep = StepStack.Pop(); // going up
return MoveNextAndUpdateYieldObject();
}
private void TestConsumer()
{
var moveNext = MoveNextAndUpdateYieldObject();
if (m_CurrentYieldObject != null)
{
InvokeDelegator();
}
if (!moveNext && !m_Runner.IsTestComplete)
{
CompleteTestRun();
throw new IndexOutOfRangeException("There are no more elements to process and IsTestComplete is false");
}
if (m_Runner.IsTestComplete)
{
CompleteTestRun();
}
}
private void CompleteTestRun()
{
if (!RunningSynchronously)
EditorApplication.update -= TestConsumer;
TestLauncherBase.ExecutePostBuildCleanupMethods(this.GetLoadedTests(), this.GetFilter(), Application.platform);
m_RunFinishedEvent.Invoke(m_Runner.Result);
RunFinished = true;
if (m_ConstructDelegator != null)
m_ConstructDelegator.DestroyCurrentTestObjectIfExists();
Dispose();
UnityWorkItemDataHolder.alreadyExecutedTests = null;
}
private void OnRestoringTest()
{
var item = m_ExecutedTests.Find(t => t.fullName == UnityTestExecutionContext.CurrentContext.CurrentTest.FullName);
if (item != null)
{
item.RestoreTestResult(UnityTestExecutionContext.CurrentContext.CurrentResult);
}
}
private static bool IsCancelled()
{
return UnityTestExecutionContext.CurrentContext.ExecutionStatus == TestExecutionStatus.AbortRequested || UnityTestExecutionContext.CurrentContext.ExecutionStatus == TestExecutionStatus.StopRequested;
}
private void InvokeDelegator()
{
if (m_CurrentYieldObject == null)
{
return;
}
if (IsCancelled())
{
return;
}
if (m_CurrentYieldObject is RestoreTestContextAfterDomainReload)
{
if (m_TestRunnerStateSerializer.ShouldRestore())
{
m_TestRunnerStateSerializer.RestoreContext();
}
return;
}
try
{
if (m_CurrentYieldObject is IEditModeTestYieldInstruction)
{
var editModeTestYieldInstruction = (IEditModeTestYieldInstruction)m_CurrentYieldObject;
if (editModeTestYieldInstruction.ExpectDomainReload)
{
PrepareForDomainReload();
}
return;
}
}
catch (Exception e)
{
UnityTestExecutionContext.CurrentContext.CurrentResult.RecordException(e);
return;
}
Debug.LogError("EditMode test can only yield null");
}
private void CompilationFailureWatch()
{
if (EditorApplication.isCompiling)
return;
EditorApplication.update -= CompilationFailureWatch;
if (EditorUtility.scriptCompilationFailed)
{
EditorUtility.ClearProgressBar();
OnRunCancel();
}
}
private void PrepareForDomainReload()
{
m_TestRunnerStateSerializer.SaveContext();
m_CurrentPC = EnumeratorStepHelper.GetEnumeratorPC(TestEnumerator.Enumerator);
m_ExecuteOnEnable = true;
RunningTests = false;
}
public T AddEventHandler<T>() where T : ScriptableObject, ITestRunnerListener
{
var eventHandler = CreateInstance<T>();
eventHandler.hideFlags |= HideFlags.DontSave;
m_CallbackObjects.Add(eventHandler);
AddListeners(eventHandler);
return eventHandler;
}
private void AddListeners(ITestRunnerListener eventHandler)
{
m_TestStartedEvent.AddListener(eventHandler.TestStarted);
m_TestFinishedEvent.AddListener(eventHandler.TestFinished);
m_RunStartedEvent.AddListener(eventHandler.RunStarted);
m_RunFinishedEvent.AddListener(eventHandler.RunFinished);
}
public void Dispose()
{
Reflect.MethodCallWrapper = null;
EditorApplication.update -= TestConsumer;
DestroyImmediate(this);
if (m_CallbackObjects != null)
{
foreach (var obj in m_CallbackObjects)
{
DestroyImmediate(obj);
}
m_CallbackObjects.Clear();
}
RunningTests = false;
EditorApplication.UnlockReloadAssemblies();
}
public void OnRunCancel()
{
UnityWorkItemDataHolder.alreadyExecutedTests = null;
m_ExecuteOnEnable = false;
m_Runner.StopRun();
RunFinished = true;
}
public ITest GetLoadedTests()
{
return m_Runner.LoadedTest;
}
public ITestFilter GetFilter()
{
return new OrFilter(m_Filters.Select(filter => filter.ToRuntimeTestRunnerFilter(RunningSynchronously).BuildNUnitFilter()).ToArray());
}
}
}

View file

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

View file

@ -0,0 +1,14 @@
using NUnit.Framework.Interfaces;
using NUnit.Framework.Internal;
using UnityEngine.TestRunner.NUnitExtensions.Runner;
namespace UnityEditor.TestTools.TestRunner
{
internal class EditmodeWorkItemFactory : WorkItemFactory
{
protected override UnityWorkItem Create(TestMethod method, ITestFilter filter, ITest loadedTest)
{
return new EditorEnumeratorTestWorkItem(method, filter);
}
}
}

View file

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

View file

@ -0,0 +1,181 @@
using System;
using System.Collections;
using NUnit.Framework.Interfaces;
using NUnit.Framework.Internal;
using NUnit.Framework.Internal.Commands;
using NUnit.Framework.Internal.Execution;
using UnityEngine;
using UnityEngine.TestRunner.NUnitExtensions.Runner;
using UnityEngine.TestTools;
namespace UnityEditor.TestTools.TestRunner
{
internal class EditorEnumeratorTestWorkItem : UnityWorkItem
{
private TestCommand m_Command;
public EditorEnumeratorTestWorkItem(TestMethod test, ITestFilter filter)
: base(test, null)
{
m_Command = TestCommandBuilder.BuildTestCommand(test, filter);
}
private static IEnumerableTestMethodCommand FindFirstIEnumerableTestMethodCommand(TestCommand command)
{
if (command == null)
{
return null;
}
if (command is IEnumerableTestMethodCommand)
{
return (IEnumerableTestMethodCommand)command;
}
if (command is DelegatingTestCommand)
{
var delegatingTestCommand = (DelegatingTestCommand)command;
return FindFirstIEnumerableTestMethodCommand(delegatingTestCommand.GetInnerCommand());
}
return null;
}
protected override IEnumerable PerformWork()
{
if (IsCancelledRun())
{
yield break;
}
if (m_DontRunRestoringResult)
{
if (EditModeTestCallbacks.RestoringTestContext == null)
{
throw new NullReferenceException("RestoringTestContext is not set");
}
EditModeTestCallbacks.RestoringTestContext();
Result = Context.CurrentResult;
yield break;
}
try
{
if (IsCancelledRun())
{
yield break;
}
if (m_Command is SkipCommand)
{
m_Command.Execute(Context);
Result = Context.CurrentResult;
yield break;
}
//Check if we can execute this test
var firstEnumerableCommand = FindFirstIEnumerableTestMethodCommand(m_Command);
if (firstEnumerableCommand == null)
{
Context.CurrentResult.SetResult(ResultState.Error, "Returning IEnumerator but not using test attribute supporting this");
yield break;
}
if (Context.TestCaseTimeout == 0)
{
Context.TestCaseTimeout = k_DefaultTimeout;
}
if (m_Command.Test.Method.ReturnType.IsType(typeof(IEnumerator)))
{
if (m_Command is ApplyChangesToContextCommand)
{
var applyChangesToContextCommand = ((ApplyChangesToContextCommand)m_Command);
applyChangesToContextCommand.ApplyChanges(Context);
m_Command = applyChangesToContextCommand.GetInnerCommand();
}
var innerCommand = m_Command as IEnumerableTestMethodCommand;
if (innerCommand == null)
{
Debug.Log("failed getting innerCommand");
throw new Exception("Tests returning IEnumerator can only use test attributes handling those");
}
foreach (var workItemStep in innerCommand.ExecuteEnumerable(Context))
{
if (IsCancelledRun())
{
yield break;
}
if (workItemStep is TestEnumerator)
{
if (EnumeratorStepHelper.UpdateEnumeratorPcIfNeeded(TestEnumerator.Enumerator))
{
yield return new RestoreTestContextAfterDomainReload();
}
continue;
}
if (workItemStep is AsyncOperation)
{
var asyncOperation = (AsyncOperation)workItemStep;
while (!asyncOperation.isDone)
{
if (IsCancelledRun())
{
yield break;
}
yield return null;
}
continue;
}
ResultedInDomainReload = false;
if (workItemStep is IEditModeTestYieldInstruction)
{
var editModeTestYieldInstruction = (IEditModeTestYieldInstruction)workItemStep;
yield return editModeTestYieldInstruction;
var enumerator = editModeTestYieldInstruction.Perform();
while (true)
{
bool moveNext;
try
{
moveNext = enumerator.MoveNext();
}
catch (Exception e)
{
Context.CurrentResult.RecordException(e);
break;
}
if (!moveNext)
{
break;
}
yield return null;
}
}
else
{
yield return workItemStep;
}
}
Result = Context.CurrentResult;
EditorApplication.isPlaying = false;
yield return null;
}
}
finally
{
WorkItemComplete();
}
}
private bool IsCancelledRun()
{
return Context.ExecutionStatus == TestExecutionStatus.AbortRequested || Context.ExecutionStatus == TestExecutionStatus.StopRequested;
}
}
}

View file

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

View file

@ -0,0 +1,51 @@
using System.Collections;
using System.Reflection;
namespace UnityEditor.TestTools.TestRunner
{
internal class EnumeratorStepHelper
{
private static int m_PC;
public static void SetEnumeratorPC(int pc)
{
m_PC = pc;
}
/// <summary>
/// Gets the current enumerator PC
/// </summary>
/// <returns>
/// The PC
/// 0 if no current Enumeration
/// </returns>
public static int GetEnumeratorPC(IEnumerator enumerator)
{
if (enumerator == null)
{
return 0;
}
return (int)GetPCFieldInfo(enumerator).GetValue(enumerator);
}
public static bool UpdateEnumeratorPcIfNeeded(IEnumerator enumerator)
{
if (m_PC != 0)
{
GetPCFieldInfo(enumerator).SetValue(enumerator, m_PC);
m_PC = 0;
return true;
}
return false;
}
private static FieldInfo GetPCFieldInfo(IEnumerator enumerator)
{
var field = enumerator.GetType().GetField("$PC", BindingFlags.NonPublic | BindingFlags.Instance);
if (field == null) // Roslyn
field = enumerator.GetType().GetField("<>1__state", BindingFlags.NonPublic | BindingFlags.Instance);
return field;
}
}
}

View file

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

View file

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: d9682e749d3efc642af54d789d9090a6
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,57 @@
using System;
using System.Collections;
using UnityEditor;
namespace UnityEngine.TestTools
{
/// <summary>
/// Implements <see cref="IEditModeTestYieldInstruction"/>. Creates a yield instruction to enter Play Mode.
/// </summary>
public class EnterPlayMode : IEditModeTestYieldInstruction
{
/// <summary>
/// Returns true if the instruction expects a domain reload to occur.
/// </summary>
public bool ExpectDomainReload { get; }
/// <summary>
/// Returns true if the instruction expects the Unity Editor to be in **Play Mode**.
/// </summary>
public bool ExpectedPlaymodeState { get; private set; }
/// <summary>
/// When creating an Editor test that uses the UnityTest attribute, use this to trigger the Editor to enter Play Mode.
/// Throws an exception if the Editor is already in Play Mode or if there is a script compilation error.
/// </summary>
/// <param name="expectDomainReload">A flag indication whether to expect a domain reload.</param>
public EnterPlayMode(bool expectDomainReload = true)
{
ExpectDomainReload = expectDomainReload;
}
/// <summary>
/// Performs the multi-step instructions of entering PlayMode.
/// </summary>
/// <returns>An IEnumerator with the async steps.</returns>
/// <exception cref="Exception">An exception is thrown if the editor is already in PlayMode or if script compilation failed.</exception>
public IEnumerator Perform()
{
if (EditorApplication.isPlaying)
{
throw new Exception("Editor is already in PlayMode");
}
if (EditorUtility.scriptCompilationFailed)
{
throw new Exception("Script compilation failed");
}
yield return null;
ExpectedPlaymodeState = true;
EditorApplication.UnlockReloadAssemblies();
EditorApplication.isPlaying = true;
while (!EditorApplication.isPlaying)
{
yield return null;
}
}
}
}

View file

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

View file

@ -0,0 +1,48 @@
using System;
using System.Collections;
using UnityEditor;
namespace UnityEngine.TestTools
{
/// <summary>
/// Implements <see cref="IEditModeTestYieldInstruction"/>. A new instance of the class is a yield instruction to exit Play Mode.
/// </summary>
public class ExitPlayMode : IEditModeTestYieldInstruction
{
/// <summary>
/// Gets the value of ExpectDomainReload
/// </summary>
public bool ExpectDomainReload { get; }
/// <summary>
/// Gets the value of ExpectedPlaymodeState
/// </summary>
public bool ExpectedPlaymodeState { get; private set; }
/// <summary>
/// Sets ExpectDomainReload and ExpectedPlaymodeState to false.
/// </summary>
public ExitPlayMode()
{
ExpectDomainReload = false;
ExpectedPlaymodeState = false;
}
/// <summary>
/// Performs the multi-step instruction of exiting PlayMode.
/// </summary>
/// <returns>An IEnumerator with the async steps.</returns>
/// <exception cref="Exception">An exception is thrown if the editor is not in PlayMode.</exception>
public IEnumerator Perform()
{
if (!EditorApplication.isPlayingOrWillChangePlaymode)
{
throw new Exception("Editor is already in EditMode");
}
EditorApplication.isPlaying = false;
while (EditorApplication.isPlaying)
{
yield return null;
}
}
}
}

View file

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

View file

@ -0,0 +1,111 @@
using System;
using System.Collections;
using UnityEditor;
namespace UnityEngine.TestTools
{
/// <summary>
/// `RecompileScripts` is an <see cref="IEditModeTestYieldInstruction"/> that you can yield in Edit Mode tests. It lets you trigger a recompilation of scripts in the Unity Editor.
/// </summary>
public class RecompileScripts : IEditModeTestYieldInstruction
{
/// <summary>
/// Creates a new instance of the `RecompileScripts` yield instruction.
/// <example>
/// <code>
/// [UnitySetUp]
/// public IEnumerator SetUp()
/// {
/// using (var file = File.CreateText("Assets/temp/myScript.cs"))
/// {
/// file.Write("public class ATempClass { }");
/// }
/// AssetDatabase.Refresh();
/// yield return new RecompileScripts();
/// }
/// </code>
/// </example>
/// </summary>
public RecompileScripts() : this(true)
{
}
/// <summary>
/// Creates a new instance of the `RecompileScripts` yield instruction.
/// </summary>
/// <param name="expectScriptCompilation">This parameter indicates if you expect a script compilation to start (defaults to true). If a script compilation does not start and `expectScriptCompilation` is true, then it throws an exception.</param>
public RecompileScripts(bool expectScriptCompilation) : this(expectScriptCompilation, true)
{
}
/// <summary>
/// Creates a new instance of the `RecompileScripts` yield instruction.
/// </summary>
/// <param name="expectScriptCompilation">This parameter indicates if you expect a script compilation to start (defaults to true). If a script compilation does not start and `expectScriptCompilation` is `true`, then it throws an exception.</param>
/// <param name="expectScriptCompilationSuccess">This parameter indicates if you expect a script compilation to succeed. If not succeeded then an exception will be thrown.</param>
public RecompileScripts(bool expectScriptCompilation, bool expectScriptCompilationSuccess)
{
ExpectScriptCompilation = expectScriptCompilation;
ExpectScriptCompilationSuccess = expectScriptCompilationSuccess;
ExpectDomainReload = true;
}
/// <summary>
/// Returns true if the instruction expects a domain reload to occur.
/// </summary>
public bool ExpectDomainReload { get; private set; }
/// <summary>
/// Returns true if the instruction expects the Unity Editor to be in **Play Mode**.
/// </summary>
public bool ExpectedPlaymodeState { get; }
/// <summary>
/// Indicates whether a script compilation is expected.
/// </summary>
public bool ExpectScriptCompilation { get; private set; }
/// <summary>
/// Indicates whether the expected script compilation is expected to succeed.
/// </summary>
public bool ExpectScriptCompilationSuccess { get; private set; }
/// <summary>
/// The current active instance of the RecompileScripts yield instruction.
/// </summary>
public static RecompileScripts Current { get; private set; }
/// <summary>
/// Perform the multi step instruction of triggering a recompilation of scripts and waiting for its completion.
/// </summary>
/// <returns>An IEnumerator with the async steps.</returns>
/// <exception cref="Exception">Throws an exception if the editor does not need to recompile scripts or if the script compilation failed when expected to succeed.</exception>
public IEnumerator Perform()
{
Current = this;
// We need to yield, to give the test runner a chance to prepare for the domain reload
// If the script compilation happens very fast, then EditModeRunner.MoveNextAndUpdateYieldObject will not have a chance to set m_CurrentYieldObject
// This really should be fixed in EditModeRunner.MoveNextAndUpdateYieldObject
yield return null;
AssetDatabase.Refresh();
if (ExpectScriptCompilation && !EditorApplication.isCompiling)
{
Current = null;
throw new Exception("Editor does not need to recompile scripts");
}
EditorApplication.UnlockReloadAssemblies();
while (EditorApplication.isCompiling)
{
yield return null;
}
Current = null;
if (ExpectScriptCompilationSuccess && EditorUtility.scriptCompilationFailed)
{
EditorApplication.LockReloadAssemblies();
throw new Exception("Script compilation failed");
}
}
}
}

View file

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

View file

@ -0,0 +1,63 @@
using System;
using System.Collections;
using UnityEditor;
using UnityEditorInternal;
namespace UnityEngine.TestTools
{
/// <summary>
/// WaitForDomainReload is an <see cref="IEditModeTestYieldInstruction"/> that you can yield in Edit Mode tests. It delays the execution of scripts until after an incoming domain reload. If the domain reload results in a script compilation failure, then it throws an exception.
/// </summary>
public class WaitForDomainReload : IEditModeTestYieldInstruction
{
/// <summary>
/// Create a new instance of the `WaitForDomainReload` yield instruction.
/// <example>
/// <code>
/// [UnitySetUp]
/// public IEnumerator SetUp()
/// {
/// File.Copy("Resources/MyDll.dll", @"Assets/MyDll.dll", true); // Trigger a domain reload.
/// AssetDatabase.Refresh();
/// yield return new WaitForDomainReload();
/// }
/// </code>
/// </example>
/// </summary>
public WaitForDomainReload()
{
ExpectDomainReload = true;
}
/// <summary>
/// Returns true if the instruction expects a domain reload to occur.
/// </summary>
public bool ExpectDomainReload { get;  }
/// <summary>
/// Returns true if the instruction expects the Unity Editor to be in **Play Mode**.
/// </summary>
public bool ExpectedPlaymodeState { get; }
/// <summary>
/// Perform the multi step action of waiting for a domain reload.
/// </summary>
/// <returns>An IEnumerator with steps.</returns>
/// <exception cref="Exception">Throws an exception if script compilation failed or if the expected domain reload did not occur.</exception>
public IEnumerator Perform()
{
EditorApplication.UnlockReloadAssemblies();
while (InternalEditorUtility.IsScriptReloadRequested() || EditorApplication.isCompiling)
{
yield return null;
}
// Add this point the domain reload should have occured and stopped any further progress on the instruction.
EditorApplication.LockReloadAssemblies();
throw new Exception(
EditorUtility.scriptCompilationFailed ?
"Script compilation failed" :
"Expected domain reload, but it did not occur");
}
}
}

View file

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

View file

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 1f5bbb88ca730434483440cbc0278ef6
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,48 @@
using System;
using System.Collections.Generic;
using UnityEditor.TestTools.TestRunner.Api;
using UnityEngine.TestRunner.NUnitExtensions;
using UnityEngine.TestTools;
namespace UnityEditor.TestTools.TestRunner
{
internal class CachingTestListProvider
{
private readonly ITestListProvider m_InnerTestListProvider;
private readonly ITestListCache m_TestListCache;
private readonly ITestAdaptorFactory m_TestAdaptorFactory;
public CachingTestListProvider(ITestListProvider innerTestListProvider, ITestListCache testListCache, ITestAdaptorFactory testAdaptorFactory)
{
m_InnerTestListProvider = innerTestListProvider;
m_TestListCache = testListCache;
m_TestAdaptorFactory = testAdaptorFactory;
}
public IEnumerator<ITestAdaptor> GetTestListAsync(TestPlatform platform)
{
var testFromCache = m_TestListCache.GetTestFromCacheAsync(platform);
while (testFromCache.MoveNext())
{
yield return null;
}
if (testFromCache.Current != null)
{
yield return testFromCache.Current;
}
else
{
var test = m_InnerTestListProvider.GetTestListAsync(platform);
while (test.MoveNext())
{
yield return null;
}
test.Current.ParseForNameDuplicates();
m_TestListCache.CacheTest(platform, test.Current);
yield return m_TestAdaptorFactory.Create(test.Current);
}
}
}
}

View file

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

View file

@ -0,0 +1,13 @@
using System.Linq;
using UnityEngine.TestTools.Utils;
namespace UnityEditor.TestTools.TestRunner
{
internal class EditorAssembliesProxy : IEditorAssembliesProxy
{
public IAssemblyWrapper[] loadedAssemblies
{
get { return EditorAssemblies.loadedAssemblies.OrderBy(a => a.FullName).Select(x => new EditorAssemblyWrapper(x)).ToArray(); }
}
}
}

View file

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

View file

@ -0,0 +1,18 @@
using System.Reflection;
using UnityEngine.TestTools.Utils;
namespace UnityEditor.TestTools.TestRunner
{
internal class EditorAssemblyWrapper : AssemblyWrapper
{
public EditorAssemblyWrapper(Assembly assembly)
: base(assembly) {}
public override AssemblyName[] GetReferencedAssemblies()
{
return Assembly.GetReferencedAssemblies();
}
public override string Location { get { return Assembly.Location; } }
}
}

View file

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

View file

@ -0,0 +1,17 @@
using UnityEditor.Scripting.ScriptCompilation;
namespace UnityEditor.TestTools.TestRunner
{
internal class EditorCompilationInterfaceProxy : IEditorCompilationInterfaceProxy
{
public ScriptAssembly[] GetAllEditorScriptAssemblies()
{
return EditorCompilationInterface.Instance.GetAllEditorScriptAssemblies(EditorCompilationInterface.GetAdditionalEditorScriptCompilationOptions());
}
public PrecompiledAssembly[] GetAllPrecompiledAssemblies()
{
return EditorCompilationInterface.Instance.GetAllPrecompiledAssemblies();
}
}
}

View file

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

View file

@ -0,0 +1,120 @@
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using UnityEditor.Scripting.ScriptCompilation;
using UnityEngine.TestTools;
using UnityEngine.TestTools.Utils;
namespace UnityEditor.TestTools.TestRunner
{
internal class EditorLoadedTestAssemblyProvider : IEditorLoadedTestAssemblyProvider
{
private const string k_NunitAssemblyName = "nunit.framework";
private const string k_TestRunnerAssemblyName = "UnityEngine.TestRunner";
internal const string k_PerformanceTestingAssemblyName = "Unity.PerformanceTesting";
private readonly IEditorAssembliesProxy m_EditorAssembliesProxy;
private readonly ScriptAssembly[] m_AllEditorScriptAssemblies;
private readonly PrecompiledAssembly[] m_AllPrecompiledAssemblies;
public EditorLoadedTestAssemblyProvider(IEditorCompilationInterfaceProxy compilationInterfaceProxy, IEditorAssembliesProxy editorAssembliesProxy)
{
m_EditorAssembliesProxy = editorAssembliesProxy;
m_AllEditorScriptAssemblies = compilationInterfaceProxy.GetAllEditorScriptAssemblies();
m_AllPrecompiledAssemblies = compilationInterfaceProxy.GetAllPrecompiledAssemblies();
}
public List<IAssemblyWrapper> GetAssembliesGroupedByType(TestPlatform mode)
{
var assemblies = GetAssembliesGroupedByTypeAsync(mode);
while (assemblies.MoveNext())
{
}
return assemblies.Current.Where(pair => mode.IsFlagIncluded(pair.Key)).SelectMany(pair => pair.Value).ToList();
}
public IEnumerator<IDictionary<TestPlatform, List<IAssemblyWrapper>>> GetAssembliesGroupedByTypeAsync(TestPlatform mode)
{
IAssemblyWrapper[] loadedAssemblies = m_EditorAssembliesProxy.loadedAssemblies;
IDictionary<TestPlatform, List<IAssemblyWrapper>> result = new Dictionary<TestPlatform, List<IAssemblyWrapper>>()
{
{TestPlatform.EditMode, new List<IAssemblyWrapper>() },
{TestPlatform.PlayMode, new List<IAssemblyWrapper>() }
};
var filteredAssemblies = FilterAssembliesWithTestReference(loadedAssemblies);
foreach (var loadedAssembly in filteredAssemblies)
{
var assemblyName = new FileInfo(loadedAssembly.Location).Name;
var scriptAssemblies = m_AllEditorScriptAssemblies.Where(x => x.Filename == assemblyName).ToList();
var precompiledAssemblies = m_AllPrecompiledAssemblies.Where(x => new FileInfo(x.Path).Name == assemblyName).ToList();
if (scriptAssemblies.Count < 1 && precompiledAssemblies.Count < 1)
{
continue;
}
var assemblyFlags = scriptAssemblies.Any() ? scriptAssemblies.Single().Flags : precompiledAssemblies.Single().Flags;
var assemblyType = (assemblyFlags & AssemblyFlags.EditorOnly) == AssemblyFlags.EditorOnly ? TestPlatform.EditMode : TestPlatform.PlayMode;
result[assemblyType].Add(loadedAssembly);
yield return null;
}
yield return result;
}
private IAssemblyWrapper[] FilterAssembliesWithTestReference(IAssemblyWrapper[] loadedAssemblies)
{
var filteredResults = new Dictionary<IAssemblyWrapper, bool>();
foreach (var assembly in loadedAssemblies)
{
FilterAssemblyForTestReference(assembly, loadedAssemblies, filteredResults);
}
return filteredResults.Where(pair => pair.Value).Select(pair => pair.Key).ToArray();
}
private void FilterAssemblyForTestReference(IAssemblyWrapper assemblyToFilter, IAssemblyWrapper[] loadedAssemblies, IDictionary<IAssemblyWrapper, bool> filterResults)
{
if (filterResults.ContainsKey(assemblyToFilter))
{
return;
}
var references = assemblyToFilter.GetReferencedAssemblies();
if (references.Any(IsTestReference))
{
filterResults[assemblyToFilter] = true;
return;
}
foreach (var reference in references)
{
var referencedAssembly = loadedAssemblies.FirstOrDefault(a => a.Name.Name == reference.Name);
if (referencedAssembly == null)
{
continue;
}
FilterAssemblyForTestReference(referencedAssembly, loadedAssemblies, filterResults);
if (filterResults[referencedAssembly])
{
filterResults[assemblyToFilter] = true;
return;
}
}
filterResults[assemblyToFilter] = false;
}
private static bool IsTestReference(AssemblyName assemblyName)
{
return assemblyName.Name == k_NunitAssemblyName ||
assemblyName.Name == k_TestRunnerAssemblyName ||
assemblyName.Name == k_PerformanceTestingAssemblyName;
}
}
}

View file

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

View file

@ -0,0 +1,9 @@
using UnityEngine.TestTools.Utils;
namespace UnityEditor.TestTools.TestRunner
{
internal interface IEditorAssembliesProxy
{
IAssemblyWrapper[] loadedAssemblies { get; }
}
}

View file

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

View file

@ -0,0 +1,10 @@
using UnityEditor.Scripting.ScriptCompilation;
namespace UnityEditor.TestTools.TestRunner
{
internal interface IEditorCompilationInterfaceProxy
{
ScriptAssembly[] GetAllEditorScriptAssemblies();
PrecompiledAssembly[] GetAllPrecompiledAssemblies();
}
}

View file

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

View file

@ -0,0 +1,12 @@
using System.Collections.Generic;
using UnityEngine.TestTools;
using UnityEngine.TestTools.Utils;
namespace UnityEditor.TestTools.TestRunner
{
internal interface IEditorLoadedTestAssemblyProvider
{
List<IAssemblyWrapper> GetAssembliesGroupedByType(TestPlatform mode);
IEnumerator<IDictionary<TestPlatform, List<IAssemblyWrapper>>> GetAssembliesGroupedByTypeAsync(TestPlatform mode);
}
}

View file

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

View file

@ -0,0 +1,13 @@
using System.Collections.Generic;
using NUnit.Framework.Interfaces;
using UnityEditor.TestTools.TestRunner.Api;
using UnityEngine.TestTools;
namespace UnityEditor.TestTools.TestRunner
{
interface ITestListCache
{
void CacheTest(TestPlatform platform, ITest test);
IEnumerator<ITestAdaptor> GetTestFromCacheAsync(TestPlatform platform);
}
}

View file

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

View file

@ -0,0 +1,13 @@
using System.Collections.Generic;
using NUnit.Framework.Interfaces;
using UnityEngine.TestRunner.TestLaunchers;
using UnityEngine.TestTools;
namespace UnityEditor.TestTools.TestRunner
{
interface ITestListCacheData
{
List<TestPlatform> platforms { get; }
List<ITest> cachedData { get; }
}
}

View file

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

View file

@ -0,0 +1,11 @@
using System.Collections.Generic;
using NUnit.Framework.Interfaces;
using UnityEngine.TestTools;
namespace UnityEditor.TestTools.TestRunner
{
interface ITestListProvider
{
IEnumerator<ITest> GetTestListAsync(TestPlatform platform);
}
}

View file

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

View file

@ -0,0 +1,56 @@
using System.Collections.Generic;
using NUnit.Framework.Interfaces;
using UnityEditor.TestTools.TestRunner.Api;
using UnityEngine.TestRunner.TestLaunchers;
using UnityEngine.TestTools;
namespace UnityEditor.TestTools.TestRunner
{
internal class TestListCache : ITestListCache
{
private readonly ITestAdaptorFactory m_TestAdaptorFactory;
private readonly IRemoteTestResultDataFactory m_TestResultDataFactory;
private readonly ITestListCacheData m_TestListCacheData;
public TestListCache(ITestAdaptorFactory testAdaptorFactory, IRemoteTestResultDataFactory testResultDataFactory, ITestListCacheData testListCacheData)
{
m_TestAdaptorFactory = testAdaptorFactory;
m_TestResultDataFactory = testResultDataFactory;
m_TestListCacheData = testListCacheData;
}
public void CacheTest(TestPlatform platform, ITest test)
{
var index = m_TestListCacheData.platforms.IndexOf(platform);
if (index < 0)
{
m_TestListCacheData.cachedData.Add(test);
m_TestListCacheData.platforms.Add(platform);
}
else
{
m_TestListCacheData.cachedData[index] = test;
}
}
public IEnumerator<ITestAdaptor> GetTestFromCacheAsync(TestPlatform platform)
{
var index = m_TestListCacheData.platforms.IndexOf(platform);
if (index < 0)
{
yield return null;
yield break;
}
var testData = m_TestListCacheData.cachedData[index];
yield return m_TestAdaptorFactory.Create(testData);
}
[Callbacks.DidReloadScripts]
private static void ScriptReloaded()
{
TestListCacheData.instance.cachedData.Clear();
TestListCacheData.instance.platforms.Clear();
}
}
}

View file

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

View file

@ -0,0 +1,27 @@
using System.Collections.Generic;
using NUnit.Framework.Interfaces;
using UnityEngine;
using UnityEngine.TestRunner.TestLaunchers;
using UnityEngine.TestTools;
namespace UnityEditor.TestTools.TestRunner
{
internal class TestListCacheData : ScriptableSingleton<TestListCacheData>, ITestListCacheData
{
[SerializeField]
private List<TestPlatform> m_Platforms = new List<TestPlatform>();
[SerializeField]
private List<ITest> m_CachedData = new List<ITest>();
public List<TestPlatform> platforms
{
get { return m_Platforms; }
}
public List<ITest> cachedData
{
get { return m_CachedData; }
}
}
}

View file

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

View file

@ -0,0 +1,36 @@
using System;
using System.Collections.Generic;
using UnityEditor.TestTools.TestRunner.Api;
using UnityEngine.TestTools;
namespace UnityEditor.TestTools.TestRunner
{
internal class TestListJob
{
private CachingTestListProvider m_TestListProvider;
private TestPlatform m_Platform;
private Action<ITestAdaptor> m_Callback;
private IEnumerator<ITestAdaptor> m_ResultEnumerator;
public TestListJob(CachingTestListProvider testListProvider, TestPlatform platform, Action<ITestAdaptor> callback)
{
m_TestListProvider = testListProvider;
m_Platform = platform;
m_Callback = callback;
}
public void Start()
{
m_ResultEnumerator = m_TestListProvider.GetTestListAsync(m_Platform);
EditorApplication.update += EditorUpdate;
}
private void EditorUpdate()
{
if (!m_ResultEnumerator.MoveNext())
{
m_Callback(m_ResultEnumerator.Current);
EditorApplication.update -= EditorUpdate;
}
}
}
}

View file

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

View file

@ -0,0 +1,42 @@
using System;
using System.Collections.Generic;
using System.Linq;
using NUnit.Framework.Interfaces;
using UnityEngine.TestTools;
using UnityEngine.TestTools.NUnitExtensions;
namespace UnityEditor.TestTools.TestRunner
{
internal class TestListProvider : ITestListProvider
{
private readonly EditorLoadedTestAssemblyProvider m_AssemblyProvider;
private readonly UnityTestAssemblyBuilder m_AssemblyBuilder;
public TestListProvider(EditorLoadedTestAssemblyProvider assemblyProvider, UnityTestAssemblyBuilder assemblyBuilder)
{
m_AssemblyProvider = assemblyProvider;
m_AssemblyBuilder = assemblyBuilder;
}
public IEnumerator<ITest> GetTestListAsync(TestPlatform platform)
{
var assembliesTask = m_AssemblyProvider.GetAssembliesGroupedByTypeAsync(platform);
while (assembliesTask.MoveNext())
{
yield return null;
}
var assemblies = assembliesTask.Current.Where(pair => platform.IsFlagIncluded(pair.Key))
.SelectMany(pair => pair.Value.Select(assemblyInfo => Tuple.Create(assemblyInfo.Assembly, pair.Key))).ToArray();
var settings = UnityTestAssemblyBuilder.GetNUnitTestBuilderSettings(platform);
var test = m_AssemblyBuilder.BuildAsync(assemblies.Select(a => a.Item1).ToArray(), assemblies.Select(a => a.Item2).ToArray(), settings);
while (test.MoveNext())
{
yield return null;
}
yield return test.Current;
}
}
}

View file

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