A game about forced loneliness, made by TACStudios
1using System; 2using System.Collections; 3using System.Collections.Generic; 4using System.Linq; 5using NUnit.Framework.Interfaces; 6using NUnit.Framework.Internal; 7using UnityEngine; 8using UnityEngine.TestRunner.NUnitExtensions; 9using UnityEngine.TestRunner.NUnitExtensions.Runner; 10using UnityEngine.TestTools; 11using UnityEngine.TestTools.NUnitExtensions; 12using UnityEngine.TestTools.TestRunner; 13 14namespace UnityEditor.TestTools.TestRunner 15{ 16 internal interface IUnityTestAssemblyRunnerFactory 17 { 18 IUnityTestAssemblyRunner Create(TestPlatform testPlatform, string[] orderedTestNames, int randomOrderSeed, WorkItemFactory factory, UnityTestExecutionContext context); 19 } 20 21 internal class UnityTestAssemblyRunnerFactory : IUnityTestAssemblyRunnerFactory 22 { 23 public IUnityTestAssemblyRunner Create(TestPlatform testPlatform, string[] orderedTestNames, int randomOrderSeed, 24 WorkItemFactory factory, UnityTestExecutionContext context) 25 { 26 return new UnityTestAssemblyRunner(new UnityTestAssemblyBuilder(orderedTestNames, randomOrderSeed), factory, context); 27 } 28 } 29 30 [Serializable] 31 internal class EditModeRunner : ScriptableObject, IDisposable 32 { 33 //The counter from the IEnumerator object 34 [SerializeField] 35 private int m_CurrentPC; 36 37 [SerializeField] 38 private bool m_ExecuteOnEnable; 39 40 [SerializeField] 41 private List<string> m_AlreadyStartedTests; 42 43 [SerializeField] 44 private List<TestResultSerializer> m_ExecutedTests; 45 46 private TestStartedEvent m_TestStartedEvent; 47 private TestFinishedEvent m_TestFinishedEvent; 48 49 [SerializeField] 50 private object m_CurrentYieldObject; 51 52 [SerializeField] 53 private string[] m_OrderedTestNames; 54 55 [SerializeField] 56 public bool RunFinished; 57 58 [SerializeField] 59 private bool m_DisableNestedEnumeratorBugfix; 60 61 public bool RunningSynchronously { get; private set; } 62 63 internal IUnityTestAssemblyRunner m_Runner; 64 65 private IEnumerator m_RunStep; 66 67 public IUnityTestAssemblyRunnerFactory UnityTestAssemblyRunnerFactory { get; set; } 68 69 public void Init(ITestFilter filter, bool runningSynchronously, ITest testTree, TestStartedEvent testStartedEvent, TestFinishedEvent testFinishedEvent, UnityTestExecutionContext context, 70 string[] orderedTestNames, int randomOrderSeed, bool disableNestedEnumeratorBugfix) 71 { 72 TestEnumerator.Reset(); 73 m_AlreadyStartedTests = new List<string>(); 74 m_ExecutedTests = new List<TestResultSerializer>(); 75 m_OrderedTestNames = orderedTestNames; 76 m_randomOrderSeed = randomOrderSeed; 77 RunningSynchronously = runningSynchronously; 78 m_DisableNestedEnumeratorBugfix = disableNestedEnumeratorBugfix; 79 Run(testTree, filter, context, testStartedEvent, testFinishedEvent); 80 } 81 82 public void Resume(ITestFilter filter, ITest testTree, TestStartedEvent testStartedEvent, TestFinishedEvent testFinishedEvent, UnityTestExecutionContext context) 83 { 84 if (m_ExecuteOnEnable) 85 { 86 m_ExecuteOnEnable = false; 87 88 if (m_CurrentPC >= 0) 89 { 90 EnumeratorStepHelper.SetEnumeratorPC(m_CurrentPC); 91 } 92 93 UnityWorkItemDataHolder.alreadyExecutedTests = m_ExecutedTests.Select(x => x.uniqueName).ToList(); 94 UnityWorkItemDataHolder.alreadyStartedTests = m_AlreadyStartedTests; 95 Run(testTree, filter, context, testStartedEvent, testFinishedEvent); 96 } 97 } 98 99 public void TestStartedEvent(ITest test) 100 { 101 m_AlreadyStartedTests.Add(test.GetUniqueName()); 102 } 103 104 public void TestFinishedEvent(ITestResult testResult) 105 { 106 m_AlreadyStartedTests.Remove(testResult.Test.GetUniqueName()); 107 m_ExecutedTests.Add(TestResultSerializer.MakeFromTestResult(testResult)); 108 } 109 110 private void Run(ITest testTree, ITestFilter filter, UnityTestExecutionContext context, TestStartedEvent testStartedEvent, TestFinishedEvent testFinishedEvent) 111 { 112 m_TestStartedEvent = testStartedEvent; 113 m_TestFinishedEvent = testFinishedEvent; 114 115 m_Runner = (UnityTestAssemblyRunnerFactory ?? new UnityTestAssemblyRunnerFactory()).Create(TestPlatform.EditMode, m_OrderedTestNames, m_randomOrderSeed, new EditmodeWorkItemFactory(), context); 116 m_Runner.LoadTestTree(testTree); 117 hideFlags |= HideFlags.DontSave; 118 EnumeratorHelper.ActivePcHelper = new EditModePcHelper(); 119 120 EditModeTestCallbacks.RestoringTestContext += OnRestoringTest; 121 122 m_TestStartedEvent.AddListener(TestStartedEvent); 123 m_TestFinishedEvent.AddListener(TestFinishedEvent); 124 125 AssemblyReloadEvents.beforeAssemblyReload += OnBeforeAssemblyReload; 126 127 RunningTests = true; 128 129 EditorApplication.LockReloadAssemblies(); 130 131 var testListenerWrapper = new TestListenerWrapper(m_TestStartedEvent, m_TestFinishedEvent); 132 m_RunStep = m_Runner.Run(testListenerWrapper, filter).GetEnumerator(); 133 } 134 135 private void OnBeforeAssemblyReload() 136 { 137 if (m_ExecuteOnEnable) 138 { 139 AssemblyReloadEvents.beforeAssemblyReload -= OnBeforeAssemblyReload; 140 return; 141 } 142 143 if (m_Runner != null && m_Runner.TopLevelWorkItem != null) 144 m_Runner.TopLevelWorkItem.ResultedInDomainReload = true; 145 146 if (RunningTests) 147 { 148 Debug.LogError("TestRunner: Unexpected assembly reload happened while running tests"); 149 150 EditorUtility.ClearProgressBar(); 151 152 if (m_Runner.GetCurrentContext() != null && m_Runner.GetCurrentContext().CurrentResult != null) 153 { 154 m_Runner.GetCurrentContext().CurrentResult.SetResult(ResultState.Cancelled, "Unexpected assembly reload happened"); 155 } 156 OnRunCancel(); 157 } 158 } 159 160 private bool RunningTests; 161 162 private Stack<IEnumerator> StepStack = new Stack<IEnumerator>(); 163 private int m_randomOrderSeed; 164 165 private bool MoveNextAndUpdateYieldObject() 166 { 167 var result = m_RunStep.MoveNext(); 168 169 if (result) 170 { 171 m_CurrentYieldObject = m_RunStep.Current; 172 while (m_CurrentYieldObject is IEnumerator) // going deeper 173 { 174 var currentEnumerator = (IEnumerator)m_CurrentYieldObject; 175 176 // go deeper and add parent to stack 177 StepStack.Push(m_RunStep); 178 179 m_RunStep = currentEnumerator; 180 m_CurrentYieldObject = m_RunStep.Current; 181 182 if (!m_DisableNestedEnumeratorBugfix) 183 { 184 return MoveNextAndUpdateYieldObject(); 185 } 186 } 187 188 if (StepStack.Count > 0 && m_CurrentYieldObject != null) // not null and not IEnumerator, nested 189 { 190 Debug.LogError("EditMode test can only yield null, but not <" + m_CurrentYieldObject.GetType().Name + ">"); 191 } 192 193 return true; 194 } 195 196 if (StepStack.Count == 0) // done 197 return false; 198 199 m_RunStep = StepStack.Pop(); // going up 200 return MoveNextAndUpdateYieldObject(); 201 } 202 203 public void TestConsumer(TestRunnerStateSerializer testRunnerStateSerializer) 204 { 205 var moveNext = MoveNextAndUpdateYieldObject(); 206 207 if (m_CurrentYieldObject != null) 208 { 209 InvokeDelegator(testRunnerStateSerializer); 210 } 211 212 if (!moveNext && !m_Runner.IsTestComplete) 213 { 214 CompleteTestRun(); 215 throw new IndexOutOfRangeException("There are no more elements to process and IsTestComplete is false"); 216 } 217 218 if (m_Runner.IsTestComplete) 219 { 220 CompleteTestRun(); 221 } 222 } 223 224 private void CompleteTestRun() 225 { 226 RunFinished = true; 227 UnityWorkItemDataHolder.alreadyExecutedTests = null; 228 } 229 230 private void OnRestoringTest() 231 { 232 var item = m_ExecutedTests.Find(t => t.fullName == UnityTestExecutionContext.CurrentContext.CurrentTest.FullName); 233 if (item != null) 234 { 235 item.RestoreTestResult(UnityTestExecutionContext.CurrentContext.CurrentResult); 236 } 237 } 238 239 private static bool IsCancelled() 240 { 241 return UnityTestExecutionContext.CurrentContext.ExecutionStatus == TestExecutionStatus.AbortRequested || UnityTestExecutionContext.CurrentContext.ExecutionStatus == TestExecutionStatus.StopRequested; 242 } 243 244 private void InvokeDelegator(TestRunnerStateSerializer testRunnerStateSerializer) 245 { 246 if (m_CurrentYieldObject == null) 247 { 248 return; 249 } 250 251 if (IsCancelled()) 252 { 253 return; 254 } 255 256 if (m_CurrentYieldObject is RestoreTestContextAfterDomainReload) 257 { 258 if (testRunnerStateSerializer.ShouldRestore()) 259 { 260 testRunnerStateSerializer.RestoreContext(); 261 } 262 263 return; 264 } 265 266 try 267 { 268 if (m_CurrentYieldObject is IEditModeTestYieldInstruction) 269 { 270 var editModeTestYieldInstruction = (IEditModeTestYieldInstruction)m_CurrentYieldObject; 271 if (editModeTestYieldInstruction.ExpectDomainReload) 272 { 273 PrepareForDomainReload(testRunnerStateSerializer); 274 } 275 return; 276 } 277 } 278 catch (Exception e) 279 { 280 UnityTestExecutionContext.CurrentContext.CurrentResult.RecordException(e); 281 return; 282 } 283 284 UnityTestExecutionContext.CurrentContext.CurrentResult.RecordException(new InvalidOperationException("EditMode test can only yield null")); 285 } 286 287 private void CompilationFailureWatch() 288 { 289 if (EditorApplication.isCompiling) 290 return; 291 292 EditorApplication.update -= CompilationFailureWatch; 293 294 if (EditorUtility.scriptCompilationFailed) 295 { 296 EditorUtility.ClearProgressBar(); 297 OnRunCancel(); 298 } 299 } 300 301 private void PrepareForDomainReload(TestRunnerStateSerializer testRunnerStateSerializer) 302 { 303 testRunnerStateSerializer.SaveContext(); 304 m_CurrentPC = EnumeratorStepHelper.GetEnumeratorPC(TestEnumerator.Enumerator); 305 m_ExecuteOnEnable = true; 306 307 RunningTests = false; 308 } 309 310 public void Dispose() 311 { 312 Reflect.MethodCallWrapper = null; 313 314 DestroyImmediate(this); 315 316 RunningTests = false; 317 EditorApplication.UnlockReloadAssemblies(); 318 } 319 320 public void OnRunCancel() 321 { 322 UnityWorkItemDataHolder.alreadyExecutedTests = null; 323 m_ExecuteOnEnable = false; 324 m_Runner.StopRun(); 325 RunFinished = true; 326 } 327 } 328}