Singularity/Library/PackageCache/com.unity.burst@1.8.4/Tests/Editor/BurstInspectorGUITests.cs

589 lines
21 KiB
C#
Raw Permalink Normal View History

2024-05-06 14:45:45 -04:00
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using NUnit.Framework;
using Unity.Burst.Editor;
using UnityEditor;
using UnityEngine;
using UnityEngine.TestTools;
using Unity.Collections;
using Unity.Burst;
using Unity.Jobs;
[TestFixture]
[UnityPlatform(RuntimePlatform.WindowsEditor, RuntimePlatform.OSXEditor)]
public class BurstInspectorGUITests
{
private readonly WaitUntil _waitForInitialized =
new WaitUntil(() => EditorWindow.GetWindow<BurstInspectorGUI>()._initialized);
private IEnumerator SelectJobAwaitLoad(string assemblyName)
{
EditorWindow.GetWindow<BurstInspectorGUI>()._treeView.TrySelectByDisplayName(assemblyName);
return new WaitUntil(() =>
EditorWindow.GetWindow<BurstInspectorGUI>()._textArea.IsTextSet(assemblyName)
);
}
[UnitySetUp]
public IEnumerator SetUp()
{
// Close down window if it's open, to start with a fresh inspector.
EditorWindow.GetWindow<BurstInspectorGUI>().Close();
EditorWindow.GetWindow<BurstInspectorGUI>().Show();
// Make sure window is actually initialized before continuing.
yield return _waitForInitialized;
}
[UnityTest]
public IEnumerator TestInspectorOpenDuringDomainReloadDoesNotLogErrors()
{
// Show Inspector window
EditorWindow.GetWindow<BurstInspectorGUI>().Show();
Assert.IsTrue(EditorWindow.HasOpenInstances<BurstInspectorGUI>());
// Ask for domain reload
EditorUtility.RequestScriptReload();
// Wait for the domain reload to be completed
yield return new WaitForDomainReload();
Assert.IsTrue(EditorWindow.HasOpenInstances<BurstInspectorGUI>());
// Hide Inspector window
EditorWindow.GetWindow<BurstInspectorGUI>().Close();
Assert.IsFalse(EditorWindow.HasOpenInstances<BurstInspectorGUI>());
}
[UnityTest]
public IEnumerator DisassemblerNotChangingUnexpectedlyTest()
{
const string jobName2 = "BurstReflectionTests.MyJob - (IJob)";
const string jobName = "BurstInspectorGUITests.MyJob - (IJob)";
// Selecting a specific assembly.
yield return SelectJobAwaitLoad(jobName);
var window = EditorWindow.GetWindow<BurstInspectorGUI>();
try
{
// Sending event to set the displayname, to avoid it resetting _scrollPos because of target change.
window.SendEvent(new Event()
{
type = EventType.Repaint,
mousePosition = new Vector2(window.position.width / 2f, window.position.height / 2f)
});
yield return null;
// Doing actual test work:
var prev = new BurstDisassemblerWithCopy(window._burstDisassembler);
window.SendEvent(new Event()
{
type = EventType.Repaint,
mousePosition = new Vector2(window.position.width / 2f, window.position.height / 2f)
});
yield return null;
Assert.IsTrue(prev.Equals(window._burstDisassembler),
"Public fields changed in burstDisassembler even though they shouldn't");
prev = new BurstDisassemblerWithCopy(window._burstDisassembler);
window.SendEvent(new Event() { type = EventType.MouseUp, mousePosition = Vector2.zero });
yield return null;
Assert.IsTrue(prev.Equals(window._burstDisassembler),
"Public fields changed in burstDisassembler even though they shouldn't");
prev = new BurstDisassemblerWithCopy(window._burstDisassembler);
yield return SelectJobAwaitLoad(jobName2);
window = EditorWindow.GetWindow<BurstInspectorGUI>();
window.SendEvent(new Event()
{
type = EventType.Repaint,
mousePosition = new Vector2(window.position.width / 2f, window.position.height / 2f)
});
yield return null;
Assert.IsFalse(prev.Equals(window._burstDisassembler), "Public fields of burstDisassembler did not change");
}
finally
{
window.Close();
}
}
[UnityTest]
public IEnumerator InspectorStallingLoadTest()
{
// Error was triggered by selecting a display name, filtering it out, and then doing a script recompilation.
yield return SelectJobAwaitLoad("BurstInspectorGUITests.MyJob - (IJob)");
var win = EditorWindow.GetWindow<BurstInspectorGUI>();
win._searchFieldJobs.SetFocus();
yield return null;
// Simulate event for sending "a" as it will filter out the chosen job.
win.SendEvent(Event.KeyboardEvent("a"));
yield return null;
// Send RequestScriptReload to try and trigger the bug
// and wait for it to return
EditorUtility.RequestScriptReload();
yield return new WaitForDomainReload();
win = EditorWindow.GetWindow<BurstInspectorGUI>();
// Wait for it to actually initialize.
yield return _waitForInitialized;
Assert.IsTrue(win._initialized, "BurstInspector did not initialize properly after script reload");
win.Close();
}
[UnityTest]
public IEnumerator FontStyleDuringDomainReloadTest()
{
// Enter play mod
yield return new EnterPlayMode();
// Exit play mode
yield return new ExitPlayMode();
// Wait for the inspector to actually reload
yield return _waitForInitialized;
var inspectorWindow = EditorWindow.GetWindow<BurstInspectorGUI>();
#if UNITY_2023_1_OR_NEWER
Assert.AreEqual("RobotoMono-Regular", inspectorWindow._font.name);
#else
if (Application.platform == RuntimePlatform.WindowsEditor)
{
Assert.AreEqual("Consolas", inspectorWindow._font.name);
}
else
{
Assert.AreEqual("Courier", inspectorWindow._font.name);
}
#endif
inspectorWindow.Close();
}
[UnityTest]
public IEnumerator BranchHoverTest()
{
const string jobName = "BurstInspectorGUITests.MyJob - (IJob)";
yield return SelectJobAwaitLoad(jobName);
var info = SetupBranchTest();
var window = EditorWindow.GetWindow<BurstInspectorGUI>();
window.SendEvent(new Event() { type = EventType.MouseUp, mousePosition = info.mousePos });
var branch = window._textArea.hoveredBranch;
yield return null;
// Close window to avoid it sending more events
window.Close();
Assert.AreNotEqual(branch, default(LongTextArea.Branch), "Mouse is not hovering any branch.");
Assert.AreEqual(info.blockIdx.src, branch.Edge.OriginRef.BlockIndex);
Assert.AreEqual(info.blockIdx.dst, branch.Edge.LineRef.BlockIndex);
}
[UnityTest]
public IEnumerator ClickBranchTest()
{
const string jobName = "BurstInspectorGUITests.MyJob - (IJob)";
yield return SelectJobAwaitLoad(jobName);
var info = SetupBranchTest();
var window = EditorWindow.GetWindow<BurstInspectorGUI>();
// Seeing if clicking the branch takes us to a spot where branch is still hovered.
window.SendEvent(new Event() { type = EventType.MouseDown, mousePosition = info.mousePos });
var branch = window._textArea.hoveredBranch;
yield return null;
Assert.AreNotEqual(branch, default(LongTextArea.Branch), "Mouse is not hovering any branch.");
Assert.AreEqual(info.blockIdx.src, branch.Edge.OriginRef.BlockIndex);
Assert.AreEqual(info.blockIdx.dst, branch.Edge.LineRef.BlockIndex);
// Going back again.
window.SendEvent(new Event() { type = EventType.MouseDown, mousePosition = info.mousePos });
var branch2 = window._textArea.hoveredBranch;
yield return null;
Assert.AreNotEqual(branch2, default(LongTextArea.Branch), "Mouse is not hovering any branch.");
Assert.AreEqual(info.blockIdx.src, branch2.Edge.OriginRef.BlockIndex);
Assert.AreEqual(info.blockIdx.dst, branch2.Edge.LineRef.BlockIndex);
// Close window to avoid it sending more events.
window.Close();
}
private struct InfoThingy
{
public (int src, int dst) blockIdx;
public Vector2 mousePos;
}
private InfoThingy SetupBranchTest()
{
var window = EditorWindow.GetWindow<BurstInspectorGUI>();
// Make sure we use fontSize 12:
window.fontSizeIndex = 4;
window._textArea.Invalidate();
window.fixedFontStyle = null;
// Force window size to actually show branch arrows.
window.position = new Rect(window.position.x, window.position.y, 390, 405);
// Sending event to set the displayname, to avoid it resetting _scrollPos because of target change.
// Sending two events as initial guess for buttonbar width might be off, and it will be a precise calculation after second event.
window.SendEvent(new Event() { type = EventType.Repaint, mousePosition = new Vector2(window.position.width / 2f, window.position.height / 2f) });
window.SendEvent(new Event() { type = EventType.Repaint, mousePosition = new Vector2(window.position.width / 2f, window.position.height / 2f) });
// Setting up for the test.
// Finding an edge:
int dstBlockIdx = -1;
int srcBlockIdx = -1;
int line = -1;
for (int idx = 0; idx < window._burstDisassembler.Blocks.Count; idx++)
{
var block = window._burstDisassembler.Blocks[idx];
if (block.Edges != null)
{
foreach (var edge in block.Edges)
{
if (edge.Kind == BurstDisassembler.AsmEdgeKind.OutBound)
{
dstBlockIdx = edge.LineRef.BlockIndex;
line = window._textArea.blockLine[dstBlockIdx];
if ((dstBlockIdx == idx + 1 && edge.LineRef.LineIndex == 0)) // pointing to next line
{
continue;
}
srcBlockIdx = idx;
break;
}
}
if (srcBlockIdx != -1)
{
break;
}
}
}
if (srcBlockIdx == -1)
{
window.Close();
throw new System.Exception("No edges present in assembly for \"BurstInspectorGUITests.MyJob - (IJob)\"");
}
float dist = window._textArea.fontHeight * line;
float x = (window.position.width - (window._inspectorView.width + BurstInspectorGUI._scrollbarThickness)) + window._textArea.horizontalPad - (2*window._textArea.fontWidth);
// setting _ScrollPos so end of arrow is at bottom of screen, to make sure there is actually room for the scrolling.
window._scrollPos = new Vector2(0, dist - window._inspectorView.height * 0.93f);
// Setting mousePos to bottom of inspector view.
float topOfInspectorToBranchArrow = window._buttonOverlapInspectorView + 66.5f;//66.5f is the size of space over the treeview of different jobs.
var mousePos = new Vector2(x, topOfInspectorToBranchArrow + window._inspectorView.height - 0.5f*window._textArea.fontHeight);
return new InfoThingy() { blockIdx = (srcBlockIdx, dstBlockIdx), mousePos = mousePos};
}
public static IEnumerable ValueSource
{
get
{
yield return "BurstInspectorGUITests.MyJob - (IJob)";
yield return "BurstReflectionTests.GenericType`1.NestedGeneric`1[System.Int32,System.Single].TestMethod3()";
yield return "BurstReflectionTests.GenericType`1.NestedNonGeneric[System.Int32].TestMethod2()";
yield return "BurstReflectionTests.GenericParallelForJob`1[System.Int32] - (IJobParallelFor)";
}
}
[UnityTest]
public IEnumerator FocusCodeTest([ValueSource(nameof(ValueSource))] string job)
{
var win = EditorWindow.GetWindow<BurstInspectorGUI>();
yield return SelectJobAwaitLoad(job);
// Doesn't check that it's at the right spot, simply that it actually moves
Assert.IsFalse(Mathf.Approximately(win._inspectorView.y, 0f), "Inspector view did not change");
win.Close();
}
public static IEnumerable FocusCodeNotBranchesSource
{
get
{
yield return (1000, false);
yield return (563, true);
}
}
[UnityTest]
public IEnumerator FocusCodeNotBranchesTest([ValueSource(nameof(FocusCodeNotBranchesSource))] (int, bool) input)
{
var (width, doFocus) = input;
const string case1 = "BurstInspectorGUITests.BranchArrows - (IJob)";
const string case2 = "BurstInspectorGUITests.BranchArrows2 - (IJob)";
var win = EditorWindow.GetWindow<BurstInspectorGUI>();
// Force window size to be small enough for it to position it more to the right.
win.position = new Rect(win.position.x, win.position.y, width, 405);
// Test one where it should focus.
yield return SelectJobAwaitLoad(case1);
var val1 = win._inspectorView.x;
var result1 = Mathf.Approximately(val1, 0f);
// Test two with no focus.
win._assemblyKind = BurstInspectorGUI.AssemblyOptions.PlainWithDebugInformation;
yield return SelectJobAwaitLoad(case2);
var val2 = win._inspectorView.x;
var result2 = Mathf.Approximately(val2, 0f);
// Cleanup and test assertions.
win.Close();
Assert.AreEqual(doFocus, result1 == doFocus, $"Inspector view wrong.");
//Assert.IsFalse(result1, $"Inspector view did not change (Is {val1}).");
Assert.IsTrue(result2, $"Inspector view changed unexpectedly (Is {val2}).");
}
[UnityTest]
public IEnumerator SelectionNotOutsideBoundsTest()
{
void MoveSelection(BurstInspectorGUI gui, LongTextArea.Direction dir)
{
switch (dir)
{
case LongTextArea.Direction.Down:
gui._textArea.SelectAll();
gui._textArea.MoveSelectionDown(gui._inspectorView, true);
break;
case LongTextArea.Direction.Right:
gui._textArea.SelectAll();
gui._textArea.MoveSelectionRight(gui._inspectorView, true);
break;
case LongTextArea.Direction.Left:
gui._textArea.selectDragPos = Vector2.zero;
gui._textArea.MoveSelectionLeft(gui._inspectorView, true);
break;
case LongTextArea.Direction.Up:
gui._textArea.selectDragPos = Vector2.zero;
gui._textArea.MoveSelectionUp(gui._inspectorView, true);
break;
}
}
var win = EditorWindow.GetWindow<BurstInspectorGUI>();
yield return SelectJobAwaitLoad("BurstInspectorGUITests.MyJob - (IJob)");
try
{
foreach (var dir in Enum.GetValues(typeof(LongTextArea.Direction)))
{
MoveSelection(win, (LongTextArea.Direction)dir);
yield return null;
// Check that no errors have happened.
LogAssert.NoUnexpectedReceived();
}
}
finally
{
win.Close();
}
}
[UnityTest]
public IEnumerator SelectionInAssemblySearchBarTest()
{
yield return SelectJobAwaitLoad("BurstInspectorGUITests.MyJob - (IJob)");
var win = EditorWindow.GetWindow<BurstInspectorGUI>();
win._searchFieldAssembly.SetFocus();
yield return null;
// Send events to input some text.
win.SendEvent(Event.KeyboardEvent("a"));
win.SendEvent(Event.KeyboardEvent("b"));
yield return null;
// Move select some using keyboard input
win.SendEvent(Event.KeyboardEvent("left"));
win.SendEvent(Event.KeyboardEvent("#right"));
yield return null;
// Do a copy
var savedClipBoard = EditorGUIUtility.systemCopyBuffer;
win.SendEvent(SystemInfo.operatingSystemFamily == OperatingSystemFamily.MacOSX
? Event.KeyboardEvent("%c")
: Event.KeyboardEvent("^c"));
yield return null;
var copiedText = EditorGUIUtility.systemCopyBuffer;
EditorGUIUtility.systemCopyBuffer = savedClipBoard;
// Check that all is good
win.Close();
Assert.AreEqual("b", copiedText, "Copied text did not match expectation.");
}
[UnityTest]
public IEnumerator GoToNextSearchTargetTest()
{
var active = -1;
var nextActive = -1;
yield return SelectJobAwaitLoad("BurstInspectorGUITests.MyJob - (IJob)");
var win = EditorWindow.GetWindow<BurstInspectorGUI>();
try
{
win._searchFieldAssembly.SetFocus();
yield return null;
// Do a search in the text.
win.SendEvent(Event.KeyboardEvent("p"));
win.SendEvent(Event.KeyboardEvent("u"));
win.SendEvent(Event.KeyboardEvent("return"));
yield return null;
active = win._textArea._activeSearchHitIdx;
// Select next search target.
win.SendEvent(Event.KeyboardEvent("return"));
yield return null;
nextActive = win._textArea._activeSearchHitIdx;
}
finally
{
win.Close();
}
Assert.AreNotEqual(active, nextActive, "Active search target was not changed.");
}
[BurstCompile]
private struct MyJob : IJob
{
[ReadOnly]
public NativeArray<float> Inpút;
[WriteOnly]
public NativeArray<float> Output;
public void Execute()
{
float result = 0.0f;
for (int i = 0; i < Inpút.Length; i++)
{
result += Inpút[i];
}
Output[0] = result;
}
}
[BurstCompile]
private struct BranchArrows : IJob
{
[ReadOnly]
public NativeArray<float> Inpút;
[WriteOnly]
public NativeArray<float> Output;
public void Execute()
{
float result = 0.0f;
for (int i = 0; i < Inpút.Length; i++)
{
if (Inpút[i] < 10) { result += 1; }
else if (Inpút[i] < 20) { result += 2; }
else if (Inpút[i] < 30) { result += 3; }
else if (Inpút[i] < 40) { result += 4; }
else if (Inpút[i] < 50) { result += 5; }
else if (Inpút[i] < 60) { result += 6; }
else if (Inpút[i] < 70) { result += 7; }
else if (Inpút[i] < 80) { result += 8; }
else if (Inpút[i] < 90) { result += 9; }
result += Inpút[i];
}
Output[0] = result;
}
}
[BurstCompile]
private struct BranchArrows2 : IJob
{
[ReadOnly]
public NativeArray<float> Inpút;
[WriteOnly]
public NativeArray<float> Output;
public void Execute()
{
float result = 0.0f;
for (int i = 0; i < Inpút.Length; i++)
{
if (Inpút[i] < 10) { result += 1; }
else if (Inpút[i] < 20) { result += 2; }
else if (Inpút[i] < 30) { result += 3; }
else if (Inpút[i] < 40) { result += 4; }
else if (Inpút[i] < 50) { result += 5; }
else if (Inpút[i] < 60) { result += 6; }
else if (Inpút[i] < 70) { result += 7; }
else if (Inpút[i] < 80) { result += 8; }
else if (Inpút[i] < 90) { result += 9; }
result += Inpút[i];
}
Output[0] = result;
}
}
private class BurstDisassemblerWithCopy : BurstDisassembler
{
public List<AsmBlock> BlocksCopy;
public bool IsColoredCopy;
public List<AsmLine> LinesCopy;
public List<AsmToken> TokensCopy;
public BurstDisassemblerWithCopy(BurstDisassembler disassembler) : base()
{
IsColoredCopy = disassembler.IsColored;
BlocksCopy = new List<AsmBlock>(disassembler.Blocks);
LinesCopy = new List<AsmLine>(disassembler.Lines);
TokensCopy = new List<AsmToken>(disassembler.Tokens);
}
public bool Equals(BurstDisassembler other)
{
return IsColoredCopy == other.IsColored
&& BlocksCopy.SequenceEqual(other.Blocks)
&& LinesCopy.SequenceEqual(other.Lines)
&& TokensCopy.SequenceEqual(other.Tokens);
}
}
}