initial project folder

This commit is contained in:
ToAallonranta
2020-01-29 10:05:38 +02:00
parent e6d2f9b9ca
commit 837543ed9a
3804 changed files with 100819 additions and 0 deletions

View File

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

View File

@ -0,0 +1,116 @@
using System;
using System.Linq;
using System.Text;
using NUnit.Framework.Interfaces;
using NUnit.Framework.Internal;
using UnityEngine;
using UnityEngine.TestRunner.TestLaunchers;
namespace UnityEditor.TestTools.TestRunner.Api
{
internal class CallbacksDelegator
{
private static CallbacksDelegator s_instance;
public static CallbacksDelegator instance
{
get
{
if (s_instance == null)
{
s_instance = new CallbacksDelegator(CallbacksHolder.instance.GetAll, new TestAdaptorFactory());
}
return s_instance;
}
}
private readonly Func<ICallbacks[]> m_CallbacksProvider;
private readonly ITestAdaptorFactory m_AdaptorFactory;
public CallbacksDelegator(Func<ICallbacks[]> callbacksProvider, ITestAdaptorFactory adaptorFactory)
{
m_CallbacksProvider = callbacksProvider;
m_AdaptorFactory = adaptorFactory;
}
public void RunStarted(ITest testsToRun)
{
var testRunnerTestsToRun = m_AdaptorFactory.Create(testsToRun);
TryInvokeAllCallbacks(callbacks => callbacks.RunStarted(testRunnerTestsToRun));
}
public void RunStartedRemotely(byte[] testsToRunData)
{
var testData = Deserialize<RemoteTestResultDataWithTestData>(testsToRunData);
var testsToRun = m_AdaptorFactory.BuildTree(testData);
TryInvokeAllCallbacks(callbacks => callbacks.RunStarted(testsToRun));
}
public void RunFinished(ITestResult testResults)
{
var testResult = m_AdaptorFactory.Create(testResults);
TryInvokeAllCallbacks(callbacks => callbacks.RunFinished(testResult));
}
public void RunFinishedRemotely(byte[] testResultsData)
{
var remoteTestResult = Deserialize<RemoteTestResultDataWithTestData>(testResultsData);
var testResult = m_AdaptorFactory.Create(remoteTestResult.results.First(), remoteTestResult);
TryInvokeAllCallbacks(callbacks => callbacks.RunFinished(testResult));
}
public void RunFailed(string failureMessage)
{
var nunitTestResult = new TestSuiteResult(new TestSuite("test"));
nunitTestResult.SetResult(ResultState.Error, failureMessage);
var testResult = m_AdaptorFactory.Create(nunitTestResult);
TryInvokeAllCallbacks(callbacks => callbacks.RunFinished(testResult));
}
public void TestStarted(ITest test)
{
var testRunnerTest = m_AdaptorFactory.Create(test);
TryInvokeAllCallbacks(callbacks => callbacks.TestStarted(testRunnerTest));
}
public void TestStartedRemotely(byte[] testStartedData)
{
var testData = Deserialize<RemoteTestResultDataWithTestData>(testStartedData);
var testsToRun = m_AdaptorFactory.BuildTree(testData);
TryInvokeAllCallbacks(callbacks => callbacks.TestStarted(testsToRun));
}
public void TestFinished(ITestResult result)
{
var testResult = m_AdaptorFactory.Create(result);
TryInvokeAllCallbacks(callbacks => callbacks.TestFinished(testResult));
}
public void TestFinishedRemotely(byte[] testResultsData)
{
var remoteTestResult = Deserialize<RemoteTestResultDataWithTestData>(testResultsData);
var testResult = m_AdaptorFactory.Create(remoteTestResult.results.First(), remoteTestResult);
TryInvokeAllCallbacks(callbacks => callbacks.TestFinished(testResult));
}
private void TryInvokeAllCallbacks(Action<ICallbacks> callbackAction)
{
foreach (var testRunnerApiCallback in m_CallbacksProvider())
{
try
{
callbackAction(testRunnerApiCallback);
}
catch (Exception ex)
{
Debug.LogException(ex);
}
}
}
private static T Deserialize<T>(byte[] data)
{
return JsonUtility.FromJson<T>(Encoding.UTF8.GetString(data));
}
}
}

View File

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

View File

@ -0,0 +1,28 @@
using UnityEngine;
using UnityEngine.TestTools.TestRunner;
namespace UnityEditor.TestTools.TestRunner.Api
{
internal class CallbacksDelegatorListener : ScriptableObject, ITestRunnerListener
{
public void RunStarted(NUnit.Framework.Interfaces.ITest testsToRun)
{
CallbacksDelegator.instance.RunStarted(testsToRun);
}
public void RunFinished(NUnit.Framework.Interfaces.ITestResult testResults)
{
CallbacksDelegator.instance.RunFinished(testResults);
}
public void TestStarted(NUnit.Framework.Interfaces.ITest test)
{
CallbacksDelegator.instance.TestStarted(test);
}
public void TestFinished(NUnit.Framework.Interfaces.ITestResult result)
{
CallbacksDelegator.instance.TestFinished(result);
}
}
}

View File

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

View File

@ -0,0 +1,40 @@
using System.Collections.Generic;
using System.Linq;
namespace UnityEditor.TestTools.TestRunner.Api
{
internal class CallbacksHolder : ScriptableSingleton<CallbacksHolder>
{
private List<CallbackWithPriority> m_Callbacks = new List<CallbackWithPriority>();
public void Add(ICallbacks callback, int priority)
{
m_Callbacks.Add(new CallbackWithPriority(callback, priority));
}
public void Remove(ICallbacks callback)
{
m_Callbacks.RemoveAll(callbackWithPriority => callbackWithPriority.Callback == callback);
}
public ICallbacks[] GetAll()
{
return m_Callbacks.OrderByDescending(callback => callback.Priority).Select(callback => callback.Callback).ToArray();
}
public void Clear()
{
m_Callbacks.Clear();
}
private struct CallbackWithPriority
{
public ICallbacks Callback;
public int Priority;
public CallbackWithPriority(ICallbacks callback, int priority)
{
Callback = callback;
Priority = priority;
}
}
}
}

View File

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

View File

@ -0,0 +1,9 @@
namespace UnityEditor.TestTools.TestRunner.Api
{
internal class ExecutionSettings
{
public BuildTarget? targetPlatform;
public ITestRunSettings overloadTestRunSettings;
public Filter filter;
}
}

View File

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

View File

@ -0,0 +1,34 @@
using System;
using UnityEngine;
using UnityEngine.TestTools.TestRunner.GUI;
namespace UnityEditor.TestTools.TestRunner.Api
{
[Serializable]
internal class Filter
{
[SerializeField]
public TestMode testMode;
[SerializeField]
public string[] testNames;
[SerializeField]
public string[] groupNames;
[SerializeField]
public string[] categoryNames;
[SerializeField]
public string[] assemblyNames;
public static Filter empty = new Filter();
internal TestRunnerFilter ToTestRunnerFilter()
{
return new TestRunnerFilter()
{
testNames = testNames,
categoryNames = categoryNames,
groupNames = groupNames,
assemblyNames = assemblyNames
};
}
}
}

View File

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

View File

@ -0,0 +1,10 @@
namespace UnityEditor.TestTools.TestRunner.Api
{
internal interface ICallbacks
{
void RunStarted(ITestAdaptor testsToRun);
void RunFinished(ITestResultAdaptor result);
void TestStarted(ITestAdaptor test);
void TestFinished(ITestResultAdaptor result);
}
}

View File

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

View File

@ -0,0 +1,27 @@
using System.Collections.Generic;
using NUnit.Framework.Interfaces;
namespace UnityEditor.TestTools.TestRunner.Api
{
internal interface ITestAdaptor
{
string Id { get; }
string Name { get; }
string FullName { get; }
int TestCaseCount { get; }
bool HasChildren { get; }
bool IsSuite { get; }
IEnumerable<ITestAdaptor> Children { get; }
int TestCaseTimeout { get; }
ITypeInfo TypeInfo { get; }
IMethodInfo Method { get; }
string[] Categories { get; }
bool IsTestAssembly { get; }
RunState RunState { get; }
string Description { get; }
string SkipReason { get; }
string ParentId { get; }
string UniqueName { get; }
string ParentUniqueName { get; }
}
}

View File

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

View File

@ -0,0 +1,16 @@
using System.Collections.Generic;
using NUnit.Framework.Interfaces;
using UnityEngine.TestRunner.TestLaunchers;
namespace UnityEditor.TestTools.TestRunner.Api
{
internal interface ITestAdaptorFactory
{
ITestAdaptor Create(ITest test);
ITestAdaptor Create(RemoteTestData testData);
ITestResultAdaptor Create(ITestResult testResult);
ITestResultAdaptor Create(RemoteTestResultData testResult, RemoteTestResultDataWithTestData allData);
ITestAdaptor BuildTree(RemoteTestResultDataWithTestData data);
IEnumerator<ITestAdaptor> BuildTreeAsync(RemoteTestResultDataWithTestData data);
}
}

View File

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

View File

