Initial Commit
This commit is contained in:
parent
53eb92e9af
commit
270ab7d11f
15341 changed files with 700234 additions and 0 deletions
|
@ -0,0 +1,109 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using NUnit.Framework.Interfaces;
|
||||
using UnityEngine;
|
||||
using UnityEngine.TestTools;
|
||||
|
||||
namespace UnityEditor.TestTools.TestRunner
|
||||
{
|
||||
internal abstract class AttributeFinderBase : IAttributeFinder
|
||||
{
|
||||
public abstract IEnumerable<Type> Search(ITest tests, ITestFilter filter, RuntimePlatform testTargetPlatform);
|
||||
}
|
||||
|
||||
internal interface IAttributeFinder
|
||||
{
|
||||
IEnumerable<Type> Search(ITest tests, ITestFilter filter, RuntimePlatform testTargetPlatform);
|
||||
}
|
||||
|
||||
internal abstract class AttributeFinderBase<T1, T2> : AttributeFinderBase where T2 : Attribute
|
||||
{
|
||||
private readonly Func<T2, Type> m_TypeSelector;
|
||||
protected AttributeFinderBase(Func<T2, Type> typeSelector)
|
||||
{
|
||||
m_TypeSelector = typeSelector;
|
||||
}
|
||||
|
||||
public override IEnumerable<Type> Search(ITest tests, ITestFilter filter, RuntimePlatform testTargetPlatform)
|
||||
{
|
||||
var selectedTests = new List<ITest>();
|
||||
GetMatchingTests(tests, filter, ref selectedTests, testTargetPlatform);
|
||||
|
||||
var result = new List<Type>();
|
||||
result.AddRange(GetTypesFromPrebuildAttributes(selectedTests));
|
||||
result.AddRange(GetTypesFromInterface(selectedTests, testTargetPlatform));
|
||||
|
||||
return result.Distinct();
|
||||
}
|
||||
|
||||
private static void GetMatchingTests(ITest tests, ITestFilter filter, ref List<ITest> resultList, RuntimePlatform testTargetPlatform)
|
||||
{
|
||||
foreach (var test in tests.Tests)
|
||||
{
|
||||
if (IsTestEnabledOnPlatform(test, testTargetPlatform))
|
||||
{
|
||||
if (test.IsSuite)
|
||||
{
|
||||
GetMatchingTests(test, filter, ref resultList, testTargetPlatform);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (filter.Pass(test))
|
||||
resultList.Add(test);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static bool IsTestEnabledOnPlatform(ITest test, RuntimePlatform testTargetPlatform)
|
||||
{
|
||||
if (test.Method == null)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
var attributesFromMethods = test.Method.GetCustomAttributes<UnityPlatformAttribute>(true);
|
||||
var attributesFromTypes = test.Method.TypeInfo.GetCustomAttributes<UnityPlatformAttribute>(true);
|
||||
|
||||
if (attributesFromMethods.Length == 0 && attributesFromTypes.Length == 0)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!attributesFromMethods.All(a => a.IsPlatformSupported(testTargetPlatform)))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!attributesFromTypes.All(a => a.IsPlatformSupported(testTargetPlatform)))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private IEnumerable<Type> GetTypesFromPrebuildAttributes(IEnumerable<ITest> tests)
|
||||
{
|
||||
var allAssemblies = AppDomain.CurrentDomain.GetAssemblies();
|
||||
allAssemblies = allAssemblies.Where(x => x.GetReferencedAssemblies().Any(z => z.Name == "UnityEditor.TestRunner")).ToArray();
|
||||
var attributesFromAssemblies = allAssemblies.SelectMany(assembly => assembly.GetCustomAttributes(typeof(T2), true).OfType<T2>());
|
||||
var attributesFromMethods = tests.SelectMany(t => t.Method.GetCustomAttributes<T2>(true).Select(attribute => attribute));
|
||||
var attributesFromTypes = tests.SelectMany(t => t.Method.TypeInfo.GetCustomAttributes<T2>(true).Select(attribute => attribute));
|
||||
|
||||
var result = new List<T2>();
|
||||
result.AddRange(attributesFromAssemblies);
|
||||
result.AddRange(attributesFromMethods);
|
||||
result.AddRange(attributesFromTypes);
|
||||
|
||||
return result.Select(m_TypeSelector).Where(type => type != null);
|
||||
}
|
||||
|
||||
private static IEnumerable<Type> GetTypesFromInterface(IEnumerable<ITest> selectedTests, RuntimePlatform testTargetPlatform)
|
||||
{
|
||||
var typesWithInterfaces = selectedTests.Where(t => typeof(T1).IsAssignableFrom(t.Method.TypeInfo.Type) && IsTestEnabledOnPlatform(t, testTargetPlatform));
|
||||
return typesWithInterfaces.Select(t => t.Method.TypeInfo.Type);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 5d4de3d4682a8d641907cc75e4fb950e
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,44 @@
|
|||
namespace UnityEditor.TestTools.TestRunner
|
||||
{
|
||||
internal class DelayedCallback
|
||||
{
|
||||
private System.Action m_Callback;
|
||||
private double m_CallbackTime;
|
||||
private double m_Delay;
|
||||
|
||||
public DelayedCallback(System.Action function, double timeFromNow)
|
||||
{
|
||||
m_Callback = function;
|
||||
m_CallbackTime = EditorApplication.timeSinceStartup + timeFromNow;
|
||||
m_Delay = timeFromNow;
|
||||
EditorApplication.update += Update;
|
||||
}
|
||||
|
||||
public void Clear()
|
||||
{
|
||||
EditorApplication.update -= Update;
|
||||
m_CallbackTime = 0.0;
|
||||
m_Callback = null;
|
||||
}
|
||||
|
||||
private void Update()
|
||||
{
|
||||
if (EditorApplication.timeSinceStartup > m_CallbackTime)
|
||||
{
|
||||
// Clear state before firing callback to ensure reset (callback could call ExitGUI)
|
||||
var callback = m_Callback;
|
||||
Clear();
|
||||
|
||||
callback?.Invoke();
|
||||
}
|
||||
}
|
||||
|
||||
public void Reset()
|
||||
{
|
||||
if (m_Callback != null)
|
||||
{
|
||||
m_CallbackTime = EditorApplication.timeSinceStartup + m_Delay;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
fileFormatVersion: 2
|
||||
guid: b9d121df8c444236a5b38ccfadfdd1a7
|
||||
timeCreated: 1583140472
|
|
@ -0,0 +1,161 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using NUnit.Framework.Interfaces;
|
||||
using UnityEditor.SceneManagement;
|
||||
using UnityEditor.TestTools.TestRunner.Api;
|
||||
using UnityEditor.TestTools.TestRunner.GUI;
|
||||
using UnityEngine;
|
||||
using UnityEngine.SceneManagement;
|
||||
using UnityEngine.TestRunner.Utils;
|
||||
using UnityEngine.TestTools;
|
||||
using UnityEngine.TestTools.TestRunner;
|
||||
|
||||
namespace UnityEditor.TestTools.TestRunner
|
||||
{
|
||||
internal class EditModeLauncher : TestLauncherBase
|
||||
{
|
||||
public static bool IsRunning;
|
||||
internal readonly EditModeRunner m_EditModeRunner;
|
||||
public bool launchedOutsideApi;
|
||||
|
||||
// provided for backward compatibility with Rider UnitTesting prior to Rider package v.1.1.1
|
||||
public EditModeLauncher(UITestRunnerFilter filter, TestPlatform platform)
|
||||
{
|
||||
launchedOutsideApi = true;
|
||||
var apiFilter = new[]
|
||||
{
|
||||
new Filter()
|
||||
{
|
||||
testMode = TestMode.EditMode,
|
||||
testNames = filter.testNames,
|
||||
categoryNames = filter.categoryNames,
|
||||
groupNames = filter.groupNames,
|
||||
assemblyNames = filter.assemblyNames
|
||||
}
|
||||
};
|
||||
|
||||
ScriptableObject.CreateInstance<TestRunnerApi>().Execute(new ExecutionSettings(apiFilter));
|
||||
}
|
||||
|
||||
public EditModeLauncher(Filter[] filters, TestPlatform platform, bool runSynchronously)
|
||||
{
|
||||
TestEnumerator.Reset();
|
||||
m_EditModeRunner = ScriptableObject.CreateInstance<EditModeRunner>();
|
||||
m_EditModeRunner.UnityTestAssemblyRunnerFactory = new UnityTestAssemblyRunnerFactory();
|
||||
m_EditModeRunner.Init(filters, platform, runSynchronously);
|
||||
}
|
||||
|
||||
public override void Run()
|
||||
{
|
||||
if (launchedOutsideApi)
|
||||
{
|
||||
// Do not use the launcher, as it will be relaunched trough the api. See ctor.
|
||||
return;
|
||||
}
|
||||
|
||||
IsRunning = true;
|
||||
|
||||
SceneSetup[] previousSceneSetup;
|
||||
if (!OpenNewScene(out previousSceneSetup))
|
||||
return;
|
||||
|
||||
var callback = AddEventHandler<EditModeRunnerCallback>();
|
||||
callback.previousSceneSetup = previousSceneSetup;
|
||||
callback.runner = m_EditModeRunner;
|
||||
AddEventHandler<CallbacksDelegatorListener>();
|
||||
|
||||
m_EditModeRunner.Run();
|
||||
AddEventHandler<BackgroundListener>();
|
||||
AddEventHandler<TestRunCallbackListener>();
|
||||
|
||||
if (m_EditModeRunner.RunningSynchronously)
|
||||
m_EditModeRunner.CompleteSynchronously();
|
||||
}
|
||||
|
||||
private static bool OpenNewScene(out SceneSetup[] previousSceneSetup)
|
||||
{
|
||||
previousSceneSetup = null;
|
||||
|
||||
var sceneCount = SceneManager.sceneCount;
|
||||
|
||||
var scene = SceneManager.GetSceneAt(0);
|
||||
var isSceneNotPersisted = string.IsNullOrEmpty(scene.path);
|
||||
|
||||
if (sceneCount == 1 && isSceneNotPersisted)
|
||||
{
|
||||
EditorSceneManager.NewScene(NewSceneSetup.DefaultGameObjects, NewSceneMode.Single);
|
||||
return true;
|
||||
}
|
||||
RemoveUntitledScenes();
|
||||
|
||||
// In case the user chose not to save the dirty scenes we reload them
|
||||
ReloadUnsavedDirtyScene();
|
||||
|
||||
previousSceneSetup = EditorSceneManager.GetSceneManagerSetup();
|
||||
|
||||
scene = EditorSceneManager.NewScene(NewSceneSetup.EmptyScene, NewSceneMode.Additive);
|
||||
SceneManager.SetActiveScene(scene);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private static void ReloadUnsavedDirtyScene()
|
||||
{
|
||||
for (var i = 0; i < SceneManager.sceneCount; i++)
|
||||
{
|
||||
var scene = SceneManager.GetSceneAt(i);
|
||||
var isSceneNotPersisted = string.IsNullOrEmpty(scene.path);
|
||||
var isSceneDirty = scene.isDirty;
|
||||
if (isSceneNotPersisted && isSceneDirty)
|
||||
{
|
||||
EditorSceneManager.ReloadScene(scene);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void RemoveUntitledScenes()
|
||||
{
|
||||
int sceneCount = SceneManager.sceneCount;
|
||||
|
||||
var scenesToClose = new List<Scene>();
|
||||
for (var i = 0; i < sceneCount; i++)
|
||||
{
|
||||
var scene = SceneManager.GetSceneAt(i);
|
||||
var isSceneNotPersisted = string.IsNullOrEmpty(scene.path);
|
||||
if (isSceneNotPersisted)
|
||||
{
|
||||
scenesToClose.Add(scene);
|
||||
}
|
||||
}
|
||||
foreach (Scene scene in scenesToClose)
|
||||
{
|
||||
EditorSceneManager.CloseScene(scene, true);
|
||||
}
|
||||
}
|
||||
|
||||
public class BackgroundListener : ScriptableObject, ITestRunnerListener
|
||||
{
|
||||
public void RunStarted(ITest testsToRun)
|
||||
{
|
||||
}
|
||||
|
||||
public void RunFinished(ITestResult testResults)
|
||||
{
|
||||
IsRunning = false;
|
||||
}
|
||||
|
||||
public void TestStarted(ITest test)
|
||||
{
|
||||
}
|
||||
|
||||
public void TestFinished(ITestResult result)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
public T AddEventHandler<T>() where T : ScriptableObject, ITestRunnerListener
|
||||
{
|
||||
return m_EditModeRunner.AddEventHandler<T>();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: ac68f5ae37c8957468562b8da42f9984
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,31 @@
|
|||
using System;
|
||||
using UnityEngine;
|
||||
|
||||
namespace UnityEditor.TestTools.TestRunner
|
||||
{
|
||||
internal class EditModeLauncherContextSettings : IDisposable
|
||||
{
|
||||
private bool m_RunInBackground;
|
||||
|
||||
public EditModeLauncherContextSettings()
|
||||
{
|
||||
SetupProjectParameters();
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
CleanupProjectParameters();
|
||||
}
|
||||
|
||||
private void SetupProjectParameters()
|
||||
{
|
||||
m_RunInBackground = Application.runInBackground;
|
||||
Application.runInBackground = true;
|
||||
}
|
||||
|
||||
private void CleanupProjectParameters()
|
||||
{
|
||||
Application.runInBackground = m_RunInBackground;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: a582090813554df479fb9ca03e9857d3
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,8 @@
|
|||
fileFormatVersion: 2
|
||||
guid: ebc4d20cc106cea49b1df1153f0b3b5e
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,66 @@
|
|||
using System;
|
||||
using UnityEngine;
|
||||
using System.Net;
|
||||
|
||||
namespace UnityEditor.TestTools.TestRunner
|
||||
{
|
||||
internal class AndroidPlatformSetup : IPlatformSetup
|
||||
{
|
||||
private string m_oldApplicationIdentifier;
|
||||
private string m_oldDeviceSocketAddress;
|
||||
[SerializeField]
|
||||
private bool m_Stripping;
|
||||
|
||||
public void Setup()
|
||||
{
|
||||
m_oldApplicationIdentifier = PlayerSettings.GetApplicationIdentifier(BuildTargetGroup.Android);
|
||||
PlayerSettings.SetApplicationIdentifier(BuildTargetGroup.Android, "com.UnityTestRunner.UnityTestRunner");
|
||||
|
||||
m_oldDeviceSocketAddress = EditorUserBuildSettings.androidDeviceSocketAddress;
|
||||
var androidDeviceConnection = Environment.GetEnvironmentVariable("ANDROID_DEVICE_CONNECTION");
|
||||
EditorUserBuildSettings.waitForPlayerConnection = true;
|
||||
if (androidDeviceConnection != null)
|
||||
{
|
||||
EditorUserBuildSettings.androidDeviceSocketAddress = androidDeviceConnection;
|
||||
}
|
||||
m_Stripping = PlayerSettings.stripEngineCode;
|
||||
PlayerSettings.stripEngineCode = false;
|
||||
}
|
||||
|
||||
public void PostBuildAction()
|
||||
{
|
||||
PlayerSettings.stripEngineCode = m_Stripping;
|
||||
}
|
||||
|
||||
public void PostSuccessfulBuildAction()
|
||||
{
|
||||
}
|
||||
|
||||
public void PostSuccessfulLaunchAction()
|
||||
{
|
||||
var connectionResult = -1;
|
||||
var maxTryCount = 10;
|
||||
var tryCount = maxTryCount;
|
||||
while (tryCount-- > 0 && connectionResult == -1)
|
||||
{
|
||||
connectionResult = EditorConnectionInternal.ConnectPlayerProxy(IPAddress.Loopback.ToString(), 34999);
|
||||
if (EditorUtility.DisplayCancelableProgressBar("Editor Connection", "Connecting to the player",
|
||||
1 - ((float)tryCount / maxTryCount)))
|
||||
{
|
||||
EditorUtility.ClearProgressBar();
|
||||
throw new TestLaunchFailedException();
|
||||
}
|
||||
}
|
||||
EditorUtility.ClearProgressBar();
|
||||
if (connectionResult == -1)
|
||||
throw new TestLaunchFailedException(
|
||||
"Timed out trying to connect to the player. Player failed to launch or crashed soon after launching");
|
||||
}
|
||||
|
||||
public void CleanUp()
|
||||
{
|
||||
EditorUserBuildSettings.androidDeviceSocketAddress = m_oldDeviceSocketAddress;
|
||||
PlayerSettings.SetApplicationIdentifier(BuildTargetGroup.Android, m_oldApplicationIdentifier);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 961642509dec50b44a293d26240140ec
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,42 @@
|
|||
using System;
|
||||
using System.Diagnostics;
|
||||
using UnityEngine;
|
||||
|
||||
namespace UnityEditor.TestTools.TestRunner
|
||||
{
|
||||
[Serializable]
|
||||
internal class ApplePlatformSetup : IPlatformSetup
|
||||
{
|
||||
[SerializeField]
|
||||
private bool m_Stripping;
|
||||
|
||||
public ApplePlatformSetup(BuildTarget buildTarget)
|
||||
{
|
||||
}
|
||||
|
||||
public void Setup()
|
||||
{
|
||||
// Camera and fonts are stripped out and app crashes on iOS when test runner is trying to add a scene with... camera and text
|
||||
m_Stripping = PlayerSettings.stripEngineCode;
|
||||
PlayerSettings.stripEngineCode = false;
|
||||
}
|
||||
|
||||
public void PostBuildAction()
|
||||
{
|
||||
// Restoring player setting as early as possible
|
||||
PlayerSettings.stripEngineCode = m_Stripping;
|
||||
}
|
||||
|
||||
public void PostSuccessfulBuildAction()
|
||||
{
|
||||
}
|
||||
|
||||
public void PostSuccessfulLaunchAction()
|
||||
{
|
||||
}
|
||||
|
||||
public void CleanUp()
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: f6c189a159d3bde4c964cee562e508ea
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,11 @@
|
|||
namespace UnityEditor.TestTools.TestRunner
|
||||
{
|
||||
internal interface IPlatformSetup
|
||||
{
|
||||
void Setup();
|
||||
void PostBuildAction();
|
||||
void PostSuccessfulBuildAction();
|
||||
void PostSuccessfulLaunchAction();
|
||||
void CleanUp();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 9d614808f9add8a4f8e4860db2c7af0d
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,50 @@
|
|||
using System;
|
||||
using System.Threading;
|
||||
using UnityEngine;
|
||||
|
||||
namespace UnityEditor.TestTools.TestRunner
|
||||
{
|
||||
internal class LuminPlatformSetup : IPlatformSetup
|
||||
{
|
||||
private const string kDeviceAddress = "127.0.0.1";
|
||||
private const int kDevicePort = 55000;
|
||||
|
||||
public void Setup()
|
||||
{
|
||||
}
|
||||
|
||||
public void PostBuildAction()
|
||||
{
|
||||
}
|
||||
|
||||
public void PostSuccessfulBuildAction()
|
||||
{
|
||||
}
|
||||
|
||||
public void PostSuccessfulLaunchAction()
|
||||
{
|
||||
var connectionResult = -1;
|
||||
var maxTryCount = 100;
|
||||
var tryCount = maxTryCount;
|
||||
while (tryCount-- > 0 && connectionResult == -1)
|
||||
{
|
||||
Thread.Sleep(1000);
|
||||
connectionResult = EditorConnectionInternal.ConnectPlayerProxy(kDeviceAddress, kDevicePort);
|
||||
if (EditorUtility.DisplayCancelableProgressBar("Editor Connection", "Connecting to the player",
|
||||
1 - ((float)tryCount / maxTryCount)))
|
||||
{
|
||||
EditorUtility.ClearProgressBar();
|
||||
throw new TestLaunchFailedException();
|
||||
}
|
||||
}
|
||||
EditorUtility.ClearProgressBar();
|
||||
if (connectionResult == -1)
|
||||
throw new TestLaunchFailedException(
|
||||
"Timed out trying to connect to the player. Player failed to launch or crashed soon after launching");
|
||||
}
|
||||
|
||||
public void CleanUp()
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: c38ae0585d6a55042a2d678330689685
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,123 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
namespace UnityEditor.TestTools.TestRunner
|
||||
{
|
||||
[Serializable]
|
||||
internal class PlatformSpecificSetup
|
||||
{
|
||||
[SerializeField]
|
||||
private ApplePlatformSetup m_AppleiOSPlatformSetup = new ApplePlatformSetup(BuildTarget.iOS);
|
||||
[SerializeField]
|
||||
private ApplePlatformSetup m_AppleTvOSPlatformSetup = new ApplePlatformSetup(BuildTarget.tvOS);
|
||||
[SerializeField]
|
||||
private XboxOnePlatformSetup m_XboxOnePlatformSetup = new XboxOnePlatformSetup();
|
||||
[SerializeField]
|
||||
private AndroidPlatformSetup m_AndroidPlatformSetup = new AndroidPlatformSetup();
|
||||
[SerializeField]
|
||||
private SwitchPlatformSetup m_SwitchPlatformSetup = new SwitchPlatformSetup();
|
||||
#if UNITY_2019_3_OR_NEWER
|
||||
[SerializeField]
|
||||
private StadiaPlatformSetup m_StadiaPlatformSetup = new StadiaPlatformSetup();
|
||||
#endif
|
||||
[SerializeField]
|
||||
private UwpPlatformSetup m_UwpPlatformSetup = new UwpPlatformSetup();
|
||||
|
||||
[SerializeField]
|
||||
private LuminPlatformSetup m_LuminPlatformSetup = new LuminPlatformSetup();
|
||||
|
||||
|
||||
private IDictionary<BuildTarget, IPlatformSetup> m_SetupTypes;
|
||||
|
||||
[SerializeField]
|
||||
private BuildTarget m_Target;
|
||||
|
||||
public PlatformSpecificSetup()
|
||||
{
|
||||
}
|
||||
|
||||
public PlatformSpecificSetup(BuildTarget target)
|
||||
{
|
||||
m_Target = target;
|
||||
}
|
||||
|
||||
public void Setup()
|
||||
{
|
||||
var dictionary = GetSetup();
|
||||
|
||||
if (!dictionary.ContainsKey(m_Target))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
dictionary[m_Target].Setup();
|
||||
}
|
||||
|
||||
public void PostBuildAction()
|
||||
{
|
||||
var dictionary = GetSetup();
|
||||
|
||||
if (!dictionary.ContainsKey(m_Target))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
dictionary[m_Target].PostBuildAction();
|
||||
}
|
||||
|
||||
public void PostSuccessfulBuildAction()
|
||||
{
|
||||
var dictionary = GetSetup();
|
||||
|
||||
if (!dictionary.ContainsKey(m_Target))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
dictionary[m_Target].PostSuccessfulBuildAction();
|
||||
}
|
||||
|
||||
public void PostSuccessfulLaunchAction()
|
||||
{
|
||||
var dictionary = GetSetup();
|
||||
|
||||
if (!dictionary.ContainsKey(m_Target))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
dictionary[m_Target].PostSuccessfulLaunchAction();
|
||||
}
|
||||
|
||||
public void CleanUp()
|
||||
{
|
||||
var dictionary = GetSetup();
|
||||
|
||||
if (!dictionary.ContainsKey(m_Target))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
dictionary[m_Target].CleanUp();
|
||||
}
|
||||
|
||||
private IDictionary<BuildTarget, IPlatformSetup> GetSetup()
|
||||
{
|
||||
m_SetupTypes = new Dictionary<BuildTarget, IPlatformSetup>()
|
||||
{
|
||||
{BuildTarget.iOS, m_AppleiOSPlatformSetup},
|
||||
{BuildTarget.tvOS, m_AppleTvOSPlatformSetup},
|
||||
{BuildTarget.XboxOne, m_XboxOnePlatformSetup},
|
||||
{BuildTarget.Android, m_AndroidPlatformSetup},
|
||||
{BuildTarget.WSAPlayer, m_UwpPlatformSetup},
|
||||
{BuildTarget.Lumin, m_LuminPlatformSetup},
|
||||
#if UNITY_2019_3_OR_NEWER
|
||||
{BuildTarget.Stadia, m_StadiaPlatformSetup},
|
||||
#endif
|
||||
{BuildTarget.Switch, m_SwitchPlatformSetup}
|
||||
};
|
||||
return m_SetupTypes;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 6cccd50ebf7384242bda4d7bcb282ebf
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,25 @@
|
|||
namespace UnityEditor.TestTools.TestRunner
|
||||
{
|
||||
internal class StadiaPlatformSetup : IPlatformSetup
|
||||
{
|
||||
public void Setup()
|
||||
{
|
||||
}
|
||||
|
||||
public void PostBuildAction()
|
||||
{
|
||||
}
|
||||
|
||||
public void PostSuccessfulBuildAction()
|
||||
{
|
||||
}
|
||||
|
||||
public void PostSuccessfulLaunchAction()
|
||||
{
|
||||
}
|
||||
|
||||
public void CleanUp()
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: fa19b42bd3dc35e40a618448bd330270
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,41 @@
|
|||
namespace UnityEditor.TestTools.TestRunner
|
||||
{
|
||||
internal class SwitchPlatformSetup : IPlatformSetup
|
||||
{
|
||||
public void Setup()
|
||||
{
|
||||
EditorUserBuildSettings.switchCreateRomFile = true;
|
||||
EditorUserBuildSettings.switchNVNGraphicsDebugger = false;
|
||||
#if UNITY_2020_1_OR_NEWER
|
||||
EditorUserBuildSettings.switchNVNDrawValidation_Heavy = true; // catches more graphics errors
|
||||
#else
|
||||
EditorUserBuildSettings.switchNVNDrawValidation = true; // catches more graphics errors
|
||||
#endif
|
||||
EditorUserBuildSettings.development = true;
|
||||
EditorUserBuildSettings.switchRedirectWritesToHostMount = true;
|
||||
|
||||
// We can use these when more debugging is required:
|
||||
//EditorUserBuildSettings.switchNVNDrawValidation = false; // cannot be used with shader debug
|
||||
//EditorUserBuildSettings.switchNVNGraphicsDebugger = true;
|
||||
//EditorUserBuildSettings.switchNVNShaderDebugging = true;
|
||||
//EditorUserBuildSettings.switchCreateSolutionFile = true; // for shorter iteration time
|
||||
//EditorUserBuildSettings.allowDebugging = true; // managed debugger can be attached
|
||||
}
|
||||
|
||||
public void PostBuildAction()
|
||||
{
|
||||
}
|
||||
|
||||
public void PostSuccessfulBuildAction()
|
||||
{
|
||||
}
|
||||
|
||||
public void PostSuccessfulLaunchAction()
|
||||
{
|
||||
}
|
||||
|
||||
public void CleanUp()
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: adf7bea9401c1834380d55601add6cfb
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,52 @@
|
|||
using System;
|
||||
|
||||
namespace UnityEditor.TestTools.TestRunner
|
||||
{
|
||||
internal class UwpPlatformSetup : IPlatformSetup
|
||||
{
|
||||
private const string k_SettingsBuildConfiguration = "BuildConfiguration";
|
||||
private bool m_InternetClientServer;
|
||||
private bool m_PrivateNetworkClientServer;
|
||||
|
||||
public void Setup()
|
||||
{
|
||||
m_InternetClientServer = PlayerSettings.WSA.GetCapability(PlayerSettings.WSACapability.InternetClientServer);
|
||||
m_PrivateNetworkClientServer = PlayerSettings.WSA.GetCapability(PlayerSettings.WSACapability.PrivateNetworkClientServer);
|
||||
PlayerSettings.WSA.SetCapability(PlayerSettings.WSACapability.InternetClientServer, true);
|
||||
PlayerSettings.WSA.SetCapability(PlayerSettings.WSACapability.PrivateNetworkClientServer, true);
|
||||
|
||||
// This setting is initialized only when Window Store App is selected from the Build Settings window, and
|
||||
// is typically an empty strings when running tests via UTR on the command-line.
|
||||
bool wsaSettingNotInitialized = string.IsNullOrEmpty(EditorUserBuildSettings.wsaArchitecture);
|
||||
|
||||
// If WSA build settings aren't fully initialized or running from a build machine, specify a default build configuration.
|
||||
// Otherwise we can use the existing configuration specified by the user in Build Settings.
|
||||
if (!string.IsNullOrEmpty(Environment.GetEnvironmentVariable("UNITY_THISISABUILDMACHINE")) || wsaSettingNotInitialized)
|
||||
{
|
||||
EditorUserBuildSettings.wsaSubtarget = WSASubtarget.PC;
|
||||
EditorUserBuildSettings.wsaArchitecture = "x64";
|
||||
EditorUserBuildSettings.SetPlatformSettings(BuildPipeline.GetBuildTargetName(BuildTarget.WSAPlayer), k_SettingsBuildConfiguration, WSABuildType.Debug.ToString());
|
||||
EditorUserBuildSettings.wsaUWPBuildType = WSAUWPBuildType.ExecutableOnly;
|
||||
PlayerSettings.SetIl2CppCompilerConfiguration(BuildTargetGroup.WSA, Il2CppCompilerConfiguration.Debug);
|
||||
}
|
||||
}
|
||||
|
||||
public void PostBuildAction()
|
||||
{
|
||||
}
|
||||
|
||||
public void PostSuccessfulBuildAction()
|
||||
{
|
||||
}
|
||||
|
||||
public void PostSuccessfulLaunchAction()
|
||||
{
|
||||
}
|
||||
|
||||
public void CleanUp()
|
||||
{
|
||||
PlayerSettings.WSA.SetCapability(PlayerSettings.WSACapability.InternetClientServer, m_InternetClientServer);
|
||||
PlayerSettings.WSA.SetCapability(PlayerSettings.WSACapability.PrivateNetworkClientServer, m_PrivateNetworkClientServer);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 667c6ad86a0b7a548aaa5c287f2c2861
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,47 @@
|
|||
namespace UnityEditor.TestTools.TestRunner
|
||||
{
|
||||
internal class XboxOnePlatformSetup : IPlatformSetup
|
||||
{
|
||||
private XboxOneDeployMethod oldXboxOneDeployMethod;
|
||||
private XboxOneDeployDrive oldXboxOneDeployDrive;
|
||||
private string oldXboxOneAdditionalDebugPorts;
|
||||
|
||||
public void Setup()
|
||||
{
|
||||
oldXboxOneDeployMethod = EditorUserBuildSettings.xboxOneDeployMethod;
|
||||
oldXboxOneDeployDrive = EditorUserBuildSettings.xboxOneDeployDrive;
|
||||
oldXboxOneAdditionalDebugPorts = EditorUserBuildSettings.xboxOneAdditionalDebugPorts;
|
||||
|
||||
EditorUserBuildSettings.xboxOneDeployMethod = XboxOneDeployMethod.Package;
|
||||
EditorUserBuildSettings.xboxOneDeployDrive = XboxOneDeployDrive.Default;
|
||||
|
||||
// This causes the XboxOne post processing systems to open this port in your package manifest.
|
||||
// In addition it will open the ephemeral range for debug connections as well.
|
||||
// Failure to do this will cause connection problems.
|
||||
EditorUserBuildSettings.xboxOneAdditionalDebugPorts = "34999";
|
||||
}
|
||||
|
||||
public void PostBuildAction()
|
||||
{
|
||||
}
|
||||
|
||||
public void PostSuccessfulBuildAction()
|
||||
{
|
||||
}
|
||||
|
||||
public void PostSuccessfulLaunchAction()
|
||||
{
|
||||
}
|
||||
|
||||
public void CleanUp()
|
||||
{
|
||||
EditorUserBuildSettings.xboxOneDeployMethod = oldXboxOneDeployMethod;
|
||||
EditorUserBuildSettings.xboxOneDeployDrive = oldXboxOneDeployDrive;
|
||||
|
||||
// This causes the XboxOne post processing systems to open this port in your package manifest.
|
||||
// In addition it will open the ephemeral range for debug connections as well.
|
||||
// Failure to do this will cause connection problems.
|
||||
EditorUserBuildSettings.xboxOneAdditionalDebugPorts = oldXboxOneAdditionalDebugPorts;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: aed7ab02155e43341a2dbcb7bc17c160
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,255 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using NUnit.Framework.Internal.Filters;
|
||||
using UnityEditor;
|
||||
using UnityEditor.SceneManagement;
|
||||
using UnityEditor.TestRunner.TestLaunchers;
|
||||
using UnityEditor.TestTools.TestRunner.Api;
|
||||
using UnityEngine;
|
||||
using UnityEngine.SceneManagement;
|
||||
using UnityEngine.TestRunner.Utils;
|
||||
using UnityEngine.TestTools.TestRunner;
|
||||
using UnityEngine.TestTools.TestRunner.Callbacks;
|
||||
|
||||
namespace UnityEditor.TestTools.TestRunner
|
||||
{
|
||||
internal class TestLaunchFailedException : Exception
|
||||
{
|
||||
public TestLaunchFailedException() {}
|
||||
public TestLaunchFailedException(string message) : base(message) {}
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
internal class PlayerLauncher : RuntimeTestLauncherBase
|
||||
{
|
||||
private readonly PlaymodeTestsControllerSettings m_Settings;
|
||||
private readonly BuildTarget m_TargetPlatform;
|
||||
private ITestRunSettings m_OverloadTestRunSettings;
|
||||
private string m_SceneName;
|
||||
private int m_HeartbeatTimeout;
|
||||
|
||||
public PlayerLauncher(PlaymodeTestsControllerSettings settings, BuildTarget? targetPlatform, ITestRunSettings overloadTestRunSettings, int heartbeatTimeout)
|
||||
{
|
||||
m_Settings = settings;
|
||||
m_TargetPlatform = targetPlatform ?? EditorUserBuildSettings.activeBuildTarget;
|
||||
m_OverloadTestRunSettings = overloadTestRunSettings;
|
||||
m_HeartbeatTimeout = heartbeatTimeout;
|
||||
}
|
||||
|
||||
protected override RuntimePlatform? TestTargetPlatform
|
||||
{
|
||||
get { return BuildTargetConverter.TryConvertToRuntimePlatform(m_TargetPlatform); }
|
||||
}
|
||||
|
||||
public override void Run()
|
||||
{
|
||||
var editorConnectionTestCollector = RemoteTestRunController.instance;
|
||||
editorConnectionTestCollector.hideFlags = HideFlags.HideAndDontSave;
|
||||
editorConnectionTestCollector.Init(m_TargetPlatform, m_HeartbeatTimeout);
|
||||
|
||||
var remotePlayerLogController = RemotePlayerLogController.instance;
|
||||
remotePlayerLogController.hideFlags = HideFlags.HideAndDontSave;
|
||||
|
||||
using (var settings = new PlayerLauncherContextSettings(m_OverloadTestRunSettings))
|
||||
{
|
||||
m_SceneName = CreateSceneName();
|
||||
var scene = PrepareScene(m_SceneName);
|
||||
string scenePath = scene.path;
|
||||
|
||||
var filter = m_Settings.BuildNUnitFilter();
|
||||
var runner = LoadTests(filter);
|
||||
var exceptionThrown = ExecutePreBuildSetupMethods(runner.LoadedTest, filter);
|
||||
if (exceptionThrown)
|
||||
{
|
||||
ReopenOriginalScene(m_Settings.originalScene);
|
||||
AssetDatabase.DeleteAsset(m_SceneName);
|
||||
CallbacksDelegator.instance.RunFailed("Run Failed: One or more errors in a prebuild setup. See the editor log for details.");
|
||||
return;
|
||||
}
|
||||
|
||||
EditorSceneManager.MarkSceneDirty(scene);
|
||||
EditorSceneManager.SaveScene(scene);
|
||||
|
||||
var playerBuildOptions = GetBuildOptions(scenePath);
|
||||
|
||||
var success = BuildAndRunPlayer(playerBuildOptions);
|
||||
|
||||
editorConnectionTestCollector.PostBuildAction();
|
||||
ExecutePostBuildCleanupMethods(runner.LoadedTest, filter);
|
||||
|
||||
ReopenOriginalScene(m_Settings.originalScene);
|
||||
AssetDatabase.DeleteAsset(m_SceneName);
|
||||
|
||||
if (!success)
|
||||
{
|
||||
editorConnectionTestCollector.CleanUp();
|
||||
ScriptableObject.DestroyImmediate(editorConnectionTestCollector);
|
||||
Debug.LogError("Player build failed");
|
||||
throw new TestLaunchFailedException("Player build failed");
|
||||
}
|
||||
|
||||
if ((playerBuildOptions.BuildPlayerOptions.options & BuildOptions.AutoRunPlayer) != 0)
|
||||
{
|
||||
editorConnectionTestCollector.PostSuccessfulBuildAction();
|
||||
editorConnectionTestCollector.PostSuccessfulLaunchAction();
|
||||
}
|
||||
|
||||
var runSettings = m_OverloadTestRunSettings as PlayerLauncherTestRunSettings;
|
||||
if (success && runSettings != null && runSettings.buildOnly)
|
||||
{
|
||||
EditorUtility.RevealInFinder(playerBuildOptions.BuildPlayerOptions.locationPathName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public Scene PrepareScene(string sceneName)
|
||||
{
|
||||
var scene = CreateBootstrapScene(sceneName, runner =>
|
||||
{
|
||||
runner.AddEventHandlerMonoBehaviour<PlayModeRunnerCallback>();
|
||||
runner.settings = m_Settings;
|
||||
var commandLineArgs = Environment.GetCommandLineArgs();
|
||||
if (!commandLineArgs.Contains("-doNotReportTestResultsBackToEditor"))
|
||||
{
|
||||
runner.AddEventHandlerMonoBehaviour<RemoteTestResultSender>();
|
||||
}
|
||||
runner.AddEventHandlerMonoBehaviour<PlayerQuitHandler>();
|
||||
runner.AddEventHandlerScriptableObject<TestRunCallbackListener>();
|
||||
});
|
||||
return scene;
|
||||
}
|
||||
|
||||
private static bool BuildAndRunPlayer(PlayerLauncherBuildOptions buildOptions)
|
||||
{
|
||||
Debug.LogFormat(LogType.Log, LogOption.NoStacktrace, null, "Building player with following options:\n{0}", buildOptions);
|
||||
|
||||
|
||||
// Android has to be in listen mode to establish player connection
|
||||
if (buildOptions.BuildPlayerOptions.target == BuildTarget.Android)
|
||||
{
|
||||
buildOptions.BuildPlayerOptions.options &= ~BuildOptions.ConnectToHost;
|
||||
}
|
||||
|
||||
// For now, so does Lumin
|
||||
if (buildOptions.BuildPlayerOptions.target == BuildTarget.Lumin)
|
||||
{
|
||||
buildOptions.BuildPlayerOptions.options &= ~BuildOptions.ConnectToHost;
|
||||
}
|
||||
|
||||
var result = BuildPipeline.BuildPlayer(buildOptions.BuildPlayerOptions);
|
||||
if (result.summary.result != Build.Reporting.BuildResult.Succeeded)
|
||||
Debug.LogError(result.SummarizeErrors());
|
||||
|
||||
return result.summary.result == Build.Reporting.BuildResult.Succeeded;
|
||||
}
|
||||
|
||||
internal PlayerLauncherBuildOptions GetBuildOptions(string scenePath)
|
||||
{
|
||||
var buildOnly = false;
|
||||
var runSettings = m_OverloadTestRunSettings as PlayerLauncherTestRunSettings;
|
||||
if (runSettings != null)
|
||||
{
|
||||
buildOnly = runSettings.buildOnly;
|
||||
}
|
||||
|
||||
var buildOptions = new BuildPlayerOptions();
|
||||
|
||||
var scenes = new List<string>() { scenePath };
|
||||
scenes.AddRange(EditorBuildSettings.scenes.Select(x => x.path));
|
||||
buildOptions.scenes = scenes.ToArray();
|
||||
|
||||
buildOptions.options |= BuildOptions.Development | BuildOptions.ConnectToHost | BuildOptions.IncludeTestAssemblies | BuildOptions.StrictMode;
|
||||
buildOptions.target = m_TargetPlatform;
|
||||
|
||||
if (EditorUserBuildSettings.waitForPlayerConnection)
|
||||
buildOptions.options |= BuildOptions.WaitForPlayerConnection;
|
||||
|
||||
if (EditorUserBuildSettings.allowDebugging)
|
||||
buildOptions.options |= BuildOptions.AllowDebugging;
|
||||
|
||||
if (EditorUserBuildSettings.installInBuildFolder)
|
||||
buildOptions.options |= BuildOptions.InstallInBuildFolder;
|
||||
else if (!buildOnly)
|
||||
buildOptions.options |= BuildOptions.AutoRunPlayer;
|
||||
|
||||
var buildTargetGroup = EditorUserBuildSettings.activeBuildTargetGroup;
|
||||
|
||||
//Check if Lz4 is supported for the current buildtargetgroup and enable it if need be
|
||||
if (PostprocessBuildPlayer.SupportsLz4Compression(buildTargetGroup, m_TargetPlatform))
|
||||
{
|
||||
if (EditorUserBuildSettings.GetCompressionType(buildTargetGroup) == Compression.Lz4)
|
||||
buildOptions.options |= BuildOptions.CompressWithLz4;
|
||||
else if (EditorUserBuildSettings.GetCompressionType(buildTargetGroup) == Compression.Lz4HC)
|
||||
buildOptions.options |= BuildOptions.CompressWithLz4HC;
|
||||
}
|
||||
|
||||
string buildLocation;
|
||||
if (buildOnly)
|
||||
{
|
||||
buildLocation = buildOptions.locationPathName = runSettings.buildOnlyLocationPath;
|
||||
}
|
||||
else
|
||||
{
|
||||
var reduceBuildLocationPathLength = false;
|
||||
|
||||
//Some platforms hit MAX_PATH limits during the build process, in these cases minimize the path length
|
||||
if ((m_TargetPlatform == BuildTarget.WSAPlayer) || (m_TargetPlatform == BuildTarget.XboxOne))
|
||||
{
|
||||
reduceBuildLocationPathLength = true;
|
||||
}
|
||||
|
||||
var uniqueTempPathInProject = FileUtil.GetUniqueTempPathInProject();
|
||||
var playerDirectoryName = reduceBuildLocationPathLength ? "PwT" : "PlayerWithTests";
|
||||
|
||||
if (reduceBuildLocationPathLength)
|
||||
{
|
||||
uniqueTempPathInProject = Path.GetTempFileName();
|
||||
File.Delete(uniqueTempPathInProject);
|
||||
Directory.CreateDirectory(uniqueTempPathInProject);
|
||||
}
|
||||
|
||||
var tempPath = Path.GetFullPath(uniqueTempPathInProject);
|
||||
buildLocation = Path.Combine(tempPath, playerDirectoryName);
|
||||
|
||||
// iOS builds create a folder with Xcode project instead of an executable, therefore no executable name is added
|
||||
if (m_TargetPlatform == BuildTarget.iOS)
|
||||
{
|
||||
buildOptions.locationPathName = buildLocation;
|
||||
}
|
||||
else
|
||||
{
|
||||
string extensionForBuildTarget =
|
||||
PostprocessBuildPlayer.GetExtensionForBuildTarget(buildTargetGroup, buildOptions.target,
|
||||
buildOptions.options);
|
||||
var playerExecutableName = "PlayerWithTests";
|
||||
playerExecutableName += string.Format(".{0}", extensionForBuildTarget);
|
||||
buildOptions.locationPathName = Path.Combine(buildLocation, playerExecutableName);
|
||||
}
|
||||
}
|
||||
|
||||
return new PlayerLauncherBuildOptions
|
||||
{
|
||||
BuildPlayerOptions = ModifyBuildOptions(buildOptions),
|
||||
PlayerDirectory = buildLocation,
|
||||
};
|
||||
}
|
||||
|
||||
private BuildPlayerOptions ModifyBuildOptions(BuildPlayerOptions buildOptions)
|
||||
{
|
||||
var allAssemblies = AppDomain.CurrentDomain.GetAssemblies()
|
||||
.Where(x => x.GetReferencedAssemblies().Any(z => z.Name == "UnityEditor.TestRunner")).ToArray();
|
||||
var attributes = allAssemblies.SelectMany(assembly => assembly.GetCustomAttributes(typeof(TestPlayerBuildModifierAttribute), true).OfType<TestPlayerBuildModifierAttribute>()).ToArray();
|
||||
var modifiers = attributes.Select(attribute => attribute.ConstructModifier()).ToArray();
|
||||
|
||||
foreach (var modifier in modifiers)
|
||||
{
|
||||
buildOptions = modifier.ModifyOptions(buildOptions);
|
||||
}
|
||||
|
||||
return buildOptions;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: d973fc1524e4d724081553934c55958c
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,23 @@
|
|||
using System.Text;
|
||||
|
||||
namespace UnityEditor.TestTools.TestRunner
|
||||
{
|
||||
internal class PlayerLauncherBuildOptions
|
||||
{
|
||||
public BuildPlayerOptions BuildPlayerOptions;
|
||||
public string PlayerDirectory;
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
var str = new StringBuilder();
|
||||
str.AppendLine("locationPathName = " + BuildPlayerOptions.locationPathName);
|
||||
str.AppendLine("target = " + BuildPlayerOptions.target);
|
||||
str.AppendLine("scenes = " + string.Join(", ", BuildPlayerOptions.scenes));
|
||||
str.AppendLine("assetBundleManifestPath = " + BuildPlayerOptions.assetBundleManifestPath);
|
||||
str.AppendLine("options.Development = " + ((BuildPlayerOptions.options & BuildOptions.Development) != 0));
|
||||
str.AppendLine("options.AutoRunPlayer = " + ((BuildPlayerOptions.options & BuildOptions.AutoRunPlayer) != 0));
|
||||
str.AppendLine("options.ForceEnableAssertions = " + ((BuildPlayerOptions.options & BuildOptions.ForceEnableAssertions) != 0));
|
||||
return str.ToString();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 2a0bd678385f98e4d8eabdfc07d62b4f
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,113 @@
|
|||
using System;
|
||||
using System.IO;
|
||||
using UnityEditor.TestTools.TestRunner.Api;
|
||||
using UnityEngine;
|
||||
|
||||
namespace UnityEditor.TestTools.TestRunner
|
||||
{
|
||||
internal class PlayerLauncherContextSettings : IDisposable
|
||||
{
|
||||
private ITestRunSettings m_OverloadSettings;
|
||||
|
||||
private EditorBuildSettingsScene[] m_EditorBuildSettings;
|
||||
#pragma warning disable 618
|
||||
private ResolutionDialogSetting m_DisplayResolutionDialog;
|
||||
#pragma warning restore 618
|
||||
private bool m_RunInBackground;
|
||||
private FullScreenMode m_FullScreenMode;
|
||||
private bool m_ResizableWindow;
|
||||
private bool m_ShowUnitySplashScreen;
|
||||
private string m_OldproductName;
|
||||
private string m_OldAotOptions;
|
||||
#pragma warning disable 618
|
||||
private Lightmapping.GIWorkflowMode m_OldLightmapping;
|
||||
#pragma warning restore 618
|
||||
private bool m_explicitNullChecks;
|
||||
|
||||
private bool m_Disposed;
|
||||
|
||||
public PlayerLauncherContextSettings(ITestRunSettings overloadSettings)
|
||||
{
|
||||
m_OverloadSettings = overloadSettings;
|
||||
SetupProjectParameters();
|
||||
|
||||
if (overloadSettings != null)
|
||||
{
|
||||
overloadSettings.Apply();
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (!m_Disposed)
|
||||
{
|
||||
CleanupProjectParameters();
|
||||
if (m_OverloadSettings != null)
|
||||
{
|
||||
m_OverloadSettings.Dispose();
|
||||
}
|
||||
|
||||
m_Disposed = true;
|
||||
}
|
||||
}
|
||||
|
||||
private void SetupProjectParameters()
|
||||
{
|
||||
EditorApplication.LockReloadAssemblies();
|
||||
|
||||
m_EditorBuildSettings = EditorBuildSettings.scenes;
|
||||
|
||||
#pragma warning disable 618
|
||||
m_DisplayResolutionDialog = PlayerSettings.displayResolutionDialog;
|
||||
PlayerSettings.displayResolutionDialog = ResolutionDialogSetting.Disabled;
|
||||
#pragma warning restore 618
|
||||
|
||||
m_RunInBackground = PlayerSettings.runInBackground;
|
||||
PlayerSettings.runInBackground = true;
|
||||
|
||||
m_FullScreenMode = PlayerSettings.fullScreenMode;
|
||||
PlayerSettings.fullScreenMode = FullScreenMode.Windowed;
|
||||
|
||||
m_OldAotOptions = PlayerSettings.aotOptions;
|
||||
PlayerSettings.aotOptions = "nimt-trampolines=1024";
|
||||
|
||||
m_ResizableWindow = PlayerSettings.resizableWindow;
|
||||
PlayerSettings.resizableWindow = true;
|
||||
|
||||
m_ShowUnitySplashScreen = PlayerSettings.SplashScreen.show;
|
||||
PlayerSettings.SplashScreen.show = false;
|
||||
|
||||
m_OldproductName = PlayerSettings.productName;
|
||||
PlayerSettings.productName = string.Join("_", Application.productName.Split(Path.GetInvalidFileNameChars()));
|
||||
|
||||
#pragma warning disable 618
|
||||
m_OldLightmapping = Lightmapping.giWorkflowMode;
|
||||
Lightmapping.giWorkflowMode = Lightmapping.GIWorkflowMode.OnDemand;
|
||||
#pragma warning restore 618
|
||||
|
||||
m_explicitNullChecks = EditorUserBuildSettings.explicitNullChecks;
|
||||
EditorUserBuildSettings.explicitNullChecks = true;
|
||||
}
|
||||
|
||||
private void CleanupProjectParameters()
|
||||
{
|
||||
EditorBuildSettings.scenes = m_EditorBuildSettings;
|
||||
|
||||
PlayerSettings.fullScreenMode = m_FullScreenMode;
|
||||
PlayerSettings.runInBackground = m_RunInBackground;
|
||||
#pragma warning disable 618
|
||||
PlayerSettings.displayResolutionDialog = m_DisplayResolutionDialog;
|
||||
#pragma warning restore 618
|
||||
PlayerSettings.resizableWindow = m_ResizableWindow;
|
||||
PlayerSettings.SplashScreen.show = m_ShowUnitySplashScreen;
|
||||
PlayerSettings.productName = m_OldproductName;
|
||||
PlayerSettings.aotOptions = m_OldAotOptions;
|
||||
#pragma warning disable 618
|
||||
Lightmapping.giWorkflowMode = m_OldLightmapping;
|
||||
#pragma warning restore 618
|
||||
EditorUserBuildSettings.explicitNullChecks = m_explicitNullChecks;
|
||||
|
||||
EditorApplication.UnlockReloadAssemblies();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 6965880f76f40194593cb53a88f74005
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,19 @@
|
|||
using UnityEditor.TestTools.TestRunner.Api;
|
||||
|
||||
namespace UnityEditor.TestTools.TestRunner
|
||||
{
|
||||
class PlayerLauncherTestRunSettings : ITestRunSettings
|
||||
{
|
||||
public bool buildOnly { set; get; }
|
||||
|
||||
public string buildOnlyLocationPath { set; get; }
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
}
|
||||
|
||||
void ITestRunSettings.Apply()
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: c1cba6f3ed484514097080a3bb835958
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,133 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using NUnit.Framework.Interfaces;
|
||||
using NUnit.Framework.Internal.Filters;
|
||||
using UnityEditor.TestTools.TestRunner.Api;
|
||||
using UnityEngine;
|
||||
using UnityEngine.SceneManagement;
|
||||
using UnityEngine.TestRunner.Utils;
|
||||
using UnityEngine.TestTools.TestRunner;
|
||||
using UnityEngine.TestTools.TestRunner.Callbacks;
|
||||
|
||||
namespace UnityEditor.TestTools.TestRunner
|
||||
{
|
||||
internal class PlaymodeLauncher : RuntimeTestLauncherBase
|
||||
{
|
||||
public static bool IsRunning;
|
||||
private Scene m_Scene;
|
||||
private bool m_IsTestSetupPerformed;
|
||||
private readonly PlaymodeTestsControllerSettings m_Settings;
|
||||
private ITestFilter testFilter;
|
||||
|
||||
[SerializeField]
|
||||
private List<Type> m_EventHandlers = new List<Type>();
|
||||
|
||||
public PlaymodeLauncher(PlaymodeTestsControllerSettings settings)
|
||||
{
|
||||
m_Settings = settings;
|
||||
}
|
||||
|
||||
public override void Run()
|
||||
{
|
||||
IsRunning = true;
|
||||
ConsoleWindow.SetConsoleErrorPause(false);
|
||||
Application.runInBackground = true;
|
||||
|
||||
var sceneName = CreateSceneName();
|
||||
m_Scene = CreateBootstrapScene(sceneName, runner =>
|
||||
{
|
||||
runner.AddEventHandlerMonoBehaviour<PlayModeRunnerCallback>();
|
||||
runner.AddEventHandlerScriptableObject<TestRunnerCallback>();
|
||||
runner.AddEventHandlerScriptableObject<CallbacksDelegatorListener>();
|
||||
runner.AddEventHandlerScriptableObject<TestRunCallbackListener>();
|
||||
|
||||
foreach (var eventHandler in m_EventHandlers)
|
||||
{
|
||||
var obj = ScriptableObject.CreateInstance(eventHandler);
|
||||
runner.AddEventHandlerScriptableObject(obj as ITestRunnerListener);
|
||||
}
|
||||
|
||||
runner.settings = m_Settings;
|
||||
});
|
||||
|
||||
if (m_Settings.sceneBased)
|
||||
{
|
||||
var newListOfScenes =
|
||||
new List<EditorBuildSettingsScene> {new EditorBuildSettingsScene(sceneName, true)};
|
||||
newListOfScenes.AddRange(EditorBuildSettings.scenes);
|
||||
EditorBuildSettings.scenes = newListOfScenes.ToArray();
|
||||
}
|
||||
|
||||
EditorApplication.update += UpdateCallback;
|
||||
}
|
||||
|
||||
public void UpdateCallback()
|
||||
{
|
||||
if (m_IsTestSetupPerformed)
|
||||
{
|
||||
if (m_Scene.IsValid())
|
||||
SceneManager.SetActiveScene(m_Scene);
|
||||
EditorApplication.update -= UpdateCallback;
|
||||
EditorApplication.isPlaying = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
testFilter = m_Settings.BuildNUnitFilter();
|
||||
var runner = LoadTests(testFilter);
|
||||
|
||||
var exceptionThrown = ExecutePreBuildSetupMethods(runner.LoadedTest, testFilter);
|
||||
if (exceptionThrown)
|
||||
{
|
||||
EditorApplication.update -= UpdateCallback;
|
||||
IsRunning = false;
|
||||
var controller = PlaymodeTestsController.GetController();
|
||||
ReopenOriginalScene(controller);
|
||||
AssetDatabase.DeleteAsset(controller.settings.bootstrapScene);
|
||||
CallbacksDelegator.instance.RunFailed("Run Failed: One or more errors in a prebuild setup. See the editor log for details.");
|
||||
return;
|
||||
}
|
||||
m_IsTestSetupPerformed = true;
|
||||
}
|
||||
}
|
||||
|
||||
[InitializeOnLoad]
|
||||
public class BackgroundWatcher
|
||||
{
|
||||
static BackgroundWatcher()
|
||||
{
|
||||
EditorApplication.playModeStateChanged += OnPlayModeStateChanged;
|
||||
}
|
||||
|
||||
private static void OnPlayModeStateChanged(PlayModeStateChange state)
|
||||
{
|
||||
if (!PlaymodeTestsController.IsControllerOnScene())
|
||||
return;
|
||||
var runner = PlaymodeTestsController.GetController();
|
||||
if (runner == null)
|
||||
return;
|
||||
if (state == PlayModeStateChange.ExitingPlayMode)
|
||||
{
|
||||
AssetDatabase.DeleteAsset(runner.settings.bootstrapScene);
|
||||
ExecutePostBuildCleanupMethods(runner.m_Runner.LoadedTest, runner.settings.BuildNUnitFilter(), Application.platform);
|
||||
IsRunning = false;
|
||||
}
|
||||
else if (state == PlayModeStateChange.EnteredEditMode)
|
||||
{
|
||||
//reopen the original scene once we exit playmode
|
||||
ReopenOriginalScene(runner);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected static void ReopenOriginalScene(PlaymodeTestsController runner)
|
||||
{
|
||||
ReopenOriginalScene(runner.settings.originalScene);
|
||||
}
|
||||
|
||||
public void AddEventHandler<T>() where T : ScriptableObject, ITestRunnerListener
|
||||
{
|
||||
m_EventHandlers.Add(typeof(T));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: d3217d58bbd1d2b4aaee933e2e8b9195
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,9 @@
|
|||
using UnityEngine.TestTools;
|
||||
|
||||
namespace UnityEditor.TestTools.TestRunner
|
||||
{
|
||||
internal class PostbuildCleanupAttributeFinder : AttributeFinderBase<IPostBuildCleanup, PostBuildCleanupAttribute>
|
||||
{
|
||||
public PostbuildCleanupAttributeFinder() : base(attribute => attribute.TargetClass) {}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 2c2dfcbbb77359547bcaa7cdabd47ebb
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,9 @@
|
|||
using UnityEngine.TestTools;
|
||||
|
||||
namespace UnityEditor.TestTools.TestRunner
|
||||
{
|
||||
internal class PrebuildSetupAttributeFinder : AttributeFinderBase<IPrebuildSetup, PrebuildSetupAttribute>
|
||||
{
|
||||
public PrebuildSetupAttributeFinder() : base((attribute) => attribute.TargetClass) {}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 3c4ccfb0896bcf44da13e152b267aa49
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,89 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UnityEditor.DeploymentTargets;
|
||||
using UnityEditor.TestTools.TestRunner.CommandLineTest;
|
||||
using UnityEngine;
|
||||
|
||||
namespace UnityEditor.TestRunner.TestLaunchers
|
||||
{
|
||||
[Serializable]
|
||||
internal class RemotePlayerLogController : ScriptableSingleton<RemotePlayerLogController>
|
||||
{
|
||||
private List<LogWriter> m_LogWriters;
|
||||
|
||||
private Dictionary<string, DeploymentTargetLogger> m_Loggers;
|
||||
|
||||
private string m_DeviceLogsDirectory;
|
||||
|
||||
public void SetBuildTarget(BuildTarget buildTarget)
|
||||
{
|
||||
m_Loggers = GetDeploymentTargetLoggers(buildTarget);
|
||||
|
||||
if (m_Loggers == null)
|
||||
Debug.Log("Deployment target logger could not be created");
|
||||
}
|
||||
|
||||
public void SetLogsDirectory(string dir)
|
||||
{
|
||||
m_DeviceLogsDirectory = dir;
|
||||
}
|
||||
|
||||
public void StartLogWriters()
|
||||
{
|
||||
if (m_DeviceLogsDirectory == null || m_Loggers == null)
|
||||
return;
|
||||
|
||||
m_LogWriters = new List<LogWriter>();
|
||||
|
||||
foreach (var logger in m_Loggers)
|
||||
{
|
||||
m_LogWriters.Add(new LogWriter(m_DeviceLogsDirectory, logger.Key, logger.Value));
|
||||
logger.Value.Start();
|
||||
}
|
||||
}
|
||||
|
||||
public void StopLogWriters()
|
||||
{
|
||||
if (m_LogWriters == null)
|
||||
return;
|
||||
|
||||
foreach (var logWriter in m_LogWriters)
|
||||
{
|
||||
logWriter.Stop();
|
||||
}
|
||||
}
|
||||
|
||||
private Dictionary<string, DeploymentTargetLogger> GetDeploymentTargetLoggers(BuildTarget buildTarget)
|
||||
{
|
||||
DeploymentTargetManager deploymentTargetManager;
|
||||
|
||||
try
|
||||
{
|
||||
deploymentTargetManager = DeploymentTargetManager.CreateInstance(EditorUserBuildSettings.activeBuildTargetGroup, buildTarget);
|
||||
|
||||
if (deploymentTargetManager == null)
|
||||
return null;
|
||||
}
|
||||
catch (NotSupportedException ex)
|
||||
{
|
||||
Debug.Log(ex.Message);
|
||||
Debug.Log("Deployment target logger not initialised");
|
||||
return null;
|
||||
}
|
||||
|
||||
var targets = deploymentTargetManager.GetKnownTargets();
|
||||
var loggers = new Dictionary<string, DeploymentTargetLogger>();
|
||||
|
||||
foreach (var target in targets)
|
||||
{
|
||||
if (target.status != DeploymentTargetStatus.Ready) continue;
|
||||
|
||||
var logger = deploymentTargetManager.GetTargetLogger(target.id);
|
||||
logger.Clear();
|
||||
loggers.Add(target.id, logger);
|
||||
}
|
||||
|
||||
return loggers;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: edd2a1fe1acbbde43aad39862bb3f4a8
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,115 @@
|
|||
using System;
|
||||
using UnityEditor.Networking.PlayerConnection;
|
||||
using UnityEditor.TestTools.TestRunner;
|
||||
using UnityEditor.TestTools.TestRunner.Api;
|
||||
using UnityEditor.TestTools.TestRunner.UnityTestProtocol;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Networking.PlayerConnection;
|
||||
using UnityEngine.TestRunner.TestLaunchers;
|
||||
|
||||
namespace UnityEditor.TestRunner.TestLaunchers
|
||||
{
|
||||
[Serializable]
|
||||
internal class RemoteTestRunController : ScriptableSingleton<RemoteTestRunController>
|
||||
{
|
||||
internal const int k_HeartbeatTimeout = 60 * 10;
|
||||
|
||||
[SerializeField]
|
||||
private RemoteTestResultReciever m_RemoteTestResultReciever;
|
||||
|
||||
[SerializeField]
|
||||
private PlatformSpecificSetup m_PlatformSpecificSetup;
|
||||
|
||||
[SerializeField]
|
||||
private bool m_RegisteredConnectionCallbacks;
|
||||
|
||||
[SerializeField]
|
||||
private int m_HearbeatTimeOut;
|
||||
|
||||
private UnityEditor.TestTools.TestRunner.DelayedCallback m_TimeoutCallback;
|
||||
|
||||
public void Init(BuildTarget buildTarget, int heartbeatTimeout)
|
||||
{
|
||||
m_HearbeatTimeOut = heartbeatTimeout;
|
||||
m_PlatformSpecificSetup = new PlatformSpecificSetup(buildTarget);
|
||||
m_PlatformSpecificSetup.Setup();
|
||||
m_RemoteTestResultReciever = new RemoteTestResultReciever();
|
||||
EditorConnection.instance.Initialize();
|
||||
if (!m_RegisteredConnectionCallbacks)
|
||||
{
|
||||
EditorConnection.instance.Initialize();
|
||||
DelegateEditorConnectionEvents();
|
||||
}
|
||||
}
|
||||
|
||||
private void DelegateEditorConnectionEvents()
|
||||
{
|
||||
m_RegisteredConnectionCallbacks = true;
|
||||
//This is needed because RemoteTestResultReceiver is not a ScriptableObject
|
||||
EditorConnection.instance.Register(PlayerConnectionMessageIds.runStartedMessageId, RunStarted);
|
||||
EditorConnection.instance.Register(PlayerConnectionMessageIds.runFinishedMessageId, RunFinished);
|
||||
EditorConnection.instance.Register(PlayerConnectionMessageIds.testStartedMessageId, TestStarted);
|
||||
EditorConnection.instance.Register(PlayerConnectionMessageIds.testFinishedMessageId, TestFinished);
|
||||
EditorConnection.instance.Register(PlayerConnectionMessageIds.playerAliveHeartbeat, PlayerAliveHeartbeat);
|
||||
}
|
||||
|
||||
private void RunStarted(MessageEventArgs messageEventArgs)
|
||||
{
|
||||
m_TimeoutCallback?.Reset();
|
||||
m_RemoteTestResultReciever.RunStarted(messageEventArgs);
|
||||
CallbacksDelegator.instance.RunStartedRemotely(messageEventArgs.data);
|
||||
}
|
||||
|
||||
private void RunFinished(MessageEventArgs messageEventArgs)
|
||||
{
|
||||
m_TimeoutCallback?.Clear();
|
||||
m_RemoteTestResultReciever.RunFinished(messageEventArgs);
|
||||
m_PlatformSpecificSetup.CleanUp();
|
||||
|
||||
CallbacksDelegator.instance.RunFinishedRemotely(messageEventArgs.data);
|
||||
}
|
||||
|
||||
private void TestStarted(MessageEventArgs messageEventArgs)
|
||||
{
|
||||
m_TimeoutCallback?.Reset();
|
||||
CallbacksDelegator.instance.TestStartedRemotely(messageEventArgs.data);
|
||||
}
|
||||
|
||||
private void TestFinished(MessageEventArgs messageEventArgs)
|
||||
{
|
||||
m_TimeoutCallback?.Reset();
|
||||
CallbacksDelegator.instance.TestFinishedRemotely(messageEventArgs.data);
|
||||
}
|
||||
|
||||
private void PlayerAliveHeartbeat(MessageEventArgs messageEventArgs)
|
||||
{
|
||||
m_TimeoutCallback?.Reset();
|
||||
}
|
||||
|
||||
private void TimeoutCallback()
|
||||
{
|
||||
CallbacksDelegator.instance.RunFailed($"Test execution timed out. No activity received from the player in {m_HearbeatTimeOut} seconds.");
|
||||
}
|
||||
|
||||
public void PostBuildAction()
|
||||
{
|
||||
m_PlatformSpecificSetup.PostBuildAction();
|
||||
}
|
||||
|
||||
public void PostSuccessfulBuildAction()
|
||||
{
|
||||
m_PlatformSpecificSetup.PostSuccessfulBuildAction();
|
||||
m_TimeoutCallback = new UnityEditor.TestTools.TestRunner.DelayedCallback(TimeoutCallback, m_HearbeatTimeOut);
|
||||
}
|
||||
|
||||
public void PostSuccessfulLaunchAction()
|
||||
{
|
||||
m_PlatformSpecificSetup.PostSuccessfulLaunchAction();
|
||||
}
|
||||
|
||||
public void CleanUp()
|
||||
{
|
||||
m_PlatformSpecificSetup.CleanUp();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 7d36034e63ad8254b9b2f55280fcc040
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,22 @@
|
|||
using System;
|
||||
using UnityEditor.Networking.PlayerConnection;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Networking.PlayerConnection;
|
||||
using UnityEngine.TestRunner.TestLaunchers;
|
||||
|
||||
namespace UnityEditor.TestTools.TestRunner
|
||||
{
|
||||
[Serializable]
|
||||
internal class RemoteTestResultReciever
|
||||
{
|
||||
public void RunStarted(MessageEventArgs messageEventArgs)
|
||||
{
|
||||
}
|
||||
|
||||
public void RunFinished(MessageEventArgs messageEventArgs)
|
||||
{
|
||||
EditorConnection.instance.Send(PlayerConnectionMessageIds.quitPlayerMessageId, null, messageEventArgs.playerId);
|
||||
EditorConnection.instance.DisconnectAll();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: fdb35ef8fc437e14fa4b6c74a0609e86
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,92 @@
|
|||
using System;
|
||||
using System.Linq;
|
||||
using NUnit.Framework.Interfaces;
|
||||
using UnityEditor.Events;
|
||||
using UnityEditor.SceneManagement;
|
||||
using UnityEngine;
|
||||
using UnityEngine.SceneManagement;
|
||||
using UnityEngine.TestRunner.NUnitExtensions.Runner;
|
||||
using UnityEngine.TestTools;
|
||||
using UnityEngine.TestTools.NUnitExtensions;
|
||||
using UnityEngine.TestTools.TestRunner;
|
||||
using UnityEngine.TestTools.Utils;
|
||||
|
||||
namespace UnityEditor.TestTools.TestRunner
|
||||
{
|
||||
internal abstract class RuntimeTestLauncherBase : TestLauncherBase
|
||||
{
|
||||
protected Scene CreateBootstrapScene(string sceneName, Action<PlaymodeTestsController> runnerSetup)
|
||||
{
|
||||
var scene = EditorSceneManager.NewScene(NewSceneSetup.EmptyScene, NewSceneMode.Single);
|
||||
var go = new GameObject(PlaymodeTestsController.kPlaymodeTestControllerName);
|
||||
|
||||
var editorLoadedTestAssemblyProvider = new EditorLoadedTestAssemblyProvider(new EditorCompilationInterfaceProxy(), new EditorAssembliesProxy());
|
||||
|
||||
var runner = go.AddComponent<PlaymodeTestsController>();
|
||||
runnerSetup(runner);
|
||||
runner.settings.bootstrapScene = sceneName;
|
||||
runner.AssembliesWithTests = editorLoadedTestAssemblyProvider.GetAssembliesGroupedByType(TestPlatform.PlayMode).Select(x => x.Assembly.GetName().Name).ToList();
|
||||
|
||||
EditorSceneManager.MarkSceneDirty(scene);
|
||||
AssetDatabase.SaveAssets();
|
||||
EditorSceneManager.SaveScene(scene, sceneName, false);
|
||||
|
||||
return scene;
|
||||
}
|
||||
|
||||
public string CreateSceneName()
|
||||
{
|
||||
return "Assets/InitTestScene" + DateTime.Now.Ticks + ".unity";
|
||||
}
|
||||
|
||||
protected UnityTestAssemblyRunner LoadTests(ITestFilter filter)
|
||||
{
|
||||
var editorLoadedTestAssemblyProvider = new EditorLoadedTestAssemblyProvider(new EditorCompilationInterfaceProxy(), new EditorAssembliesProxy());
|
||||
var assembliesWithTests = editorLoadedTestAssemblyProvider.GetAssembliesGroupedByType(TestPlatform.PlayMode).Select(x => x.Assembly.GetName().Name).ToList();
|
||||
|
||||
var nUnitTestAssemblyRunner = new UnityTestAssemblyRunner(new UnityTestAssemblyBuilder(), null);
|
||||
var assemblyProvider = new PlayerTestAssemblyProvider(new AssemblyLoadProxy(), assembliesWithTests);
|
||||
nUnitTestAssemblyRunner.Load(assemblyProvider.GetUserAssemblies().Select(a => a.Assembly).ToArray(), TestPlatform.PlayMode, UnityTestAssemblyBuilder.GetNUnitTestBuilderSettings(TestPlatform.PlayMode));
|
||||
return nUnitTestAssemblyRunner;
|
||||
}
|
||||
|
||||
protected static void ReopenOriginalScene(string originalSceneName)
|
||||
{
|
||||
EditorSceneManager.NewScene(NewSceneSetup.DefaultGameObjects);
|
||||
if (!string.IsNullOrEmpty(originalSceneName))
|
||||
{
|
||||
EditorSceneManager.OpenScene(originalSceneName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal static class PlaymodeTestsControllerExtensions
|
||||
{
|
||||
internal static T AddEventHandlerMonoBehaviour<T>(this PlaymodeTestsController controller) where T : MonoBehaviour, ITestRunnerListener
|
||||
{
|
||||
var eventHandler = controller.gameObject.AddComponent<T>();
|
||||
SetListeners(controller, eventHandler);
|
||||
return eventHandler;
|
||||
}
|
||||
|
||||
internal static T AddEventHandlerScriptableObject<T>(this PlaymodeTestsController controller) where T : ScriptableObject, ITestRunnerListener
|
||||
{
|
||||
var eventListener = ScriptableObject.CreateInstance<T>();
|
||||
AddEventHandlerScriptableObject(controller, eventListener);
|
||||
return eventListener;
|
||||
}
|
||||
|
||||
internal static void AddEventHandlerScriptableObject(this PlaymodeTestsController controller, ITestRunnerListener obj)
|
||||
{
|
||||
SetListeners(controller, obj);
|
||||
}
|
||||
|
||||
private static void SetListeners(PlaymodeTestsController controller, ITestRunnerListener eventHandler)
|
||||
{
|
||||
UnityEventTools.AddPersistentListener(controller.testStartedEvent, eventHandler.TestStarted);
|
||||
UnityEventTools.AddPersistentListener(controller.testFinishedEvent, eventHandler.TestFinished);
|
||||
UnityEventTools.AddPersistentListener(controller.runStartedEvent, eventHandler.RunStarted);
|
||||
UnityEventTools.AddPersistentListener(controller.runFinishedEvent, eventHandler.RunFinished);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 0efb23ecb373b6d4bbe5217485785138
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,92 @@
|
|||
using System;
|
||||
using System.Linq;
|
||||
using NUnit.Framework.Interfaces;
|
||||
using Unity.Profiling;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Profiling;
|
||||
using UnityEngine.TestTools;
|
||||
using UnityEngine.TestTools.Logging;
|
||||
using UnityEngine.TestTools.TestRunner;
|
||||
|
||||
namespace UnityEditor.TestTools.TestRunner
|
||||
{
|
||||
internal abstract class TestLauncherBase
|
||||
{
|
||||
public abstract void Run();
|
||||
|
||||
protected virtual RuntimePlatform? TestTargetPlatform
|
||||
{
|
||||
get { return Application.platform; }
|
||||
}
|
||||
|
||||
protected bool ExecutePreBuildSetupMethods(ITest tests, ITestFilter testRunnerFilter)
|
||||
{
|
||||
using (new ProfilerMarker(nameof(ExecutePreBuildSetupMethods)).Auto()) {
|
||||
var attributeFinder = new PrebuildSetupAttributeFinder();
|
||||
var logString = "Executing setup for: {0}";
|
||||
return ExecuteMethods<IPrebuildSetup>(tests, testRunnerFilter, attributeFinder, logString, targetClass => targetClass.Setup(), TestTargetPlatform);
|
||||
}
|
||||
}
|
||||
|
||||
public void ExecutePostBuildCleanupMethods(ITest tests, ITestFilter testRunnerFilter)
|
||||
{
|
||||
using (new ProfilerMarker(nameof(ExecutePostBuildCleanupMethods)).Auto())
|
||||
ExecutePostBuildCleanupMethods(tests, testRunnerFilter, TestTargetPlatform);
|
||||
}
|
||||
|
||||
public static void ExecutePostBuildCleanupMethods(ITest tests, ITestFilter testRunnerFilter, RuntimePlatform? testTargetPlatform)
|
||||
{
|
||||
using (new ProfilerMarker(nameof(ExecutePostBuildCleanupMethods)).Auto()) {
|
||||
var attributeFinder = new PostbuildCleanupAttributeFinder();
|
||||
var logString = "Executing cleanup for: {0}";
|
||||
ExecuteMethods<IPostBuildCleanup>(tests, testRunnerFilter, attributeFinder, logString, targetClass => targetClass.Cleanup(), testTargetPlatform);
|
||||
}
|
||||
}
|
||||
|
||||
private static bool ExecuteMethods<T>(ITest tests, ITestFilter testRunnerFilter, AttributeFinderBase attributeFinder, string logString, Action<T> action, RuntimePlatform? testTargetPlatform)
|
||||
{
|
||||
var exceptionsThrown = false;
|
||||
|
||||
if (testTargetPlatform == null)
|
||||
{
|
||||
Debug.LogError("Could not determine test target platform from build target " + EditorUserBuildSettings.activeBuildTarget);
|
||||
return true;
|
||||
}
|
||||
|
||||
foreach (var targetClassType in attributeFinder.Search(tests, testRunnerFilter, testTargetPlatform.Value))
|
||||
{
|
||||
try
|
||||
{
|
||||
var targetClass = (T)Activator.CreateInstance(targetClassType);
|
||||
|
||||
Debug.LogFormat(logString, targetClassType.FullName);
|
||||
|
||||
using (var logScope = new LogScope())
|
||||
{
|
||||
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 (InvalidCastException) {}
|
||||
catch (Exception e)
|
||||
{
|
||||
Debug.LogException(e);
|
||||
exceptionsThrown = true;
|
||||
}
|
||||
}
|
||||
|
||||
return exceptionsThrown;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 1cddf785b0d07434d8e0607c97b09135
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
Loading…
Add table
Add a link
Reference in a new issue