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 { /// /// Specialization of BaseDelegator that makes sure objects are created on the MainThread. /// It also deals with ScriptableObjects so that tests can survive assembly reload. /// 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); } } }