File size: 4,935 Bytes
18a519f
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
using System;
using System.Collections;
using UnityEditor;

namespace UnityEngine.TestTools
{
    /// <summary>
    /// `RecompileScripts` is an <see cref="IEditModeTestYieldInstruction"/> that you can yield in Edit Mode tests. It lets you trigger a recompilation of scripts in the Unity Editor.
    /// </summary>
    public class RecompileScripts : IEditModeTestYieldInstruction
    {
        /// <summary>
        /// Creates a new instance of the `RecompileScripts` yield instruction.
        /// <example>
        /// <code>
        /// [UnitySetUp]
        /// public IEnumerator SetUp()
        /// {
        ///     using (var file = File.CreateText("Assets/temp/myScript.cs"))
        ///     {
        ///         file.Write("public class ATempClass {  }");
        ///     }
        ///     AssetDatabase.Refresh();
        ///     yield return new RecompileScripts();
        /// }
        /// </code>
        /// </example>
        /// </summary>
        public RecompileScripts() : this(true)
        {
        }
        /// <summary>
        /// Creates a new instance of the `RecompileScripts` yield instruction.
        /// </summary>
        /// <param name="expectScriptCompilation">This parameter indicates if you expect a script compilation to start (defaults to true). If a script compilation does not start and `expectScriptCompilation` is true, then it throws an exception.</param>
        public RecompileScripts(bool expectScriptCompilation) : this(expectScriptCompilation, true)
        {
        }
        /// <summary>
        /// Creates a new instance of the `RecompileScripts` yield instruction.
        /// </summary>
        /// <param name="expectScriptCompilation">This parameter indicates if you expect a script compilation to start (defaults to true).  If a script compilation does not start and `expectScriptCompilation` is `true`, then it throws an exception.</param>
        /// <param name="expectScriptCompilationSuccess">This parameter indicates if you expect a script compilation to succeed. If not succeeded then an exception will be thrown.</param>
        public RecompileScripts(bool expectScriptCompilation, bool expectScriptCompilationSuccess)
        {
            ExpectScriptCompilation = expectScriptCompilation;
            ExpectScriptCompilationSuccess = expectScriptCompilationSuccess;
            ExpectDomainReload = true;
        }

        /// <summary>
        /// Returns true if the instruction expects a domain reload to occur.
        /// </summary>
        public bool ExpectDomainReload { get; private set; }
        /// <summary>
        /// Returns true if the instruction expects the Unity Editor to be in **Play Mode**.
        /// </summary>
        public bool ExpectedPlaymodeState { get; }
        /// <summary>
        /// Indicates whether a script compilation is expected.
        /// </summary>
        public bool ExpectScriptCompilation { get; private set; }
        /// <summary>
        /// Indicates whether the expected script compilation is expected to succeed.
        /// </summary>
        public bool ExpectScriptCompilationSuccess { get; private set; }

        /// <summary>
        /// The current active instance of the RecompileScripts yield instruction.
        /// </summary>
        public static RecompileScripts Current { get; private set; }

        /// <summary>
        /// Perform the multi step instruction of triggering a recompilation of scripts and waiting for its completion.
        /// </summary>
        /// <returns>An IEnumerator with the async steps.</returns>
        /// <exception cref="Exception">Throws an exception if the editor does not need to recompile scripts or if the script compilation failed when expected to succeed.</exception>
        public IEnumerator Perform()
        {
            Current = this;

            // We need to yield, to give the test runner a chance to prepare for the domain reload
            //  If the script compilation happens very fast, then EditModeRunner.MoveNextAndUpdateYieldObject will not have a chance to set m_CurrentYieldObject
            // This really should be fixed in EditModeRunner.MoveNextAndUpdateYieldObject
            yield return null;

            AssetDatabase.Refresh();

            if (ExpectScriptCompilation && !EditorApplication.isCompiling)
            {
                Current = null;
                throw new Exception("Editor does not need to recompile scripts");
            }

            EditorApplication.UnlockReloadAssemblies();

            while (EditorApplication.isCompiling)
            {
                yield return null;
            }

            Current = null;

            if (ExpectScriptCompilationSuccess && EditorUtility.scriptCompilationFailed)
            {
                EditorApplication.LockReloadAssemblies();
                throw new Exception("Script compilation failed");
            }
        }
    }
}