first commit
This commit is contained in:
@@ -0,0 +1,846 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using UnityEditor.IMGUI.Controls;
|
||||
using UnityEditor.TestTools.TestRunner.Api;
|
||||
using UnityEditor.TestTools.TestRunner.GUI.TestAssets;
|
||||
using UnityEngine;
|
||||
|
||||
namespace UnityEditor.TestTools.TestRunner.GUI
|
||||
{
|
||||
[Serializable]
|
||||
internal class TestListGUI
|
||||
{
|
||||
private static readonly GUIContent s_GUIRunSelectedTests = EditorGUIUtility.TrTextContent("Run Selected", "Run selected test(s)");
|
||||
private static readonly GUIContent s_GUIRunAllTests = EditorGUIUtility.TrTextContent("Run All", "Run all tests");
|
||||
private static readonly GUIContent s_GUIRerunFailedTests = EditorGUIUtility.TrTextContent("Rerun Failed", "Rerun all failed tests");
|
||||
private static readonly GUIContent s_GUIRun = EditorGUIUtility.TrTextContent("Run");
|
||||
private static readonly GUIContent s_GUIRunUntilFailed = EditorGUIUtility.TrTextContent("Run Until Failed");
|
||||
private static readonly GUIContent s_GUIRun100Times = EditorGUIUtility.TrTextContent("Run 100 times");
|
||||
private static readonly GUIContent s_GUIOpenTest = EditorGUIUtility.TrTextContent("Open source code");
|
||||
private static readonly GUIContent s_GUIOpenErrorLine = EditorGUIUtility.TrTextContent("Open error line");
|
||||
private static readonly GUIContent s_GUIClearResults = EditorGUIUtility.TrTextContent("Clear Results", "Clear all test results");
|
||||
private static readonly GUIContent s_SaveResults = EditorGUIUtility.TrTextContent("Export Results", "Save the latest test results to a file");
|
||||
private static readonly GUIContent s_GUICancelRun = EditorGUIUtility.TrTextContent("Cancel Run");
|
||||
|
||||
[SerializeField]
|
||||
private TestRunnerWindow m_Window;
|
||||
[NonSerialized]
|
||||
private TestRunnerApi m_TestRunnerApi;
|
||||
|
||||
[NonSerialized]
|
||||
internal TestMode m_TestMode;
|
||||
|
||||
[NonSerialized]
|
||||
internal bool m_RunOnPlatform;
|
||||
|
||||
[NonSerialized]
|
||||
internal bool m_buildOnly;
|
||||
|
||||
[SerializeField]
|
||||
private TestRunProgress runProgress;
|
||||
public Dictionary<string, TestTreeViewItem> filteredTree { get; set; }
|
||||
|
||||
public List<TestRunnerResult> newResultList
|
||||
{
|
||||
get { return m_NewResultList; }
|
||||
set
|
||||
{
|
||||
m_NewResultList = value;
|
||||
m_ResultByKey = null;
|
||||
}
|
||||
}
|
||||
|
||||
[SerializeField]
|
||||
private List<TestRunnerResult> m_NewResultList = new List<TestRunnerResult>();
|
||||
|
||||
private Dictionary<string, TestRunnerResult> m_ResultByKey;
|
||||
internal Dictionary<string, TestRunnerResult> ResultsByKey
|
||||
{
|
||||
get
|
||||
{
|
||||
if (m_ResultByKey == null)
|
||||
{
|
||||
m_ResultByKey = new Dictionary<string, TestRunnerResult>();
|
||||
foreach (var result in newResultList)
|
||||
{
|
||||
if (m_ResultByKey.ContainsKey(result.uniqueId))
|
||||
{
|
||||
Debug.LogWarning($"Multiple tests has the same unique id '{result.uniqueId}', their results will be overwritten.");
|
||||
continue;
|
||||
}
|
||||
m_ResultByKey.Add(result.uniqueId, result);
|
||||
}
|
||||
}
|
||||
|
||||
return m_ResultByKey;
|
||||
}
|
||||
}
|
||||
|
||||
[SerializeField]
|
||||
private string m_ResultText;
|
||||
[SerializeField]
|
||||
private string m_ResultStacktrace;
|
||||
|
||||
private TreeViewController m_TestListTree;
|
||||
[SerializeField]
|
||||
internal TreeViewState m_TestListState;
|
||||
[SerializeField]
|
||||
internal TestRunnerUIFilter m_TestRunnerUIFilter = new TestRunnerUIFilter();
|
||||
|
||||
private Vector2 m_TestInfoScroll, m_TestListScroll;
|
||||
private List<TestRunnerResult> m_QueuedResults = new List<TestRunnerResult>();
|
||||
private ITestResultAdaptor m_LatestTestResults;
|
||||
|
||||
public TestListGUI()
|
||||
{
|
||||
MonoCecilHelper = new MonoCecilHelper();
|
||||
AssetsDatabaseHelper = new AssetsDatabaseHelper();
|
||||
|
||||
GuiHelper = new GuiHelper(MonoCecilHelper, AssetsDatabaseHelper);
|
||||
TestRunnerApi.runProgressChanged.AddListener(UpdateProgressStatus);
|
||||
}
|
||||
|
||||
private void UpdateProgressStatus(TestRunProgress progress)
|
||||
{
|
||||
runProgress = progress;
|
||||
TestRunnerWindow.s_Instance.Repaint();
|
||||
}
|
||||
|
||||
private IMonoCecilHelper MonoCecilHelper { get; set; }
|
||||
private IAssetsDatabaseHelper AssetsDatabaseHelper { get; set; }
|
||||
private IGuiHelper GuiHelper { get; set; }
|
||||
|
||||
private struct PlayerMenuItem
|
||||
{
|
||||
public GUIContent name;
|
||||
public bool filterSelectedTestsOnly;
|
||||
}
|
||||
|
||||
[SerializeField]
|
||||
private int m_SelectedOption;
|
||||
|
||||
public void PrintHeadPanel()
|
||||
{
|
||||
if (m_RunOnPlatform)
|
||||
{
|
||||
EditorGUILayout.BeginHorizontal(EditorStyles.toolbar);
|
||||
GUILayout.Label("Running on " + EditorUserBuildSettings.activeBuildTarget);
|
||||
EditorGUILayout.EndHorizontal();
|
||||
}
|
||||
|
||||
using (new EditorGUI.DisabledScope(m_TestListTree == null || IsBusy()))
|
||||
{
|
||||
m_TestRunnerUIFilter.OnModeGUI();
|
||||
DrawFilters();
|
||||
}
|
||||
}
|
||||
|
||||
public void PrintProgressBar(Rect rect)
|
||||
{
|
||||
if (runProgress == null || runProgress.HasFinished || string.IsNullOrEmpty(runProgress.RunGuid))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
EditorGUILayout.BeginHorizontal(EditorStyles.toolbar);
|
||||
|
||||
EditorGUI.ProgressBar(EditorGUILayout.GetControlRect(), runProgress.Progress, runProgress.CurrentStepName);
|
||||
if (GUILayout.Button(s_GUICancelRun, GUILayout.Width(100)))
|
||||
{
|
||||
TestRunnerApi.CancelTestRun(runProgress.RunGuid);
|
||||
}
|
||||
|
||||
EditorGUILayout.EndHorizontal();
|
||||
}
|
||||
|
||||
public void PrintBottomPanel()
|
||||
{
|
||||
using (new EditorGUI.DisabledScope(m_TestListTree == null || IsBusy()))
|
||||
{
|
||||
EditorGUILayout.BeginHorizontal(EditorStyles.toolbar);
|
||||
{
|
||||
using (new EditorGUI.DisabledScope(m_LatestTestResults == null))
|
||||
{
|
||||
if (GUILayout.Button(s_SaveResults))
|
||||
{
|
||||
var filePath = EditorUtility.SaveFilePanel(s_SaveResults.text, "",
|
||||
$"TestResults_{DateTime.Now:yyyyMMdd_HHmmss}.xml", "xml");
|
||||
if (!string.IsNullOrEmpty(filePath))
|
||||
{
|
||||
TestRunnerApi.SaveResultToFile(m_LatestTestResults, filePath);
|
||||
}
|
||||
|
||||
GUIUtility.ExitGUI();
|
||||
}
|
||||
}
|
||||
|
||||
if (GUILayout.Button(s_GUIClearResults))
|
||||
{
|
||||
foreach (var result in newResultList)
|
||||
{
|
||||
result.Clear();
|
||||
}
|
||||
|
||||
m_TestRunnerUIFilter.UpdateCounters(newResultList, filteredTree);
|
||||
Reload();
|
||||
GUIUtility.ExitGUI();
|
||||
}
|
||||
|
||||
GUILayout.FlexibleSpace();
|
||||
|
||||
using (new EditorGUI.DisabledScope(m_TestRunnerUIFilter.FailedCount == 0))
|
||||
{
|
||||
if (GUILayout.Button(s_GUIRerunFailedTests))
|
||||
{
|
||||
RunTests(RunFilterType.RunFailed);
|
||||
GUIUtility.ExitGUI();
|
||||
}
|
||||
}
|
||||
|
||||
using (new EditorGUI.DisabledScope(m_TestListTree == null || !m_TestListTree.HasSelection()))
|
||||
{
|
||||
if (GUILayout.Button(s_GUIRunSelectedTests))
|
||||
{
|
||||
RunTests(RunFilterType.RunSelected);
|
||||
GUIUtility.ExitGUI();
|
||||
}
|
||||
}
|
||||
|
||||
if (GUILayout.Button(s_GUIRunAllTests))
|
||||
{
|
||||
RunTests(RunFilterType.RunAll);
|
||||
GUIUtility.ExitGUI();
|
||||
}
|
||||
|
||||
if (m_TestMode == TestMode.PlayMode && m_RunOnPlatform)
|
||||
{
|
||||
PlayerMenuItem[] menuItems;
|
||||
|
||||
if (EditorUserBuildSettings.installInBuildFolder)
|
||||
{
|
||||
// Note: We select here m_buildOnly = false, so build location dialog won't show up
|
||||
// The player won't actually be ran when using together with EditorUserBuildSettings.installInBuildFolder
|
||||
m_buildOnly = false;
|
||||
|
||||
menuItems = new []
|
||||
{
|
||||
new PlayerMenuItem()
|
||||
{
|
||||
name = new GUIContent("Install All Tests In Build Folder"), filterSelectedTestsOnly = false
|
||||
},
|
||||
new PlayerMenuItem()
|
||||
{
|
||||
name = new GUIContent("Install Selected Tests In Build Folder"), filterSelectedTestsOnly = true
|
||||
}
|
||||
};
|
||||
}
|
||||
else
|
||||
{
|
||||
m_buildOnly = true;
|
||||
|
||||
menuItems = new []
|
||||
{
|
||||
new PlayerMenuItem()
|
||||
{
|
||||
name = new GUIContent($"{GetBuildText()} All Tests"), filterSelectedTestsOnly = false
|
||||
},
|
||||
new PlayerMenuItem()
|
||||
{
|
||||
name = new GUIContent($"{GetBuildText()} Selected Tests"), filterSelectedTestsOnly = true
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
if (GUILayout.Button(GUIContent.none, EditorStyles.toolbarDropDown))
|
||||
{
|
||||
Vector2 mousePos = Event.current.mousePosition;
|
||||
|
||||
EditorUtility.DisplayCustomMenu(new Rect(mousePos.x, mousePos.y, 0, 0),
|
||||
menuItems.Select(m => m.name).ToArray(),
|
||||
-1,
|
||||
(object userData, string[] options, int selected) => RunTests(menuItems[selected].filterSelectedTestsOnly ? RunFilterType.BuildSelected : RunFilterType.BuildAll), menuItems);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
EditorGUILayout.EndHorizontal();
|
||||
}
|
||||
}
|
||||
|
||||
private string GetBuildText()
|
||||
{
|
||||
switch (EditorUserBuildSettings.activeBuildTarget)
|
||||
{
|
||||
case BuildTarget.Android:
|
||||
if (EditorUserBuildSettings.exportAsGoogleAndroidProject)
|
||||
return "Export";
|
||||
break;
|
||||
case BuildTarget.iOS:
|
||||
return "Export";
|
||||
}
|
||||
return "Build";
|
||||
}
|
||||
|
||||
private string PickBuildLocation()
|
||||
{
|
||||
var target = EditorUserBuildSettings.activeBuildTarget;
|
||||
var targetGroup = BuildPipeline.GetBuildTargetGroup(target);
|
||||
var lastLocation = EditorUserBuildSettings.GetBuildLocation(target);
|
||||
var extension = PostprocessBuildPlayer.GetExtensionForBuildTarget(targetGroup, target, BuildOptions.None);
|
||||
var defaultName = FileUtil.GetLastPathNameComponent(lastLocation);
|
||||
lastLocation = string.IsNullOrEmpty(lastLocation) ? string.Empty : Path.GetDirectoryName(lastLocation);
|
||||
bool updateExistingBuild;
|
||||
var location = EditorUtility.SaveBuildPanel(target, $"{GetBuildText()} {target}", lastLocation, defaultName, extension,
|
||||
out updateExistingBuild);
|
||||
if (!string.IsNullOrEmpty(location))
|
||||
EditorUserBuildSettings.SetBuildLocation(target, location);
|
||||
return location;
|
||||
}
|
||||
|
||||
private void DrawFilters()
|
||||
{
|
||||
EditorGUILayout.BeginHorizontal(EditorStyles.toolbar);
|
||||
m_TestRunnerUIFilter.Draw();
|
||||
EditorGUILayout.EndHorizontal();
|
||||
}
|
||||
|
||||
public bool HasTreeData()
|
||||
{
|
||||
return m_TestListTree != null;
|
||||
}
|
||||
|
||||
public void RenderTestList()
|
||||
{
|
||||
if (m_TestListTree == null)
|
||||
{
|
||||
GUILayout.Label("Loading...");
|
||||
return;
|
||||
}
|
||||
|
||||
m_TestListScroll = EditorGUILayout.BeginScrollView(m_TestListScroll,
|
||||
GUILayout.ExpandWidth(true),
|
||||
GUILayout.MaxWidth(2000));
|
||||
|
||||
if (m_TestListTree.data.root == null || m_TestListTree.data.rowCount == 0 || (!m_TestListTree.isSearching && !m_TestListTree.data.GetItem(0).hasChildren))
|
||||
{
|
||||
if (m_TestRunnerUIFilter.IsFiltering)
|
||||
{
|
||||
var notMatchFoundStyle = new GUIStyle("label");
|
||||
notMatchFoundStyle.normal.textColor = Color.red;
|
||||
notMatchFoundStyle.alignment = TextAnchor.MiddleCenter;
|
||||
GUILayout.Label("No match found", notMatchFoundStyle);
|
||||
if (GUILayout.Button("Clear filters"))
|
||||
{
|
||||
m_TestRunnerUIFilter.Clear();
|
||||
UpdateTestTree();
|
||||
m_Window.Repaint();
|
||||
}
|
||||
}
|
||||
RenderNoTestsInfo();
|
||||
}
|
||||
else
|
||||
{
|
||||
var treeRect = EditorGUILayout.GetControlRect(GUILayout.ExpandHeight(true), GUILayout.ExpandWidth(true));
|
||||
var treeViewKeyboardControlId = GUIUtility.GetControlID(FocusType.Keyboard);
|
||||
|
||||
m_TestListTree.OnGUI(treeRect, treeViewKeyboardControlId);
|
||||
}
|
||||
|
||||
m_TestRunnerUIFilter.UpdateCounters(newResultList, filteredTree);
|
||||
EditorGUILayout.EndScrollView();
|
||||
}
|
||||
|
||||
private void RenderNoTestsInfo()
|
||||
{
|
||||
var testScriptAssetsCreator = new TestScriptAssetsCreator();
|
||||
if (!testScriptAssetsCreator.ActiveFolderContainsTestAssemblyDefinition())
|
||||
{
|
||||
var noTestsText = "No tests to show.";
|
||||
|
||||
if (!PlayerSettings.playModeTestRunnerEnabled)
|
||||
{
|
||||
const string testsMustLiveInCustomTestAssemblies =
|
||||
"Test scripts can be added to assemblies referencing the \"nunit.framework.dll\" library " +
|
||||
"or folders with Assembly Definition References targeting \"UnityEngine.TestRunner\" or \"UnityEditor.TestRunner\".";
|
||||
|
||||
noTestsText += Environment.NewLine + testsMustLiveInCustomTestAssemblies;
|
||||
}
|
||||
|
||||
EditorGUILayout.HelpBox(noTestsText, MessageType.Info);
|
||||
if (GUILayout.Button("Create a new Test Assembly Folder in the active path."))
|
||||
{
|
||||
testScriptAssetsCreator.AddNewFolderWithTestAssemblyDefinition(m_TestMode == TestMode.EditMode);
|
||||
}
|
||||
}
|
||||
|
||||
const string notTestAssembly = "Test Scripts can only be created inside test assemblies.";
|
||||
const string createTestScriptInCurrentFolder = "Create a new Test Script in the active path.";
|
||||
var canAddTestScriptAndItWillCompile = testScriptAssetsCreator.TestScriptWillCompileInActiveFolder();
|
||||
|
||||
using (new EditorGUI.DisabledScope(!canAddTestScriptAndItWillCompile))
|
||||
{
|
||||
var createTestScriptInCurrentFolderGUI = !canAddTestScriptAndItWillCompile
|
||||
? new GUIContent(createTestScriptInCurrentFolder, notTestAssembly)
|
||||
: new GUIContent(createTestScriptInCurrentFolder);
|
||||
|
||||
if (GUILayout.Button(createTestScriptInCurrentFolderGUI))
|
||||
{
|
||||
testScriptAssetsCreator.AddNewTestScript();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void RenderDetails(float width)
|
||||
{
|
||||
m_TestInfoScroll = EditorGUILayout.BeginScrollView(m_TestInfoScroll, GUILayout.ExpandWidth(true));
|
||||
var resultTextHeight = TestRunnerWindow.Styles.info.CalcHeight(new GUIContent(m_ResultText), width);
|
||||
EditorGUILayout.SelectableLabel(m_ResultText, TestRunnerWindow.Styles.info,
|
||||
GUILayout.ExpandHeight(true),
|
||||
GUILayout.ExpandWidth(true),
|
||||
GUILayout.MinHeight(resultTextHeight));
|
||||
EditorGUILayout.EndScrollView();
|
||||
}
|
||||
|
||||
public void Reload()
|
||||
{
|
||||
if (m_TestListTree != null)
|
||||
{
|
||||
m_TestListTree.ReloadData();
|
||||
UpdateQueuedResults();
|
||||
}
|
||||
}
|
||||
|
||||
public void Repaint()
|
||||
{
|
||||
if (m_TestListTree == null || m_TestListTree.data.root == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
m_TestListTree.Repaint();
|
||||
if (m_TestListTree.data.rowCount == 0)
|
||||
m_TestListTree.SetSelection(new int[0], false);
|
||||
TestSelectionCallback(m_TestListState.selectedIDs.ToArray());
|
||||
}
|
||||
|
||||
public void Init(TestRunnerWindow window, ITestAdaptor rootTest)
|
||||
{
|
||||
Init(window, new[] {rootTest});
|
||||
}
|
||||
|
||||
private void Init(TestRunnerWindow window, ITestAdaptor[] rootTests)
|
||||
{
|
||||
if (m_Window == null)
|
||||
{
|
||||
m_Window = window;
|
||||
}
|
||||
|
||||
if (m_TestListTree == null)
|
||||
{
|
||||
if (m_TestListState == null)
|
||||
{
|
||||
m_TestListState = new TreeViewState();
|
||||
}
|
||||
if (m_TestListTree == null)
|
||||
m_TestListTree = new TreeViewController(m_Window, m_TestListState);
|
||||
|
||||
m_TestListTree.deselectOnUnhandledMouseDown = false;
|
||||
|
||||
m_TestListTree.selectionChangedCallback += TestSelectionCallback;
|
||||
m_TestListTree.itemDoubleClickedCallback += TestDoubleClickCallback;
|
||||
m_TestListTree.contextClickItemCallback += TestContextClickCallback;
|
||||
|
||||
var testListTreeViewDataSource = new TestListTreeViewDataSource(m_TestListTree, this, rootTests);
|
||||
|
||||
m_TestListTree.Init(new Rect(),
|
||||
testListTreeViewDataSource,
|
||||
new TestListTreeViewGUI(m_TestListTree),
|
||||
null);
|
||||
}
|
||||
|
||||
m_TestRunnerUIFilter.UpdateCounters(newResultList, filteredTree);
|
||||
m_TestRunnerUIFilter.RebuildTestList = () => m_TestListTree.ReloadData();
|
||||
m_TestRunnerUIFilter.UpdateTestTreeRoots = UpdateTestTree;
|
||||
m_TestRunnerUIFilter.SearchStringChanged = s => m_TestListTree.ReloadData();
|
||||
m_TestRunnerUIFilter.SearchStringCleared = () => FrameSelection();
|
||||
}
|
||||
|
||||
public void UpdateResult(TestRunnerResult result)
|
||||
{
|
||||
if (!HasTreeData())
|
||||
{
|
||||
m_QueuedResults.Add(result);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
if (!ResultsByKey.TryGetValue(result.uniqueId, out var testRunnerResult))
|
||||
{
|
||||
// Add missing result due to e.g. changes in code for uniqueId due to change of package version.
|
||||
m_NewResultList.Add(result);
|
||||
ResultsByKey[result.uniqueId] = result;
|
||||
testRunnerResult = result;
|
||||
}
|
||||
|
||||
testRunnerResult.Update(result);
|
||||
Repaint();
|
||||
m_Window.Repaint();
|
||||
}
|
||||
|
||||
public void RunFinished(ITestResultAdaptor results)
|
||||
{
|
||||
m_LatestTestResults = results;
|
||||
UpdateTestTree();
|
||||
}
|
||||
|
||||
private void UpdateTestTree()
|
||||
{
|
||||
var testList = this;
|
||||
if (m_TestRunnerApi == null)
|
||||
{
|
||||
m_TestRunnerApi= ScriptableObject.CreateInstance<TestRunnerApi>();
|
||||
}
|
||||
|
||||
m_TestRunnerApi.RetrieveTestList(GetExecutionSettings(), rootTest =>
|
||||
{
|
||||
testList.UpdateTestTree(new[] { rootTest });
|
||||
testList.Reload();
|
||||
});
|
||||
}
|
||||
|
||||
public void UpdateTestTree(ITestAdaptor[] tests)
|
||||
{
|
||||
if (!HasTreeData())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
(m_TestListTree.data as TestListTreeViewDataSource).UpdateRootTest(tests);
|
||||
|
||||
m_TestListTree.ReloadData();
|
||||
Repaint();
|
||||
m_Window.Repaint();
|
||||
}
|
||||
|
||||
private void UpdateQueuedResults()
|
||||
{
|
||||
foreach (var testRunnerResult in m_QueuedResults)
|
||||
{
|
||||
if (ResultsByKey.TryGetValue(testRunnerResult.uniqueId, out var existingResult))
|
||||
{
|
||||
existingResult.Update(testRunnerResult);
|
||||
}
|
||||
}
|
||||
m_QueuedResults.Clear();
|
||||
TestSelectionCallback(m_TestListState.selectedIDs.ToArray());
|
||||
m_TestRunnerUIFilter.UpdateCounters(newResultList, filteredTree);
|
||||
Repaint();
|
||||
m_Window.Repaint();
|
||||
}
|
||||
|
||||
internal void TestSelectionCallback(int[] selected)
|
||||
{
|
||||
if (m_TestListTree != null && selected.Length > 0)
|
||||
{
|
||||
if (m_TestListTree != null)
|
||||
{
|
||||
var node = m_TestListTree.FindItem(selected[0]);
|
||||
if (node is TestTreeViewItem)
|
||||
{
|
||||
var test = node as TestTreeViewItem;
|
||||
m_ResultText = test.GetResultText();
|
||||
m_ResultStacktrace = test.result.stacktrace;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (selected.Length == 0)
|
||||
{
|
||||
m_ResultText = "";
|
||||
}
|
||||
}
|
||||
|
||||
private void TestDoubleClickCallback(int id)
|
||||
{
|
||||
if (IsBusy())
|
||||
return;
|
||||
|
||||
RunTests(RunFilterType.RunSpecific, id);
|
||||
GUIUtility.ExitGUI();
|
||||
}
|
||||
|
||||
private void RunTests(RunFilterType runFilter, params int[] specificTests)
|
||||
{
|
||||
if (EditorUtility.scriptCompilationFailed)
|
||||
{
|
||||
Debug.LogError("Fix compilation issues before running tests");
|
||||
return;
|
||||
}
|
||||
|
||||
var filters = ConstructFilter(runFilter, specificTests);
|
||||
if (filters == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (var filter in filters)
|
||||
{
|
||||
filter.ClearResults(newResultList.OfType<UITestRunnerFilter.IClearableResult>().ToDictionary(result => result.Id));
|
||||
}
|
||||
|
||||
var testFilters = filters.Select(filter => new Filter
|
||||
{
|
||||
testMode = m_TestMode,
|
||||
assemblyNames = filter.assemblyNames,
|
||||
categoryNames = filter.categoryNames,
|
||||
groupNames = filter.groupNames,
|
||||
testNames = filter.testNames,
|
||||
}).ToArray();
|
||||
|
||||
#if UNITY_2022_2_OR_NEWER
|
||||
var executionSettings =
|
||||
CreateExecutionSettings(m_RunOnPlatform ? EditorUserBuildSettings.activeBuildTarget : null,
|
||||
testFilters);
|
||||
#else
|
||||
var executionSettings =
|
||||
CreateExecutionSettings(m_RunOnPlatform ? EditorUserBuildSettings.activeBuildTarget : (BuildTarget?)null,
|
||||
testFilters);
|
||||
#endif
|
||||
if (runFilter == RunFilterType.BuildAll || runFilter == RunFilterType.BuildSelected)
|
||||
{
|
||||
var runSettings = new PlayerLauncherTestRunSettings();
|
||||
runSettings.buildOnly = m_buildOnly;
|
||||
|
||||
if (runSettings.buildOnly)
|
||||
{
|
||||
runSettings.buildOnlyLocationPath = PickBuildLocation();
|
||||
if (string.IsNullOrEmpty(runSettings.buildOnlyLocationPath))
|
||||
{
|
||||
Debug.LogWarning("Aborting, build selection was canceled.");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
executionSettings.overloadTestRunSettings = runSettings;
|
||||
|
||||
Debug.Log(executionSettings.ToString());
|
||||
}
|
||||
|
||||
if (m_TestRunnerApi == null)
|
||||
{
|
||||
m_TestRunnerApi = ScriptableObject.CreateInstance<TestRunnerApi>();
|
||||
}
|
||||
|
||||
m_TestRunnerApi.Execute(executionSettings);
|
||||
|
||||
if (executionSettings.targetPlatform != null && !(runFilter == RunFilterType.BuildAll || runFilter == RunFilterType.BuildSelected))
|
||||
{
|
||||
GUIUtility.ExitGUI();
|
||||
}
|
||||
}
|
||||
|
||||
private void TestContextClickCallback(int id)
|
||||
{
|
||||
if (id == 0)
|
||||
return;
|
||||
|
||||
var m = new GenericMenu();
|
||||
var multilineSelection = m_TestListState.selectedIDs.Count > 1;
|
||||
|
||||
if (!multilineSelection)
|
||||
{
|
||||
var testNode = GetSelectedTest();
|
||||
var isNotSuite = !testNode.IsGroupNode;
|
||||
if (isNotSuite)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(m_ResultStacktrace))
|
||||
{
|
||||
m.AddItem(s_GUIOpenErrorLine,
|
||||
false,
|
||||
data =>
|
||||
{
|
||||
if (!GuiHelper.OpenScriptInExternalEditor(m_ResultStacktrace))
|
||||
{
|
||||
GuiHelper.OpenScriptInExternalEditor(testNode.type, testNode.method);
|
||||
}
|
||||
},
|
||||
"");
|
||||
}
|
||||
|
||||
m.AddItem(s_GUIOpenTest,
|
||||
false,
|
||||
data => GuiHelper.OpenScriptInExternalEditor(testNode.type, testNode.method),
|
||||
"");
|
||||
m.AddSeparator("");
|
||||
}
|
||||
}
|
||||
|
||||
if (!IsBusy())
|
||||
{
|
||||
m.AddItem(multilineSelection ? s_GUIRunSelectedTests : s_GUIRun,
|
||||
false,
|
||||
data => RunTests(RunFilterType.RunSelected),
|
||||
"");
|
||||
}
|
||||
else
|
||||
m.AddDisabledItem(multilineSelection ? s_GUIRunSelectedTests : s_GUIRun, false);
|
||||
|
||||
m.ShowAsContext();
|
||||
}
|
||||
|
||||
private enum RunFilterType
|
||||
{
|
||||
RunAll,
|
||||
RunSelected,
|
||||
RunFailed,
|
||||
RunSpecific,
|
||||
BuildAll,
|
||||
BuildSelected
|
||||
}
|
||||
|
||||
private struct FilterConstructionStep
|
||||
{
|
||||
public int Id;
|
||||
public TreeViewItem Item;
|
||||
}
|
||||
|
||||
private UITestRunnerFilter[] ConstructFilter(RunFilterType runFilter, int[] specificTests = null)
|
||||
{
|
||||
if ((runFilter == RunFilterType.RunAll || runFilter == RunFilterType.BuildAll) && !m_TestRunnerUIFilter.IsFiltering)
|
||||
{
|
||||
// Shortcut for RunAll, which will not trigger any explicit tests
|
||||
return new[] {new UITestRunnerFilter()};
|
||||
}
|
||||
|
||||
var includedIds = GetIdsIncludedInRunFilter(runFilter, specificTests);
|
||||
var testsInFilter = includedIds.Select(id => m_TestListTree.FindItem(id)).Cast<TestTreeViewItem>()
|
||||
.SelectMany(item => item.GetMinimizedSelectedTree()).Distinct().ToArray();
|
||||
|
||||
if (testsInFilter.Length == 0)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
if (testsInFilter.Any(test => test.Parent == null))
|
||||
{
|
||||
// The root element is included in the minified list, which means we are running all tests
|
||||
// It should however trigger explicit tests, which is done by a groupNames filter matching all groups
|
||||
return new[]
|
||||
{
|
||||
new UITestRunnerFilter()
|
||||
{
|
||||
groupNames = new[] {".*"}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
var assemblies = testsInFilter.Where(test => test.IsTestAssembly).ToArray();
|
||||
var tests = testsInFilter.Where(test => !test.IsTestAssembly).ToArray();
|
||||
|
||||
var filters = new List<UITestRunnerFilter>();
|
||||
if (tests.Length > 0)
|
||||
{
|
||||
filters.Add(new UITestRunnerFilter
|
||||
{
|
||||
testNames = tests.Select(test => test.FullName).ToArray()
|
||||
});
|
||||
}
|
||||
|
||||
if (assemblies.Length > 0)
|
||||
{
|
||||
filters.Add(new UITestRunnerFilter
|
||||
{
|
||||
assemblyNames = assemblies.Select(test =>
|
||||
{
|
||||
// remove .dll from the end of the name
|
||||
var name = test.Name;
|
||||
if (name.EndsWith(".dll"))
|
||||
name = name.Substring(0, name.Length - 4);
|
||||
return name;
|
||||
}).ToArray()
|
||||
});
|
||||
}
|
||||
|
||||
return filters.ToArray();
|
||||
}
|
||||
|
||||
private IEnumerable<int> GetIdsIncludedInRunFilter(RunFilterType runFilter, int[] specificTests)
|
||||
{
|
||||
switch (runFilter)
|
||||
{
|
||||
case RunFilterType.RunSelected:
|
||||
case RunFilterType.BuildSelected:
|
||||
return m_TestListState.selectedIDs;
|
||||
case RunFilterType.RunSpecific:
|
||||
if (specificTests == null)
|
||||
{
|
||||
throw new ArgumentNullException(
|
||||
$"For {nameof(RunFilterType.RunSpecific)}, the {nameof(specificTests)} argument must not be null.");
|
||||
}
|
||||
|
||||
return specificTests;
|
||||
default:
|
||||
return m_TestListTree.GetRowIDs();
|
||||
}
|
||||
}
|
||||
|
||||
private TestTreeViewItem GetSelectedTest()
|
||||
{
|
||||
foreach (var lineId in m_TestListState.selectedIDs)
|
||||
{
|
||||
var line = m_TestListTree.FindItem(lineId);
|
||||
if (line is TestTreeViewItem)
|
||||
{
|
||||
return line as TestTreeViewItem;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private void FrameSelection()
|
||||
{
|
||||
if (m_TestListTree.HasSelection())
|
||||
{
|
||||
var firstClickedID = m_TestListState.selectedIDs.First() == m_TestListState.lastClickedID ? m_TestListState.selectedIDs.Last() : m_TestListState.selectedIDs.First();
|
||||
m_TestListTree.Frame(firstClickedID, true, false);
|
||||
}
|
||||
}
|
||||
|
||||
public void RebuildUIFilter()
|
||||
{
|
||||
m_TestRunnerUIFilter.UpdateCounters(newResultList, filteredTree);
|
||||
if (m_TestRunnerUIFilter.IsFiltering)
|
||||
{
|
||||
m_TestListTree.ReloadData();
|
||||
}
|
||||
}
|
||||
|
||||
private static bool IsBusy()
|
||||
{
|
||||
return TestRunnerApi.IsRunActive() || EditorApplication.isCompiling || EditorApplication.isPlaying;
|
||||
}
|
||||
|
||||
public ExecutionSettings GetExecutionSettings()
|
||||
{
|
||||
var filter = new Filter
|
||||
{
|
||||
testMode = m_TestMode
|
||||
};
|
||||
|
||||
#if UNITY_2022_2_OR_NEWER
|
||||
return CreateExecutionSettings(m_RunOnPlatform ? EditorUserBuildSettings.activeBuildTarget : null, filter);
|
||||
#else
|
||||
return CreateExecutionSettings(m_RunOnPlatform ? EditorUserBuildSettings.activeBuildTarget : (BuildTarget?)null, filter);
|
||||
#endif
|
||||
}
|
||||
|
||||
private static ExecutionSettings CreateExecutionSettings(BuildTarget? buildTarget, params Filter[] filters)
|
||||
{
|
||||
return new ExecutionSettings(filters)
|
||||
{
|
||||
targetPlatform = buildTarget,
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b8abb41ceb6f62c45a00197ae59224c1
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Reference in New Issue
Block a user