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,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);
}
}
}

View file

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

View file

@ -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;
}
}
}
}

View file

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: b9d121df8c444236a5b38ccfadfdd1a7
timeCreated: 1583140472

View file

@ -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>();
}
}
}

View file

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

View file

@ -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;
}
}
}

View file

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

View file

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

View file

@ -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);
}
}
}

View file

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

View file

@ -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()
{
}
}
}

View file

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

View file

@ -0,0 +1,11 @@
namespace UnityEditor.TestTools.TestRunner
{
internal interface IPlatformSetup
{
void Setup();
void PostBuildAction();
void PostSuccessfulBuildAction();
void PostSuccessfulLaunchAction();
void CleanUp();
}
}

View file

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

View file

@ -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()
{
}
}
}

View file

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

View file

@ -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;
}
}
}

View file

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

View file

@ -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()
{
}
}
}

View file

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

View file

@ -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()
{
}
}
}

View file

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

View file

@ -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);
}
}
}

View file

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

View file

@ -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;
}
}
}

View file

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

View file

@ -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;
}
}
}

View file

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

View file

@ -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();
}
}
}

View file

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

View file

@ -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();
}
}
}

View file

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

View file

@ -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()
{
}
}
}

View file

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

View file

@ -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));
}
}
}

View file

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

View file

@ -0,0 +1,9 @@
using UnityEngine.TestTools;
namespace UnityEditor.TestTools.TestRunner
{
internal class PostbuildCleanupAttributeFinder : AttributeFinderBase<IPostBuildCleanup, PostBuildCleanupAttribute>
{
public PostbuildCleanupAttributeFinder() : base(attribute => attribute.TargetClass) {}
}
}

View file

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

View file

@ -0,0 +1,9 @@
using UnityEngine.TestTools;
namespace UnityEditor.TestTools.TestRunner
{
internal class PrebuildSetupAttributeFinder : AttributeFinderBase<IPrebuildSetup, PrebuildSetupAttribute>
{
public PrebuildSetupAttributeFinder() : base((attribute) => attribute.TargetClass) {}
}
}

View file

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

View file

@ -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;
}
}
}

View file

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

View file

@ -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();
}
}
}

View file

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

View file

@ -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();
}
}
}

View file

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

View file

@ -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);
}
}
}

View file

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

View file

@ -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;
}
}
}

View file

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