@ -0,0 +1,86 @@
using System;
using System.Collections.Generic;
using NUnit.Framework.Interfaces;
namespace UnityEditor.TestTools.TestRunner.Api
{
internal interface ITestResultAdaptor
{
ITestAdaptor Test { get; }
string Name { get; }
/// <summary>Gets the full name of the test result</summary>
string FullName { get; }
string ResultState { get; }
TestStatus TestStatus { get; }
/// <summary>Gets the elapsed time for running the test in seconds</summary>
double Duration { get; }
/// <summary>Gets or sets the time the test started running.</summary>
DateTime StartTime { get; }
/// <summary>Gets or sets the time the test finished running.</summary>
DateTime EndTime { get; }
/// <summary>
/// Gets the message associated with a test
/// failure or with not running the test
/// </summary>
string Message { get; }
/// <summary>
/// Gets any stacktrace associated with an
/// error or failure. Not available in
/// the Compact Framework 1.0.
/// </summary>
string StackTrace { get; }
/// <summary>
/// Gets the number of asserts executed
/// when running the test and all its children.
/// </summary>
int AssertCount { get; }
/// <summary>
/// Gets the number of test cases that failed
/// when running the test and all its children.
/// </summary>
int FailCount { get; }
/// <summary>
/// Gets the number of test cases that passed
/// when running the test and all its children.
/// </summary>
int PassCount { get; }
/// <summary>
/// Gets the number of test cases that were skipped
/// when running the test and all its children.
/// </summary>
int SkipCount { get; }
/// <summary>
/// Gets the number of test cases that were inconclusive
/// when running the test and all its children.
/// </summary>
int InconclusiveCount { get; }
/// <summary>
/// Indicates whether this result has any child results.
/// Accessing HasChildren should not force creation of the
/// Children collection in classes implementing this interface.
/// </summary>
bool HasChildren { get; }
/// <summary>Gets the the collection of child results.</summary>
IEnumerable<ITestResultAdaptor> Children { get; }
/// <summary>Gets any text output written to this result.</summary>
string Output { get; }
TNode ToXml();
}
}

View File

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

View File

@ -0,0 +1,9 @@
using System;
namespace UnityEditor.TestTools.TestRunner.Api
{
internal interface ITestRunSettings : IDisposable
{
void Apply();
}
}

View File

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

View File

@ -0,0 +1,12 @@
using System;
namespace UnityEditor.TestTools.TestRunner.Api
{
interface ITestRunnerApi
{
void Execute(ExecutionSettings executionSettings);
void RegisterCallbacks<T>(T testCallbacks, int priority = 0) where T : ICallbacks;
void UnregisterCallbacks<T>(T testCallbacks) where T : ICallbacks;
void RetrieveTestList(ExecutionSettings executionSettings, Action<ITestAdaptor> callback);
}
}

View File

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

View File

