Skip to content
This repository has been archived by the owner on Apr 8, 2024. It is now read-only.

Commit

Permalink
fix: make IMGUI tests green again (#173)
Browse files Browse the repository at this point in the history
  • Loading branch information
Aleksei Korolev authored Sep 25, 2020
1 parent baa38fa commit ad991c9
Show file tree
Hide file tree
Showing 57 changed files with 11,694 additions and 2,037 deletions.
2 changes: 1 addition & 1 deletion Editor/CourseAssets/CourseAssetManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ internal static void Delete(string courseName)
{
if (CourseAssetUtils.DoesCourseAssetExist(courseName))
{
Directory.Delete(CourseAssetUtils.GetCourseAssetDirectory(courseName));
Directory.Delete(CourseAssetUtils.GetCourseAssetDirectory(courseName), true);
AssetDatabase.Refresh();
}
}
Expand Down
26 changes: 23 additions & 3 deletions Editor/EditorUtils.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
using System.Collections.Generic;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using JetBrains.Annotations;
using UnityEditor;
using UnityEditor.Callbacks;
Expand All @@ -18,6 +20,8 @@ internal static class EditorUtils

private static string coreFolder;

private static MethodInfo repaintImmediately = typeof(EditorWindow).GetMethod("RepaintImmediately", BindingFlags.Instance | BindingFlags.NonPublic, null, new Type[] { }, new ParameterModifier[] { });

static EditorUtils()
{
AssemblyReloadEvents.afterAssemblyReload += ResolveCoreFolder;
Expand Down Expand Up @@ -69,6 +73,22 @@ internal static bool IsWindowOpened<T>() where T : EditorWindow
return windows != null && windows.Length > 0;
}

/// <summary>
/// Causes the target <paramref name="window"/> to repaint immediately. Used for testing.
/// </summary>
internal static void RepaintImmediately(this EditorWindow window)
{
repaintImmediately.Invoke(window, new object[] { });
}

/// <summary>
/// Takes the focus away the field where you was typing something into.
/// </summary>
internal static void ResetKeyboardElementFocus()
{
GUIUtility.keyboardControl = 0;
}

/// <summary>
/// Gets the root folder of the training module.
/// </summary>
Expand Down Expand Up @@ -105,13 +125,13 @@ internal static ApiCompatibilityLevel GetCurrentCompatibilityLevel()
BuildTargetGroup buildTargetGroup = BuildPipeline.GetBuildTargetGroup(buildTarget);
return PlayerSettings.GetApiCompatibilityLevel(buildTargetGroup);
}

/// <summary>
/// Returns a list of scriptable objects from provided type;
/// </summary>
internal static IEnumerable<T> GetAllScriptableObjects<T>() where T : ScriptableObject
{
string[] guids = AssetDatabase.FindAssets("t:"+ typeof(T).Name);
string[] guids = AssetDatabase.FindAssets("t:" + typeof(T).Name);
return guids.Select(AssetDatabase.GUIDToAssetPath).Select(AssetDatabase.LoadAssetAtPath<T>);
}

Expand Down
57 changes: 27 additions & 30 deletions Editor/TestTools/EditorImguiTester/EditorImguiTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,13 @@ private static JsonSerializerSettings JsonSerializerSettings
{
get
{
return new JsonSerializerSettings {Converters = new List<JsonConverter> {new ImguiEventConverter()}};
return new JsonSerializerSettings
{
Converters = new List<JsonConverter>
{
new ImguiEventConverter()
}
};
}
}

Expand Down Expand Up @@ -103,36 +109,35 @@ public IEnumerator Test()
try
{
result = BaseGiven();

BaseWhen(result, (sender, args) =>
{
try
{
BaseThen(args.Result);
state = TestState.Passed;
}
catch (Exception e)
{
Debug.LogErrorFormat("Test {0} failed: {1}", GetType().GetNameWithNesting(), e.Message);
state = TestState.Failed;
}
});
}
catch (Exception e)
{
Debug.LogErrorFormat("Test {0} failed: {1}", GetType().GetNameWithNesting(), e.Message);
Debug.LogErrorFormat("Test {0} failed during initialization: {1}", GetType().GetNameWithNesting(), e);
state = TestState.Failed;
}

//Make sure that we call when/then outside of the OnGUI call so RepaintImmediately would not throw an error.
EditorApplication.delayCall += () =>
{
try
{
BaseWhen(result);
BaseThen(result);
state = TestState.Passed;
}
catch (Exception e)
{
Debug.LogErrorFormat("Test {0} failed: {1}", GetType().GetNameWithNesting(), e);
state = TestState.Failed;
}
};

while (state == TestState.Pending)
{
yield return null;
}

if (Finished != null)
{
Finished(this, new EditorImguiTestFinishedEventArgs(state));
}
Finished?.Invoke(this, new EditorImguiTestFinishedEventArgs(state));
}

