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: 6dba53789da15814387fa5b1445e81e0
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,86 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using NUnit.Framework.Interfaces;
using UnityEngine;
using UnityEngine.TestTools.Logging;
using UnityEngine.TestTools.TestRunner;
namespace UnityEditor.TestTools.TestRunner.TestRun.Tasks
{
internal abstract class BuildActionTaskBase<T> : TestTaskBase
{
private string typeName;
internal IAttributeFinder attributeFinder;
internal RuntimePlatform targetPlatform = Application.platform;
internal Action<string> logAction = Debug.Log;
internal Func<ILogScope> logScopeProvider = () => new LogScope();
internal Func<Type, object> createInstance = Activator.CreateInstance;
protected BuildActionTaskBase(IAttributeFinder attributeFinder)
{
this.attributeFinder = attributeFinder;
typeName = typeof(T).Name;
}
protected abstract void Action(T target);
public override IEnumerator Execute(TestJobData testJobData)
{
if (testJobData.testTree == null)
{
throw new Exception($"Test tree is not available for {GetType().Name}.");
}
var enumerator = ExecuteMethods(testJobData.testTree, testJobData.executionSettings.BuildNUnitFilter());
while (enumerator.MoveNext())
{
yield return null;
}
}
protected IEnumerator ExecuteMethods(ITest testTree, ITestFilter testRunnerFilter)
{
var exceptions = new List<Exception>();
foreach (var targetClassType in attributeFinder.Search(testTree, testRunnerFilter, targetPlatform))
{
try
{
var targetClass = (T) createInstance(targetClassType);
logAction($"Executing {typeName} for: {targetClassType.FullName}.");
using (var logScope = logScopeProvider())
{
Action(targetClass);
if (logScope.AnyFailingLogs())
{
var failingLog = logScope.FailingLogs.First();
throw new UnhandledLogMessageException(failingLog);
}
if (logScope.ExpectedLogs.Any())
{
var expectedLogs = logScope.ExpectedLogs.First();
throw new UnexpectedLogMessageException(expectedLogs);
}
}
}
catch (Exception ex)
{
exceptions.Add(ex);
}
yield return null;
}
if (exceptions.Count > 0)
{
throw new AggregateException($"One or more exceptions when executing {typeName}.", exceptions);
}
}
}
}

View file

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

View file

@ -0,0 +1,61 @@
using System;
using System.Collections;
using System.Linq;
using UnityEditor.TestTools.TestRunner.Api;
using UnityEngine.TestRunner.NUnitExtensions;
using UnityEngine.TestTools;
using UnityEngine.TestTools.NUnitExtensions;
namespace UnityEditor.TestTools.TestRunner.TestRun.Tasks
{
internal class BuildTestTreeTask : TestTaskBase
{
private TestPlatform m_TestPlatform;
public BuildTestTreeTask(TestPlatform testPlatform)
{
m_TestPlatform = testPlatform;
}
internal IEditorLoadedTestAssemblyProvider m_testAssemblyProvider = new EditorLoadedTestAssemblyProvider(new EditorCompilationInterfaceProxy(), new EditorAssembliesProxy());
internal IAsyncTestAssemblyBuilder m_testAssemblyBuilder = new UnityTestAssemblyBuilder();
internal ICallbacksDelegator m_CallbacksDelegator = CallbacksDelegator.instance;
public override IEnumerator Execute(TestJobData testJobData)
{
if (testJobData.testTree != null)
{
yield break;
}
var assembliesEnumerator = m_testAssemblyProvider.GetAssembliesGroupedByTypeAsync(m_TestPlatform);
while (assembliesEnumerator.MoveNext())
{
yield return null;
}
if (assembliesEnumerator.Current == null)
{
throw new Exception("Assemblies not retrieved.");
}
var assemblies = assembliesEnumerator.Current.Where(pair => m_TestPlatform.IsFlagIncluded(pair.Key)).SelectMany(pair => pair.Value).Select(x => x.Assembly).ToArray();
var buildSettings = UnityTestAssemblyBuilder.GetNUnitTestBuilderSettings(m_TestPlatform);
var enumerator = m_testAssemblyBuilder.BuildAsync(assemblies, Enumerable.Repeat(m_TestPlatform, assemblies.Length).ToArray(), buildSettings);
while (enumerator.MoveNext())
{
yield return null;
}
var testList = enumerator.Current;
if (testList== null)
{
throw new Exception("Test list not retrieved.");
}
testList.ParseForNameDuplicates();
testJobData.testTree = testList;
m_CallbacksDelegator.TestTreeRebuild(testList);
}
}
}

View file

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

View file