@ -0,0 +1,11 @@
namespace UnityEditor.TestTools.TestRunner.Api
{
internal enum RunState
{
NotRunnable,
Runnable,
Explicit,
Skipped,
Ignored,
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 8bb59cb2f66d156418ca1bd1e2703233
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 System.Linq;
using NUnit.Framework.Interfaces;
using NUnit.Framework.Internal;
using UnityEngine.TestRunner.NUnitExtensions;
using UnityEngine.TestRunner.NUnitExtensions.Runner;
using UnityEngine.TestRunner.TestLaunchers;
using UnityEngine.TestTools.Utils;
namespace UnityEditor.TestTools.TestRunner.Api
{
internal class TestAdaptor : ITestAdaptor
{
internal TestAdaptor(ITest test) : this(test, new ITest[0])
{
}
internal TestAdaptor(ITest test, ITest[] additionalChildren)
{
Id = test.Id;
Name = test.Name;
var childIndex = -1;
if (test.Properties["childIndex"].Count > 0)
{
childIndex = (int)test.Properties["childIndex"][0];
}
FullName = childIndex != -1 ? GetIndexedTestCaseName(test.FullName, childIndex) : test.FullName;
TestCaseCount = test.TestCaseCount;
HasChildren = test.HasChildren;
IsSuite = test.IsSuite;
Children = new[] {test.Tests, additionalChildren}.SelectMany(t => t).Select(t => new TestAdaptor(t)).ToArray();
if (UnityTestExecutionContext.CurrentContext != null)
{
TestCaseTimeout = UnityTestExecutionContext.CurrentContext.TestCaseTimeout;
}
else
{
TestCaseTimeout = CoroutineRunner.k_DefaultTimeout;
}
TypeInfo = test.TypeInfo;
Method = test.Method;
FullPath = GetFullPath(test);
Categories = test.GetAllCategoriesFromTest().Distinct().ToArray();
IsTestAssembly = test is TestAssembly;
RunState = (RunState)Enum.Parse(typeof(RunState), test.RunState.ToString());
Description = (string)test.Properties.Get(PropertyNames.Description);
SkipReason = test.GetSkipReason();
ParentId = test.GetParentId();
UniqueName = test.GetUniqueName();
ParentUniqueName = test.GetParentUniqueName();
}
internal TestAdaptor(RemoteTestData test)
{
Id = test.id;
Name = test.name;
FullName = test.ChildIndex != -1 ? GetIndexedTestCaseName(test.fullName, test.ChildIndex) : test.fullName;
TestCaseCount = test.testCaseCount;
HasChildren = test.hasChildren;
IsSuite = test.isSuite;
m_ChildrenIds = test.childrenIds;
TestCaseTimeout = test.testCaseTimeout;
Categories = test.Categories;
IsTestAssembly = test.IsTestAssembly;
RunState = (RunState)Enum.Parse(typeof(RunState), test.RunState.ToString());
Description = test.Description;
SkipReason = test.SkipReason;
ParentId = test.ParentId;
UniqueName = test.UniqueName;
ParentUniqueName = test.ParentUniqueName;
}
internal void ApplyChildren(IEnumerable<TestAdaptor> allTests)
{
Children = m_ChildrenIds.Select(id => allTests.First(t => t.Id == id)).ToArray();
}
public string Id { get; private set; }
public string Name { get; private set; }
public string FullName { get; private set; }
public int TestCaseCount { get; private set; }
public bool HasChildren { get; private set; }
public bool IsSuite { get; private set; }
public IEnumerable<ITestAdaptor> Children { get; private set; }
public int TestCaseTimeout { get; private set; }
public ITypeInfo TypeInfo { get; private set; }
public IMethodInfo Method { get; private set; }
public string FullPath { get; private set; }
private string[] m_ChildrenIds;
public string[] Categories { get; private set; }
public bool IsTestAssembly { get; private set; }
public RunState RunState { get; }
public string Description { get; }
public string SkipReason { get; }
public string ParentId { get; }
public string UniqueName { get; }
public string ParentUniqueName { get; }
private static string GetFullPath(ITest test)
{
if (test.Parent != null && test.Parent.Parent != null)
return GetFullPath(test.Parent) + "/" + test.Name;
return test.Name;
}
private static string GetIndexedTestCaseName(string fullName, int index)
{
var generatedTestSuffix = " GeneratedTestCase" + index;
if (fullName.EndsWith(")"))
{
// Test names from generated TestCaseSource look like Test(TestCaseSourceType)
// This inserts a unique test case index in the name, so that it becomes Test(TestCaseSourceType GeneratedTestCase0)
return fullName.Substring(0, fullName.Length - 1) + generatedTestSuffix + fullName[fullName.Length - 1];
}
// In some cases there can be tests with duplicate names generated in other ways and they won't have () in their name
// We just append a suffix at the end of the name in that case
return fullName + generatedTestSuffix;
}
}
}

View File

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

View File

@ -0,0 +1,59 @@
using System.Collections.Generic;
using System.Linq;
using NUnit.Framework.Interfaces;
using UnityEngine.TestRunner.TestLaunchers;
namespace UnityEditor.TestTools.TestRunner.Api
{
internal class TestAdaptorFactory : ITestAdaptorFactory
{
public ITestAdaptor Create(ITest test)
{
return new TestAdaptor(test);
}
public ITestAdaptor Create(RemoteTestData testData)
{
return new TestAdaptor(testData);
}
public ITestResultAdaptor Create(ITestResult testResult)
{
return new TestResultAdaptor(testResult);
}
public ITestResultAdaptor Create(RemoteTestResultData testResult, RemoteTestResultDataWithTestData allData)
{
return new TestResultAdaptor(testResult, allData);
}
public ITestAdaptor BuildTree(RemoteTestResultDataWithTestData data)
{
var tests = data.tests.Select(remoteTestData => new TestAdaptor(remoteTestData)).ToList();
foreach (var test in tests)
{
test.ApplyChildren(tests);
}
return tests.First();
}
public IEnumerator<ITestAdaptor> BuildTreeAsync(RemoteTestResultDataWithTestData data)
{
var tests = data.tests.Select(remoteTestData => new TestAdaptor(remoteTestData)).ToList();
for (var index = 0; index < tests.Count; index++)
{
var test = tests[index];
test.ApplyChildren(tests);
if (index % 100 == 0)
{
yield return null;
}
}
yield return tests.First();
}
}
}

View File

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

View File

@ -0,0 +1,57 @@
using System;
using UnityEngine.TestTools;
using UnityEngine.TestTools.TestRunner;
namespace UnityEditor.TestTools.TestRunner.Api
{
internal class TestLauncherFactory
{
internal TestLauncherBase GetLauncher(ExecutionSettings executionSettings)
{
if (executionSettings.filter.testMode == TestMode.EditMode)
{
return GetEditModeLauncher(executionSettings.filter);
}
else
{
var settings = PlaymodeTestsControllerSettings.CreateRunnerSettings(executionSettings.filter.ToTestRunnerFilter());
return GetPlayModeLauncher(settings, executionSettings);
}
}
static TestLauncherBase GetEditModeLauncher(Filter filter)
{
return GetEditModeLauncherForProvidedAssemblies(filter);
}
static TestLauncherBase GetPlayModeLauncher(PlaymodeTestsControllerSettings settings, ExecutionSettings executionSettings)
{
if (executionSettings.targetPlatform != null)
{
return GetPlayerLauncher(settings, executionSettings.targetPlatform.Value, executionSettings.overloadTestRunSettings);
}
if (PlayerSettings.runPlayModeTestAsEditModeTest)
{
return GetEditModeLauncherForProvidedAssemblies(executionSettings.filter, TestPlatform.PlayMode);
}
return GetPlayModeLauncher(settings);
}
static TestLauncherBase GetEditModeLauncherForProvidedAssemblies(Filter filter, TestPlatform testPlatform = TestPlatform.EditMode)
{
return new EditModeLauncher(filter.ToTestRunnerFilter(), testPlatform);
}
static TestLauncherBase GetPlayModeLauncher(PlaymodeTestsControllerSettings settings)
{
return new PlaymodeLauncher(settings);
}
static TestLauncherBase GetPlayerLauncher(PlaymodeTestsControllerSettings settings, BuildTarget targetPlatform, ITestRunSettings overloadTestRunSettings)
{
return new PlayerLauncher(settings, targetPlatform, overloadTestRunSettings);
}
}
}

View File

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

View File

@ -0,0 +1,11 @@
using System;
namespace UnityEditor.TestTools.TestRunner.Api
{
[Flags]
internal enum TestMode
{
EditMode = 1 << 0,
PlayMode = 1 << 1
}
}

View File

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

View File

@ -0,0 +1,87 @@
using System;
using System.Collections.Generic;
using System.Linq;
using NUnit.Framework.Interfaces;
using UnityEngine.TestRunner.TestLaunchers;
namespace UnityEditor.TestTools.TestRunner.Api
{
internal class TestResultAdaptor : ITestResultAdaptor
{
private TNode m_Node;
internal TestResultAdaptor(ITestResult result)
{
Test = new TestAdaptor(result.Test);
Name = result.Name;
FullName = result.FullName;
ResultState = result.ResultState.ToString();
TestStatus = ParseTestStatus(result.ResultState.Status);
Duration = result.Duration;
StartTime = result.StartTime;
EndTime = result.EndTime;
Message = result.Message;
StackTrace = result.StackTrace;
AssertCount = result.AssertCount;
FailCount = result.FailCount;
PassCount = result.PassCount;
SkipCount = result.SkipCount;
InconclusiveCount = result.InconclusiveCount;
HasChildren = result.HasChildren;
Output = result.Output;
Children = result.Children.Select(child => new TestResultAdaptor(child)).ToArray();
m_Node = result.ToXml(true);
}
internal TestResultAdaptor(RemoteTestResultData result, RemoteTestResultDataWithTestData allData)
{
Test = new TestAdaptor(allData.tests.First(t => t.id == result.testId));
Name = result.name;
FullName = result.fullName;
ResultState = result.resultState;
TestStatus = ParseTestStatus(result.testStatus);
Duration = result.duration;
StartTime = result.startTime;
EndTime = result.endTime;
Message = result.message;
StackTrace = result.stackTrace;
AssertCount = result.assertCount;
FailCount = result.failCount;
PassCount = result.passCount;
SkipCount = result.skipCount;
InconclusiveCount = result.inconclusiveCount;
HasChildren = result.hasChildren;
Output = result.output;
Children = result.childrenIds.Select(childId => new TestResultAdaptor(allData.results.First(r => r.testId == childId), allData)).ToArray();
m_Node = TNode.FromXml(result.xml);
}
public ITestAdaptor Test { get; private set; }
public string Name { get; private set; }
public string FullName { get; private set; }
public string ResultState { get; private set; }
public TestStatus TestStatus { get; private set; }
public double Duration { get; private set; }
public DateTime StartTime { get; private set; }
public DateTime EndTime { get; private set; }
public string Message { get; private set; }
public string StackTrace { get; private set; }
public int AssertCount { get; private set; }
public int FailCount { get; private set; }
public int PassCount { get; private set; }
public int SkipCount { get; private set; }
public int InconclusiveCount { get; private set; }
public bool HasChildren { get; private set; }
public IEnumerable<ITestResultAdaptor> Children { get; private set; }
public string Output { get; private set; }
public TNode ToXml()
{
return m_Node;
}
private static TestStatus ParseTestStatus(NUnit.Framework.Interfaces.TestStatus testStatus)
{
return (TestStatus)Enum.Parse(typeof(TestStatus), testStatus.ToString());
}
}
}

View File

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

View File

@ -0,0 +1,12 @@
using System;
using UnityEngine;
namespace UnityEditor.TestTools.TestRunner.Api
{
[Serializable]
internal class TestRunData : ScriptableSingleton<TestRunData>
{
[SerializeField]
public ExecutionSettings executionSettings;
}
}

View File

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

View File

@ -0,0 +1,81 @@
using System;
using System.Linq;
using System.Threading;
using UnityEngine;
using UnityEngine.TestRunner.TestLaunchers;
using UnityEngine.TestTools;
using UnityEngine.TestTools.NUnitExtensions;
namespace UnityEditor.TestTools.TestRunner.Api
{
internal class TestRunnerApi : ScriptableObject, ITestRunnerApi
{
public void Execute(ExecutionSettings executionSettings)
{
if (executionSettings == null)
{
throw new ArgumentException("Filter for execution is undefined.");
}
var launcherFactory = new TestLauncherFactory();
var data = TestRunData.instance;
data.executionSettings = executionSettings;
var testLauncher = launcherFactory.GetLauncher(executionSettings);
testLauncher.Run();
}
public void RegisterCallbacks<T>(T testCallbacks, int priority = 0) where T : ICallbacks
{
if (testCallbacks == null)
{
throw new ArgumentException("TestCallbacks for execution is undefined.");
}
CallbacksHolder.instance.Add(testCallbacks, priority);
}
public void UnregisterCallbacks<T>(T testCallbacks) where T : ICallbacks
{
if (testCallbacks == null)
{
throw new ArgumentException("TestCallbacks for execution is undefined.");
}
CallbacksHolder.instance.Remove(testCallbacks);
}
public void RetrieveTestList(ExecutionSettings executionSettings, Action<ITestAdaptor> callback)
{
if (executionSettings == null)
{
throw new ArgumentException("Filter for execution is undefined.");
}
if (callback == null)
{
throw new ArgumentException("Callback is undefined.");
}
var platform = ParseTestMode(executionSettings.filter.testMode);
var testAssemblyProvider = new EditorLoadedTestAssemblyProvider(new EditorCompilationInterfaceProxy(), new EditorAssembliesProxy());
var testAdaptorFactory = new TestAdaptorFactory();
var testListCache = new TestListCache(testAdaptorFactory, new RemoteTestResultDataFactory(), TestListCacheData.instance);
var testListProvider = new TestListProvider(testAssemblyProvider, new UnityTestAssemblyBuilder());
var cachedTestListProvider = new CachingTestListProvider(testListProvider, testListCache, testAdaptorFactory);
var job = new TestListJob(cachedTestListProvider, platform, callback);
job.Start();
}
private static TestPlatform ParseTestMode(TestMode testmode)
{
if (testmode == TestMode.EditMode)
{
return TestPlatform.EditMode;
}
return TestPlatform.PlayMode;
}
}
}

View File

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

View File

@ -0,0 +1,10 @@
namespace UnityEditor.TestTools.TestRunner.Api
{
internal enum TestStatus
{
Skipped,
Passed,
Failed,
Inconclusive
}
}

View File

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

View File

@ -0,0 +1,14 @@
using System.Reflection;
using System.Runtime.CompilerServices;
[assembly: AssemblyTitle("UnityEditor.TestRunner")]
[assembly: InternalsVisibleTo("Assembly-CSharp-Editor-testable")]
[assembly: InternalsVisibleTo("DynamicProxyGenAssembly2")]
[assembly: InternalsVisibleTo("Unity.PerformanceTesting.Editor")]
[assembly: InternalsVisibleTo("Unity.IntegrationTests")]
[assembly: InternalsVisibleTo("UnityEditor.TestRunner.Tests")]
[assembly: InternalsVisibleTo("Unity.TestTools.CodeCoverage.Editor")]
[assembly: InternalsVisibleTo("Unity.PackageManagerUI.Develop.Editor")]
[assembly: InternalsVisibleTo("Unity.PackageManagerUI.Develop.EditorTests")]
[assembly: AssemblyVersion("1.0.0")]

View File

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

View File

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

View File

@ -0,0 +1,45 @@
using System;
using System.Linq;
namespace UnityEditor.TestRunner.CommandLineParser
{
internal class CommandLineOption : ICommandLineOption
{
Action<string> m_ArgAction;
public CommandLineOption(string argName, Action action)
{
ArgName = argName;
m_ArgAction = s => action();
}
public CommandLineOption(string argName, Action<string> action)
{
ArgName = argName;
m_ArgAction = action;
}
public CommandLineOption(string argName, Action<string[]> action)
{
ArgName = argName;
m_ArgAction = s => action(SplitStringToArray(s));
}
public string ArgName { get; private set; }
public void ApplyValue(string value)
{
m_ArgAction(value);
}
static string[] SplitStringToArray(string value)
{
if (string.IsNullOrEmpty(value))
{
return null;
}
return value.Split(';').ToArray();
}
}
}

View File

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

View File

@ -0,0 +1,49 @@
using System;
namespace UnityEditor.TestRunner.CommandLineParser
{
internal class CommandLineOptionSet
{
ICommandLineOption[] m_Options;
public CommandLineOptionSet(params ICommandLineOption[] options)
{
m_Options = options;
}
public void Parse(string[] args)
{
var i = 0;
while (i < args.Length)
{
var arg = args[i];
if (!arg.StartsWith("-"))
{
i++;
continue;
}
string value = null;
if (i + 1 < args.Length && !args[i + 1].StartsWith("-"))
{
value = args[i + 1];
i++;
}
ApplyValueToMatchingOptions(arg, value);
i++;
}
}
private void ApplyValueToMatchingOptions(string argName, string value)
{
foreach (var option in m_Options)
{
if ("-" + option.ArgName == argName)
{
option.ApplyValue(value);
}
}
}
}
}

View File

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

View File

@ -0,0 +1,8 @@
namespace UnityEditor.TestRunner.CommandLineParser
{
interface ICommandLineOption
{
string ArgName { get; }
void ApplyValue(string value);
}
}

View File

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

View File

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

View File

@ -0,0 +1,137 @@
using System;
using System.Linq;
using UnityEditor.TestRunner.TestLaunchers;
using UnityEditor.TestTools.TestRunner.Api;
using UnityEngine;
namespace UnityEditor.TestTools.TestRunner.CommandLineTest
{
internal class Executer
{
private ITestRunnerApi m_TestRunnerApi;
private ISettingsBuilder m_SettingsBuilder;
private Action<string, object[]> m_LogErrorFormat;
private Action<Exception> m_LogException;
private Action<int> m_ExitEditorApplication;
private Func<bool> m_ScriptCompilationFailedCheck;
public Executer(ITestRunnerApi testRunnerApi, ISettingsBuilder settingsBuilder, Action<string, object[]> logErrorFormat, Action<Exception> logException, Action<int> exitEditorApplication, Func<bool> scriptCompilationFailedCheck)
{
m_TestRunnerApi = testRunnerApi;
m_SettingsBuilder = settingsBuilder;
m_LogErrorFormat = logErrorFormat;
m_LogException = logException;
m_ExitEditorApplication = exitEditorApplication;
m_ScriptCompilationFailedCheck = scriptCompilationFailedCheck;
}
internal void InitializeAndExecuteRun(string[] commandLineArgs)
{
Api.ExecutionSettings executionSettings;
try
{
executionSettings = m_SettingsBuilder.BuildApiExecutionSettings(commandLineArgs);
if (executionSettings.targetPlatform.HasValue)
RemotePlayerLogController.instance.SetBuildTarget(executionSettings.targetPlatform.Value);
}
catch (SetupException exception)
{
HandleSetupException(exception);
return;
}
try
{
Debug.Log("Executing tests with settings: " + ExecutionSettingsToString(executionSettings));
m_TestRunnerApi.Execute(executionSettings);
}
catch (Exception exception)
{
m_LogException(exception);
m_ExitEditorApplication((int)ReturnCodes.RunError);
}
}
internal ExecutionSettings BuildExecutionSettings(string[] commandLineArgs)
{
return m_SettingsBuilder.BuildExecutionSettings(commandLineArgs);
}
internal enum ReturnCodes
{
Ok = 0,
Failed = 2,
RunError = 3,
PlatformNotFoundReturnCode = 4
}
internal void SetUpCallbacks(ExecutionSettings executionSettings)
{
RemotePlayerLogController.instance.SetLogsDirectory(executionSettings.DeviceLogsDirectory);
var resultSavingCallback = ScriptableObject.CreateInstance<ResultsSavingCallbacks>();
resultSavingCallback.m_ResultFilePath = executionSettings.TestResultsFile;
var logSavingCallback = ScriptableObject.CreateInstance<LogSavingCallbacks>();
m_TestRunnerApi.RegisterCallbacks(resultSavingCallback);
m_TestRunnerApi.RegisterCallbacks(logSavingCallback);
m_TestRunnerApi.RegisterCallbacks(ScriptableObject.CreateInstance<ExitCallbacks>(), -10);
var timeoutCallbacks = ScriptableObject.CreateInstance<TimeoutCallbacks>();
timeoutCallbacks.Init((action, time) => new DelayedCallback(action, time), m_LogErrorFormat, m_ExitEditorApplication);
m_TestRunnerApi.RegisterCallbacks(timeoutCallbacks);
}
internal void ExitOnCompileErrors()
{
if (m_ScriptCompilationFailedCheck())
{
var handling = s_ExceptionHandlingMapping.First(h => h.m_ExceptionType == SetupException.ExceptionType.ScriptCompilationFailed);
m_LogErrorFormat(handling.m_Message, new object[0]);
m_ExitEditorApplication(handling.m_ReturnCode);
}
}
void HandleSetupException(SetupException exception)
{
ExceptionHandling handling = s_ExceptionHandlingMapping.FirstOrDefault(h => h.m_ExceptionType == exception.Type) ?? new ExceptionHandling(exception.Type, "Unknown command line test run error. " + exception.Type, ReturnCodes.RunError);
m_LogErrorFormat(handling.m_Message, exception.Details);
m_ExitEditorApplication(handling.m_ReturnCode);
}
private class ExceptionHandling
{
internal SetupException.ExceptionType m_ExceptionType;
internal string m_Message;
internal int m_ReturnCode;
public ExceptionHandling(SetupException.ExceptionType exceptionType, string message, ReturnCodes returnCode)
{
m_ExceptionType = exceptionType;
m_Message = message;
m_ReturnCode = (int)returnCode;
}
}
static ExceptionHandling[] s_ExceptionHandlingMapping = new[]
{
new ExceptionHandling(SetupException.ExceptionType.ScriptCompilationFailed, "Scripts had compilation errors.", ReturnCodes.RunError),
new ExceptionHandling(SetupException.ExceptionType.PlatformNotFound, "Test platform not found ({0}).", ReturnCodes.PlatformNotFoundReturnCode),
new ExceptionHandling(SetupException.ExceptionType.TestSettingsFileNotFound, "Test settings file not found at {0}.", ReturnCodes.RunError)
};
private static string ExecutionSettingsToString(Api.ExecutionSettings executionSettings)
{
if (executionSettings == null)
{
return "none";
}
if (executionSettings.filter == null)
{
return "no filter";
}
return "test mode = " + executionSettings.filter.testMode;
}
}
}

View File

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

View File

@ -0,0 +1,11 @@
using System;
namespace UnityEditor.TestTools.TestRunner.CommandLineTest
{
[Serializable]
internal class ExecutionSettings
{
public string TestResultsFile;
public string DeviceLogsDirectory;
}
}

View File

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

View File

@ -0,0 +1,48 @@
using System;
using UnityEditor.TestTools.TestRunner.Api;
using UnityEngine;
namespace UnityEditor.TestTools.TestRunner.CommandLineTest
{
[Serializable]
internal class ExitCallbacks : ScriptableObject, ICallbacks
{
private bool m_AnyTestsExecuted;
private bool m_RunFailed;
internal static bool preventExit;
public void RunFinished(ITestResultAdaptor testResults)
{
if (preventExit)
{
return;
}
if (!m_AnyTestsExecuted)
{
Debug.LogFormat(LogType.Warning, LogOption.NoStacktrace, null, "No tests were executed");
}
EditorApplication.Exit(m_RunFailed ? (int)Executer.ReturnCodes.Failed : (int)Executer.ReturnCodes.Ok);
}
public void TestStarted(ITestAdaptor test)
{
if (!test.IsSuite)
{
m_AnyTestsExecuted = true;
}
}
public void TestFinished(ITestResultAdaptor result)
{
if (!result.Test.IsSuite && (result.TestStatus == TestStatus.Failed))
{
m_RunFailed = true;
}
}
public void RunStarted(ITestAdaptor testsToRun)
{
}
}
}

View File

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

View File

@ -0,0 +1,10 @@
using UnityEditor.TestTools.TestRunner.Api;
namespace UnityEditor.TestTools.TestRunner.CommandLineTest
{
interface ISettingsBuilder
{
Api.ExecutionSettings BuildApiExecutionSettings(string[] commandLineArgs);
ExecutionSettings BuildExecutionSettings(string[] commandLineArgs);
}
}

View File

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

View File

@ -0,0 +1,29 @@
using System;
using UnityEditor.TestRunner.TestLaunchers;
using UnityEditor.TestTools.TestRunner.Api;
using UnityEngine;
namespace UnityEditor.TestTools.TestRunner.CommandLineTest
{
[Serializable]
internal class LogSavingCallbacks : ScriptableObject, ICallbacks
{
public void RunStarted(ITestAdaptor testsToRun)
{
RemotePlayerLogController.instance.StartLogWriters();
}
public virtual void RunFinished(ITestResultAdaptor testResults)
{
RemotePlayerLogController.instance.StopLogWriters();
}
public void TestStarted(ITestAdaptor test)
{
}
public void TestFinished(ITestResultAdaptor result)
{
}
}
}

View File

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

View File

@ -0,0 +1,92 @@
using System;
using System.Collections.Generic;
using System.IO;
using UnityEditor.DeploymentTargets;
using UnityEditor.Utils;
using UnityEngine;
namespace UnityEditor.TestTools.TestRunner.CommandLineTest
{
internal class LogWriter : IDisposable
{
private string m_LogsDirectory;
private string m_DeviceID;
private Dictionary<string, StreamWriter> m_LogStreams;
private DeploymentTargetLogger m_Logger;
internal LogWriter(string logsDirectory, string deviceID, DeploymentTargetLogger logger)
{
m_LogStreams = new Dictionary<string, StreamWriter>();
m_Logger = logger;
m_LogsDirectory = logsDirectory;
m_DeviceID = deviceID;
logger.logMessage += WriteLogToFile;
}
private void WriteLogToFile(string id, string logLine)
{
StreamWriter logStream;
var streamExists = m_LogStreams.TryGetValue(id, out logStream);
if (!streamExists)
{
var filePath = GetLogFilePath(m_LogsDirectory, m_DeviceID, id);
logStream = CreateLogFile(filePath);
m_LogStreams.Add(id, logStream);
}
try
{
if (logLine != null)
logStream.WriteLine(logLine);
}
catch (Exception ex)
{
Debug.LogError($"Writing {id} log failed.");
Debug.LogException(ex);
}
}
public void Stop()
{
m_Logger.Stop();
foreach (var logStream in m_LogStreams)
{
logStream.Value.Close();
}
}
public void Dispose()
{
Stop();
}
private StreamWriter CreateLogFile(string path)
{
Debug.LogFormat(LogType.Log, LogOption.NoStacktrace, null, "Creating {0} device log: {1}", m_DeviceID, path);
StreamWriter streamWriter = null;
try
{
if (!Directory.Exists(path))
Directory.CreateDirectory(Path.GetDirectoryName(path));
streamWriter = File.CreateText(path);
}
catch (Exception ex)
{
Debug.LogError($"Creating device log {path} file failed.");
Debug.LogException(ex);
}
return streamWriter;
}
private string GetLogFilePath(string lgosDirectory, string deviceID, string logID)
{
var fileName = "Device-" + deviceID + "-" + logID + ".txt";
fileName = string.Join("_", fileName.Split(Path.GetInvalidFileNameChars()));
return Paths.Combine(lgosDirectory, fileName);
}
}
}

View File

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

View File

@ -0,0 +1,50 @@
using System;
using System.IO;
using UnityEditor.TestTools.TestRunner.Api;
using UnityEditor.Utils;
using UnityEngine;
namespace UnityEditor.TestTools.TestRunner.CommandLineTest
{
[Serializable]
internal class ResultsSavingCallbacks : ScriptableObject, ICallbacks
{
[SerializeField]
public string m_ResultFilePath;
public ResultsSavingCallbacks()
{
this.m_ResultFilePath = GetDefaultResultFilePath();
}
public void RunStarted(ITestAdaptor testsToRun)
{
}
public virtual void RunFinished(ITestResultAdaptor testResults)
{
if (string.IsNullOrEmpty(m_ResultFilePath))
{
m_ResultFilePath = GetDefaultResultFilePath();
}
var resultWriter = new ResultsWriter();
resultWriter.WriteResultToFile(testResults, m_ResultFilePath);
}
public void TestStarted(ITestAdaptor test)
{
}
public void TestFinished(ITestResultAdaptor result)
{
}
private static string GetDefaultResultFilePath()
{
var fileName = "TestResults-" + DateTime.Now.Ticks + ".xml";
var projectPath = Directory.GetCurrentDirectory();
return Paths.Combine(projectPath, fileName);
}
}
}

View File

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

View File

@ -0,0 +1,99 @@
using System;
using System.IO;
using System.Xml;
using NUnit.Framework.Interfaces;
using UnityEditor.TestTools.TestRunner.Api;
using UnityEngine;
namespace UnityEditor.TestTools.TestRunner.CommandLineTest
{
internal class ResultsWriter
{
private const string k_nUnitVersion = "3.5.0.0";
private const string k_TestRunNode = "test-run";
private const string k_Id = "id";
private const string k_Testcasecount = "testcasecount";
private const string k_Result = "result";
private const string k_Total = "total";
private const string k_Passed = "passed";
private const string k_Failed = "failed";
private const string k_Inconclusive = "inconclusive";
private const string k_Skipped = "skipped";
private const string k_Asserts = "asserts";
private const string k_EngineVersion = "engine-version";
private const string k_ClrVersion = "clr-version";
private const string k_StartTime = "start-time";
private const string k_EndTime = "end-time";
private const string k_Duration = "duration";
private const string k_TimeFormat = "u";
public void WriteResultToFile(ITestResultAdaptor result, string filePath)
{
Debug.LogFormat(LogType.Log, LogOption.NoStacktrace, null, "Saving results to: {0}", filePath);
try
{
if (!Directory.Exists(filePath))
{
CreateDirectory(filePath);
}
using (var fileStream = File.CreateText(filePath))
{
WriteResultToStream(result, fileStream);
}
}
catch (Exception ex)
{
Debug.LogError("Saving result file failed.");
Debug.LogException(ex);
}
}
void CreateDirectory(string filePath)
{
Directory.CreateDirectory(Path.GetDirectoryName(filePath));
}
public void WriteResultToStream(ITestResultAdaptor result, StreamWriter streamWriter, XmlWriterSettings settings = null)
{
settings = settings ?? new XmlWriterSettings();
settings.Indent = true;
settings.NewLineOnAttributes = false;
using (var xmlWriter = XmlWriter.Create(streamWriter, settings))
{
WriteResultsToXml(result, xmlWriter);
}
}
void WriteResultsToXml(ITestResultAdaptor result, XmlWriter xmlWriter)
{
// XML format as specified at https://github.com/nunit/docs/wiki/Test-Result-XML-Format
var testRunNode = new TNode(k_TestRunNode);
testRunNode.AddAttribute(k_Id, "2");
testRunNode.AddAttribute(k_Testcasecount, (result.PassCount + result.FailCount + result.SkipCount + result.InconclusiveCount).ToString());
testRunNode.AddAttribute(k_Result, result.ResultState.ToString());
testRunNode.AddAttribute(k_Total, (result.PassCount + result.FailCount + result.SkipCount + result.InconclusiveCount).ToString());
testRunNode.AddAttribute(k_Passed, result.PassCount.ToString());
testRunNode.AddAttribute(k_Failed, result.FailCount.ToString());
testRunNode.AddAttribute(k_Inconclusive, result.InconclusiveCount.ToString());
testRunNode.AddAttribute(k_Skipped, result.SkipCount.ToString());
testRunNode.AddAttribute(k_Asserts, result.AssertCount.ToString());
testRunNode.AddAttribute(k_EngineVersion, k_nUnitVersion);
testRunNode.AddAttribute(k_ClrVersion, Environment.Version.ToString());
testRunNode.AddAttribute(k_StartTime, result.StartTime.ToString(k_TimeFormat));
testRunNode.AddAttribute(k_EndTime, result.EndTime.ToString(k_TimeFormat));
testRunNode.AddAttribute(k_Duration, result.Duration.ToString());
var resultNode = result.ToXml();
testRunNode.ChildNodes.Add(resultNode);
testRunNode.WriteTo(xmlWriter);
}
}
}

View File

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

View File

@ -0,0 +1,8 @@
namespace UnityEditor.TestTools.TestRunner.CommandLineTest
{
internal class RunData : ScriptableSingleton<RunData>
{
public bool isRunning;
public ExecutionSettings executionSettings;
}
}

View File

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

View File

@ -0,0 +1,29 @@
using UnityEditor.TestTools.TestRunner.Api;
namespace UnityEditor.TestTools.TestRunner.CommandLineTest
{
internal class RunSettings : ITestRunSettings
{
private ITestSettings m_TestSettings;
public RunSettings(ITestSettings testSettings)
{
this.m_TestSettings = testSettings;
}
public void Apply()
{
if (m_TestSettings != null)
{
m_TestSettings.SetupProjectParameters();
}
}
public void Dispose()
{
if (m_TestSettings != null)
{
m_TestSettings.Dispose();
}
}
}
}

View File

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

View File

@ -0,0 +1,173 @@
using System;
using System.IO;
using UnityEditor.TestRunner.CommandLineParser;
using UnityEditor.TestTools.TestRunner.Api;
using UnityEngine.TestTools.TestRunner.GUI;
namespace UnityEditor.TestTools.TestRunner.CommandLineTest
{
internal class SettingsBuilder : ISettingsBuilder
{
private ITestSettingsDeserializer m_TestSettingsDeserializer;
private Action<string> m_LogAction;
private Action<string> m_LogWarningAction;
private Func<string, bool> m_FileExistsCheck;
private Func<bool> m_ScriptCompilationFailedCheck;
public SettingsBuilder(ITestSettingsDeserializer testSettingsDeserializer, Action<string> logAction, Action<string> logWarningAction, Func<string, bool> fileExistsCheck, Func<bool> scriptCompilationFailedCheck)
{
m_LogAction = logAction;
m_LogWarningAction = logWarningAction;
m_FileExistsCheck = fileExistsCheck;
m_ScriptCompilationFailedCheck = scriptCompilationFailedCheck;
m_TestSettingsDeserializer = testSettingsDeserializer;
}
public Api.ExecutionSettings BuildApiExecutionSettings(string[] commandLineArgs)
{
var quit = false;
string testPlatform = TestMode.EditMode.ToString();
string[] testFilters = null;
string[] testCategories = null;
string testSettingsFilePath = null;
int testRepetitions = 1;
var optionSet = new CommandLineOptionSet(
new CommandLineOption("quit", () => { quit = true; }),
new CommandLineOption("testPlatform", platform => { testPlatform = platform; }),
new CommandLineOption("editorTestsFilter", filters => { testFilters = filters; }),
new CommandLineOption("testFilter", filters => { testFilters = filters; }),
new CommandLineOption("editorTestsCategories", catagories => { testCategories = catagories; }),
new CommandLineOption("testCategory", catagories => { testCategories = catagories; }),
new CommandLineOption("testSettingsFile", settingsFilePath => { testSettingsFilePath = settingsFilePath; }),
new CommandLineOption("testRepetitions", reps => { testRepetitions = int.Parse(reps); })
);
optionSet.Parse(commandLineArgs);
DisplayQuitWarningIfQuitIsGiven(quit);
CheckForScriptCompilationErrors();
LogParametersForRun(testPlatform, testFilters, testCategories, testSettingsFilePath);
var testSettings = GetTestSettings(testSettingsFilePath);
var filter = new Filter()
{
groupNames = testFilters,
categoryNames = testCategories
};
var buildTarget = SetFilterAndGetBuildTarget(testPlatform, filter);
RerunCallbackData.instance.runFilter = new TestRunnerFilter()
{
categoryNames = filter.categoryNames,
groupNames = filter.groupNames,
testRepetitions = testRepetitions
};
RerunCallbackData.instance.testMode = filter.testMode;
return new Api.ExecutionSettings()
{
filter = filter,
overloadTestRunSettings = new RunSettings(testSettings),
targetPlatform = buildTarget
};
}
public ExecutionSettings BuildExecutionSettings(string[] commandLineArgs)
{
string resultFilePath = null;
string deviceLogsDirectory = null;
var optionSet = new CommandLineOptionSet(
new CommandLineOption("editorTestsResultFile", filePath => { resultFilePath = filePath; }),
new CommandLineOption("testResults", filePath => { resultFilePath = filePath; }),
new CommandLineOption("deviceLogs", dirPath => { deviceLogsDirectory = dirPath; })
);
optionSet.Parse(commandLineArgs);
return new ExecutionSettings()
{
TestResultsFile = resultFilePath,
DeviceLogsDirectory = deviceLogsDirectory
};
}
void DisplayQuitWarningIfQuitIsGiven(bool quitIsGiven)
{
if (quitIsGiven)
{
m_LogWarningAction("Running tests from command line arguments will not work when \"quit\" is specified.");
}
}
void CheckForScriptCompilationErrors()
{
if (m_ScriptCompilationFailedCheck())
{
throw new SetupException(SetupException.ExceptionType.ScriptCompilationFailed);
}
}
void LogParametersForRun(string testPlatform, string[] testFilters, string[] testCategories, string testSettingsFilePath)
{
m_LogAction("Running tests for " + testPlatform);
if (testFilters != null && testFilters.Length > 0)
{
m_LogAction("With test filter: " + string.Join(", ", testFilters));
}
if (testCategories != null && testCategories.Length > 0)
{
m_LogAction("With test categories: " + string.Join(", ", testCategories));
}
if (!string.IsNullOrEmpty(testSettingsFilePath))
{
m_LogAction("With test settings file: " + testSettingsFilePath);
}
}
ITestSettings GetTestSettings(string testSettingsFilePath)
{
ITestSettings testSettings = null;
if (!string.IsNullOrEmpty(testSettingsFilePath))
{
if (!m_FileExistsCheck(testSettingsFilePath))
{
throw new SetupException(SetupException.ExceptionType.TestSettingsFileNotFound, testSettingsFilePath);
}
testSettings = m_TestSettingsDeserializer.GetSettingsFromJsonFile(testSettingsFilePath);
}
return testSettings;
}
static BuildTarget? SetFilterAndGetBuildTarget(string testPlatform, Filter filter)
{
BuildTarget? buildTarget = null;
if (testPlatform.ToLower() == "editmode")
{
filter.testMode = TestMode.EditMode;
}
else if (testPlatform.ToLower() == "playmode")
{
filter.testMode = TestMode.PlayMode;
}
else
{
try
{
buildTarget = (BuildTarget)Enum.Parse(typeof(BuildTarget), testPlatform, true);
filter.testMode = TestMode.PlayMode;
}
catch (ArgumentException)
{
throw new SetupException(SetupException.ExceptionType.PlatformNotFound, testPlatform);
}
}
return buildTarget;
}
}
}

View File

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

View File

@ -0,0 +1,23 @@
using System;
namespace UnityEditor.TestTools.TestRunner.CommandLineTest
{
internal class SetupException : Exception
{
public ExceptionType Type { get; }
public object[] Details { get; }
public SetupException(ExceptionType type, params object[] details)
{
Type = type;
Details = details;
}
public enum ExceptionType
{
ScriptCompilationFailed,
PlatformNotFound,
TestSettingsFileNotFound,
}
}
}

View File

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

View File

@ -0,0 +1,80 @@
using System;
using System.IO;
using UnityEditor.TestRunner.CommandLineParser;
using UnityEditor.TestTools.TestRunner.Api;
using UnityEngine;
namespace UnityEditor.TestTools.TestRunner.CommandLineTest
{
[InitializeOnLoad]
static class TestStarter
{
static TestStarter()
{
if (!ShouldRunTests())
{
return;
}
if (EditorApplication.isCompiling)
{
return;
}
executer.ExitOnCompileErrors();
if (RunData.instance.isRunning)
{
executer.SetUpCallbacks(RunData.instance.executionSettings);
return;
}
EditorApplication.update += UpdateWatch;
}
static void UpdateWatch()
{
EditorApplication.update -= UpdateWatch;
if (RunData.instance.isRunning)
{
return;
}
RunData.instance.isRunning = true;
var commandLineArgs = Environment.GetCommandLineArgs();
RunData.instance.executionSettings = executer.BuildExecutionSettings(commandLineArgs);
executer.SetUpCallbacks(RunData.instance.executionSettings);
executer.InitializeAndExecuteRun(commandLineArgs);
}
static bool ShouldRunTests()
{
var shouldRunTests = false;
var optionSet = new CommandLineOptionSet(
new CommandLineOption("runTests", () => { shouldRunTests = true; }),
new CommandLineOption("runEditorTests", () => { shouldRunTests = true; })
);
optionSet.Parse(Environment.GetCommandLineArgs());
return shouldRunTests;
}
static Executer s_Executer;
static Executer executer
{
get
{
if (s_Executer == null)
{
Func<bool> compilationCheck = () => EditorUtility.scriptCompilationFailed;
Action<string> actionLogger = (string msg) => { Debug.LogFormat(LogType.Log, LogOption.NoStacktrace, null, msg); };
var apiSettingsBuilder = new SettingsBuilder(new TestSettingsDeserializer(() => new TestSettings()), actionLogger, Debug.LogWarning, File.Exists, compilationCheck);
s_Executer = new Executer(ScriptableObject.CreateInstance<TestRunnerApi>(), apiSettingsBuilder, Debug.LogErrorFormat, Debug.LogException, EditorApplication.Exit, compilationCheck);
}
return s_Executer;
}
}
}
}

View File

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

View File

@ -0,0 +1,74 @@
using System;
using UnityEditor.TestRunner.TestLaunchers;
using UnityEditor.TestTools.TestRunner.Api;
using UnityEngine;
namespace UnityEditor.TestTools.TestRunner.CommandLineTest
{
internal class TimeoutCallbacks : ScriptableObject, ICallbacks
{
internal const int k_DefaultTimeout = 600;
private Func<Action, double, IDelayedCallback> m_DelayedCallbackFactory;
private Action<string, object[]> m_LogErrorFormat;
private Action<int> m_ExitApplication;
private double m_CurrentTimeout;
private IDelayedCallback m_TimeoutCallback;
public void Init(Func<Action, double, IDelayedCallback> delayedCallbackFactory, Action<string, object[]> logErrorFormat, Action<int> exitApplication)
{
m_DelayedCallbackFactory = delayedCallbackFactory;
m_LogErrorFormat = logErrorFormat;
m_ExitApplication = exitApplication;
}
public void RunFinished(ITestResultAdaptor result)
{
if (m_TimeoutCallback != null)
{
m_TimeoutCallback.Clear();
}
}
public void RunStarted(ITestAdaptor testsToRun)
{
ResetToTimeout(k_DefaultTimeout);
}
public void TestFinished(ITestResultAdaptor result)
{
ResetToTimeout(k_DefaultTimeout);
}
public void TestStarted(ITestAdaptor test)
{
ResetToTimeout(k_DefaultTimeout + test.TestCaseTimeout / 1000);
}
private void ResetToTimeout(double timeoutValue)
{
if (m_TimeoutCallback != null && Math.Abs(m_CurrentTimeout - timeoutValue) < 0.1f)
{
m_TimeoutCallback.Reset();
}
else
{
if (m_TimeoutCallback != null)
{
m_TimeoutCallback.Clear();
}
m_TimeoutCallback = m_DelayedCallbackFactory(TimeoutReached, timeoutValue);
m_CurrentTimeout = timeoutValue;
}
}
private void TimeoutReached()
{
RemotePlayerLogController.instance.StopLogWriters();
m_LogErrorFormat("Test execution timed out.", new object[0]);
m_ExitApplication((int)Executer.ReturnCodes.RunError);
}
}
}

View File

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

View File

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

View File

@ -0,0 +1,11 @@
namespace UnityEditor.TestTools.TestRunner.GUI
{
internal class AssetsDatabaseHelper : IAssetsDatabaseHelper
{
public void OpenAssetInItsDefaultExternalEditor(string assetPath, int line)
{
var asset = AssetDatabase.LoadMainAssetAtPath(assetPath);
AssetDatabase.OpenAsset(asset, line);
}
}
}

View File

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

View File

@ -0,0 +1,101 @@
using System;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text.RegularExpressions;
using UnityEditor.Utils;
using UnityEngine;
namespace UnityEditor.TestTools.TestRunner.GUI
{
internal class GuiHelper : IGuiHelper
{
public GuiHelper(IMonoCecilHelper monoCecilHelper, IAssetsDatabaseHelper assetsDatabaseHelper)
{
MonoCecilHelper = monoCecilHelper;
AssetsDatabaseHelper = assetsDatabaseHelper;
}
protected IMonoCecilHelper MonoCecilHelper { get; private set; }
public IAssetsDatabaseHelper AssetsDatabaseHelper { get; private set; }
public void OpenScriptInExternalEditor(Type type, MethodInfo method)
{
var fileOpenInfo = GetFileOpenInfo(type, method);
if (string.IsNullOrEmpty(fileOpenInfo.FilePath))
{
Debug.LogWarning("Failed to open test method source code in external editor. Inconsistent filename and yield return operator in target method.");
return;
}
if (fileOpenInfo.LineNumber == 1)
{
Debug.LogWarning("Failed to get a line number for unity test method. So please find it in opened file in external editor.");
}
AssetsDatabaseHelper.OpenAssetInItsDefaultExternalEditor(fileOpenInfo.FilePath, fileOpenInfo.LineNumber);
}
public IFileOpenInfo GetFileOpenInfo(Type type, MethodInfo method)
{
const string fileExtension = ".cs";
var fileOpenInfo = MonoCecilHelper.TryGetCecilFileOpenInfo(type, method);
if (string.IsNullOrEmpty(fileOpenInfo.FilePath))
{
var dirPath = Paths.UnifyDirectorySeparator(Application.dataPath);
var allCsFiles = Directory.GetFiles(dirPath, string.Format("*{0}", fileExtension), SearchOption.AllDirectories)
.Select(Paths.UnifyDirectorySeparator);
var fileName = allCsFiles.FirstOrDefault(x =>
x.Split(Path.DirectorySeparatorChar).Last().Equals(string.Concat(type.Name, fileExtension)));
fileOpenInfo.FilePath = fileName ?? string.Empty;
}
fileOpenInfo.FilePath = FilePathToAssetsRelativeAndUnified(fileOpenInfo.FilePath);
return fileOpenInfo;
}
public string FilePathToAssetsRelativeAndUnified(string filePath)
{
if (string.IsNullOrEmpty(filePath))
return string.Empty;
filePath = Paths.UnifyDirectorySeparator(filePath);
var length = Paths.UnifyDirectorySeparator(Application.dataPath).Length - "Assets".Length;
return filePath.Substring(length);
}
public bool OpenScriptInExternalEditor(string stacktrace)
{
if (string.IsNullOrEmpty(stacktrace))
return false;
var regex = new Regex("in (?<path>.*):{1}(?<line>[0-9]+)");
var matchingLines = stacktrace.Split(new[] { Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries).Where(x => regex.IsMatch(x)).ToList();
if (!matchingLines.Any())
return false;
var fileOpenInfo = matchingLines
.Select(x => regex.Match(x))
.Select(x =>
new FileOpenInfo
{
FilePath = x.Groups["path"].Value,
LineNumber = int.Parse(x.Groups["line"].Value)
})
.First(openInfo => !string.IsNullOrEmpty(openInfo.FilePath) && File.Exists(openInfo.FilePath));
var filePath = FilePathToAssetsRelativeAndUnified(fileOpenInfo.FilePath);
AssetsDatabaseHelper.OpenAssetInItsDefaultExternalEditor(filePath, fileOpenInfo.LineNumber);
return true;
}
}
}

View File

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

View File

@ -0,0 +1,7 @@
namespace UnityEditor.TestTools.TestRunner.GUI
{
internal interface IAssetsDatabaseHelper
{
void OpenAssetInItsDefaultExternalEditor(string assetPath, int line);
}
}

View File

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

View File

@ -0,0 +1,13 @@
using System;
using System.Reflection;
namespace UnityEditor.TestTools.TestRunner.GUI
{
internal interface IGuiHelper
{
bool OpenScriptInExternalEditor(string stacktrace);
void OpenScriptInExternalEditor(Type type, MethodInfo method);
IFileOpenInfo GetFileOpenInfo(Type type, MethodInfo method);
string FilePathToAssetsRelativeAndUnified(string filePath);
}
}

View File

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

View File

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

View File

@ -0,0 +1,12 @@
namespace UnityEditor.TestTools.TestRunner.GUI
{
internal class RenderingOptions
{
public string nameFilter;
public bool showSucceeded;
public bool showFailed;
public bool showIgnored;
public bool showNotRunned;
public string[] categories;
}
}

View File

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

View File

@ -0,0 +1,175 @@
// ****************************************************************
// Based on nUnit 2.6.2 (http://www.nunit.org/)
// ****************************************************************
using System;
using System.Collections.Generic;
using UnityEngine.TestTools.TestRunner.GUI;
namespace UnityEditor.TestTools.TestRunner.GUI
{
/// <summary>
/// Summary description for ResultSummarizer.
/// </summary>
internal class ResultSummarizer
{
private int m_ErrorCount = -1;
private int m_FailureCount;
private int m_IgnoreCount = -1;
private int m_InconclusiveCount = -1;
private int m_NotRunnable = -1;
private int m_ResultCount;
private int m_SkipCount;
private int m_SuccessCount;
private int m_TestsRun;
private TimeSpan m_Duration = TimeSpan.FromSeconds(0);
public ResultSummarizer(IEnumerable<TestRunnerResult> results)
{
foreach (var result in results)
Summarize(result);
}
public bool success
{
get { return m_FailureCount == 0; }
}
/// <summary>
/// Returns the number of test cases for which results
/// have been summarized. Any tests excluded by use of
/// Category or Explicit attributes are not counted.
/// </summary>
public int ResultCount
{
get { return m_ResultCount; }
}
/// <summary>
/// Returns the number of test cases actually run, which
/// is the same as ResultCount, less any Skipped, Ignored
/// or NonRunnable tests.
/// </summary>
public int TestsRun
{
get { return m_TestsRun; }
}
/// <summary>
/// Returns the number of tests that passed
/// </summary>
public int Passed
{
get { return m_SuccessCount; }
}
/// <summary>
/// Returns the number of test cases that had an error.
/// </summary>
public int errors
{
get { return m_ErrorCount; }
}
/// <summary>
/// Returns the number of test cases that failed.
/// </summary>
public int failures
{
get { return m_FailureCount; }
}
/// <summary>
/// Returns the number of test cases that failed.
/// </summary>
public int inconclusive
{
get { return m_InconclusiveCount; }
}
/// <summary>
/// Returns the number of test cases that were not runnable
/// due to errors in the signature of the class or method.
/// Such tests are also counted as Errors.
/// </summary>
public int notRunnable
{
get { return m_NotRunnable; }
}
/// <summary>
/// Returns the number of test cases that were skipped.
/// </summary>
public int Skipped
{
get { return m_SkipCount; }
}
public int ignored
{
get { return m_IgnoreCount; }
}
public double duration
{
get { return m_Duration.TotalSeconds; }
}
public int testsNotRun
{
get { return m_SkipCount + m_IgnoreCount + m_NotRunnable; }
}
public void Summarize(TestRunnerResult result)
{
m_Duration += TimeSpan.FromSeconds(result.duration);
m_ResultCount++;
if (result.resultStatus != TestRunnerResult.ResultStatus.NotRun)
{
//TODO implement missing features
// if(result.IsIgnored)
// {
// m_IgnoreCount++;
// return;
// }
m_SkipCount++;
return;
}
switch (result.resultStatus)
{
case TestRunnerResult.ResultStatus.Passed:
m_SuccessCount++;
m_TestsRun++;
break;
case TestRunnerResult.ResultStatus.Failed:
m_FailureCount++;
m_TestsRun++;
break;
//TODO implement missing features
// case TestResultState.Error:
// case TestResultState.Cancelled:
// m_ErrorCount++;
// m_TestsRun++;
// break;
// case TestResultState.Inconclusive:
// m_InconclusiveCount++;
// m_TestsRun++;
// break;
// case TestResultState.NotRunnable:
// m_NotRunnable++;
// // errorCount++;
// break;
// case TestResultState.Ignored:
// m_IgnoreCount++;
// break;
default:
m_SkipCount++;
break;
}
}
}
}

View File

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

View File

@ -0,0 +1,105 @@
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
using UnityEngine.TestTools.TestRunner.GUI;
namespace UnityEditor.TestTools.TestRunner.GUI
{
internal class TestFilterSettings
{
public bool showSucceeded;
public bool showFailed;
public bool showIgnored;
public bool showNotRun;
public string filterByName;
public int filterByCategory;
private GUIContent m_SucceededBtn;
private GUIContent m_FailedBtn;
private GUIContent m_IgnoredBtn;
private GUIContent m_NotRunBtn;
public string[] availableCategories;
private readonly string m_PrefsKey;
public TestFilterSettings(string prefsKey)
{
availableCategories = null;
m_PrefsKey = prefsKey;
Load();
UpdateCounters(Enumerable.Empty<TestRunnerResult>());
}
public void Load()
{
showSucceeded = EditorPrefs.GetBool(m_PrefsKey + ".ShowSucceeded", true);
showFailed = EditorPrefs.GetBool(m_PrefsKey + ".ShowFailed", true);
showIgnored = EditorPrefs.GetBool(m_PrefsKey + ".ShowIgnored", true);
showNotRun = EditorPrefs.GetBool(m_PrefsKey + ".ShowNotRun", true);
filterByName = EditorPrefs.GetString(m_PrefsKey + ".FilterByName", string.Empty);
filterByCategory = EditorPrefs.GetInt(m_PrefsKey + ".FilterByCategory", 0);
}
public void Save()
{
EditorPrefs.SetBool(m_PrefsKey + ".ShowSucceeded", showSucceeded);
EditorPrefs.SetBool(m_PrefsKey + ".ShowFailed", showFailed);
EditorPrefs.SetBool(m_PrefsKey + ".ShowIgnored", showIgnored);
EditorPrefs.SetBool(m_PrefsKey + ".ShowNotRun", showNotRun);
EditorPrefs.SetString(m_PrefsKey + ".FilterByName", filterByName);
EditorPrefs.SetInt(m_PrefsKey + ".FilterByCategory", filterByCategory);
}
public void UpdateCounters(IEnumerable<TestRunnerResult> results)
{
var summary = new ResultSummarizer(results);
m_SucceededBtn = new GUIContent(summary.Passed.ToString(), Icons.s_SuccessImg, "Show tests that succeeded");
m_FailedBtn = new GUIContent((summary.errors + summary.failures + summary.inconclusive).ToString(), Icons.s_FailImg, "Show tests that failed");
m_IgnoredBtn = new GUIContent((summary.ignored + summary.notRunnable).ToString(), Icons.s_IgnoreImg, "Show tests that are ignored");
m_NotRunBtn = new GUIContent((summary.testsNotRun - summary.ignored - summary.notRunnable).ToString(), Icons.s_UnknownImg, "Show tests that didn't run");
}
public string[] GetSelectedCategories()
{
if (availableCategories == null)
return new string[0];
return availableCategories.Where((c, i) => (filterByCategory & (1 << i)) != 0).ToArray();
}
public void OnGUI()
{
EditorGUI.BeginChangeCheck();
filterByName = GUILayout.TextField(filterByName, "ToolbarSeachTextField", GUILayout.MinWidth(100), GUILayout.MaxWidth(250), GUILayout.ExpandWidth(true));
if (GUILayout.Button(GUIContent.none, string.IsNullOrEmpty(filterByName) ? "ToolbarSeachCancelButtonEmpty" : "ToolbarSeachCancelButton"))
filterByName = string.Empty;
if (availableCategories != null && availableCategories.Length > 0)
filterByCategory = EditorGUILayout.MaskField(filterByCategory, availableCategories, EditorStyles.toolbarDropDown, GUILayout.MaxWidth(90));
showSucceeded = GUILayout.Toggle(showSucceeded, m_SucceededBtn, EditorStyles.toolbarButton);
showFailed = GUILayout.Toggle(showFailed, m_FailedBtn, EditorStyles.toolbarButton);
showIgnored = GUILayout.Toggle(showIgnored, m_IgnoredBtn, EditorStyles.toolbarButton);
showNotRun = GUILayout.Toggle(showNotRun, m_NotRunBtn, EditorStyles.toolbarButton);
if (EditorGUI.EndChangeCheck())
Save();
}
public RenderingOptions BuildRenderingOptions()
{
var options = new RenderingOptions();
options.showSucceeded = showSucceeded;
options.showFailed = showFailed;
options.showIgnored = showIgnored;
options.showNotRunned = showNotRun;
options.nameFilter = filterByName;
options.categories = GetSelectedCategories();
return options;
}
}
}

View File

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

View File

@ -0,0 +1,111 @@
using System.Collections.Generic;
using System.Linq;
using UnityEditor.IMGUI.Controls;
using UnityEditor.TestTools.TestRunner.Api;
using UnityEngine.TestRunner.NUnitExtensions;
using UnityEngine.TestTools.TestRunner.GUI;
using UnityEngine.TestRunner.NUnitExtensions.Filters;
namespace UnityEditor.TestTools.TestRunner.GUI
{
internal class TestTreeViewBuilder
{
public List<TestRunnerResult> results = new List<TestRunnerResult>();
private readonly List<TestRunnerResult> m_OldTestResultList;
private readonly TestRunnerUIFilter m_UIFilter;
private readonly ITestAdaptor m_TestListRoot;
private readonly List<string> m_AvailableCategories = new List<string>();
public string[] AvailableCategories
{
get { return m_AvailableCategories.Distinct().OrderBy(a => a).ToArray(); }
}
public TestTreeViewBuilder(ITestAdaptor tests, List<TestRunnerResult> oldTestResultResults, TestRunnerUIFilter uiFilter)
{
m_AvailableCategories.Add(CategoryFilterExtended.k_DefaultCategory);
m_OldTestResultList = oldTestResultResults;
m_TestListRoot = tests;
m_UIFilter = uiFilter;
}
public TreeViewItem BuildTreeView(TestFilterSettings settings, bool sceneBased, string sceneName)
{
var rootItem = new TreeViewItem(int.MaxValue, 0, null, "Invisible Root Item");
ParseTestTree(0, rootItem, m_TestListRoot);
return rootItem;
}
private bool IsFilteredOutByUIFilter(ITestAdaptor test, TestRunnerResult result)
{
if (m_UIFilter.PassedHidden && result.resultStatus == TestRunnerResult.ResultStatus.Passed)
return true;
if (m_UIFilter.FailedHidden && (result.resultStatus == TestRunnerResult.ResultStatus.Failed || result.resultStatus == TestRunnerResult.ResultStatus.Inconclusive))
return true;
if (m_UIFilter.NotRunHidden && (result.resultStatus == TestRunnerResult.ResultStatus.NotRun || result.resultStatus == TestRunnerResult.ResultStatus.Skipped))
return true;
if (m_UIFilter.CategoryFilter.Length > 0)
return !test.Categories.Any(category => m_UIFilter.CategoryFilter.Contains(category));
return false;
}
private void ParseTestTree(int depth, TreeViewItem rootItem, ITestAdaptor testElement)
{
m_AvailableCategories.AddRange(testElement.Categories);
var testElementId = testElement.UniqueName;
if (!testElement.HasChildren)
{
var result = m_OldTestResultList.FirstOrDefault(a => a.uniqueId == testElementId);
if (result != null &&
(result.ignoredOrSkipped
|| result.notRunnable
|| testElement.RunState == RunState.NotRunnable
|| testElement.RunState == RunState.Ignored
|| testElement.RunState == RunState.Skipped
)
)
{
//if the test was or becomes ignored or not runnable, we recreate the result in case it has changed
result = null;
}
if (result == null)
{
result = new TestRunnerResult(testElement);
}
results.Add(result);
var test = new TestTreeViewItem(testElement, depth, rootItem);
if (!IsFilteredOutByUIFilter(testElement, result))
rootItem.AddChild(test);
test.SetResult(result);
return;
}
var groupResult = m_OldTestResultList.FirstOrDefault(a => a.uniqueId == testElementId);
if (groupResult == null)
{
groupResult = new TestRunnerResult(testElement);
}
results.Add(groupResult);
var group = new TestTreeViewItem(testElement, depth, rootItem);
group.SetResult(groupResult);
depth++;
foreach (var child in testElement.Children)
{
ParseTestTree(depth, group, child);
}
if (testElement.IsTestAssembly && !testElement.HasChildren)
return;
if (group.hasChildren)
rootItem.AddChild(group);
}
}
}

View File

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

View File

@ -0,0 +1,135 @@
using System;
using System.IO;
using System.Linq;
using UnityEditor.ProjectWindowCallback;
using UnityEditor.Scripting.ScriptCompilation;
using UnityEngine;
namespace UnityEditor.TestTools.TestRunner.GUI
{
internal class TestListGUIHelper
{
private const string kResourcesTemplatePath = "Resources/ScriptTemplates";
private const string kAssemblyDefinitionTestTemplate = "92-Assembly Definition-NewTestAssembly.asmdef.txt";
private const string kAssemblyDefinitionEditModeTestTemplate =
"92-Assembly Definition-NewEditModeTestAssembly.asmdef.txt";
private const string kTestScriptTemplate = "83-C# Script-NewTestScript.cs.txt";
private const string kNewTestScriptName = "NewTestScript.cs";
private const string kNunit = "nunit.framework.dll";
[MenuItem("Assets/Create/Testing/Tests Assembly Folder", false, 83)]
public static void MenuItemAddFolderAndAsmDefForTesting()
{
AddFolderAndAsmDefForTesting();
}
[MenuItem("Assets/Create/Testing/Tests Assembly Folder", true, 83)]
public static bool MenuItemAddFolderAndAsmDefForTestingWithValidation()
{
return !SelectedFolderContainsTestAssembly();
}
public static void AddFolderAndAsmDefForTesting(bool isEditorOnly = false)
{
ProjectWindowUtil.CreateFolderWithTemplates("Tests",
isEditorOnly ? kAssemblyDefinitionEditModeTestTemplate : kAssemblyDefinitionTestTemplate);
}
public static bool SelectedFolderContainsTestAssembly()
{
var theNearestCustomScriptAssembly = GetTheNearestCustomScriptAssembly();
if (theNearestCustomScriptAssembly != null)
{
return theNearestCustomScriptAssembly.PrecompiledReferences != null && theNearestCustomScriptAssembly.PrecompiledReferences.Any(x => Path.GetFileName(x) == kNunit);
}
return false;
}
[MenuItem("Assets/Create/Testing/C# Test Script", false, 83)]
public static void AddTest()
{
var basePath = Path.Combine(EditorApplication.applicationContentsPath, kResourcesTemplatePath);
var destPath = Path.Combine(GetActiveFolderPath(), kNewTestScriptName);
var templatePath = Path.Combine(basePath, kTestScriptTemplate);
var icon = EditorGUIUtility.IconContent("cs Script Icon").image as Texture2D;
ProjectWindowUtil.StartNameEditingIfProjectWindowExists(0,
ScriptableObject.CreateInstance<DoCreateScriptAsset>(), destPath, icon, templatePath);
AssetDatabase.Refresh();
}
[MenuItem("Assets/Create/Testing/C# Test Script", true, 83)]
public static bool CanAddScriptAndItWillCompile()
{
return CanAddEditModeTestScriptAndItWillCompile() || CanAddPlayModeTestScriptAndItWillCompile();
}
public static bool CanAddEditModeTestScriptAndItWillCompile()
{
var theNearestCustomScriptAssembly = GetTheNearestCustomScriptAssembly();
if (theNearestCustomScriptAssembly != null)
{
return (theNearestCustomScriptAssembly.AssemblyFlags & AssemblyFlags.EditorOnly) ==
AssemblyFlags.EditorOnly;
}
var activeFolderPath = GetActiveFolderPath();
return activeFolderPath.ToLower().Contains("/editor");
}
public static bool CanAddPlayModeTestScriptAndItWillCompile()
{
if (PlayerSettings.playModeTestRunnerEnabled)
{
return true;
}
var theNearestCustomScriptAssembly = GetTheNearestCustomScriptAssembly();
if (theNearestCustomScriptAssembly == null)
{
return false;
}
var hasTestAssemblyFlag = theNearestCustomScriptAssembly.PrecompiledReferences != null && theNearestCustomScriptAssembly.PrecompiledReferences.Any(x => Path.GetFileName(x) == kNunit);;
var editorOnlyAssembly = (theNearestCustomScriptAssembly.AssemblyFlags & AssemblyFlags.EditorOnly) != 0;
return hasTestAssemblyFlag && !editorOnlyAssembly;
}
public static string GetActiveFolderPath()
{
var path = "Assets";
foreach (var obj in Selection.GetFiltered(typeof(UnityEngine.Object), SelectionMode.Assets))
{
path = AssetDatabase.GetAssetPath(obj);
if (!string.IsNullOrEmpty(path) && File.Exists(path))
{
path = Path.GetDirectoryName(path);
break;
}
}
return path;
}
private static CustomScriptAssembly GetTheNearestCustomScriptAssembly()
{
CustomScriptAssembly findCustomScriptAssemblyFromScriptPath;
try
{
findCustomScriptAssemblyFromScriptPath =
EditorCompilationInterface.Instance.FindCustomScriptAssemblyFromScriptPath(
Path.Combine(GetActiveFolderPath(), "Foo.cs"));
}
catch (Exception)
{
return null;
}
return findCustomScriptAssemblyFromScriptPath;
}
}
}

View File

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

View File

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

Some files were not shown because too many files have changed in this diff Show More