123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298 |
- 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 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 where T : class
- {
- 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 static MethodInfo[] GetActions(IDictionary<Type, List<MethodInfo>> cacheStorage, Type fixtureType, Type attributeType, Type returnType)
- {
- if (cacheStorage.TryGetValue(fixtureType, out var result))
- {
- return result.ToArray();
- }
-
- cacheStorage[fixtureType] = GetMethodsWithAttributeFromFixture(fixtureType, attributeType, returnType);
-
- return cacheStorage[fixtureType].ToArray();
- }
-
- protected static T[] GetTestActions(IDictionary<MethodInfo, List<T>> cacheStorage, MethodInfo methodInfo)
- {
- if (cacheStorage.TryGetValue(methodInfo, out var result))
- {
- return result.ToArray();
- }
-
- var attributesForMethodInfo = new List<T>();
- var attributes = methodInfo.GetCustomAttributes(false);
- foreach (var attribute in attributes)
- {
- if (attribute is T attribute1)
- {
- attributesForMethodInfo.Add(attribute1);
- }
- }
-
- cacheStorage[methodInfo] = attributesForMethodInfo;
-
- return cacheStorage[methodInfo].ToArray();
- }
-
- private static List<MethodInfo> GetMethodsWithAttributeFromFixture(Type fixtureType, Type setUpType, Type returnType)
- {
- MethodInfo[] methodsWithAttribute = Reflect.GetMethodsWithAttribute(fixtureType, setUpType, true);
- return methodsWithAttribute.Where(x => x.ReturnType == returnType).ToList();
- }
-
- 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;
- }
- }
- }
- }
|