@ -0,0 +1,50 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using UnityEngine;
namespace UnityEditor.TestTools.TestRunner.TestRun.Tasks
{
internal class CleanupVerificationTask : FileCleanupVerifierTaskBase
{
private const string k_Indent = " ";
internal Action<object> logAction = Debug.LogWarning;
public override IEnumerator Execute(TestJobData testJobData)
{
var currentFiles = GetAllFilesInAssetsDirectory();
var existingFiles = testJobData.existingFiles;
if (currentFiles.Length != existingFiles.Length)
{
var existingFilesHashSet = new HashSet<string>(existingFiles);
var newFiles = currentFiles.Where(file => !existingFilesHashSet.Contains(file)).ToArray();
LogWarningForFilesIfAny(newFiles);
}
yield return null;
}
private void LogWarningForFilesIfAny(string[] filePaths)
{
if (filePaths.Length == 0)
{
return;
}
var stringWriter = new StringWriter();
stringWriter.WriteLine("Files generated by test without cleanup.");
stringWriter.WriteLine(k_Indent + "Found {0} new files.", filePaths.Length);
foreach (var filePath in filePaths)
{
stringWriter.WriteLine(k_Indent + filePath);
}
logAction(stringWriter.ToString());
}
}
}

View file

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

View file

@ -0,0 +1,14 @@
using System;
namespace UnityEditor.TestTools.TestRunner.TestRun.Tasks
{
internal abstract class FileCleanupVerifierTaskBase : TestTaskBase
{
internal Func<string[]> GetAllAssetPathsAction = AssetDatabase.GetAllAssetPaths;
protected string[] GetAllFilesInAssetsDirectory()
{
return GetAllAssetPathsAction();
}
}
}

View file

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

View file

@ -0,0 +1,26 @@
using System.Collections;
using UnityEngine;
using UnityEngine.TestTools;
namespace UnityEditor.TestTools.TestRunner.TestRun.Tasks
{
internal class LegacyEditModeRunTask : TestTaskBase
{
public LegacyEditModeRunTask() : base(true)
{
}
public override IEnumerator Execute(TestJobData testJobData)
{
var testLauncher = new EditModeLauncher(testJobData.executionSettings.filters, TestPlatform.EditMode, testJobData.executionSettings.runSynchronously);
testJobData.editModeRunner = testLauncher.m_EditModeRunner;
testLauncher.Run();
while (testJobData.editModeRunner != null && !testJobData.editModeRunner.RunFinished)
{
yield return null;
}
}
}
}

View file

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

View file

@ -0,0 +1,26 @@
using System.Collections;
using System.Linq;
using UnityEngine.TestTools.TestRunner;
namespace UnityEditor.TestTools.TestRunner.TestRun.Tasks
{
internal class LegacyPlayModeRunTask : TestTaskBase
{
public LegacyPlayModeRunTask() : base(true)
{
}
public override IEnumerator Execute(TestJobData testJobData)
{
var settings = PlaymodeTestsControllerSettings.CreateRunnerSettings(testJobData.executionSettings.filters.Select(filter => filter.ToRuntimeTestRunnerFilter(testJobData.executionSettings.runSynchronously)).ToArray());
var launcher = new PlaymodeLauncher(settings);
launcher.Run();
while (PlaymodeLauncher.IsRunning)
{
yield return null;
}
}
}
}

View file

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

View file

@ -0,0 +1,18 @@
using System.Collections;
using System.Linq;
using UnityEngine.TestTools.TestRunner;
namespace UnityEditor.TestTools.TestRunner.TestRun.Tasks
{
internal class LegacyPlayerRunTask : TestTaskBase
{
public override IEnumerator Execute(TestJobData testJobData)
{
var executionSettings = testJobData.executionSettings;
var settings = PlaymodeTestsControllerSettings.CreateRunnerSettings(executionSettings.filters.Select(filter => filter.ToRuntimeTestRunnerFilter(executionSettings.runSynchronously)).ToArray());
var launcher = new PlayerLauncher(settings, executionSettings.targetPlatform, executionSettings.overloadTestRunSettings, executionSettings.playerHeartbeatTimeout);
launcher.Run();
yield return null;
}
}
}

View file

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

View file

@ -0,0 +1,39 @@
using System;
using System.Collections;
using UnityEngine;
namespace UnityEditor.TestTools.TestRunner.TestRun.Tasks
{
internal class PerformUndoTask : TestTaskBase
{
private const double warningThreshold = 1000;
internal Action<int> RevertAllDownToGroup = Undo.RevertAllDownToGroup;
internal Action<string> LogWarning = Debug.LogWarning;
internal Action<string, string, float> DisplayProgressBar = EditorUtility.DisplayProgressBar;
internal Action ClearProgressBar = EditorUtility.ClearProgressBar;
internal Func<DateTime> TimeNow = () => DateTime.Now;
public override IEnumerator Execute(TestJobData testJobData)
{
if (testJobData.undoGroup < 0)
{
yield break;
}
DisplayProgressBar("Undo", "Reverting changes to the scene", 0);
var undoStartTime = TimeNow();
RevertAllDownToGroup(testJobData.undoGroup);
var timeDelta = TimeNow() - undoStartTime;
if (timeDelta.TotalMilliseconds >= warningThreshold)
{
LogWarning($"Undo after editor test run took {timeDelta.Seconds} second{(timeDelta.Seconds == 1 ? "" : "s")}.");
}
ClearProgressBar();
}
}
}

