145 lines
		
	
	
		
			4.8 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
			
		
		
	
	
			145 lines
		
	
	
		
			4.8 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
| using System;
 | |
| using System.Collections;
 | |
| using NUnit.Framework.Interfaces;
 | |
| using NUnit.Framework.Internal;
 | |
| using NUnit.Framework.Internal.Commands;
 | |
| 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)
 | |
|         {
 | |
|             var unityContext = (UnityTestExecutionContext) 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, new EnumeratorContext(context), unityContext);
 | |
|                 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 IEnumerator ExecuteEnumerableAndRecordExceptions(IEnumerator enumerator, EnumeratorContext context, UnityTestExecutionContext unityContext)
 | |
|         {
 | |
|             while (true)
 | |
|             {
 | |
|                 if (context.ExceptionWasRecorded)
 | |
|                 {
 | |
|                     break;
 | |
|                 }
 | |
| 
 | |
|                 bool executionDone = false;
 | |
|                 try
 | |
|                 {
 | |
|                     executionDone = !enumerator.MoveNext();
 | |
|                     if (unityContext.TestMode == TestPlatform.PlayMode && enumerator.Current is IEditModeTestYieldInstruction)
 | |
|                     {
 | |
|                         throw new Exception($"PlayMode test are not allowed to yield {enumerator.Current.GetType().Name}");
 | |
|                     }
 | |
|                 }
 | |
|                 catch (Exception ex)
 | |
|                 {
 | |
|                     context.RecordExceptionWithHint(ex);
 | |
|                     break;
 | |
|                 }
 | |
| 
 | |
|                 if (unityContext.HasTimedOut())
 | |
|                 {
 | |
|                     unityContext.CurrentResult.RecordException(new UnityTestTimeoutException(unityContext.TestCaseTimeout));
 | |
|                     yield return new RestoreTestContextAfterDomainReload(); // If this is right after a domain reload, give the editor a chance to restore.
 | |
|                     yield break;
 | |
|                 }
 | |
|                 if (executionDone)
 | |
|                 {
 | |
|                     break;
 | |
|                 }
 | |
| 
 | |
|                 if (enumerator.Current is IEnumerator nestedEnumerator)
 | |
|                 {
 | |
|                     yield return ExecuteEnumerableAndRecordExceptions(nestedEnumerator, context, unityContext);
 | |
|                 }
 | |
|                 else
 | |
|                 {
 | |
|                     yield return enumerator.Current;
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         private class EnumeratorContext
 | |
|         {
 | |
|             private readonly ITestExecutionContext m_Context;
 | |
| 
 | |
|             public EnumeratorContext(ITestExecutionContext context)
 | |
|             {
 | |
|                 m_Context = context;
 | |
|             }
 | |
| 
 | |
|             public bool ExceptionWasRecorded
 | |
|             {
 | |
|                 get;
 | |
|                 private set;
 | |
|             }
 | |
| 
 | |
|             public void RecordExceptionWithHint(Exception ex)
 | |
|             {
 | |
|                 if (ExceptionWasRecorded)
 | |
|                 {
 | |
|                     return;
 | |
|                 }
 | |
|                 m_Context.CurrentResult.RecordException(ex);
 | |
|                 ExceptionWasRecorded = true;
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         public override TestResult Execute(ITestExecutionContext context)
 | |
|         {
 | |
|             throw new NotImplementedException("Use ExecuteEnumerable");
 | |
|         }
 | |
|     }
 | |
| }
 |