/// <summary>
Expand All @@ -142,14 +147,6 @@ public IEnumerator Test()
[TearDown]
public void Teardown()
{
if (EditorUtils.IsWindowOpened<EditorWindowTestPlayer>())
{
foreach (EditorWindowTestPlayer window in Resources.FindObjectsOfTypeAll<EditorWindowTestPlayer>())
{
window.Close();
}
}

if (result != null)
{
result.Close();
Expand All @@ -173,7 +170,7 @@ protected virtual void AdditionalTeardown()
/// <summary>
/// Apply recorded user actions to the given <paramref name="window"/>.
/// </summary>
private void BaseWhen(EditorWindow window, EditorWindowTestPlayer.FinishedHandler onFinishedCallback)
private void BaseWhen(EditorWindow window)
{
TextAsset recordedActionsAsset = AssetDatabase.LoadAssetAtPath<TextAsset>(PathToRecordedActions);
if (recordedActionsAsset == null)
Expand All @@ -182,7 +179,7 @@ private void BaseWhen(EditorWindow window, EditorWindowTestPlayer.FinishedHandle
}

List<UserAction> userActions = JsonConvert.DeserializeObject<List<UserAction>>(recordedActionsAsset.text, JsonSerializerSettings);
EditorWindowTestPlayer.StartPlayback(window, userActions, onFinishedCallback);
EditorWindowTestPlayer.StartPlayback(window, userActions);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,7 @@ private static bool IsUiDisabled
{
get
{
if (EditorWindowTestRecorder.IsRecording)
{
return true;
}

return EditorUtils.IsWindowOpened<EditorWindowTestPlayer>() && EditorWindowTestPlayer.IsPlaying;
return EditorWindowTestRecorder.IsRecording;
}
}

Expand Down Expand Up @@ -268,7 +263,7 @@ private void DrawTestView(IEditorImguiTest test)
EditorGUILayout.EndHorizontal();
}

private void DrawTestStateIndicator(Vector2 position, TestState state)
private static void DrawTestStateIndicator(Vector2 position, TestState state)
{
GUI.DrawTexture(new Rect(position, new Vector2(EditorGUIUtility.singleLineHeight, EditorGUIUtility.singleLineHeight)), iconsForStates[state]);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,87 +8,20 @@ namespace Innoactive.CreatorEditor.TestTools
/// <summary>
/// Utility window which sends given sequence of events to another window.
/// </summary>
internal class EditorWindowTestPlayer : EditorWindow
internal static class EditorWindowTestPlayer
{
/// <summary>
/// Event args for event which is fired when <see cref="EditorWindowTestPlayer"/> finished playing a <see cref="IEditorImguiTest"/>.
/// </summary>
public class FinishedEventArgs : EventArgs
{
/// <summary>
/// Reference to the <see cref="UI.Windows.CourseWindow"/> where the <see cref="IEditorImguiTest"/> was executed.
/// </summary>
public EditorWindow Result { get; }

public FinishedEventArgs(EditorWindow result)
{
Result = result;
}
}

public delegate void FinishedHandler(object sender, FinishedEventArgs e);

/// <summary>
/// Event fired when <see cref="EditorWindowTestPlayer"/> finished playing a <see cref="IEditorImguiTest"/>.
/// </summary>
public event FinishedHandler Finished;

/// <summary>
/// True if this <see cref="EditorWindowTestRecorder"/> is currently playing a <see cref="IEditorImguiTest"/>.
/// </summary>
public static bool IsPlaying { get; private set; }

private EditorWindow window;

/// <summary>
/// Start sending <paramref name="recordedActions"/> to the <see cref="window"/> and invoke <paramref name="finishedCallback"/> when done.
/// </summary>
public static void StartPlayback(EditorWindow window, IList<UserAction> recordedActions, FinishedHandler finishedCallback)
public static void StartPlayback(EditorWindow window, IList<UserAction> recordedActions)
{
foreach (EditorWindowTestPlayer testPlayer in Resources.FindObjectsOfTypeAll<EditorWindowTestPlayer>())
{
testPlayer.Close();
}

IsPlaying = true;

EditorWindowTestPlayer player = CreateInstance<EditorWindowTestPlayer>();
player.ShowUtility();
player.Finished += finishedCallback;
player.window = window;

foreach (UserAction action in recordedActions)
{
TestableEditorElements.StartPlayback(action.PrepickedSelections);
player.window.SendEvent(action.Event);
player.SendEvent(EditorGUIUtility.CommandEvent("Wait"));
}

player.SendEvent(EditorGUIUtility.CommandEvent("Finished"));
}

private void OnGUI()
{
if (Event.current.type == EventType.ExecuteCommand && Event.current.commandName == "Wait")
{
window.RepaintImmediately();
window.SendEvent(action.Event);
TestableEditorElements.StopPlayback();
Event.current.Use();
}

if (Event.current.type != EventType.ExecuteCommand)
{
return;
}

if (Event.current.commandName != "Finished")
{
return;
}

Finished?.Invoke(this, new FinishedEventArgs(window));

window.Close();
Close();
}
}
}
Loading

0 comments on commit ad991c9

Please sign in to comment.