View file

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

View file

@ -0,0 +1,20 @@
using System;
using System.Collections;
using NUnit.Framework.Interfaces;
using UnityEngine;
using UnityEngine.TestTools;
namespace UnityEditor.TestTools.TestRunner.TestRun.Tasks
{
internal class PrebuildSetupTask : BuildActionTaskBase<IPrebuildSetup>
{
public PrebuildSetupTask() : base(new PrebuildSetupAttributeFinder())
{
}
protected override void Action(IPrebuildSetup target)
{
target.Setup();
}
}
}

View file

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

View file

@ -0,0 +1,13 @@
using System.Collections;
namespace UnityEditor.TestTools.TestRunner.TestRun.Tasks
{
internal class RegisterFilesForCleanupVerificationTask : FileCleanupVerifierTaskBase
{
public override IEnumerator Execute(TestJobData testJobData)
{
testJobData.existingFiles = GetAllFilesInAssetsDirectory();
yield return null;
}
}
}

View file

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

View file

@ -0,0 +1,22 @@
using System;
using System.Collections;
using UnityEditor.SceneManagement;
namespace UnityEditor.TestTools.TestRunner.TestRun.Tasks
{
internal class SaveModiedSceneTask : TestTaskBase
{
internal Func<bool> SaveCurrentModifiedScenesIfUserWantsTo =
EditorSceneManager.SaveCurrentModifiedScenesIfUserWantsTo;
public override IEnumerator Execute(TestJobData testJobData)
{
var cancelled = !SaveCurrentModifiedScenesIfUserWantsTo();
if (cancelled)
{
throw new TestRunCanceledException();
}
yield break;
}
}
}

View file

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

View file

@ -0,0 +1,15 @@
using System;
using System.Collections;
namespace UnityEditor.TestTools.TestRunner.TestRun.Tasks
{
internal class SaveUndoIndexTask : TestTaskBase
{
internal Func<int> GetUndoGroup = Undo.GetCurrentGroup;
public override IEnumerator Execute(TestJobData testJobData)
{
testJobData.undoGroup = GetUndoGroup();
yield break;
}
}
}

View file

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

View file

@ -0,0 +1,16 @@
using System.Collections;
namespace UnityEditor.TestTools.TestRunner.TestRun.Tasks
{
internal abstract class TestTaskBase
{
public bool SupportsResumingEnumerator;
protected TestTaskBase(bool supportsResumingEnumerator = false)
{
SupportsResumingEnumerator = supportsResumingEnumerator;
}
public abstract IEnumerator Execute(TestJobData testJobData);
}
}

View file

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

View file

@ -0,0 +1,49 @@
using System;
using NUnit.Framework.Interfaces;
using UnityEditor.TestTools.TestRunner.Api;
using UnityEngine;
namespace UnityEditor.TestTools.TestRunner.TestRun
{
[Serializable]
internal class TestJobData
{
[SerializeField]
public string guid;
[SerializeField]
public int taskIndex;
[SerializeField]
public int taskPC;
[SerializeField]
public bool isRunning;
[SerializeField]
public ExecutionSettings executionSettings;
[SerializeField]
public string[] existingFiles;
[SerializeField]
public int undoGroup = -1;
[SerializeField]
public EditModeRunner editModeRunner;
[NonSerialized]
public bool isHandledByRunner;
public ITest testTree;
public TestJobData(ExecutionSettings settings)
{
guid = Guid.NewGuid().ToString();
executionSettings = settings;
isRunning = false;
taskIndex = 0;
taskPC = 0;
}
}
}

View file

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

View file

@ -0,0 +1,28 @@
using System.Collections.Generic;
using UnityEngine;
namespace UnityEditor.TestTools.TestRunner.TestRun
{
internal class TestJobDataHolder : ScriptableSingleton<TestJobDataHolder>
{
[SerializeField]
public List<TestJobData> TestRuns = new List<TestJobData>();
[InitializeOnLoadMethod]
private static void ResumeRunningJobs()
{
foreach (var testRun in instance.TestRuns.ToArray())
{
if (testRun.isRunning)
{
var runner = new TestJobRunner();
runner.RunJob(testRun);
}
else
{
instance.TestRuns.Remove(testRun);
}
}
}
}
}

