Initial Commit
This commit is contained in:
parent
53eb92e9af
commit
270ab7d11f
15341 changed files with 700234 additions and 0 deletions
|
@ -0,0 +1,79 @@
|
|||
using System;
|
||||
using System.Linq;
|
||||
using UnityEngine.TestRunner.NUnitExtensions.Runner;
|
||||
using UnityEngine.TestTools.Logging;
|
||||
using UnityEngine.TestTools.TestRunner;
|
||||
|
||||
namespace UnityEngine.TestTools.NUnitExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// This class delegates actions from the NUnit thread that should be executed on the main thread.
|
||||
/// NUnit thread calls Delegate which blocks the execution on the thread until the action is executed.
|
||||
/// The main thread will poll for awaiting actions (HasAction) and invoke them (Execute).
|
||||
/// Once the action is executed, the main thread releases the lock and executino on the NUnit thread is continued.
|
||||
/// </summary>
|
||||
internal class ActionDelegator : BaseDelegator
|
||||
{
|
||||
private Func<object> m_Action;
|
||||
public object Delegate(Action action)
|
||||
{
|
||||
return Delegate(() => { action(); return null; });
|
||||
}
|
||||
|
||||
public object Delegate(Func<object> action)
|
||||
{
|
||||
if (m_Aborted)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
AssertState();
|
||||
m_Context = UnityTestExecutionContext.CurrentContext;
|
||||
|
||||
m_Signal.Reset();
|
||||
m_Action = action;
|
||||
|
||||
WaitForSignal();
|
||||
|
||||
return HandleResult();
|
||||
}
|
||||
|
||||
private void AssertState()
|
||||
{
|
||||
if (m_Action != null)
|
||||
{
|
||||
throw new Exception("Action not executed yet");
|
||||
}
|
||||
}
|
||||
|
||||
public bool HasAction()
|
||||
{
|
||||
return m_Action != null;
|
||||
}
|
||||
|
||||
public void Execute(LogScope logScope)
|
||||
{
|
||||
try
|
||||
{
|
||||
SetCurrentTestContext();
|
||||
m_Result = m_Action();
|
||||
if (logScope.AnyFailingLogs())
|
||||
{
|
||||
var failingLog = logScope.FailingLogs.First();
|
||||
throw new UnhandledLogMessageException(failingLog);
|
||||
}
|
||||
if (logScope.ExpectedLogs.Any())
|
||||
throw new UnexpectedLogMessageException(LogScope.Current.ExpectedLogs.Peek());
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
m_Exception = e;
|
||||
}
|
||||
finally
|
||||
{
|
||||
m_Action = null;
|
||||
m_Signal.Set();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 4f939b9e23a0946439b812551e07ac81
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,8 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 0cb14878543cf3d4f8472b15f7ecf0e3
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,85 @@
|
|||
using System.Collections.Generic;
|
||||
using NUnit.Framework;
|
||||
using NUnit.Framework.Interfaces;
|
||||
using NUnit.Framework.Internal;
|
||||
|
||||
namespace UnityEngine.TestTools
|
||||
{
|
||||
/// <summary>
|
||||
/// This attribute is an alternative to the standard `Ignore` attribute in [NUnit](https://nunit.org/). It allows for ignoring tests only under a specified condition. The condition evaluates during `OnLoad`, referenced by ID.
|
||||
/// </summary>
|
||||
public class ConditionalIgnoreAttribute : NUnitAttribute, IApplyToTest
|
||||
{
|
||||
string m_ConditionKey;
|
||||
string m_IgnoreReason;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ConditionalIgnoreAttribute"/> class with a condition key.
|
||||
/// </summary>
|
||||
/// <param name="conditionKey">The key to check for enabling the conditional ignore. The condition is set with the static <see cref="AddConditionalIgnoreMapping"/> method.</param>
|
||||
/// <param name="ignoreReason">The reason for the ignore.</param>
|
||||
public ConditionalIgnoreAttribute(string conditionKey, string ignoreReason)
|
||||
{
|
||||
m_ConditionKey = conditionKey;
|
||||
m_IgnoreReason = ignoreReason;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Modifies a test as defined for the specific attribute.
|
||||
/// </summary>
|
||||
/// <param name="test">The test to modify</param>
|
||||
public void ApplyToTest(Test test)
|
||||
{
|
||||
var key = m_ConditionKey.ToLowerInvariant();
|
||||
if (m_ConditionMap.ContainsKey(key) && m_ConditionMap[key])
|
||||
{
|
||||
test.RunState = RunState.Ignored;
|
||||
string skipReason = string.Format(m_IgnoreReason);
|
||||
test.Properties.Add(PropertyNames.SkipReason, skipReason);
|
||||
}
|
||||
}
|
||||
|
||||
static Dictionary<string, bool> m_ConditionMap = new Dictionary<string, bool>();
|
||||
|
||||
/// <summary>
|
||||
/// Adds a flag indicating whether tests with the same key should be ignored.
|
||||
/// </summary>
|
||||
/// <param name="key">The key to ignore tests for.</param>
|
||||
/// <param name="value">A boolean value indicating whether the tests should be ignored.</param>
|
||||
/// <example>
|
||||
/// An example in which tests are ignored in the Mac editor only.
|
||||
/// <code>
|
||||
/// using UnityEditor;
|
||||
/// using NUnit.Framework;
|
||||
/// using UnityEngine.TestTools;
|
||||
///
|
||||
/// [InitializeOnLoad]
|
||||
/// public class OnLoad
|
||||
/// {
|
||||
/// static OnLoad()
|
||||
/// {
|
||||
/// var editorIsOSX = false;
|
||||
/// #if UNITY_EDITOR_OSX
|
||||
/// editorIsOSX = true;
|
||||
/// #endif
|
||||
///
|
||||
/// ConditionalIgnoreAttribute.AddConditionalIgnoreMapping("IgnoreInMacEditor", editorIsOSX);
|
||||
/// }
|
||||
/// }
|
||||
///
|
||||
/// public class MyTestClass
|
||||
/// {
|
||||
/// [Test, ConditionalIgnore("IgnoreInMacEditor", "Ignored on Mac editor.")]
|
||||
/// public void TestNeverRunningInMacEditor()
|
||||
/// {
|
||||
/// Assert.Pass();
|
||||
/// }
|
||||
/// }
|
||||
/// </code>
|
||||
/// </example>
|
||||
public static void AddConditionalIgnoreMapping(string key, bool value)
|
||||
{
|
||||
m_ConditionMap.Add(key.ToLowerInvariant(), value);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: c82a8473f4a8f7b42a004c91e06d2f2b
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,57 @@
|
|||
using System;
|
||||
using System.Collections;
|
||||
using NUnit.Framework;
|
||||
using NUnit.Framework.Interfaces;
|
||||
using NUnit.Framework.Internal;
|
||||
|
||||
namespace UnityEngine.TestTools
|
||||
{
|
||||
internal class TestEnumerator
|
||||
{
|
||||
private readonly ITestExecutionContext m_Context;
|
||||
private static IEnumerator m_TestEnumerator;
|
||||
|
||||
public static IEnumerator Enumerator { get { return m_TestEnumerator; } }
|
||||
|
||||
public static void Reset()
|
||||
{
|
||||
m_TestEnumerator = null;
|
||||
}
|
||||
|
||||
public TestEnumerator(ITestExecutionContext context, IEnumerator testEnumerator)
|
||||
{
|
||||
m_Context = context;
|
||||
m_TestEnumerator = testEnumerator;
|
||||
}
|
||||
|
||||
public IEnumerator Execute()
|
||||
{
|
||||
m_Context.CurrentResult.SetResult(ResultState.Success);
|
||||
|
||||
while (true)
|
||||
{
|
||||
object current = null;
|
||||
try
|
||||
{
|
||||
if (!m_TestEnumerator.MoveNext())
|
||||
{
|
||||
yield break;
|
||||
}
|
||||
|
||||
if (!m_Context.CurrentResult.ResultState.Equals(ResultState.Success))
|
||||
{
|
||||
yield break;
|
||||
}
|
||||
|
||||
current = m_TestEnumerator.Current;
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
m_Context.CurrentResult.RecordException(exception);
|
||||
yield break;
|
||||
}
|
||||
yield return current;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 750aad009559b814dbc27001341fc1c3
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,36 @@
|
|||
using System;
|
||||
|
||||
namespace UnityEngine.TestTools
|
||||
{
|
||||
/// <summary>
|
||||
/// The presence of this attribute will cause the test runner to require that every single log is expected. By
|
||||
/// default, the runner will only automatically fail on any error logs, so this adds warnings and infos as well.
|
||||
/// It is the same as calling `LogAssert.NoUnexpectedReceived()` at the bottom of every affected test.
|
||||
///
|
||||
/// This attribute can be applied to test assemblies (will affect every test in the assembly), fixtures (will
|
||||
/// affect every test in the fixture), or on individual test methods. It is also automatically inherited from base
|
||||
/// fixtures.
|
||||
///
|
||||
/// The MustExpect property (on by default) lets you selectively enable or disable the higher level value. For
|
||||
/// example when migrating an assembly to this more strict checking method, you might attach
|
||||
/// `[assembly:TestMustExpectAllLogs]` to the assembly itself, but then whitelist failing fixtures and test methods
|
||||
/// with `[TestMustExpectAllLogs(MustExpect=false)]` until they can be migrated. This also means new tests in that
|
||||
/// assembly would be required to have the more strict checking.
|
||||
/// </summary>
|
||||
[AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Class | AttributeTargets.Method)]
|
||||
public class TestMustExpectAllLogsAttribute : Attribute
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes and returns an instance of TestMustExpectAllLogsAttribute.
|
||||
/// </summary>
|
||||
/// <param name="mustExpect">
|
||||
/// A value indicating whether the test must expect all logs.
|
||||
/// </param>
|
||||
public TestMustExpectAllLogsAttribute(bool mustExpect = true)
|
||||
=> MustExpect = mustExpect;
|
||||
/// <summary>
|
||||
/// Returns the flag of whether the test must expect all logs.
|
||||
/// </summary>
|
||||
public bool MustExpect { get; }
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 3803f736886e77842995ddbc3531afaa
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,20 @@
|
|||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using NUnit.Framework.Interfaces;
|
||||
using NUnit.Framework.Internal.Builders;
|
||||
|
||||
namespace UnityEngine.TestTools
|
||||
{
|
||||
internal class UnityCombinatorialStrategy : CombinatorialStrategy, ICombiningStrategy
|
||||
{
|
||||
public new IEnumerable<ITestCaseData> GetTestCases(IEnumerable[] sources)
|
||||
{
|
||||
var testCases = base.GetTestCases(sources);
|
||||
foreach (var testCase in testCases)
|
||||
{
|
||||
testCase.GetType().GetProperty("ExpectedResult").SetValue(testCase, new object(), null);
|
||||
}
|
||||
return testCases;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 7af6ac3e6b51b8d4aab04adc85b8de2f
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,82 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using NUnit.Framework;
|
||||
using NUnit.Framework.Interfaces;
|
||||
using NUnit.Framework.Internal;
|
||||
|
||||
namespace UnityEngine.TestTools
|
||||
{
|
||||
/// <summary>
|
||||
/// Use this attribute to define a specific set of platforms you want or do not want your test(s) to run on.
|
||||
///
|
||||
/// You can use this attribute on the test method, test class, or test assembly level. Use the supported <see cref="RuntimePlatform"/> enumeration values to specify the platforms. You can also specify which platforms to test by passing one or more `RuntimePlatform` values along with or without the include or exclude properties as parameters to the [Platform](https://github.com/nunit/docs/wiki/Platform-Attribute) attribute constructor.
|
||||
///
|
||||
/// The test(s) skips if the current target platform is:
|
||||
/// - Not explicitly specified in the included platforms list
|
||||
/// - In the excluded platforms list
|
||||
/// </summary>
|
||||
[AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = true, Inherited = false)]
|
||||
public class UnityPlatformAttribute : NUnitAttribute, IApplyToTest
|
||||
{
|
||||
/// <summary>
|
||||
/// A subset of platforms you need to have your tests run on.
|
||||
/// </summary>
|
||||
public RuntimePlatform[] include { get; set; }
|
||||
/// <summary>
|
||||
/// List the platforms you do not want to have your tests run on.
|
||||
/// </summary>
|
||||
public RuntimePlatform[] exclude { get; set; }
|
||||
|
||||
private string m_skippedReason;
|
||||
|
||||
/// <summary>
|
||||
/// Constructs a new instance of the <see cref="UnityPlatformAttribute"/> class.
|
||||
/// </summary>
|
||||
public UnityPlatformAttribute()
|
||||
{
|
||||
include = new List<RuntimePlatform>().ToArray();
|
||||
exclude = new List<RuntimePlatform>().ToArray();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructs a new instance of the <see cref="UnityPlatformAttribute"/> class with a list of platforms to include.
|
||||
/// </summary>
|
||||
/// <param name="include">The different <see cref="RuntimePlatform"/> to run the test on.</param>
|
||||
public UnityPlatformAttribute(params RuntimePlatform[] include)
|
||||
: this()
|
||||
{
|
||||
this.include = include;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Modifies a test as defined for the specific attribute.
|
||||
/// </summary>
|
||||
/// <param name="test">The test to modify</param>
|
||||
public void ApplyToTest(Test test)
|
||||
{
|
||||
if (test.RunState == RunState.NotRunnable || test.RunState == RunState.Ignored || IsPlatformSupported(Application.platform))
|
||||
{
|
||||
return;
|
||||
}
|
||||
test.RunState = RunState.Skipped;
|
||||
test.Properties.Add("_SKIPREASON", m_skippedReason);
|
||||
}
|
||||
|
||||
internal bool IsPlatformSupported(RuntimePlatform testTargetPlatform)
|
||||
{
|
||||
if (include.Any() && !include.Any(x => x == testTargetPlatform))
|
||||
{
|
||||
m_skippedReason = string.Format("Only supported on {0}", string.Join(", ", include.Select(x => x.ToString()).ToArray()));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (exclude.Any(x => x == testTargetPlatform))
|
||||
{
|
||||
m_skippedReason = string.Format("Not supported on {0}", string.Join(", ", include.Select(x => x.ToString()).ToArray()));
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 5440c1153b397e14c9c7b1d6eb83b9f9
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,37 @@
|
|||
using System;
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace UnityEngine.TestTools
|
||||
{
|
||||
/// <summary>
|
||||
/// The `UnitySetUp` and <see cref="UnityTearDownAttribute"/> attributes are identical to the standard `SetUp` and `TearDown` attributes, with the exception that they allow for <see cref="IEditModeTestYieldInstruction"/>. The `UnitySetUp` and `UnityTearDown` attributes expect a return type of [IEnumerator](https://docs.microsoft.com/en-us/dotnet/api/system.collections.ienumerator?view=netframework-4.8).
|
||||
/// <example>
|
||||
/// <code>
|
||||
///public class SetUpTearDownExample
|
||||
/// {
|
||||
/// [UnitySetUp]
|
||||
/// public IEnumerator SetUp()
|
||||
/// {
|
||||
/// yield return new EnterPlayMode();
|
||||
/// }
|
||||
///
|
||||
/// [Test]
|
||||
/// public void MyTest()
|
||||
/// {
|
||||
/// Debug.Log("This runs inside playmode");
|
||||
/// }
|
||||
///
|
||||
/// [UnityTearDown]
|
||||
/// public IEnumerator TearDown()
|
||||
/// {
|
||||
/// yield return new ExitPlayMode();
|
||||
/// }
|
||||
/// }
|
||||
/// </code>
|
||||
/// </example>
|
||||
/// </summary>
|
||||
[AttributeUsage(AttributeTargets.Method)]
|
||||
public class UnitySetUpAttribute : NUnitAttribute
|
||||
{
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: cc6401f13df54ba44bfd7cdc93c7d64d
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,37 @@
|
|||
using System;
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace UnityEngine.TestTools
|
||||
{
|
||||
/// <summary>
|
||||
/// The <see cref="UnitySetUpAttribute"/> and `UnityTearDown` attributes are identical to the standard `SetUp` and `TearDown` attributes, with the exception that they allow for <see cref="IEditModeTestYieldInstruction"/>. The `UnitySetUp` and `UnityTearDown` attributes expect a return type of [IEnumerator](https://docs.microsoft.com/en-us/dotnet/api/system.collections.ienumerator?view=netframework-4.8).
|
||||
/// <example>
|
||||
/// <code>
|
||||
///public class SetUpTearDownExample
|
||||
/// {
|
||||
/// [UnitySetUp]
|
||||
/// public IEnumerator SetUp()
|
||||
/// {
|
||||
/// yield return new EnterPlayMode();
|
||||
/// }
|
||||
///
|
||||
/// [Test]
|
||||
/// public void MyTest()
|
||||
/// {
|
||||
/// Debug.Log("This runs inside playmode");
|
||||
/// }
|
||||
///
|
||||
/// [UnityTearDown]
|
||||
/// public IEnumerator TearDown()
|
||||
/// {
|
||||
/// yield return new ExitPlayMode();
|
||||
/// }
|
||||
/// }
|
||||
/// </code>
|
||||
/// </example>
|
||||
/// </summary>
|
||||
[AttributeUsage(AttributeTargets.Method)]
|
||||
public class UnityTearDownAttribute : NUnitAttribute
|
||||
{
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 600f4b74746dbf944901257f81a8af6d
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,98 @@
|
|||
using System;
|
||||
using System.Collections;
|
||||
using NUnit.Framework;
|
||||
using NUnit.Framework.Internal.Commands;
|
||||
using NUnit.Framework.Interfaces;
|
||||
using NUnit.Framework.Internal;
|
||||
using NUnit.Framework.Internal.Builders;
|
||||
using UnityEngine.TestRunner.NUnitExtensions.Runner;
|
||||
|
||||
namespace UnityEngine.TestTools
|
||||
{
|
||||
/// <summary>
|
||||
/// `UnityTest` attribute is the main addition to the standard [NUnit](http://www.nunit.org/) library for the Unity Test Framework. This type of unit test allows you to skip a frame from within a test (so background tasks can finish) or give certain commands to the Unity **Editor**, such as performing a domain reload or entering **Play Mode** from an **Edit Mode** test.
|
||||
/// In Play Mode, the `UnityTest` attribute runs as a [coroutine](https://docs.unity3d.com/Manual/Coroutines.html). Whereas Edit Mode tests run in the [EditorApplication.update](https://docs.unity3d.com/ScriptReference/EditorApplication-update.html) callback loop.
|
||||
/// The `UnityTest` attribute is, in fact, an alternative to the `NUnit` [Test attribute](https://github.com/nunit/docs/wiki/Test-Attribute), which allows yielding instructions back to the framework. Once the instruction is complete, the test run continues. If you `yield return null`, you skip a frame. That might be necessary to ensure that some changes do happen on the next iteration of either the `EditorApplication.update` loop or the [game loop](https://docs.unity3d.com/Manual/ExecutionOrder.html).
|
||||
/// <example>
|
||||
/// ## Edit Mode example
|
||||
/// The most simple example of an Edit Mode test could be the one that yields `null` to skip the current frame and then continues to run:
|
||||
/// <code>
|
||||
/// [UnityTest]
|
||||
/// public IEnumerator EditorUtility_WhenExecuted_ReturnsSuccess()
|
||||
/// {
|
||||
/// var utility = RunEditorUtilityInTheBackground();
|
||||
///
|
||||
/// while (utility.isRunning)
|
||||
/// {
|
||||
/// yield return null;
|
||||
/// }
|
||||
///
|
||||
/// Assert.IsTrue(utility.isSuccess);
|
||||
/// }
|
||||
/// </code>
|
||||
/// </example>
|
||||
/// <example>
|
||||
/// ## Play Mode example
|
||||
///
|
||||
/// In Play Mode, a test runs as a coroutine attached to a [MonoBehaviour](https://docs.unity3d.com/ScriptReference/MonoBehaviour.html). So all the yield instructions available in coroutines, are also available in your test.
|
||||
///
|
||||
/// From a Play Mode test you can use one of Unity’s [Yield Instructions](https://docs.unity3d.com/ScriptReference/YieldInstruction.html):
|
||||
///
|
||||
/// - [WaitForFixedUpdate](https://docs.unity3d.com/ScriptReference/WaitForFixedUpdate.html): to ensure changes expected within the next cycle of physics calculations.
|
||||
/// - [WaitForSeconds](https://docs.unity3d.com/ScriptReference/WaitForSeconds.html): if you want to pause your test coroutine for a fixed amount of time. Be careful about creating long-running tests.
|
||||
///
|
||||
/// The simplest example is to yield to `WaitForFixedUpdate`:
|
||||
/// <code>
|
||||
/// [UnityTest]
|
||||
/// public IEnumerator GameObject_WithRigidBody_WillBeAffectedByPhysics()
|
||||
/// {
|
||||
/// var go = new GameObject();
|
||||
/// go.AddComponent<Rigidbody>();
|
||||
/// var originalPosition = go.transform.position.y;
|
||||
///
|
||||
/// yield return new WaitForFixedUpdate();
|
||||
///
|
||||
/// Assert.AreNotEqual(originalPosition, go.transform.position.y);
|
||||
/// }
|
||||
/// </code>
|
||||
/// </example>
|
||||
/// </summary>
|
||||
[AttributeUsage(AttributeTargets.Method)]
|
||||
public class UnityTestAttribute : CombiningStrategyAttribute, ISimpleTestBuilder, IImplyFixture
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes and returns an instance of UnityTestAttribute.
|
||||
/// </summary>
|
||||
public UnityTestAttribute() : base(new UnityCombinatorialStrategy(), new ParameterDataSourceProvider()) {}
|
||||
|
||||
private readonly NUnitTestCaseBuilder _builder = new NUnitTestCaseBuilder();
|
||||
|
||||
/// <summary>
|
||||
/// This method builds the TestMethod from the Test and the method info. It also checks if the test with the `UnityTestAttribute` has an IEnumerator as return type.
|
||||
/// </summary>
|
||||
/// <param name="method">The method info.</param>
|
||||
/// <param name="suite">The test.</param>
|
||||
/// <returns>A TestMethod object</returns>
|
||||
TestMethod ISimpleTestBuilder.BuildFrom(IMethodInfo method, Test suite)
|
||||
{
|
||||
TestCaseParameters parms = new TestCaseParameters
|
||||
{
|
||||
ExpectedResult = new object(),
|
||||
HasExpectedResult = true
|
||||
};
|
||||
|
||||
var t = _builder.BuildTestMethod(method, suite, parms);
|
||||
|
||||
if (t.parms != null)
|
||||
t.parms.HasExpectedResult = false;
|
||||
|
||||
if (!method.ReturnType.IsType(typeof(IEnumerator)))
|
||||
{
|
||||
t.RunState = RunState.NotRunnable;
|
||||
t.Properties.Set(PropertyNames.SkipReason, "Method marked with UnityTest must return IEnumerator.");
|
||||
}
|
||||
|
||||
return t;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: fedb0f9e5006b1943abae52f52f08a1a
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,58 @@
|
|||
using System;
|
||||
using System.Threading;
|
||||
using NUnit.Framework.Internal;
|
||||
|
||||
namespace UnityEngine.TestTools.NUnitExtensions
|
||||
{
|
||||
internal abstract class BaseDelegator
|
||||
{
|
||||
protected ManualResetEvent m_Signal = new ManualResetEvent(false);
|
||||
|
||||
protected object m_Result;
|
||||
protected Exception m_Exception;
|
||||
protected ITestExecutionContext m_Context;
|
||||
|
||||
protected bool m_Aborted;
|
||||
|
||||
protected object HandleResult()
|
||||
{
|
||||
SetCurrentTestContext();
|
||||
if (m_Exception != null)
|
||||
{
|
||||
var temp = m_Exception;
|
||||
m_Exception = null;
|
||||
throw temp;
|
||||
}
|
||||
var tempResult = m_Result;
|
||||
m_Result = null;
|
||||
return tempResult;
|
||||
}
|
||||
|
||||
protected void WaitForSignal()
|
||||
{
|
||||
while (!m_Signal.WaitOne(100))
|
||||
{
|
||||
if (m_Aborted)
|
||||
{
|
||||
m_Aborted = false;
|
||||
Reflect.MethodCallWrapper = null;
|
||||
throw new Exception();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Abort()
|
||||
{
|
||||
m_Aborted = true;
|
||||
}
|
||||
|
||||
protected void SetCurrentTestContext()
|
||||
{
|
||||
var prop = typeof(TestExecutionContext).GetProperty("CurrentContext");
|
||||
if (prop != null)
|
||||
{
|
||||
prop.SetValue(null, m_Context, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 37cea569bfefafe49a1513c4d7f0e9eb
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,8 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 6b72875690e0f7343911e06af3145bd5
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,256 @@
|
|||
using System;
|
||||
using System.Collections;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using NUnit.Framework.Interfaces;
|
||||
using NUnit.Framework.Internal;
|
||||
using NUnit.Framework.Internal.Commands;
|
||||
using UnityEngine.TestRunner.NUnitExtensions;
|
||||
using UnityEngine.TestRunner.NUnitExtensions.Runner;
|
||||
using UnityEngine.TestTools.Logging;
|
||||
using UnityEngine.TestTools.TestRunner;
|
||||
|
||||
namespace UnityEngine.TestTools
|
||||
{
|
||||
internal abstract class BeforeAfterTestCommandBase<T> : DelegatingTestCommand, IEnumerableTestMethodCommand
|
||||
{
|
||||
private string m_BeforeErrorPrefix;
|
||||
private string m_AfterErrorPrefix;
|
||||
private bool m_SkipYieldAfterActions;
|
||||
protected BeforeAfterTestCommandBase(TestCommand innerCommand, string beforeErrorPrefix, string afterErrorPrefix, bool skipYieldAfterActions = false)
|
||||
: base(innerCommand)
|
||||
{
|
||||
m_BeforeErrorPrefix = beforeErrorPrefix;
|
||||
m_AfterErrorPrefix = afterErrorPrefix;
|
||||
m_SkipYieldAfterActions = skipYieldAfterActions;
|
||||
}
|
||||
|
||||
internal Func<long> GetUtcNow = () => new DateTimeOffset(DateTime.UtcNow).ToUnixTimeMilliseconds();
|
||||
|
||||
protected T[] BeforeActions = new T[0];
|
||||
|
||||
protected T[] AfterActions = new T[0];
|
||||
|
||||
protected abstract IEnumerator InvokeBefore(T action, Test test, UnityTestExecutionContext context);
|
||||
|
||||
protected abstract IEnumerator InvokeAfter(T action, Test test, UnityTestExecutionContext context);
|
||||
|
||||
protected virtual bool MoveBeforeEnumerator(IEnumerator enumerator, Test test)
|
||||
{
|
||||
return enumerator.MoveNext();
|
||||
}
|
||||
|
||||
protected virtual bool MoveAfterEnumerator(IEnumerator enumerator, Test test)
|
||||
{
|
||||
return enumerator.MoveNext();
|
||||
}
|
||||
|
||||
protected abstract BeforeAfterTestCommandState GetState(UnityTestExecutionContext context);
|
||||
|
||||
public IEnumerable ExecuteEnumerable(ITestExecutionContext context)
|
||||
{
|
||||
var unityContext = (UnityTestExecutionContext)context;
|
||||
var state = GetState(unityContext);
|
||||
|
||||
// When entering PlayMode state will incorrectly be seen as null. Looking at the hashcode to be certain that it is null.
|
||||
if (state?.GetHashCode() == null)
|
||||
{
|
||||
// We do not expect a state to exist in playmode
|
||||
state = ScriptableObject.CreateInstance<BeforeAfterTestCommandState>();
|
||||
}
|
||||
|
||||
state.ApplyTestResult(context.CurrentResult);
|
||||
|
||||
while (state.NextBeforeStepIndex < BeforeActions.Length)
|
||||
{
|
||||
state.Timestamp = GetUtcNow();
|
||||
var action = BeforeActions[state.NextBeforeStepIndex];
|
||||
IEnumerator enumerator;
|
||||
try
|
||||
{
|
||||
enumerator = InvokeBefore(action, Test, unityContext);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
state.TestHasRun = true;
|
||||
context.CurrentResult.RecordPrefixedException(m_BeforeErrorPrefix, ex);
|
||||
break;
|
||||
}
|
||||
ActivePcHelper.SetEnumeratorPC(enumerator, state.NextBeforeStepPc);
|
||||
|
||||
using (var logScope = new LogScope())
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!enumerator.MoveNext())
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
state.TestHasRun = true;
|
||||
context.CurrentResult.RecordPrefixedException(m_BeforeErrorPrefix, ex);
|
||||
state.StoreTestResult(context.CurrentResult);
|
||||
break;
|
||||
}
|
||||
|
||||
state.NextBeforeStepPc = ActivePcHelper.GetEnumeratorPC(enumerator);
|
||||
state.StoreTestResult(context.CurrentResult);
|
||||
if (m_SkipYieldAfterActions)
|
||||
{
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
yield return enumerator.Current;
|
||||
}
|
||||
|
||||
if (GetUtcNow() - state.Timestamp > unityContext.TestCaseTimeout || CoroutineTimedOut(unityContext))
|
||||
{
|
||||
context.CurrentResult.RecordPrefixedError(m_BeforeErrorPrefix, new UnityTestTimeoutException(unityContext.TestCaseTimeout).Message);
|
||||
state.TestHasRun = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (logScope.AnyFailingLogs())
|
||||
{
|
||||
state.TestHasRun = true;
|
||||
context.CurrentResult.RecordPrefixedError(m_BeforeErrorPrefix, new UnhandledLogMessageException(logScope.FailingLogs.First()).Message);
|
||||
state.StoreTestResult(context.CurrentResult);
|
||||
}
|
||||
}
|
||||
|
||||
state.NextBeforeStepIndex++;
|
||||
state.NextBeforeStepPc = 0;
|
||||
}
|
||||
|
||||
if (!state.TestHasRun)
|
||||
{
|
||||
if (innerCommand is IEnumerableTestMethodCommand)
|
||||
{
|
||||
var executeEnumerable = ((IEnumerableTestMethodCommand)innerCommand).ExecuteEnumerable(context);
|
||||
foreach (var iterator in executeEnumerable)
|
||||
{
|
||||
state.StoreTestResult(context.CurrentResult);
|
||||
yield return iterator;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
context.CurrentResult = innerCommand.Execute(context);
|
||||
state.StoreTestResult(context.CurrentResult);
|
||||
}
|
||||
|
||||
state.TestHasRun = true;
|
||||
}
|
||||
|
||||
while (state.NextAfterStepIndex < AfterActions.Length)
|
||||
{
|
||||
state.Timestamp = GetUtcNow();
|
||||
state.TestAfterStarted = true;
|
||||
var action = AfterActions[state.NextAfterStepIndex];
|
||||
IEnumerator enumerator;
|
||||
try
|
||||
{
|
||||
enumerator = InvokeAfter(action, Test, unityContext);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
context.CurrentResult.RecordPrefixedException(m_AfterErrorPrefix, ex);
|
||||
state.StoreTestResult(context.CurrentResult);
|
||||
break;
|
||||
}
|
||||
ActivePcHelper.SetEnumeratorPC(enumerator, state.NextAfterStepPc);
|
||||
|
||||
using (var logScope = new LogScope())
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!enumerator.MoveNext())
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
context.CurrentResult.RecordPrefixedException(m_AfterErrorPrefix, ex);
|
||||
state.StoreTestResult(context.CurrentResult);
|
||||
break;
|
||||
}
|
||||
|
||||
state.NextAfterStepPc = ActivePcHelper.GetEnumeratorPC(enumerator);
|
||||
state.StoreTestResult(context.CurrentResult);
|
||||
|
||||
|
||||
if (GetUtcNow() - state.Timestamp > unityContext.TestCaseTimeout || CoroutineTimedOut(unityContext))
|
||||
{
|
||||
context.CurrentResult.RecordPrefixedError(m_AfterErrorPrefix, new UnityTestTimeoutException(unityContext.TestCaseTimeout).Message);
|
||||
yield break;
|
||||
}
|
||||
|
||||
if (m_SkipYieldAfterActions)
|
||||
{
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
yield return enumerator.Current;
|
||||
}
|
||||
}
|
||||
|
||||
if (logScope.AnyFailingLogs())
|
||||
{
|
||||
state.TestHasRun = true;
|
||||
context.CurrentResult.RecordPrefixedError(m_AfterErrorPrefix, new UnhandledLogMessageException(logScope.FailingLogs.First()).Message);
|
||||
state.StoreTestResult(context.CurrentResult);
|
||||
}
|
||||
}
|
||||
|
||||
state.NextAfterStepIndex++;
|
||||
state.NextAfterStepPc = 0;
|
||||
}
|
||||
|
||||
state.Reset();
|
||||
}
|
||||
|
||||
public override TestResult Execute(ITestExecutionContext context)
|
||||
{
|
||||
throw new NotImplementedException("Use ExecuteEnumerable");
|
||||
}
|
||||
|
||||
private static TestCommandPcHelper pcHelper;
|
||||
private static bool CoroutineTimedOut(ITestExecutionContext unityContext)
|
||||
{
|
||||
if (string.IsNullOrEmpty(unityContext.CurrentResult.Message))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return unityContext.CurrentResult.ResultState.Equals(ResultState.Failure) &&
|
||||
unityContext.CurrentResult.Message.Contains(new UnityTestTimeoutException(unityContext.TestCaseTimeout).Message);
|
||||
}
|
||||
|
||||
|
||||
internal static TestCommandPcHelper ActivePcHelper
|
||||
{
|
||||
get
|
||||
{
|
||||
if (pcHelper == null)
|
||||
{
|
||||
pcHelper = new TestCommandPcHelper();
|
||||
}
|
||||
|
||||
return pcHelper;
|
||||
}
|
||||
set
|
||||
{
|
||||
pcHelper = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: cbbca1d8a0434be4bbc7f165523763ac
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,52 @@
|
|||
using System;
|
||||
using System.Data;
|
||||
using NUnit.Framework.Interfaces;
|
||||
using NUnit.Framework.Internal;
|
||||
|
||||
namespace UnityEngine.TestTools
|
||||
{
|
||||
internal class BeforeAfterTestCommandState : ScriptableObject
|
||||
{
|
||||
public int NextBeforeStepIndex;
|
||||
public int NextBeforeStepPc;
|
||||
public int NextAfterStepIndex;
|
||||
public int NextAfterStepPc;
|
||||
public bool TestHasRun;
|
||||
public TestStatus CurrentTestResultStatus;
|
||||
public string CurrentTestResultLabel;
|
||||
public FailureSite CurrentTestResultSite;
|
||||
public string CurrentTestMessage;
|
||||
public string CurrentTestStrackTrace;
|
||||
public bool TestAfterStarted;
|
||||
public long Timestamp;
|
||||
|
||||
public void Reset()
|
||||
{
|
||||
NextBeforeStepIndex = 0;
|
||||
NextBeforeStepPc = 0;
|
||||
NextAfterStepIndex = 0;
|
||||
NextAfterStepPc = 0;
|
||||
TestHasRun = false;
|
||||
CurrentTestResultStatus = TestStatus.Inconclusive;
|
||||
CurrentTestResultLabel = null;
|
||||
CurrentTestResultSite = default(FailureSite);
|
||||
CurrentTestMessage = null;
|
||||
CurrentTestStrackTrace = null;
|
||||
TestAfterStarted = false;
|
||||
}
|
||||
|
||||
public void StoreTestResult(TestResult result)
|
||||
{
|
||||
CurrentTestResultStatus = result.ResultState.Status;
|
||||
CurrentTestResultLabel = result.ResultState.Label;
|
||||
CurrentTestResultSite = result.ResultState.Site;
|
||||
CurrentTestMessage = result.Message;
|
||||
CurrentTestStrackTrace = result.StackTrace;
|
||||
}
|
||||
|
||||
public void ApplyTestResult(TestResult result)
|
||||
{
|
||||
result.SetResult(new ResultState(CurrentTestResultStatus, CurrentTestResultLabel, CurrentTestResultSite), CurrentTestMessage, CurrentTestStrackTrace);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 7f65567c9026afb4db5de3355accc636
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,34 @@
|
|||
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using NUnit.Framework.Interfaces;
|
||||
using NUnit.Framework.Internal;
|
||||
using NUnit.Framework.Internal.Commands;
|
||||
using UnityEngine.TestRunner.NUnitExtensions.Runner;
|
||||
|
||||
namespace UnityEngine.TestTools
|
||||
{
|
||||
internal class EnumerableApplyChangesToContextCommand : ApplyChangesToContextCommand, IEnumerableTestMethodCommand
|
||||
{
|
||||
public EnumerableApplyChangesToContextCommand(TestCommand innerCommand, IEnumerable<IApplyToContext> changes)
|
||||
: base(innerCommand, changes) { }
|
||||
|
||||
public IEnumerable ExecuteEnumerable(ITestExecutionContext context)
|
||||
{
|
||||
ApplyChanges(context);
|
||||
|
||||
if (innerCommand is IEnumerableTestMethodCommand)
|
||||
{
|
||||
var executeEnumerable = ((IEnumerableTestMethodCommand)innerCommand).ExecuteEnumerable(context);
|
||||
foreach (var iterator in executeEnumerable)
|
||||
{
|
||||
yield return iterator;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
context.CurrentResult = innerCommand.Execute(context);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 3b4429eff9fcffb48b006e8edcc90338
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,66 @@
|
|||
using System;
|
||||
using System.Collections;
|
||||
using System.Reflection;
|
||||
using NUnit.Framework;
|
||||
using NUnit.Framework.Interfaces;
|
||||
using NUnit.Framework.Internal;
|
||||
using NUnit.Framework.Internal.Commands;
|
||||
using UnityEngine.TestRunner.NUnitExtensions.Runner;
|
||||
|
||||
namespace UnityEngine.TestTools
|
||||
{
|
||||
internal class EnumerableRepeatedTestCommand : DelegatingTestCommand, IEnumerableTestMethodCommand
|
||||
{
|
||||
private int repeatCount;
|
||||
|
||||
public EnumerableRepeatedTestCommand(RepeatAttribute.RepeatedTestCommand commandToReplace) : base(commandToReplace.GetInnerCommand())
|
||||
{
|
||||
repeatCount = (int) typeof(RepeatAttribute.RepeatedTestCommand)
|
||||
.GetField("repeatCount", BindingFlags.NonPublic | BindingFlags.Instance)
|
||||
.GetValue(commandToReplace);
|
||||
}
|
||||
|
||||
public override TestResult Execute(ITestExecutionContext context)
|
||||
{
|
||||
throw new NotImplementedException("Use ExecuteEnumerable");
|
||||
}
|
||||
|
||||
public IEnumerable ExecuteEnumerable(ITestExecutionContext context)
|
||||
{
|
||||
var unityContext = (UnityTestExecutionContext)context;
|
||||
int count = unityContext.EnumerableTestState.Repeat;
|
||||
var firstCycleAfterResume = count > 0;
|
||||
|
||||
while (count < repeatCount || (firstCycleAfterResume && count <= repeatCount))
|
||||
{
|
||||
if (!firstCycleAfterResume)
|
||||
{
|
||||
count++;
|
||||
}
|
||||
|
||||
firstCycleAfterResume = false;
|
||||
unityContext.EnumerableTestState.Repeat = count;
|
||||
|
||||
if (innerCommand is IEnumerableTestMethodCommand)
|
||||
{
|
||||
var executeEnumerable = ((IEnumerableTestMethodCommand)innerCommand).ExecuteEnumerable(context);
|
||||
foreach (var iterator in executeEnumerable)
|
||||
{
|
||||
yield return iterator;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
context.CurrentResult = innerCommand.Execute(context);
|
||||
}
|
||||
|
||||
if (context.CurrentResult.ResultState != ResultState.Success)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
unityContext.EnumerableTestState.Repeat = 0;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: e273462feb9a65948826739f683cc9a9
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,67 @@
|
|||
using System;
|
||||
using System.Collections;
|
||||
using System.Reflection;
|
||||
using NUnit.Framework;
|
||||
using NUnit.Framework.Interfaces;
|
||||
using NUnit.Framework.Internal;
|
||||
using NUnit.Framework.Internal.Commands;
|
||||
using UnityEngine.TestRunner.NUnitExtensions.Runner;
|
||||
|
||||
namespace UnityEngine.TestTools
|
||||
{
|
||||
internal class EnumerableRetryTestCommand : DelegatingTestCommand, IEnumerableTestMethodCommand
|
||||
{
|
||||
private int retryCount;
|
||||
|
||||
public EnumerableRetryTestCommand(RetryAttribute.RetryCommand commandToReplace) : base(commandToReplace.GetInnerCommand())
|
||||
{
|
||||
retryCount = (int) typeof(RetryAttribute.RetryCommand)
|
||||
.GetField("_retryCount", BindingFlags.NonPublic | BindingFlags.Instance)
|
||||
.GetValue(commandToReplace);
|
||||
}
|
||||
|
||||
public override TestResult Execute(ITestExecutionContext context)
|
||||
{
|
||||
throw new NotImplementedException("Use ExecuteEnumerable");
|
||||
}
|
||||
|
||||
public IEnumerable ExecuteEnumerable(ITestExecutionContext context)
|
||||
{
|
||||
var unityContext = (UnityTestExecutionContext)context;
|
||||
int count = unityContext.EnumerableTestState.Retry;
|
||||
var firstCycleAfterResume = count > 0;
|
||||
|
||||
while (count < retryCount || (firstCycleAfterResume && count <= retryCount))
|
||||
{
|
||||
if (!firstCycleAfterResume)
|
||||
{
|
||||
count++;
|
||||
}
|
||||
|
||||
firstCycleAfterResume = false;
|
||||
|
||||
unityContext.EnumerableTestState.Retry = count;
|
||||
|
||||
if (innerCommand is IEnumerableTestMethodCommand)
|
||||
{
|
||||
var executeEnumerable = ((IEnumerableTestMethodCommand)innerCommand).ExecuteEnumerable(context);
|
||||
foreach (var iterator in executeEnumerable)
|
||||
{
|
||||
yield return iterator;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
context.CurrentResult = innerCommand.Execute(context);
|
||||
}
|
||||
|
||||
if (context.CurrentResult.ResultState != ResultState.Failure)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
unityContext.EnumerableTestState.Retry = 0;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 6de2f178a24cd2e48a0816cacd9a0583
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,57 @@
|
|||
using System;
|
||||
using System.Collections;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using NUnit.Framework.Internal;
|
||||
using NUnit.Framework.Internal.Commands;
|
||||
using Unity.Profiling;
|
||||
using UnityEngine.TestRunner.NUnitExtensions.Runner;
|
||||
|
||||
namespace UnityEngine.TestTools
|
||||
{
|
||||
internal class EnumerableSetUpTearDownCommand : BeforeAfterTestCommandBase<MethodInfo>
|
||||
{
|
||||
public EnumerableSetUpTearDownCommand(TestCommand innerCommand)
|
||||
: base(innerCommand, "SetUp", "TearDown")
|
||||
{
|
||||
if (Test.TypeInfo.Type != null)
|
||||
{
|
||||
BeforeActions = GetMethodsWithAttributeFromFixture(Test.TypeInfo.Type, typeof(UnitySetUpAttribute));
|
||||
AfterActions = GetMethodsWithAttributeFromFixture(Test.TypeInfo.Type, typeof(UnityTearDownAttribute)).Reverse().ToArray();
|
||||
}
|
||||
}
|
||||
|
||||
private static MethodInfo[] GetMethodsWithAttributeFromFixture(Type fixtureType, Type setUpType)
|
||||
{
|
||||
MethodInfo[] methodsWithAttribute = Reflect.GetMethodsWithAttribute(fixtureType, setUpType, true);
|
||||
return methodsWithAttribute.Where(x => x.ReturnType == typeof(IEnumerator)).ToArray();
|
||||
}
|
||||
|
||||
protected override bool MoveAfterEnumerator(IEnumerator enumerator, Test test)
|
||||
{
|
||||
using (new ProfilerMarker(test.Name + ".TearDown").Auto())
|
||||
return base.MoveAfterEnumerator(enumerator, test);
|
||||
}
|
||||
|
||||
protected override bool MoveBeforeEnumerator(IEnumerator enumerator, Test test)
|
||||
{
|
||||
using (new ProfilerMarker(test.Name + ".Setup").Auto())
|
||||
return base.MoveBeforeEnumerator(enumerator, test);
|
||||
}
|
||||
|
||||
protected override IEnumerator InvokeBefore(MethodInfo action, Test test, UnityTestExecutionContext context)
|
||||
{
|
||||
return (IEnumerator)Reflect.InvokeMethod(action, context.TestObject);
|
||||
}
|
||||
|
||||
protected override IEnumerator InvokeAfter(MethodInfo action, Test test, UnityTestExecutionContext context)
|
||||
{
|
||||
return (IEnumerator)Reflect.InvokeMethod(action, context.TestObject);
|
||||
}
|
||||
|
||||
protected override BeforeAfterTestCommandState GetState(UnityTestExecutionContext context)
|
||||
{
|
||||
return context.SetUpTearDownState;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: dd85a35169d313840a0874aea1a28629
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,104 @@
|
|||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using NUnit.Framework;
|
||||
using NUnit.Framework.Interfaces;
|
||||
using NUnit.Framework.Internal;
|
||||
using NUnit.Framework.Internal.Commands;
|
||||
using NUnit.Framework.Internal.Execution;
|
||||
using UnityEngine.TestRunner.NUnitExtensions;
|
||||
using Unity.Profiling;
|
||||
using UnityEngine.TestRunner.NUnitExtensions.Runner;
|
||||
using UnityEngine.TestTools.TestRunner;
|
||||
|
||||
namespace UnityEngine.TestTools
|
||||
{
|
||||
internal class EnumerableTestMethodCommand : TestCommand, IEnumerableTestMethodCommand
|
||||
{
|
||||
private readonly TestMethod testMethod;
|
||||
|
||||
public EnumerableTestMethodCommand(TestMethod testMethod)
|
||||
: base(testMethod)
|
||||
{
|
||||
this.testMethod = testMethod;
|
||||
}
|
||||
|
||||
public IEnumerable ExecuteEnumerable(ITestExecutionContext context)
|
||||
{
|
||||
yield return null;
|
||||
|
||||
IEnumerator currentExecutingTestEnumerator;
|
||||
try
|
||||
{
|
||||
currentExecutingTestEnumerator = new TestEnumeratorWrapper(testMethod).GetEnumerator(context);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
context.CurrentResult.RecordException(ex);
|
||||
yield break;
|
||||
}
|
||||
|
||||
if (currentExecutingTestEnumerator != null)
|
||||
{
|
||||
var testEnumeraterYieldInstruction = new TestEnumerator(context, currentExecutingTestEnumerator);
|
||||
|
||||
yield return testEnumeraterYieldInstruction;
|
||||
|
||||
var enumerator = testEnumeraterYieldInstruction.Execute();
|
||||
|
||||
var executingEnumerator = ExecuteEnumerableAndRecordExceptions(enumerator, context);
|
||||
while (AdvanceEnumerator(executingEnumerator))
|
||||
{
|
||||
yield return executingEnumerator.Current;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (context.CurrentResult.ResultState != ResultState.Ignored)
|
||||
{
|
||||
context.CurrentResult.SetResult(ResultState.Success);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private bool AdvanceEnumerator(IEnumerator enumerator)
|
||||
{
|
||||
using (new ProfilerMarker(testMethod.MethodName).Auto())
|
||||
return enumerator.MoveNext();
|
||||
}
|
||||
|
||||
private static IEnumerator ExecuteEnumerableAndRecordExceptions(IEnumerator enumerator, ITestExecutionContext context)
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!enumerator.MoveNext())
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
context.CurrentResult.RecordException(ex);
|
||||
break;
|
||||
}
|
||||
|
||||
if (enumerator.Current is IEnumerator)
|
||||
{
|
||||
var current = (IEnumerator)enumerator.Current;
|
||||
yield return ExecuteEnumerableAndRecordExceptions(current, context);
|
||||
}
|
||||
else
|
||||
{
|
||||
yield return enumerator.Current;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override TestResult Execute(ITestExecutionContext context)
|
||||
{
|
||||
throw new NotImplementedException("Use ExecuteEnumerable");
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 19a6f000f81e24c4a826c1abd43e77c7
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,8 @@
|
|||
namespace UnityEngine.TestTools
|
||||
{
|
||||
internal class EnumerableTestState : ScriptableObject
|
||||
{
|
||||
public int Repeat;
|
||||
public int Retry;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 356852e4738840b4b1ab533d3a66f0e1
|
||||
timeCreated: 1606321047
|
|
@ -0,0 +1,32 @@
|
|||
using System;
|
||||
using System.Collections;
|
||||
using NUnit.Framework.Internal;
|
||||
using NUnit.Framework.Internal.Commands;
|
||||
using UnityEngine.TestRunner.NUnitExtensions.Runner;
|
||||
|
||||
namespace UnityEngine.TestTools
|
||||
{
|
||||
internal class ImmediateEnumerableCommand : DelegatingTestCommand
|
||||
{
|
||||
public ImmediateEnumerableCommand(TestCommand innerCommand)
|
||||
: base(innerCommand) { }
|
||||
|
||||
public override TestResult Execute(ITestExecutionContext context)
|
||||
{
|
||||
if (innerCommand is IEnumerableTestMethodCommand)
|
||||
{
|
||||
var executeEnumerable = ((IEnumerableTestMethodCommand)innerCommand).ExecuteEnumerable(context);
|
||||
foreach (var iterator in executeEnumerable)
|
||||
{
|
||||
if (iterator != null)
|
||||
{
|
||||
throw new Exception("Only null can be yielded at this point.");
|
||||
}
|
||||
}
|
||||
return context.CurrentResult;
|
||||
}
|
||||
|
||||
return innerCommand.Execute(context);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 8349e42a2b30c7a4abd8678c203428ba
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,49 @@
|
|||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
using NUnit.Framework.Internal;
|
||||
using NUnit.Framework.Internal.Commands;
|
||||
using UnityEngine.TestRunner.NUnitExtensions.Runner;
|
||||
|
||||
namespace UnityEngine.TestTools
|
||||
{
|
||||
internal class OuterUnityTestActionCommand : BeforeAfterTestCommandBase<IOuterUnityTestAction>
|
||||
{
|
||||
public OuterUnityTestActionCommand(TestCommand innerCommand)
|
||||
: base(innerCommand, "BeforeTest", "AfterTest")
|
||||
{
|
||||
if (Test.TypeInfo.Type != null)
|
||||
{
|
||||
BeforeActions = GetUnityTestActionsFromMethod(Test.Method.MethodInfo);
|
||||
AfterActions = BeforeActions;
|
||||
}
|
||||
}
|
||||
|
||||
private static IOuterUnityTestAction[] GetUnityTestActionsFromMethod(MethodInfo method)
|
||||
{
|
||||
var attributes = method.GetCustomAttributes(false);
|
||||
List<IOuterUnityTestAction> actions = new List<IOuterUnityTestAction>();
|
||||
foreach (var attribute in attributes)
|
||||
{
|
||||
if (attribute is IOuterUnityTestAction)
|
||||
actions.Add(attribute as IOuterUnityTestAction);
|
||||
}
|
||||
return actions.ToArray();
|
||||
}
|
||||
|
||||
protected override IEnumerator InvokeBefore(IOuterUnityTestAction action, Test test, UnityTestExecutionContext context)
|
||||
{
|
||||
return action.BeforeTest(test);
|
||||
}
|
||||
|
||||
protected override IEnumerator InvokeAfter(IOuterUnityTestAction action, Test test, UnityTestExecutionContext context)
|
||||
{
|
||||
return action.AfterTest(test);
|
||||
}
|
||||
|
||||
protected override BeforeAfterTestCommandState GetState(UnityTestExecutionContext context)
|
||||
{
|
||||
return context.OuterUnityTestActionState;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 0d4fc309a0784294c8ab658b53b12320
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,51 @@
|
|||
using System;
|
||||
using System.Collections;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using NUnit.Framework;
|
||||
using NUnit.Framework.Internal;
|
||||
using NUnit.Framework.Internal.Commands;
|
||||
using NUnit.Framework.Internal.Execution;
|
||||
using Unity.Profiling;
|
||||
using UnityEngine.TestRunner.NUnitExtensions.Runner;
|
||||
|
||||
namespace UnityEngine.TestTools
|
||||
{
|
||||
internal class SetUpTearDownCommand : BeforeAfterTestCommandBase<MethodInfo>
|
||||
{
|
||||
public SetUpTearDownCommand(TestCommand innerCommand)
|
||||
: base(innerCommand, "SetUp", "TearDown", true)
|
||||
{
|
||||
if (Test.TypeInfo.Type != null)
|
||||
{
|
||||
BeforeActions = GetMethodsWithAttributeFromFixture(Test.TypeInfo.Type, typeof(SetUpAttribute));
|
||||
AfterActions = GetMethodsWithAttributeFromFixture(Test.TypeInfo.Type, typeof(TearDownAttribute)).Reverse().ToArray();
|
||||
}
|
||||
}
|
||||
|
||||
private static MethodInfo[] GetMethodsWithAttributeFromFixture(Type fixtureType, Type setUpType)
|
||||
{
|
||||
MethodInfo[] methodsWithAttribute = Reflect.GetMethodsWithAttribute(fixtureType, setUpType, true);
|
||||
return methodsWithAttribute.Where(x => x.ReturnType == typeof(void)).ToArray();
|
||||
}
|
||||
|
||||
protected override IEnumerator InvokeBefore(MethodInfo action, Test test, UnityTestExecutionContext context)
|
||||
{
|
||||
using (new ProfilerMarker(test.Name + ".Setup").Auto())
|
||||
Reflect.InvokeMethod(action, context.TestObject);
|
||||
yield return null;
|
||||
}
|
||||
|
||||
protected override IEnumerator InvokeAfter(MethodInfo action, Test test, UnityTestExecutionContext context)
|
||||
{
|
||||
using (new ProfilerMarker(test.Name + ".TearDown").Auto())
|
||||
Reflect.InvokeMethod(action, context.TestObject);
|
||||
yield return null;
|
||||
}
|
||||
|
||||
protected override BeforeAfterTestCommandState GetState(UnityTestExecutionContext context)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: e0db3f3921670cd4ca2e925737c3fba4
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,53 @@
|
|||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
using NUnit.Framework;
|
||||
using NUnit.Framework.Internal;
|
||||
using NUnit.Framework.Internal.Commands;
|
||||
using UnityEngine.TestRunner.NUnitExtensions.Runner;
|
||||
|
||||
namespace UnityEngine.TestTools
|
||||
{
|
||||
internal class TestActionCommand : BeforeAfterTestCommandBase<ITestAction>
|
||||
{
|
||||
public TestActionCommand(TestCommand innerCommand)
|
||||
: base(innerCommand, "BeforeTest", "AfterTest", true)
|
||||
{
|
||||
if (Test.TypeInfo.Type != null)
|
||||
{
|
||||
BeforeActions = GetTestActionsFromMethod(Test.Method.MethodInfo);
|
||||
AfterActions = BeforeActions;
|
||||
}
|
||||
}
|
||||
|
||||
private static ITestAction[] GetTestActionsFromMethod(MethodInfo method)
|
||||
{
|
||||
var attributes = method.GetCustomAttributes(false);
|
||||
List<ITestAction> actions = new List<ITestAction>();
|
||||
foreach (var attribute in attributes)
|
||||
{
|
||||
if (attribute is ITestAction)
|
||||
actions.Add(attribute as ITestAction);
|
||||
}
|
||||
return actions.ToArray();
|
||||
}
|
||||
|
||||
protected override IEnumerator InvokeBefore(ITestAction action, Test test, UnityTestExecutionContext context)
|
||||
{
|
||||
action.BeforeTest(test);
|
||||
yield return null;
|
||||
}
|
||||
|
||||
protected override IEnumerator InvokeAfter(ITestAction action, Test test, UnityTestExecutionContext context)
|
||||
{
|
||||
action.AfterTest(test);
|
||||
yield return null;
|
||||
}
|
||||
|
||||
protected override BeforeAfterTestCommandState GetState(UnityTestExecutionContext context)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 2de8ba3b840049641897e0da7ce1d5cd
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,18 @@
|
|||
using System;
|
||||
using System.Collections;
|
||||
|
||||
namespace UnityEngine.TestTools
|
||||
{
|
||||
internal class TestCommandPcHelper
|
||||
{
|
||||
public virtual void SetEnumeratorPC(IEnumerator enumerator, int pc)
|
||||
{
|
||||
// Noop implementation used in playmode.
|
||||
}
|
||||
|
||||
public virtual int GetEnumeratorPC(IEnumerator enumerator)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 33e6b78c96bb0694e96383e3c56b7b54
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,19 @@
|
|||
using System;
|
||||
using NUnit.Framework.Internal;
|
||||
using NUnit.Framework.Internal.Commands;
|
||||
using Unity.Profiling;
|
||||
|
||||
namespace UnityEngine.TestTools
|
||||
{
|
||||
internal class UnityTestMethodCommand : TestMethodCommand
|
||||
{
|
||||
public UnityTestMethodCommand(TestMethod testMethod)
|
||||
: base(testMethod) { }
|
||||
|
||||
public override TestResult Execute(ITestExecutionContext context)
|
||||
{
|
||||
using (new ProfilerMarker(Test.FullName).Auto())
|
||||
return base.Execute(context);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
fileFormatVersion: 2
|
||||
guid: d2ca9278c9dd49df877d622d0f657ecf
|
||||
timeCreated: 1614093428
|
|
@ -0,0 +1,141 @@
|
|||
using System;
|
||||
using System.Linq;
|
||||
using NUnit.Framework.Internal;
|
||||
using UnityEngine.TestRunner.NUnitExtensions.Runner;
|
||||
using UnityEngine.TestTools.Logging;
|
||||
using UnityEngine.TestTools.TestRunner;
|
||||
|
||||
namespace UnityEngine.TestTools.NUnitExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Specialization of BaseDelegator that makes sure objects are created on the MainThread.
|
||||
/// It also deals with ScriptableObjects so that tests can survive assembly reload.
|
||||
/// </summary>
|
||||
internal class ConstructDelegator
|
||||
{
|
||||
private Type m_RequestedType;
|
||||
private object[] m_Arguments;
|
||||
|
||||
private ScriptableObject m_CurrentRunningTest;
|
||||
private readonly IStateSerializer m_StateSerializer;
|
||||
|
||||
protected Exception m_Exception;
|
||||
protected object m_Result;
|
||||
protected ITestExecutionContext m_Context;
|
||||
|
||||
public ConstructDelegator(IStateSerializer stateSerializer)
|
||||
{
|
||||
m_StateSerializer = stateSerializer;
|
||||
}
|
||||
|
||||
protected object HandleResult()
|
||||
{
|
||||
SetCurrentTestContext();
|
||||
if (m_Exception != null)
|
||||
{
|
||||
var temp = m_Exception;
|
||||
m_Exception = null;
|
||||
throw temp;
|
||||
}
|
||||
var tempResult = m_Result;
|
||||
m_Result = null;
|
||||
return tempResult;
|
||||
}
|
||||
|
||||
protected void SetCurrentTestContext()
|
||||
{
|
||||
var prop = typeof(UnityTestExecutionContext).GetProperty("CurrentContext");
|
||||
if (prop != null)
|
||||
{
|
||||
prop.SetValue(null, m_Context, null);
|
||||
}
|
||||
}
|
||||
|
||||
public object Delegate(Type type, object[] arguments)
|
||||
{
|
||||
AssertState();
|
||||
m_Context = UnityTestExecutionContext.CurrentContext;
|
||||
|
||||
m_RequestedType = type;
|
||||
m_Arguments = arguments;
|
||||
|
||||
using (var logScope = new LogScope())
|
||||
{
|
||||
Execute(logScope);
|
||||
}
|
||||
|
||||
return HandleResult();
|
||||
}
|
||||
|
||||
private void AssertState()
|
||||
{
|
||||
if (m_RequestedType != null)
|
||||
{
|
||||
throw new Exception("Constructor not executed yet");
|
||||
}
|
||||
}
|
||||
|
||||
public bool HasAction()
|
||||
{
|
||||
return m_RequestedType != null;
|
||||
}
|
||||
|
||||
public void Execute(LogScope logScope)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (typeof(ScriptableObject).IsAssignableFrom(m_RequestedType))
|
||||
{
|
||||
if (m_CurrentRunningTest != null && m_RequestedType != m_CurrentRunningTest.GetType())
|
||||
{
|
||||
DestroyCurrentTestObjectIfExists();
|
||||
}
|
||||
if (m_CurrentRunningTest == null)
|
||||
{
|
||||
if (m_StateSerializer.CanRestoreFromScriptableObject(m_RequestedType))
|
||||
{
|
||||
m_CurrentRunningTest = m_StateSerializer.RestoreScriptableObjectInstance();
|
||||
}
|
||||
else
|
||||
{
|
||||
m_CurrentRunningTest = ScriptableObject.CreateInstance(m_RequestedType);
|
||||
}
|
||||
}
|
||||
m_Result = m_CurrentRunningTest;
|
||||
}
|
||||
else
|
||||
{
|
||||
DestroyCurrentTestObjectIfExists();
|
||||
m_Result = Activator.CreateInstance(m_RequestedType, m_Arguments);
|
||||
if (m_StateSerializer.CanRestoreFromJson(m_RequestedType))
|
||||
{
|
||||
m_StateSerializer.RestoreClassFromJson(ref m_Result);
|
||||
}
|
||||
}
|
||||
if (logScope.AnyFailingLogs())
|
||||
{
|
||||
var failingLog = logScope.FailingLogs.First();
|
||||
throw new UnhandledLogMessageException(failingLog);
|
||||
}
|
||||
if (logScope.ExpectedLogs.Any())
|
||||
throw new UnexpectedLogMessageException(LogScope.Current.ExpectedLogs.Peek());
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
m_Exception = e;
|
||||
}
|
||||
finally
|
||||
{
|
||||
m_RequestedType = null;
|
||||
m_Arguments = null;
|
||||
}
|
||||
}
|
||||
|
||||
public void DestroyCurrentTestObjectIfExists()
|
||||
{
|
||||
if (m_CurrentRunningTest == null)
|
||||
return;
|
||||
Object.DestroyImmediate(m_CurrentRunningTest);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: b42e1db66fe9c634798674cb9e1df2ca
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,8 @@
|
|||
fileFormatVersion: 2
|
||||
guid: c3de99f9efc582a48995bc8e8c2df418
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,25 @@
|
|||
using System;
|
||||
using NUnit.Framework.Interfaces;
|
||||
using NUnit.Framework.Internal.Filters;
|
||||
|
||||
namespace UnityEngine.TestRunner.NUnitExtensions.Filters
|
||||
{
|
||||
internal class AssemblyNameFilter : ValueMatchFilter
|
||||
{
|
||||
public AssemblyNameFilter(string assemblyName) : base(assemblyName) {}
|
||||
|
||||
public override bool Match(ITest test)
|
||||
{
|
||||
string assemblyName = string.Empty;
|
||||
//Assembly fullname is in the format "Assembly-name, meta data ...", so extract the name by looking for the comma
|
||||
if (test.TypeInfo != null && test.TypeInfo.Assembly != null && test.TypeInfo.FullName != null)
|
||||
assemblyName = test.TypeInfo.Assembly.FullName.Substring(0, test.TypeInfo.Assembly.FullName.IndexOf(',')).TrimEnd(',');
|
||||
return ExpectedValue.Equals(assemblyName, StringComparison.OrdinalIgnoreCase);
|
||||
}
|
||||
|
||||
protected override string ElementName
|
||||
{
|
||||
get { return "id"; }
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 91319408591cec1478efd3c62f9f418a
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,36 @@
|
|||
using System.Collections;
|
||||
using System.Linq;
|
||||
using NUnit.Framework.Interfaces;
|
||||
using NUnit.Framework.Internal;
|
||||
using NUnit.Framework.Internal.Filters;
|
||||
|
||||
namespace UnityEngine.TestRunner.NUnitExtensions.Filters
|
||||
{
|
||||
internal class CategoryFilterExtended : CategoryFilter
|
||||
{
|
||||
public static string k_DefaultCategory = "Uncategorized";
|
||||
|
||||
public CategoryFilterExtended(string name) : base(name)
|
||||
{
|
||||
}
|
||||
|
||||
public override bool Match(ITest test)
|
||||
{
|
||||
IList testCategories = test.Properties[PropertyNames.Category].Cast<string>().ToList();
|
||||
|
||||
if (test is TestMethod)
|
||||
{
|
||||
// Do not count tests with no attribute as Uncategorized if test fixture class has at least one attribute
|
||||
// The test inherits the attribute from the test fixture
|
||||
IList fixtureCategories = test.Parent.Properties[PropertyNames.Category].Cast<string>().ToList();
|
||||
if (fixtureCategories.Count > 0)
|
||||
return false;
|
||||
}
|
||||
|
||||
if (testCategories.Count == 0 && ExpectedValue == k_DefaultCategory && test is TestMethod)
|
||||
return true;
|
||||
|
||||
return base.Match(test);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: ebeedaa04bb53e24ba2e7fb6745e3fd3
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,12 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
using NUnit.Framework.Api;
|
||||
using NUnit.Framework.Interfaces;
|
||||
|
||||
namespace UnityEngine.TestTools.NUnitExtensions
|
||||
{
|
||||
internal interface IAsyncTestAssemblyBuilder : ITestAssemblyBuilder
|
||||
{
|
||||
IEnumerator<ITest> BuildAsync(Assembly[] assemblies, TestPlatform[] testPlatforms, IDictionary<string, object> options);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: c3aa5c3d59b94854e843f10b75b3ad63
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,12 @@
|
|||
using System;
|
||||
|
||||
namespace UnityEngine.TestTools.NUnitExtensions
|
||||
{
|
||||
internal interface IStateSerializer
|
||||
{
|
||||
ScriptableObject RestoreScriptableObjectInstance();
|
||||
void RestoreClassFromJson(ref object instance);
|
||||
bool CanRestoreFromJson(Type requestedType);
|
||||
bool CanRestoreFromScriptableObject(Type requestedType);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 5f875a14565308a40a5262d2504da705
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,8 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 37888acc09d9ee848bf9559f06645c45
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,359 @@
|
|||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using NUnit.Framework;
|
||||
using NUnit.Framework.Interfaces;
|
||||
using NUnit.Framework.Internal;
|
||||
using NUnit.Framework.Internal.Commands;
|
||||
using NUnit.Framework.Internal.Execution;
|
||||
using UnityEngine.TestTools.Logging;
|
||||
using UnityEngine.TestTools.TestRunner;
|
||||
|
||||
namespace UnityEngine.TestRunner.NUnitExtensions.Runner
|
||||
{
|
||||
internal class CompositeWorkItem : UnityWorkItem
|
||||
{
|
||||
private readonly TestSuite _suite;
|
||||
private readonly TestSuiteResult _suiteResult;
|
||||
private readonly ITestFilter _childFilter;
|
||||
private TestCommand _setupCommand;
|
||||
private TestCommand _teardownCommand;
|
||||
|
||||
public List<UnityWorkItem> Children { get; private set; }
|
||||
|
||||
private int _countOrder;
|
||||
|
||||
private CountdownEvent _childTestCountdown;
|
||||
|
||||
public CompositeWorkItem(TestSuite suite, ITestFilter childFilter, WorkItemFactory factory)
|
||||
: base(suite, factory)
|
||||
{
|
||||
_suite = suite;
|
||||
_suiteResult = Result as TestSuiteResult;
|
||||
_childFilter = childFilter;
|
||||
_countOrder = 0;
|
||||
}
|
||||
|
||||
protected override IEnumerable PerformWork()
|
||||
{
|
||||
InitializeSetUpAndTearDownCommands();
|
||||
|
||||
if (UnityTestExecutionContext.CurrentContext != null && m_DontRunRestoringResult && EditModeTestCallbacks.RestoringTestContext != null)
|
||||
{
|
||||
EditModeTestCallbacks.RestoringTestContext();
|
||||
}
|
||||
|
||||
if (!CheckForCancellation())
|
||||
if (Test.RunState == RunState.Explicit && !_childFilter.IsExplicitMatch(Test))
|
||||
SkipFixture(ResultState.Explicit, GetSkipReason(), null);
|
||||
else
|
||||
switch (Test.RunState)
|
||||
{
|
||||
default:
|
||||
case RunState.Runnable:
|
||||
case RunState.Explicit:
|
||||
Result.SetResult(ResultState.Success);
|
||||
|
||||
CreateChildWorkItems();
|
||||
|
||||
if (Children.Count > 0)
|
||||
{
|
||||
if (!m_DontRunRestoringResult)
|
||||
{
|
||||
//This is needed to give the editor a chance to go out of playmode if needed before creating objects.
|
||||
//If we do not, the objects could be automatically destroyed when exiting playmode and could result in errors later on
|
||||
yield return null;
|
||||
PerformOneTimeSetUp();
|
||||
}
|
||||
|
||||
if (!CheckForCancellation())
|
||||
{
|
||||
switch (Result.ResultState.Status)
|
||||
{
|
||||
case TestStatus.Passed:
|
||||
foreach (var child in RunChildren())
|
||||
{
|
||||
if (CheckForCancellation())
|
||||
{
|
||||
yield break;
|
||||
}
|
||||
|
||||
yield return child;
|
||||
}
|
||||
break;
|
||||
case TestStatus.Skipped:
|
||||
case TestStatus.Inconclusive:
|
||||
case TestStatus.Failed:
|
||||
SkipChildren(_suite, Result.ResultState.WithSite(FailureSite.Parent), "OneTimeSetUp: " + Result.Message);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (Context.ExecutionStatus != TestExecutionStatus.AbortRequested && !m_DontRunRestoringResult)
|
||||
{
|
||||
PerformOneTimeTearDown();
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case RunState.Skipped:
|
||||
SkipFixture(ResultState.Skipped, GetSkipReason(), null);
|
||||
break;
|
||||
|
||||
case RunState.Ignored:
|
||||
SkipFixture(ResultState.Ignored, GetSkipReason(), null);
|
||||
break;
|
||||
|
||||
case RunState.NotRunnable:
|
||||
SkipFixture(ResultState.NotRunnable, GetSkipReason(), GetProviderStackTrace());
|
||||
break;
|
||||
}
|
||||
if (!ResultedInDomainReload)
|
||||
{
|
||||
WorkItemComplete();
|
||||
}
|
||||
}
|
||||
|
||||
private bool CheckForCancellation()
|
||||
{
|
||||
if (Context.ExecutionStatus != TestExecutionStatus.Running)
|
||||
{
|
||||
Result.SetResult(ResultState.Cancelled, "Test cancelled by user");
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private void InitializeSetUpAndTearDownCommands()
|
||||
{
|
||||
List<SetUpTearDownItem> setUpTearDownItems = _suite.TypeInfo != null
|
||||
? CommandBuilder.BuildSetUpTearDownList(_suite.TypeInfo.Type, typeof(OneTimeSetUpAttribute), typeof(OneTimeTearDownAttribute))
|
||||
: new List<SetUpTearDownItem>();
|
||||
|
||||
var actionItems = new List<TestActionItem>();
|
||||
foreach (ITestAction action in Actions)
|
||||
{
|
||||
bool applyToSuite = (action.Targets & ActionTargets.Suite) == ActionTargets.Suite
|
||||
|| action.Targets == ActionTargets.Default && !(Test is ParameterizedMethodSuite);
|
||||
|
||||
bool applyToTest = (action.Targets & ActionTargets.Test) == ActionTargets.Test
|
||||
&& !(Test is ParameterizedMethodSuite);
|
||||
|
||||
if (applyToSuite)
|
||||
actionItems.Add(new TestActionItem(action));
|
||||
|
||||
if (applyToTest)
|
||||
Context.UpstreamActions.Add(action);
|
||||
}
|
||||
|
||||
_setupCommand = CommandBuilder.MakeOneTimeSetUpCommand(_suite, setUpTearDownItems, actionItems);
|
||||
_teardownCommand = CommandBuilder.MakeOneTimeTearDownCommand(_suite, setUpTearDownItems, actionItems);
|
||||
}
|
||||
|
||||
private void PerformOneTimeSetUp()
|
||||
{
|
||||
var logScope = new LogScope();
|
||||
try
|
||||
{
|
||||
_setupCommand.Execute(Context);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
if (ex is NUnitException || ex is TargetInvocationException)
|
||||
ex = ex.InnerException;
|
||||
|
||||
Result.RecordException(ex, FailureSite.SetUp);
|
||||
}
|
||||
|
||||
if (logScope.AnyFailingLogs())
|
||||
{
|
||||
Result.RecordException(new UnhandledLogMessageException(logScope.FailingLogs.First()));
|
||||
}
|
||||
logScope.Dispose();
|
||||
}
|
||||
|
||||
private IEnumerable RunChildren()
|
||||
{
|
||||
int childCount = Children.Count;
|
||||
if (childCount == 0)
|
||||
throw new InvalidOperationException("RunChildren called but item has no children");
|
||||
|
||||
_childTestCountdown = new CountdownEvent(childCount);
|
||||
|
||||
foreach (UnityWorkItem child in Children)
|
||||
{
|
||||
if (CheckForCancellation())
|
||||
{
|
||||
yield break;
|
||||
}
|
||||
|
||||
var unityTestExecutionContext = new UnityTestExecutionContext(Context);
|
||||
child.InitializeContext(unityTestExecutionContext);
|
||||
|
||||
var enumerable = child.Execute().GetEnumerator();
|
||||
|
||||
while (true)
|
||||
{
|
||||
if (!enumerable.MoveNext())
|
||||
{
|
||||
break;
|
||||
}
|
||||
ResultedInDomainReload |= child.ResultedInDomainReload;
|
||||
yield return enumerable.Current;
|
||||
}
|
||||
|
||||
_suiteResult.AddResult(child.Result);
|
||||
childCount--;
|
||||
}
|
||||
|
||||
if (childCount > 0)
|
||||
{
|
||||
while (childCount-- > 0)
|
||||
CountDownChildTest();
|
||||
}
|
||||
}
|
||||
|
||||
private void CreateChildWorkItems()
|
||||
{
|
||||
Children = new List<UnityWorkItem>();
|
||||
var testSuite = _suite;
|
||||
|
||||
foreach (ITest test in testSuite.Tests)
|
||||
{
|
||||
if (_childFilter.Pass(test))
|
||||
{
|
||||
var child = m_Factory.Create(test, _childFilter);
|
||||
|
||||
if (test.Properties.ContainsKey(PropertyNames.Order))
|
||||
{
|
||||
Children.Insert(0, child);
|
||||
_countOrder++;
|
||||
}
|
||||
else
|
||||
{
|
||||
Children.Add(child);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (_countOrder != 0) SortChildren();
|
||||
}
|
||||
|
||||
private class UnityWorkItemOrderComparer : IComparer<UnityWorkItem>
|
||||
{
|
||||
public int Compare(UnityWorkItem x, UnityWorkItem y)
|
||||
{
|
||||
var xKey = int.MaxValue;
|
||||
var yKey = int.MaxValue;
|
||||
|
||||
if (x.Test.Properties.ContainsKey(PropertyNames.Order))
|
||||
xKey = (int)x.Test.Properties[PropertyNames.Order][0];
|
||||
|
||||
if (y.Test.Properties.ContainsKey(PropertyNames.Order))
|
||||
yKey = (int)y.Test.Properties[PropertyNames.Order][0];
|
||||
|
||||
return xKey.CompareTo(yKey);
|
||||
}
|
||||
}
|
||||
|
||||
private void SortChildren()
|
||||
{
|
||||
Children.Sort(0, _countOrder, new UnityWorkItemOrderComparer());
|
||||
}
|
||||
|
||||
private void SkipFixture(ResultState resultState, string message, string stackTrace)
|
||||
{
|
||||
Result.SetResult(resultState.WithSite(FailureSite.SetUp), message, StackFilter.Filter(stackTrace));
|
||||
SkipChildren(_suite, resultState.WithSite(FailureSite.Parent), "OneTimeSetUp: " + message);
|
||||
}
|
||||
|
||||
private void SkipChildren(TestSuite suite, ResultState resultState, string message)
|
||||
{
|
||||
foreach (Test child in suite.Tests)
|
||||
{
|
||||
if (_childFilter.Pass(child))
|
||||
{
|
||||
Context.Listener.TestStarted(child);
|
||||
TestResult childResult = child.MakeTestResult();
|
||||
childResult.SetResult(resultState, message);
|
||||
_suiteResult.AddResult(childResult);
|
||||
|
||||
if (child.IsSuite)
|
||||
SkipChildren((TestSuite)child, resultState, message);
|
||||
|
||||
Context.Listener.TestFinished(childResult);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void PerformOneTimeTearDown()
|
||||
{
|
||||
var logScope = new LogScope();
|
||||
try
|
||||
{
|
||||
_teardownCommand.Execute(Context);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
if (ex is NUnitException || ex is TargetInvocationException)
|
||||
ex = ex.InnerException;
|
||||
|
||||
Result.RecordException(ex, FailureSite.SetUp);
|
||||
}
|
||||
|
||||
if (logScope.AnyFailingLogs())
|
||||
{
|
||||
Result.RecordException(new UnhandledLogMessageException(logScope.FailingLogs.First()));
|
||||
}
|
||||
logScope.Dispose();
|
||||
}
|
||||
|
||||
private string GetSkipReason()
|
||||
{
|
||||
return (string)Test.Properties.Get(PropertyNames.SkipReason);
|
||||
}
|
||||
|
||||
private string GetProviderStackTrace()
|
||||
{
|
||||
return (string)Test.Properties.Get(PropertyNames.ProviderStackTrace);
|
||||
}
|
||||
|
||||
private void CountDownChildTest()
|
||||
{
|
||||
_childTestCountdown.Signal();
|
||||
if (_childTestCountdown.CurrentCount == 0)
|
||||
{
|
||||
if (Context.ExecutionStatus != TestExecutionStatus.AbortRequested)
|
||||
PerformOneTimeTearDown();
|
||||
|
||||
foreach (var childResult in _suiteResult.Children)
|
||||
if (childResult.ResultState == ResultState.Cancelled)
|
||||
{
|
||||
this.Result.SetResult(ResultState.Cancelled, "Cancelled by user");
|
||||
break;
|
||||
}
|
||||
|
||||
WorkItemComplete();
|
||||
}
|
||||
}
|
||||
|
||||
public override void Cancel(bool force)
|
||||
{
|
||||
if (Children == null)
|
||||
return;
|
||||
|
||||
foreach (var child in Children)
|
||||
{
|
||||
var ctx = child.Context;
|
||||
if (ctx != null)
|
||||
ctx.ExecutionStatus = force ? TestExecutionStatus.AbortRequested : TestExecutionStatus.StopRequested;
|
||||
|
||||
if (child.State == WorkItemState.Running)
|
||||
child.Cancel(force);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 110d5035a36a6a34580fb65bb40cd78f
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,76 @@
|
|||
using System;
|
||||
using System.Collections;
|
||||
using NUnit.Framework.Interfaces;
|
||||
using NUnit.Framework.Internal;
|
||||
using NUnit.Framework.Internal.Commands;
|
||||
using NUnit.Framework.Internal.Execution;
|
||||
using UnityEngine.TestTools.TestRunner;
|
||||
using UnityEngine.TestTools.Utils;
|
||||
|
||||
namespace UnityEngine.TestRunner.NUnitExtensions.Runner
|
||||
{
|
||||
internal class CoroutineTestWorkItem : UnityWorkItem
|
||||
{
|
||||
private static MonoBehaviour m_MonoBehaviourCoroutineRunner;
|
||||
private TestCommand m_Command;
|
||||
|
||||
public static MonoBehaviour monoBehaviourCoroutineRunner
|
||||
{
|
||||
get
|
||||
{
|
||||
if (m_MonoBehaviourCoroutineRunner == null)
|
||||
{
|
||||
throw new NullReferenceException("MonoBehaviour coroutine runner not set");
|
||||
}
|
||||
return m_MonoBehaviourCoroutineRunner;
|
||||
}
|
||||
set { m_MonoBehaviourCoroutineRunner = value; }
|
||||
}
|
||||
|
||||
public CoroutineTestWorkItem(TestMethod test, ITestFilter filter)
|
||||
: base(test, null)
|
||||
{
|
||||
m_Command = m_Command = TestCommandBuilder.BuildTestCommand(test, filter);
|
||||
}
|
||||
|
||||
protected override IEnumerable PerformWork()
|
||||
{
|
||||
if (m_Command is SkipCommand)
|
||||
{
|
||||
m_Command.Execute(Context);
|
||||
Result = Context.CurrentResult;
|
||||
WorkItemComplete();
|
||||
yield break;
|
||||
}
|
||||
|
||||
if (m_Command is ApplyChangesToContextCommand)
|
||||
{
|
||||
var applyChangesToContextCommand = (ApplyChangesToContextCommand)m_Command;
|
||||
applyChangesToContextCommand.ApplyChanges(Context);
|
||||
m_Command = applyChangesToContextCommand.GetInnerCommand();
|
||||
}
|
||||
|
||||
var enumerableTestMethodCommand = (IEnumerableTestMethodCommand)m_Command;
|
||||
try
|
||||
{
|
||||
var executeEnumerable = enumerableTestMethodCommand.ExecuteEnumerable(Context).GetEnumerator();
|
||||
|
||||
var coroutineRunner = new CoroutineRunner(monoBehaviourCoroutineRunner, Context);
|
||||
yield return coroutineRunner.HandleEnumerableTest(executeEnumerable);
|
||||
|
||||
if (coroutineRunner.HasFailedWithTimeout())
|
||||
{
|
||||
Context.CurrentResult.SetResult(ResultState.Failure, new UnityTestTimeoutException(Context.TestCaseTimeout).Message);
|
||||
}
|
||||
|
||||
while (executeEnumerable.MoveNext()) {}
|
||||
|
||||
Result = Context.CurrentResult;
|
||||
}
|
||||
finally
|
||||
{
|
||||
WorkItemComplete();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: b557515fff172984e8c4400b43f1c631
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,98 @@
|
|||
using System;
|
||||
using System.Collections;
|
||||
using System.Linq;
|
||||
using NUnit.Framework.Interfaces;
|
||||
using NUnit.Framework.Internal;
|
||||
using NUnit.Framework.Internal.Commands;
|
||||
using NUnit.Framework.Internal.Execution;
|
||||
using UnityEngine.TestTools;
|
||||
using SetUpTearDownCommand = NUnit.Framework.Internal.Commands.SetUpTearDownCommand;
|
||||
using TestActionCommand = NUnit.Framework.Internal.Commands.TestActionCommand;
|
||||
|
||||
namespace UnityEngine.TestRunner.NUnitExtensions.Runner
|
||||
{
|
||||
internal class EditModeTestCallbacks
|
||||
{
|
||||
public static Action RestoringTestContext { get; set; }
|
||||
}
|
||||
|
||||
internal class DefaultTestWorkItem : UnityWorkItem
|
||||
{
|
||||
private TestCommand _command;
|
||||
public DefaultTestWorkItem(TestMethod test, ITestFilter filter)
|
||||
: base(test, null)
|
||||
{
|
||||
_command = TestCommandBuilder.BuildTestCommand(test, filter);
|
||||
}
|
||||
|
||||
protected override IEnumerable PerformWork()
|
||||
{
|
||||
if (m_DontRunRestoringResult && EditModeTestCallbacks.RestoringTestContext != null)
|
||||
{
|
||||
EditModeTestCallbacks.RestoringTestContext();
|
||||
Result = Context.CurrentResult;
|
||||
yield break;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
if (_command is SkipCommand || _command is FailCommand)
|
||||
{
|
||||
Result = _command.Execute(Context);
|
||||
yield break;
|
||||
}
|
||||
|
||||
if (!(_command is IEnumerableTestMethodCommand))
|
||||
{
|
||||
Debug.LogError("Cannot perform work on " + _command.GetType().Name);
|
||||
yield break;
|
||||
}
|
||||
if (Context.TestCaseTimeout == 0)
|
||||
{
|
||||
Context.TestCaseTimeout = k_DefaultTimeout;
|
||||
}
|
||||
foreach (var workItemStep in ((IEnumerableTestMethodCommand)_command).ExecuteEnumerable(Context))
|
||||
{
|
||||
ResultedInDomainReload = false;
|
||||
|
||||
if (workItemStep is IEditModeTestYieldInstruction)
|
||||
{
|
||||
var editModeTestYieldInstruction = (IEditModeTestYieldInstruction)workItemStep;
|
||||
yield return editModeTestYieldInstruction;
|
||||
var enumerator = editModeTestYieldInstruction.Perform();
|
||||
while (true)
|
||||
{
|
||||
bool moveNext;
|
||||
try
|
||||
{
|
||||
moveNext = enumerator.MoveNext();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Context.CurrentResult.RecordException(e);
|
||||
break;
|
||||
}
|
||||
|
||||
if (!moveNext)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
yield return null;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
yield return workItemStep;
|
||||
}
|
||||
}
|
||||
|
||||
Result = Context.CurrentResult;
|
||||
}
|
||||
finally
|
||||
{
|
||||
WorkItemComplete();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: c7cfda246e604b945b12b7afedb094ce
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,34 @@
|
|||
|
||||
using System.Collections;
|
||||
using NUnit.Framework.Interfaces;
|
||||
using NUnit.Framework.Internal;
|
||||
using NUnit.Framework.Internal.Commands;
|
||||
|
||||
namespace UnityEngine.TestRunner.NUnitExtensions.Runner
|
||||
{
|
||||
internal class FailCommand : TestCommand, IEnumerableTestMethodCommand
|
||||
{
|
||||
private ResultState m_ResultState;
|
||||
private string m_Message;
|
||||
|
||||
public FailCommand(Test test, ResultState resultState, string message)
|
||||
: base(test)
|
||||
{
|
||||
m_ResultState = resultState;
|
||||
m_Message = message;
|
||||
}
|
||||
|
||||
public override TestResult Execute(ITestExecutionContext context)
|
||||
{
|
||||
context.CurrentResult.SetResult(m_ResultState, m_Message);
|
||||
return context.CurrentResult;
|
||||
}
|
||||
|
||||
public IEnumerable ExecuteEnumerable(ITestExecutionContext context)
|
||||
{
|
||||
context.CurrentResult.SetResult(m_ResultState, m_Message);
|
||||
yield return null;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 68e5dc8bfd5d72647a93b7f2e1da831a
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,10 @@
|
|||
using System.Collections;
|
||||
using NUnit.Framework.Internal;
|
||||
|
||||
namespace UnityEngine.TestRunner.NUnitExtensions.Runner
|
||||
{
|
||||
internal interface IEnumerableTestMethodCommand
|
||||
{
|
||||
IEnumerable ExecuteEnumerable(ITestExecutionContext context);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: dbd43d8a3b8122d4e89b055f53382b11
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,13 @@
|
|||
using NUnit.Framework.Interfaces;
|
||||
using NUnit.Framework.Internal;
|
||||
|
||||
namespace UnityEngine.TestRunner.NUnitExtensions.Runner
|
||||
{
|
||||
internal class PlaymodeWorkItemFactory : WorkItemFactory
|
||||
{
|
||||
protected override UnityWorkItem Create(TestMethod method, ITestFilter filter, ITest loadedTest)
|
||||
{
|
||||
return new CoroutineTestWorkItem(method, filter);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 7ef6801a8b664544aa9f2ab1bc1f8b60
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,4 @@
|
|||
namespace UnityEngine.TestRunner.NUnitExtensions.Runner
|
||||
{
|
||||
internal class RestoreTestContextAfterDomainReload {}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 26721f9940339264fb14bdbfe1290e21
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,127 @@
|
|||
using System;
|
||||
using System.Collections;
|
||||
using System.Linq;
|
||||
using NUnit.Framework;
|
||||
using NUnit.Framework.Interfaces;
|
||||
using NUnit.Framework.Internal;
|
||||
using NUnit.Framework.Internal.Commands;
|
||||
using UnityEngine.TestTools;
|
||||
|
||||
namespace UnityEngine.TestRunner.NUnitExtensions.Runner
|
||||
{
|
||||
internal static class TestCommandBuilder
|
||||
{
|
||||
public static TestCommand BuildTestCommand(TestMethod test, ITestFilter filter)
|
||||
{
|
||||
if (test.RunState != RunState.Runnable &&
|
||||
!(test.RunState == RunState.Explicit && filter.IsExplicitMatch(test)))
|
||||
{
|
||||
return new SkipCommand(test);
|
||||
}
|
||||
|
||||
var testReturnsIEnumerator = test.Method.ReturnType.Type == typeof(IEnumerator);
|
||||
|
||||
TestCommand command;
|
||||
if (!testReturnsIEnumerator)
|
||||
{
|
||||
command = new UnityTestMethodCommand(test);
|
||||
}
|
||||
else
|
||||
{
|
||||
command = new EnumerableTestMethodCommand(test);
|
||||
}
|
||||
|
||||
command = new UnityLogCheckDelegatingCommand(command);
|
||||
foreach (var wrapper in test.Method.GetCustomAttributes<IWrapTestMethod>(true))
|
||||
{
|
||||
command = wrapper.Wrap(command);
|
||||
if (command == null)
|
||||
{
|
||||
var message = String.Format("IWrapTestMethod implementation '{0}' returned null as command.",
|
||||
wrapper.GetType().FullName);
|
||||
return new FailCommand(test, ResultState.Failure, message);
|
||||
}
|
||||
|
||||
if (testReturnsIEnumerator && !(command is IEnumerableTestMethodCommand))
|
||||
{
|
||||
command = TryReplaceWithEnumerableCommand(command);
|
||||
if (command != null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var message = String.Format("'{0}' is not supported on {1} as it does not handle returning IEnumerator.",
|
||||
wrapper.GetType().FullName,
|
||||
GetTestBuilderName(test));
|
||||
return new FailCommand(test, ResultState.Failure, message);
|
||||
}
|
||||
}
|
||||
|
||||
command = new UnityEngine.TestTools.TestActionCommand(command);
|
||||
command = new UnityEngine.TestTools.SetUpTearDownCommand(command);
|
||||
|
||||
if (!testReturnsIEnumerator)
|
||||
{
|
||||
command = new ImmediateEnumerableCommand(command);
|
||||
}
|
||||
|
||||
foreach (var wrapper in test.Method.GetCustomAttributes<IWrapSetUpTearDown>(true))
|
||||
{
|
||||
command = wrapper.Wrap(command);
|
||||
if (command == null)
|
||||
{
|
||||
var message = String.Format("IWrapSetUpTearDown implementation '{0}' returned null as command.",
|
||||
wrapper.GetType().FullName);
|
||||
return new FailCommand(test, ResultState.Failure, message);
|
||||
}
|
||||
|
||||
if (testReturnsIEnumerator && !(command is IEnumerableTestMethodCommand))
|
||||
{
|
||||
command = TryReplaceWithEnumerableCommand(command);
|
||||
if (command != null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var message = String.Format("'{0}' is not supported on {1} as it does not handle returning IEnumerator.",
|
||||
wrapper.GetType().FullName,
|
||||
GetTestBuilderName(test));
|
||||
return new FailCommand(test, ResultState.Failure, message);
|
||||
}
|
||||
}
|
||||
|
||||
command = new EnumerableSetUpTearDownCommand(command);
|
||||
command = new OuterUnityTestActionCommand(command);
|
||||
|
||||
IApplyToContext[] changes = test.Method.GetCustomAttributes<IApplyToContext>(true);
|
||||
if (changes.Length > 0)
|
||||
{
|
||||
command = new EnumerableApplyChangesToContextCommand(command, changes);
|
||||
}
|
||||
|
||||
return command;
|
||||
}
|
||||
|
||||
private static string GetTestBuilderName(TestMethod testMethod)
|
||||
{
|
||||
return new[]
|
||||
{
|
||||
testMethod.Method.GetCustomAttributes<ITestBuilder>(true).Select(attribute => attribute.GetType().Name),
|
||||
testMethod.Method.GetCustomAttributes<ISimpleTestBuilder>(true).Select(attribute => attribute.GetType().Name)
|
||||
}.SelectMany(v => v).FirstOrDefault();
|
||||
}
|
||||
|
||||
private static TestCommand TryReplaceWithEnumerableCommand(TestCommand command)
|
||||
{
|
||||
switch (command.GetType().Name)
|
||||
{
|
||||
case nameof(RepeatAttribute.RepeatedTestCommand):
|
||||
return new EnumerableRepeatedTestCommand(command as RepeatAttribute.RepeatedTestCommand);
|
||||
case nameof(RetryAttribute.RetryCommand):
|
||||
return new EnumerableRetryTestCommand(command as RetryAttribute.RetryCommand);
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: f40df9c8cf926b241b093a37028d8815
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,143 @@
|
|||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using NUnit.Framework.Internal;
|
||||
using NUnit.Framework.Internal.Commands;
|
||||
using UnityEngine.TestTools;
|
||||
using UnityEngine.TestTools.Logging;
|
||||
using UnityEngine.TestTools.TestRunner;
|
||||
|
||||
namespace UnityEngine.TestRunner.NUnitExtensions.Runner
|
||||
{
|
||||
class UnityLogCheckDelegatingCommand : DelegatingTestCommand, IEnumerableTestMethodCommand
|
||||
{
|
||||
static Dictionary<object, bool?> s_AttributeCache = new Dictionary<object, bool?>();
|
||||
|
||||
public UnityLogCheckDelegatingCommand(TestCommand innerCommand)
|
||||
: base(innerCommand) {}
|
||||
|
||||
public override TestResult Execute(ITestExecutionContext context)
|
||||
{
|
||||
using (var logScope = new LogScope())
|
||||
{
|
||||
if (ExecuteAndCheckLog(logScope, context.CurrentResult, () => innerCommand.Execute(context)))
|
||||
PostTestValidation(logScope, innerCommand, context.CurrentResult);
|
||||
}
|
||||
|
||||
return context.CurrentResult;
|
||||
}
|
||||
|
||||
public IEnumerable ExecuteEnumerable(ITestExecutionContext context)
|
||||
{
|
||||
if (!(innerCommand is IEnumerableTestMethodCommand enumerableTestMethodCommand))
|
||||
{
|
||||
Execute(context);
|
||||
yield break;
|
||||
}
|
||||
|
||||
using (var logScope = new LogScope())
|
||||
{
|
||||
IEnumerable executeEnumerable = null;
|
||||
|
||||
if (!ExecuteAndCheckLog(logScope, context.CurrentResult,
|
||||
() => executeEnumerable = enumerableTestMethodCommand.ExecuteEnumerable(context)))
|
||||
yield break;
|
||||
|
||||
foreach (var step in executeEnumerable)
|
||||
{
|
||||
// do not check expected logs here - we want to permit expecting and receiving messages to run
|
||||
// across frames. (but we do always want to catch a fail immediately.)
|
||||
if (!CheckFailingLogs(logScope, context.CurrentResult))
|
||||
yield break;
|
||||
|
||||
yield return step;
|
||||
}
|
||||
|
||||
if (!CheckLogs(context.CurrentResult, logScope))
|
||||
yield break;
|
||||
|
||||
PostTestValidation(logScope, innerCommand, context.CurrentResult);
|
||||
}
|
||||
}
|
||||
|
||||
static bool CaptureException(TestResult result, Action action)
|
||||
{
|
||||
try
|
||||
{
|
||||
action();
|
||||
return true;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
result.RecordException(e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static bool ExecuteAndCheckLog(LogScope logScope, TestResult result, Action action)
|
||||
=> CaptureException(result, action) && CheckLogs(result, logScope);
|
||||
|
||||
static void PostTestValidation(LogScope logScope, TestCommand command, TestResult result)
|
||||
{
|
||||
if (MustExpect(command.Test.Method.MethodInfo))
|
||||
CaptureException(result, logScope.NoUnexpectedReceived);
|
||||
}
|
||||
|
||||
static bool CheckLogs(TestResult result, LogScope logScope)
|
||||
=> CheckFailingLogs(logScope, result) && CheckExpectedLogs(logScope, result);
|
||||
|
||||
static bool CheckFailingLogs(LogScope logScope, TestResult result)
|
||||
{
|
||||
if (!logScope.AnyFailingLogs())
|
||||
return true;
|
||||
|
||||
var failingLog = logScope.FailingLogs.First();
|
||||
result.RecordException(new UnhandledLogMessageException(failingLog));
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool CheckExpectedLogs(LogScope logScope, TestResult result)
|
||||
{
|
||||
if (!logScope.ExpectedLogs.Any())
|
||||
return true;
|
||||
|
||||
var expectedLog = logScope.ExpectedLogs.Peek();
|
||||
result.RecordException(new UnexpectedLogMessageException(expectedLog));
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool MustExpect(MemberInfo method)
|
||||
{
|
||||
// method
|
||||
|
||||
var methodAttr = method.GetCustomAttributes<TestMustExpectAllLogsAttribute>(true).FirstOrDefault();
|
||||
if (methodAttr != null)
|
||||
return methodAttr.MustExpect;
|
||||
|
||||
// fixture
|
||||
|
||||
var fixture = method.DeclaringType;
|
||||
if (!s_AttributeCache.TryGetValue(fixture, out var mustExpect))
|
||||
{
|
||||
var fixtureAttr = fixture.GetCustomAttributes<TestMustExpectAllLogsAttribute>(true).FirstOrDefault();
|
||||
mustExpect = s_AttributeCache[fixture] = fixtureAttr?.MustExpect;
|
||||
}
|
||||
|
||||
if (mustExpect != null)
|
||||
return mustExpect.Value;
|
||||
|
||||
// assembly
|
||||
|
||||
var assembly = fixture.Assembly;
|
||||
if (!s_AttributeCache.TryGetValue(assembly, out mustExpect))
|
||||
{
|
||||
var assemblyAttr = assembly.GetCustomAttributes<TestMustExpectAllLogsAttribute>().FirstOrDefault();
|
||||
mustExpect = s_AttributeCache[assembly] = assemblyAttr?.MustExpect;
|
||||
}
|
||||
|
||||
return mustExpect == true;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 48230e4e90fb4d14a9d56bddea898413
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,98 @@
|
|||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using NUnit;
|
||||
using NUnit.Framework.Interfaces;
|
||||
using NUnit.Framework.Internal;
|
||||
using UnityEngine.TestTools;
|
||||
using UnityEngine.TestTools.NUnitExtensions;
|
||||
|
||||
namespace UnityEngine.TestRunner.NUnitExtensions.Runner
|
||||
{
|
||||
internal interface IUnityTestAssemblyRunner
|
||||
{
|
||||
ITest LoadedTest { get; }
|
||||
ITestResult Result { get; }
|
||||
bool IsTestLoaded { get; }
|
||||
bool IsTestRunning { get; }
|
||||
bool IsTestComplete { get; }
|
||||
UnityWorkItem TopLevelWorkItem { get; set; }
|
||||
UnityTestExecutionContext GetCurrentContext();
|
||||
ITest Load(Assembly[] assemblies, TestPlatform testPlatform, IDictionary<string, object> settings);
|
||||
IEnumerable Run(ITestListener listener, ITestFilter filter);
|
||||
void StopRun();
|
||||
}
|
||||
|
||||
internal class UnityTestAssemblyRunner : IUnityTestAssemblyRunner
|
||||
{
|
||||
private readonly UnityTestAssemblyBuilder unityBuilder;
|
||||
private readonly WorkItemFactory m_Factory;
|
||||
|
||||
protected UnityTestExecutionContext Context { get; set; }
|
||||
|
||||
public UnityTestExecutionContext GetCurrentContext()
|
||||
{
|
||||
return UnityTestExecutionContext.CurrentContext;
|
||||
}
|
||||
|
||||
protected IDictionary<string, object> Settings { get; set; }
|
||||
public ITest LoadedTest { get; protected set; }
|
||||
|
||||
public ITestResult Result
|
||||
{
|
||||
get { return TopLevelWorkItem == null ? null : TopLevelWorkItem.Result; }
|
||||
}
|
||||
|
||||
public bool IsTestLoaded
|
||||
{
|
||||
get { return LoadedTest != null; }
|
||||
}
|
||||
|
||||
public bool IsTestRunning
|
||||
{
|
||||
get { return TopLevelWorkItem != null && TopLevelWorkItem.State == NUnit.Framework.Internal.Execution.WorkItemState.Running; }
|
||||
}
|
||||
public bool IsTestComplete
|
||||
{
|
||||
get { return TopLevelWorkItem != null && TopLevelWorkItem.State == NUnit.Framework.Internal.Execution.WorkItemState.Complete; }
|
||||
}
|
||||
|
||||
public UnityTestAssemblyRunner(UnityTestAssemblyBuilder builder, WorkItemFactory factory)
|
||||
{
|
||||
unityBuilder = builder;
|
||||
m_Factory = factory;
|
||||
Context = new UnityTestExecutionContext();
|
||||
}
|
||||
|
||||
public ITest Load(Assembly[] assemblies, TestPlatform testPlatform, IDictionary<string, object> settings)
|
||||
{
|
||||
Settings = settings;
|
||||
|
||||
if (settings.ContainsKey(FrameworkPackageSettings.RandomSeed))
|
||||
Randomizer.InitialSeed = (int)settings[FrameworkPackageSettings.RandomSeed];
|
||||
|
||||
return LoadedTest = unityBuilder.Build(assemblies, Enumerable.Repeat(testPlatform, assemblies.Length).ToArray(), settings);
|
||||
}
|
||||
|
||||
public IEnumerable Run(ITestListener listener, ITestFilter filter)
|
||||
{
|
||||
TopLevelWorkItem = m_Factory.Create(LoadedTest, filter);
|
||||
TopLevelWorkItem.InitializeContext(Context);
|
||||
UnityTestExecutionContext.CurrentContext = Context;
|
||||
Context.Listener = listener;
|
||||
|
||||
return TopLevelWorkItem.Execute();
|
||||
}
|
||||
|
||||
public UnityWorkItem TopLevelWorkItem { get; set; }
|
||||
|
||||
public void StopRun()
|
||||
{
|
||||
if (IsTestRunning)
|
||||
{
|
||||
TopLevelWorkItem.Cancel(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 874e40a588dbb1e48bc128d686337d4e
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,130 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using NUnit.Framework;
|
||||
using NUnit.Framework.Constraints;
|
||||
using NUnit.Framework.Interfaces;
|
||||
using NUnit.Framework.Internal;
|
||||
using NUnit.Framework.Internal.Execution;
|
||||
using UnityEngine.TestTools;
|
||||
|
||||
namespace UnityEngine.TestRunner.NUnitExtensions.Runner
|
||||
{
|
||||
internal class UnityTestExecutionContext : ITestExecutionContext
|
||||
{
|
||||
private readonly UnityTestExecutionContext _priorContext;
|
||||
private TestResult _currentResult;
|
||||
private int _assertCount;
|
||||
|
||||
public static UnityTestExecutionContext CurrentContext { get; set; }
|
||||
|
||||
public UnityTestExecutionContext Context { get; private set; }
|
||||
|
||||
public Test CurrentTest { get; set; }
|
||||
public DateTime StartTime { get; set; }
|
||||
public long StartTicks { get; set; }
|
||||
public TestResult CurrentResult
|
||||
{
|
||||
get { return _currentResult; }
|
||||
set
|
||||
{
|
||||
_currentResult = value;
|
||||
if (value != null)
|
||||
OutWriter = value.OutWriter;
|
||||
}
|
||||
}
|
||||
|
||||
public object TestObject { get; set; }
|
||||
public string WorkDirectory { get; set; }
|
||||
|
||||
|
||||
private TestExecutionStatus _executionStatus;
|
||||
public TestExecutionStatus ExecutionStatus
|
||||
{
|
||||
get
|
||||
{
|
||||
// ExecutionStatus may have been set to StopRequested or AbortRequested
|
||||
// in a prior context. If so, reflect the same setting in this context.
|
||||
if (_executionStatus == TestExecutionStatus.Running && _priorContext != null)
|
||||
_executionStatus = _priorContext.ExecutionStatus;
|
||||
|
||||
return _executionStatus;
|
||||
}
|
||||
set
|
||||
{
|
||||
_executionStatus = value;
|
||||
|
||||
// Push the same setting up to all prior contexts
|
||||
if (_priorContext != null)
|
||||
_priorContext.ExecutionStatus = value;
|
||||
}
|
||||
}
|
||||
|
||||
public List<ITestAction> UpstreamActions { get; private set; }
|
||||
public int TestCaseTimeout { get; set; }
|
||||
public CultureInfo CurrentCulture { get; set; }
|
||||
public CultureInfo CurrentUICulture { get; set; }
|
||||
public ITestListener Listener { get; set; }
|
||||
|
||||
public UnityTestExecutionContext()
|
||||
{
|
||||
UpstreamActions = new List<ITestAction>();
|
||||
CurrentContext = this;
|
||||
}
|
||||
|
||||
public UnityTestExecutionContext(UnityTestExecutionContext other)
|
||||
{
|
||||
_priorContext = other;
|
||||
|
||||
CurrentTest = other.CurrentTest;
|
||||
CurrentResult = other.CurrentResult;
|
||||
TestObject = other.TestObject;
|
||||
WorkDirectory = other.WorkDirectory;
|
||||
Listener = other.Listener;
|
||||
TestCaseTimeout = other.TestCaseTimeout;
|
||||
UpstreamActions = new List<ITestAction>(other.UpstreamActions);
|
||||
SetUpTearDownState = other.SetUpTearDownState;
|
||||
OuterUnityTestActionState = other.OuterUnityTestActionState;
|
||||
EnumerableTestState = other.EnumerableTestState;
|
||||
|
||||
TestContext.CurrentTestExecutionContext = this;
|
||||
|
||||
CurrentCulture = other.CurrentCulture;
|
||||
CurrentUICulture = other.CurrentUICulture;
|
||||
CurrentContext = this;
|
||||
}
|
||||
|
||||
public TextWriter OutWriter { get; private set; }
|
||||
public bool StopOnError { get; set; }
|
||||
|
||||
public IWorkItemDispatcher Dispatcher { get; set; }
|
||||
|
||||
public ParallelScope ParallelScope { get; set; }
|
||||
public string WorkerId { get; private set; }
|
||||
public Randomizer RandomGenerator { get; private set; }
|
||||
public ValueFormatter CurrentValueFormatter { get; private set; }
|
||||
public bool IsSingleThreaded { get; set; }
|
||||
public BeforeAfterTestCommandState SetUpTearDownState { get; set; }
|
||||
public BeforeAfterTestCommandState OuterUnityTestActionState { get; set; }
|
||||
public EnumerableTestState EnumerableTestState { get; set; }
|
||||
|
||||
internal int AssertCount
|
||||
{
|
||||
get
|
||||
{
|
||||
return _assertCount;
|
||||
}
|
||||
}
|
||||
|
||||
public void IncrementAssertCount()
|
||||
{
|
||||
_assertCount += 1;
|
||||
}
|
||||
|
||||
public void AddFormatter(ValueFormatterFactory formatterFactory)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 59ff995fabb3bac45afa0f96f333e5dc
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,117 @@
|
|||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using NUnit.Framework;
|
||||
using NUnit.Framework.Interfaces;
|
||||
using NUnit.Framework.Internal;
|
||||
using NUnit.Framework.Internal.Execution;
|
||||
|
||||
namespace UnityEngine.TestRunner.NUnitExtensions.Runner
|
||||
{
|
||||
internal abstract class UnityWorkItem
|
||||
{
|
||||
protected readonly WorkItemFactory m_Factory;
|
||||
protected bool m_ExecuteTestStartEvent;
|
||||
protected bool m_DontRunRestoringResult;
|
||||
protected const int k_DefaultTimeout = 1000 * 180;
|
||||
public event EventHandler Completed;
|
||||
|
||||
public bool ResultedInDomainReload { get; internal set; }
|
||||
|
||||
public UnityTestExecutionContext Context { get; private set; }
|
||||
|
||||
public Test Test { get; private set; }
|
||||
|
||||
public TestResult Result { get; protected set; }
|
||||
|
||||
public WorkItemState State { get; private set; }
|
||||
|
||||
public List<ITestAction> Actions { get; private set; }
|
||||
|
||||
protected UnityWorkItem(Test test, WorkItemFactory factory)
|
||||
{
|
||||
m_Factory = factory;
|
||||
Test = test;
|
||||
Actions = new List<ITestAction>();
|
||||
Result = test.MakeTestResult();
|
||||
State = WorkItemState.Ready;
|
||||
m_ExecuteTestStartEvent = ShouldExecuteStartEvent();
|
||||
m_DontRunRestoringResult = ShouldRestore(test);
|
||||
}
|
||||
|
||||
protected static bool ShouldRestore(ITest loadedTest)
|
||||
{
|
||||
return UnityWorkItemDataHolder.alreadyExecutedTests != null &&
|
||||
UnityWorkItemDataHolder.alreadyExecutedTests.Contains(loadedTest.GetUniqueName());
|
||||
}
|
||||
|
||||
protected bool ShouldExecuteStartEvent()
|
||||
{
|
||||
return UnityWorkItemDataHolder.alreadyStartedTests != null &&
|
||||
UnityWorkItemDataHolder.alreadyStartedTests.All(x => x != Test.GetUniqueName()) &&
|
||||
!ShouldRestore(Test);
|
||||
}
|
||||
|
||||
protected abstract IEnumerable PerformWork();
|
||||
|
||||
public void InitializeContext(UnityTestExecutionContext context)
|
||||
{
|
||||
Context = context;
|
||||
|
||||
if (Test is TestAssembly)
|
||||
Actions.AddRange(ActionsHelper.GetActionsFromTestAssembly((TestAssembly)Test));
|
||||
else if (Test is ParameterizedMethodSuite)
|
||||
Actions.AddRange(ActionsHelper.GetActionsFromTestMethodInfo(Test.Method));
|
||||
else if (Test.TypeInfo != null)
|
||||
Actions.AddRange(ActionsHelper.GetActionsFromTypesAttributes(Test.TypeInfo.Type));
|
||||
}
|
||||
|
||||
public virtual IEnumerable Execute()
|
||||
{
|
||||
Context.CurrentTest = this.Test;
|
||||
Context.CurrentResult = this.Result;
|
||||
|
||||
if (m_ExecuteTestStartEvent)
|
||||
{
|
||||
Context.Listener.TestStarted(Test);
|
||||
}
|
||||
|
||||
Context.StartTime = DateTime.UtcNow;
|
||||
Context.StartTicks = Stopwatch.GetTimestamp();
|
||||
|
||||
State = WorkItemState.Running;
|
||||
|
||||
return PerformWork();
|
||||
}
|
||||
|
||||
protected void WorkItemComplete()
|
||||
{
|
||||
State = WorkItemState.Complete;
|
||||
|
||||
Result.StartTime = Context.StartTime;
|
||||
Result.EndTime = DateTime.UtcNow;
|
||||
|
||||
long tickCount = Stopwatch.GetTimestamp() - Context.StartTicks;
|
||||
double seconds = (double)tickCount / Stopwatch.Frequency;
|
||||
Result.Duration = seconds;
|
||||
|
||||
//Result.AssertCount += Context.AssertCount;
|
||||
|
||||
Context.Listener.TestFinished(Result);
|
||||
|
||||
if (Completed != null)
|
||||
Completed(this, EventArgs.Empty);
|
||||
|
||||
Context.TestObject = null;
|
||||
Test.Fixture = null;
|
||||
}
|
||||
|
||||
public virtual void Cancel(bool force)
|
||||
{
|
||||
Result.SetResult(ResultState.Cancelled, "Cancelled by user");
|
||||
Context.Listener.TestFinished(Result);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 79ced2556f0af814a840b86232613ff1
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,10 @@
|
|||
using System.Collections.Generic;
|
||||
|
||||
namespace UnityEngine.TestRunner.NUnitExtensions.Runner
|
||||
{
|
||||
internal class UnityWorkItemDataHolder
|
||||
{
|
||||
public static List<string> alreadyStartedTests = new List<string>();
|
||||
public static List<string> alreadyExecutedTests;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 5b3e90046c38f1d4dad2e0d5a79e871c
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,28 @@
|
|||
using System.Collections;
|
||||
using NUnit.Framework.Interfaces;
|
||||
using NUnit.Framework.Internal;
|
||||
|
||||
namespace UnityEngine.TestRunner.NUnitExtensions.Runner
|
||||
{
|
||||
internal abstract class WorkItemFactory
|
||||
{
|
||||
public UnityWorkItem Create(ITest loadedTest, ITestFilter filter)
|
||||
{
|
||||
TestSuite suite = loadedTest as TestSuite;
|
||||
if (suite != null)
|
||||
{
|
||||
return new CompositeWorkItem(suite, filter, this);
|
||||
}
|
||||
|
||||
var testMethod = (TestMethod)loadedTest;
|
||||
if (testMethod.Method.ReturnType.Type != typeof(IEnumerator))
|
||||
{
|
||||
return new DefaultTestWorkItem(testMethod, filter);
|
||||
}
|
||||
|
||||
return Create(testMethod, filter, loadedTest);
|
||||
}
|
||||
|
||||
protected abstract UnityWorkItem Create(TestMethod method, ITestFilter filter, ITest loadedTest);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 5c15bf0966eb95847a4260d830a30d30
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,153 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using NUnit.Framework.Interfaces;
|
||||
using NUnit.Framework.Internal;
|
||||
using UnityEngine.TestRunner.NUnitExtensions.Filters;
|
||||
|
||||
namespace UnityEngine.TestRunner.NUnitExtensions
|
||||
{
|
||||
internal static class TestExtensions
|
||||
{
|
||||
private static IEnumerable<string> GetTestCategories(this ITest test)
|
||||
{
|
||||
var categories = test.Properties[PropertyNames.Category].Cast<string>().ToList();
|
||||
if (categories.Count == 0 && test is TestMethod)
|
||||
{
|
||||
// only mark tests as Uncategorized if the test fixture doesn't have a category,
|
||||
// otherwise the test inherits the Fixture category
|
||||
var fixtureCategories = test.Parent.Properties[PropertyNames.Category].Cast<string>().ToList();
|
||||
if (fixtureCategories.Count == 0)
|
||||
categories.Add(CategoryFilterExtended.k_DefaultCategory);
|
||||
}
|
||||
return categories;
|
||||
}
|
||||
|
||||
public static bool HasCategory(this ITest test, string[] categoryFilter)
|
||||
{
|
||||
var categories = test.GetAllCategoriesFromTest().Distinct();
|
||||
return categoryFilter.Any(c => categories.Any(r => r == c));
|
||||
}
|
||||
|
||||
public static List<string> GetAllCategoriesFromTest(this ITest test)
|
||||
{
|
||||
if (test.Parent == null)
|
||||
return test.GetTestCategories().ToList();
|
||||
|
||||
var categories = GetAllCategoriesFromTest(test.Parent);
|
||||
categories.AddRange(test.GetTestCategories());
|
||||
return categories;
|
||||
}
|
||||
|
||||
public static void ParseForNameDuplicates(this ITest test)
|
||||
{
|
||||
var duplicates = new Dictionary<string, int>();
|
||||
for (var i = 0; i < test.Tests.Count; i++)
|
||||
{
|
||||
var child = test.Tests[i];
|
||||
int count;
|
||||
if (duplicates.TryGetValue(child.FullName, out count))
|
||||
{
|
||||
count++;
|
||||
child.Properties.Add("childIndex", count);
|
||||
duplicates[child.FullName] = count;
|
||||
}
|
||||
else
|
||||
{
|
||||
duplicates.Add(child.FullName, 1);
|
||||
}
|
||||
ParseForNameDuplicates(child);
|
||||
}
|
||||
}
|
||||
|
||||
public static int GetChildIndex(this ITest test)
|
||||
{
|
||||
var index = test.Properties["childIndex"];
|
||||
return (int)index[0];
|
||||
}
|
||||
|
||||
public static bool HasChildIndex(this ITest test)
|
||||
{
|
||||
var index = test.Properties["childIndex"];
|
||||
return index.Count > 0;
|
||||
}
|
||||
|
||||
static string GetAncestorPath(ITest test)
|
||||
{
|
||||
var path = "";
|
||||
var testParent = test.Parent;
|
||||
|
||||
while (testParent != null && testParent.Parent != null && !string.IsNullOrEmpty(testParent.Name))
|
||||
{
|
||||
path = testParent.Name + "/" + path;
|
||||
testParent = testParent.Parent;
|
||||
}
|
||||
|
||||
return path;
|
||||
}
|
||||
|
||||
public static string GetUniqueName(this ITest test)
|
||||
{
|
||||
var id = GetAncestorPath(test) + GetFullName(test);
|
||||
if (test.HasChildIndex())
|
||||
{
|
||||
var index = test.GetChildIndex();
|
||||
if (index >= 0)
|
||||
id += index;
|
||||
}
|
||||
if (test.IsSuite)
|
||||
{
|
||||
id += "[suite]";
|
||||
}
|
||||
return id;
|
||||
}
|
||||
|
||||
public static string GetFullName(ITest test)
|
||||
{
|
||||
var typeInfo = test.TypeInfo ?? test.Parent?.TypeInfo ?? test.Tests.FirstOrDefault()?.TypeInfo;
|
||||
if (typeInfo == null)
|
||||
{
|
||||
return "[" + test.Name + "]";
|
||||
}
|
||||
|
||||
var assemblyId = typeInfo.Assembly.GetName().Name;
|
||||
if (assemblyId == test.Name)
|
||||
{
|
||||
return $"[{test.Name}]";
|
||||
}
|
||||
|
||||
return string.Format("[{0}][{1}]", assemblyId, test.FullName);
|
||||
}
|
||||
|
||||
public static string GetSkipReason(this ITest test)
|
||||
{
|
||||
if (test.Properties.ContainsKey(PropertyNames.SkipReason))
|
||||
return (string)test.Properties.Get(PropertyNames.SkipReason);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public static string GetParentId(this ITest test)
|
||||
{
|
||||
if (test.Parent != null)
|
||||
return test.Parent.Id;
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public static string GetParentFullName(this ITest test)
|
||||
{
|
||||
if (test.Parent != null)
|
||||
return test.Parent.FullName;
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public static string GetParentUniqueName(this ITest test)
|
||||
{
|
||||
if (test.Parent != null)
|
||||
return GetUniqueName(test.Parent);
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 8bc74398aa3944646ade4ee78cd57484
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,77 @@
|
|||
using System;
|
||||
using NUnit.Framework;
|
||||
using NUnit.Framework.Interfaces;
|
||||
using NUnit.Framework.Internal;
|
||||
|
||||
namespace UnityEngine.TestRunner.NUnitExtensions
|
||||
{
|
||||
internal static class TestResultExtensions
|
||||
{
|
||||
public static void RecordPrefixedException(this TestResult testResult, string prefix, Exception ex, ResultState resultState = null)
|
||||
|
||||
{
|
||||
if (ex is NUnitException)
|
||||
{
|
||||
ex = ex.InnerException;
|
||||
}
|
||||
|
||||
if (resultState == null)
|
||||
{
|
||||
resultState = testResult.ResultState == ResultState.Cancelled
|
||||
? ResultState.Cancelled
|
||||
: ResultState.Error;
|
||||
}
|
||||
|
||||
var exceptionMessage = ExceptionHelper.BuildMessage(ex);
|
||||
string stackTrace = "--" + prefix + NUnit.Env.NewLine + ExceptionHelper.BuildStackTrace(ex);
|
||||
if (testResult.StackTrace != null)
|
||||
{
|
||||
stackTrace = testResult.StackTrace + NUnit.Env.NewLine + stackTrace;
|
||||
}
|
||||
|
||||
if (testResult.Test.IsSuite)
|
||||
{
|
||||
resultState = resultState.WithSite(FailureSite.TearDown);
|
||||
}
|
||||
|
||||
if (ex is ResultStateException)
|
||||
{
|
||||
exceptionMessage = ex.Message;
|
||||
resultState = ((ResultStateException)ex).ResultState;
|
||||
stackTrace = StackFilter.Filter(ex.StackTrace);
|
||||
}
|
||||
|
||||
string message = (string.IsNullOrEmpty(prefix) ? "" : (prefix + " : ")) + exceptionMessage;
|
||||
if (testResult.Message != null)
|
||||
{
|
||||
message = testResult.Message + NUnit.Env.NewLine + message;
|
||||
}
|
||||
|
||||
testResult.SetResult(resultState, message, stackTrace);
|
||||
}
|
||||
|
||||
public static void RecordPrefixedError(this TestResult testResult, string prefix, string error, ResultState resultState = null)
|
||||
|
||||
{
|
||||
if (resultState == null)
|
||||
{
|
||||
resultState = testResult.ResultState == ResultState.Cancelled
|
||||
? ResultState.Cancelled
|
||||
: ResultState.Error;
|
||||
}
|
||||
|
||||
if (testResult.Test.IsSuite)
|
||||
{
|
||||
resultState = resultState.WithSite(FailureSite.TearDown);
|
||||
}
|
||||
|
||||
string message = (string.IsNullOrEmpty(prefix) ? "" : (prefix + " : ")) + error;
|
||||
if (testResult.Message != null)
|
||||
{
|
||||
message = testResult.Message + NUnit.Env.NewLine + message;
|
||||
}
|
||||
|
||||
testResult.SetResult(resultState, message);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 65fb6da362a78334ab360a125cfafdaf
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,58 @@
|
|||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Reflection;
|
||||
using NUnit;
|
||||
using NUnit.Framework.Api;
|
||||
using NUnit.Framework.Interfaces;
|
||||
using NUnit.Framework.Internal;
|
||||
|
||||
namespace UnityEngine.TestTools.NUnitExtensions
|
||||
{
|
||||
internal class UnityTestAssemblyBuilder : DefaultTestAssemblyBuilder, IAsyncTestAssemblyBuilder
|
||||
{
|
||||
private readonly string m_ProductName;
|
||||
public UnityTestAssemblyBuilder()
|
||||
{
|
||||
m_ProductName = Application.productName;
|
||||
}
|
||||
|
||||
public ITest Build(Assembly[] assemblies, TestPlatform[] testPlatforms, IDictionary<string, object> options)
|
||||
{
|
||||
var test = BuildAsync(assemblies, testPlatforms, options);
|
||||
while (test.MoveNext())
|
||||
{
|
||||
}
|
||||
|
||||
return test.Current;
|
||||
}
|
||||
|
||||
public IEnumerator<ITest> BuildAsync(Assembly[] assemblies, TestPlatform[] testPlatforms, IDictionary<string, object> options)
|
||||
{
|
||||
var productName = string.Join("_", m_ProductName.Split(Path.GetInvalidFileNameChars()));
|
||||
var suite = new TestSuite(productName);
|
||||
for (var index = 0; index < assemblies.Length; index++)
|
||||
{
|
||||
var assembly = assemblies[index];
|
||||
var platform = testPlatforms[index];
|
||||
|
||||
var assemblySuite = Build(assembly, options) as TestSuite;
|
||||
if (assemblySuite != null && assemblySuite.HasChildren)
|
||||
{
|
||||
assemblySuite.Properties.Set("platform", platform);
|
||||
suite.Add(assemblySuite);
|
||||
}
|
||||
|
||||
yield return null;
|
||||
}
|
||||
|
||||
yield return suite;
|
||||
}
|
||||
|
||||
public static Dictionary<string, object> GetNUnitTestBuilderSettings(TestPlatform testPlatform)
|
||||
{
|
||||
var emptySettings = new Dictionary<string, object>();
|
||||
emptySettings.Add(FrameworkPackageSettings.TestParameters, "platform=" + testPlatform);
|
||||
return emptySettings;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 98ba0396e4b4ee8498a8f097affcfddf
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
Loading…
Add table
Add a link
Reference in a new issue