text: using System;
  using System.Reflection;
  using System.Text;
  using System.Collections.Generic;
  using UnityEngine;
  using UnityEngine.TestRunner.NUnitExtensions.Runner;
  using UnityEngine.TestTools.NUnitExtensions;
  using UnityEngine.TestTools.Logging;
  
  namespace UnityEditor.TestTools.TestRunner
  {
      [Serializable]
      internal class TestRunnerStateSerializer : IStateSerializer
      {
          private const BindingFlags Flags = BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance | BindingFlags.FlattenHierarchy;
  
          [SerializeField]
          private HideFlags m_OriginalHideFlags;
  
          [SerializeField]
          private bool m_ShouldRestore;
  
          [SerializeField]
          private string m_TestObjectTypeName;
  
          [SerializeField]
          private ScriptableObject m_TestObject;
  
          [SerializeField]
          private string m_TestObjectTxt;
  
          [SerializeField]
          private long StartTicks;
  
          [SerializeField]
          private double StartTimeOA;
  
          [SerializeField]
          private string output;
  
          [SerializeField]
          private LogMatch[] m_ExpectedLogs;
  
          public bool ShouldRestore()
          {
              return m_ShouldRestore;
          }
  
          public void SaveContext()
          {
              var currentContext = UnityTestExecutionContext.CurrentContext;
  
              if (currentContext.TestObject != null)
              {
                  m_TestObjectTypeName = currentContext.TestObject.GetType().AssemblyQualifiedName;
                  m_TestObject = null;
                  m_TestObjectTxt = null;
                  if (currentContext.TestObject is ScriptableObject)
                  {
                      m_TestObject = currentContext.TestObject as ScriptableObject;
                      m_OriginalHideFlags = m_TestObject.hideFlags;
                      m_TestObject.hideFlags |= HideFlags.DontSave;
                  }
                  else
                  {
                      m_TestObjectTxt = JsonUtility.ToJson(currentContext.TestObject);
                  }
              }
  
              output = currentContext.CurrentResult.Output;
              StartTicks = currentContext.StartTicks;
              StartTimeOA = currentContext.StartTime.ToOADate();
              if (LogScope.HasCurrentLogScope())
              {
                  m_ExpectedLogs = LogScope.Current.ExpectedLogs.ToArray();
              }
  
              m_ShouldRestore = true;
          }
  
          public void RestoreContext()
          {
              var currentContext = UnityTestExecutionContext.CurrentContext;
  
              var outputProp = currentContext.CurrentResult.GetType().BaseType.GetField("_output", Flags);
              (outputProp.GetValue(currentContext.CurrentResult) as StringBuilder).Append(output);
  
              currentContext.StartTicks = StartTicks;
              currentContext.StartTime = DateTime.FromOADate(StartTimeOA);
              if (LogScope.HasCurrentLogScope())
              {
                  LogScope.Current.ExpectedLogs = new Queue<LogMatch>(m_ExpectedLogs);
              }
  
              m_ShouldRestore = false;
          }
  
          public bool CanRestoreFromScriptableObject(Type requestedType)
          {
              if (m_TestObject == null)
              {
                  return false;
              }
              return m_TestObjectTypeName == requestedType.AssemblyQualifiedName;
          }
  
          public ScriptableObject RestoreScriptableObjectInstance()
          {
              if (m_TestObject == null)
              {
                  Debug.LogError("No object to restore");
                  return null;
              }
              EditorApplication.playModeStateChanged += OnPlayModeStateChanged;
              var temp = m_TestObject;
              m_TestObject = null;
              m_TestObjectTypeName = null;
              return temp;
          }
  
          public bool CanRestoreFromJson(Type requestedType)
          {
              if (string.IsNullOrEmpty(m_TestObjectTxt))
              {
                  return false;
              }
              return m_TestObjectTypeName == requestedType.AssemblyQualifiedName;
          }
  
          public void RestoreClassFromJson(ref object instance)
          {
              if (string.IsNullOrEmpty(m_TestObjectTxt))
              {
                  Debug.LogWarning("No JSON representation to restore");
                  return;
              }
              JsonUtility.FromJsonOverwrite(m_TestObjectTxt, instance);
              m_TestObjectTxt = null;
              m_TestObjectTypeName = null;
          }
  
          private void OnPlayModeStateChanged(PlayModeStateChange state)
          {
              if (m_TestObject == null)
              {
                  EditorApplication.playModeStateChanged -= OnPlayModeStateChanged;
                  return;
              }
  
              //We set the DontSave flag here because the ScriptableObject would be nulled right before entering EditMode
              if (state == PlayModeStateChange.ExitingPlayMode)
              {
                  m_TestObject.hideFlags |= HideFlags.DontSave;
              }
              else if (state == PlayModeStateChange.EnteredEditMode)
              {
                  m_TestObject.hideFlags = m_OriginalHideFlags;
                  EditorApplication.playModeStateChanged -= OnPlayModeStateChanged;
              }
          }
      }
  }
  