View file

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

View file

@ -0,0 +1,166 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UnityEditor.TestTools.TestRunner.Api;
using UnityEditor.TestTools.TestRunner.TestRun.Tasks;
using UnityEngine;
using UnityEngine.TestTools;
namespace UnityEditor.TestTools.TestRunner.TestRun
{
internal class TestJobRunner
{
private static IEnumerable<TestTaskBase> GetTaskList(ExecutionSettings settings)
{
if (settings == null)
{
yield break;
}
if (settings.EditModeIncluded() || (PlayerSettings.runPlayModeTestAsEditModeTest && settings.PlayModeInEditorIncluded()))
{
yield return new SaveModiedSceneTask();
yield return new RegisterFilesForCleanupVerificationTask();
yield return new SaveUndoIndexTask();
yield return new BuildTestTreeTask(TestPlatform.EditMode);
yield return new PrebuildSetupTask();
yield return new LegacyEditModeRunTask();
yield return new PerformUndoTask();
yield return new CleanupVerificationTask();
yield break;
}
if (settings.PlayModeInEditorIncluded() && !PlayerSettings.runPlayModeTestAsEditModeTest)
{
yield return new SaveModiedSceneTask();
yield return new LegacyPlayModeRunTask();
yield break;
}
if (settings.PlayerIncluded())
{
yield return new LegacyPlayerRunTask();
yield break;
}
}
internal List<TestJobData> SavedTestJobData = TestJobDataHolder.instance.TestRuns;
internal Action<EditorApplication.CallbackFunction> SubscribeCallback = (callback) => EditorApplication.update += callback;
// ReSharper disable once DelegateSubtraction
internal Action<EditorApplication.CallbackFunction> UnsubscribeCallback = (callback) => EditorApplication.update -= callback;
internal TestCommandPcHelper PcHelper = new EditModePcHelper();
internal Func<ExecutionSettings, IEnumerable<TestTaskBase>> GetTasks = GetTaskList;
internal Action<Exception> LogException = Debug.LogException;
internal Action<string> LogError = Debug.LogError;
internal Action<string> ReportRunFailed = CallbacksDelegator.instance.RunFailed;
private TestJobData m_JobData;
private TestTaskBase[] Tasks;
private IEnumerator m_Enumerator = null;
public string RunJob(TestJobData data)
{
if (data == null)
{
throw new ArgumentException(null, nameof(data));
}
if (m_JobData != null && m_JobData.isRunning)
{
throw new Exception("TestJobRunner is already running a job.");
}
if (data.isHandledByRunner)
{
throw new Exception("Test job is already being handled.");
}
m_JobData = data;
m_JobData.isHandledByRunner = true;
if (!m_JobData.isRunning)
{
m_JobData.isRunning = true;
SavedTestJobData.Add(m_JobData);
}
Tasks = GetTasks(data.executionSettings).ToArray();
if (!data.executionSettings.runSynchronously)
{
SubscribeCallback(ExecuteStep);
}
else
{
while (data.isRunning)
{
ExecuteStep();
}
}
return data.guid;
}
private void ExecuteStep()
{
try
{
if (m_JobData.taskIndex >= Tasks.Length)
{
StopRun();
return;
}
if (m_Enumerator == null)
{
var task = Tasks[m_JobData.taskIndex];
m_Enumerator = task.Execute(m_JobData);
if (task.SupportsResumingEnumerator)
{
PcHelper.SetEnumeratorPC(m_Enumerator, m_JobData.taskPC);
}
}
if (!m_Enumerator.MoveNext())
{
m_JobData.taskIndex++;
m_JobData.taskPC = 0;
m_Enumerator = null;
return;
}
if (Tasks[m_JobData.taskIndex].SupportsResumingEnumerator)
{
m_JobData.taskPC = PcHelper.GetEnumeratorPC(m_Enumerator);
}
}
catch (TestRunCanceledException)
{
StopRun();
}
catch (AggregateException ex)
{
StopRun();
LogError(ex.Message);
foreach (var innerException in ex.InnerExceptions)
{
LogException(innerException);
}
ReportRunFailed("Multiple unexpected errors happened while running tests.");
}
catch (Exception ex)
{
StopRun();
LogException(ex);
ReportRunFailed("An unexpected error happened while running tests.");
}
}
private void StopRun()
{
m_JobData.isRunning = false;
UnsubscribeCallback(ExecuteStep);
SavedTestJobData.Remove(m_JobData);
}
}
}

View file

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

View file

@ -0,0 +1,9 @@
using System;
namespace UnityEditor.TestTools.TestRunner.TestRun
{
internal class TestRunCanceledException : Exception
{
}
}

View file

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