mirror of
https://gitgud.io/AbstractConcept/rimworld-animation-studio.git
synced 2024-08-15 00:43:27 +00:00
Initial commit
This commit is contained in:
commit
3c7cc0c973
8391 changed files with 704313 additions and 0 deletions
|
@ -0,0 +1,11 @@
|
|||
namespace UnityEditor.TestTools.TestRunner.GUI
|
||||
{
|
||||
internal class AssetsDatabaseHelper : IAssetsDatabaseHelper
|
||||
{
|
||||
public void OpenAssetInItsDefaultExternalEditor(string assetPath, int line)
|
||||
{
|
||||
var asset = AssetDatabase.LoadMainAssetAtPath(assetPath);
|
||||
AssetDatabase.OpenAsset(asset, line);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 740b3785866edda4b8d1e1a05570a5f8
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,138 @@
|
|||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Text.RegularExpressions;
|
||||
using Unity.CodeEditor;
|
||||
using UnityEditor.Utils;
|
||||
using UnityEngine;
|
||||
|
||||
namespace UnityEditor.TestTools.TestRunner.GUI
|
||||
{
|
||||
internal class GuiHelper : IGuiHelper
|
||||
{
|
||||
public GuiHelper(IMonoCecilHelper monoCecilHelper, IAssetsDatabaseHelper assetsDatabaseHelper)
|
||||
{
|
||||
MonoCecilHelper = monoCecilHelper;
|
||||
AssetsDatabaseHelper = assetsDatabaseHelper;
|
||||
Editor = new DefaultExternalCodeEditor();
|
||||
GetCSFiles = (dirPath, fileExtension) =>
|
||||
{
|
||||
return Directory.GetFiles(dirPath, $"*{fileExtension}", SearchOption.AllDirectories)
|
||||
.Select(Paths.UnifyDirectorySeparator);
|
||||
};
|
||||
}
|
||||
internal Func<string, string, IEnumerable<string>> GetCSFiles;
|
||||
protected IMonoCecilHelper MonoCecilHelper { get; private set; }
|
||||
public IAssetsDatabaseHelper AssetsDatabaseHelper { get; private set; }
|
||||
public IExternalCodeEditor Editor { get; internal set; }
|
||||
private const string FileExtension = ".cs";
|
||||
|
||||
public void OpenScriptInExternalEditor(Type type, MethodInfo method)
|
||||
{
|
||||
var fileOpenInfo = GetFileOpenInfo(type, method);
|
||||
|
||||
if (string.IsNullOrEmpty(fileOpenInfo.FilePath))
|
||||
{
|
||||
Debug.LogWarning("Failed to open test method source code in external editor. Inconsistent filename and yield return operator in target method.");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (fileOpenInfo.LineNumber == 1)
|
||||
{
|
||||
Debug.LogWarning("Failed to get a line number for unity test method. So please find it in opened file in external editor.");
|
||||
}
|
||||
|
||||
if (!fileOpenInfo.FilePath.Contains("Assets"))
|
||||
{
|
||||
Editor.OpenProject(fileOpenInfo.FilePath, fileOpenInfo.LineNumber, 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
AssetsDatabaseHelper.OpenAssetInItsDefaultExternalEditor(fileOpenInfo.FilePath, fileOpenInfo.LineNumber);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public IFileOpenInfo GetFileOpenInfo(Type type, MethodInfo method)
|
||||
{
|
||||
var fileOpenInfo = MonoCecilHelper.TryGetCecilFileOpenInfo(type, method);
|
||||
if (string.IsNullOrEmpty(fileOpenInfo.FilePath))
|
||||
{
|
||||
var dirPath = Paths.UnifyDirectorySeparator(Application.dataPath);
|
||||
var allCsFiles = GetCSFiles(dirPath, FileExtension);
|
||||
|
||||
var fileName = allCsFiles.FirstOrDefault(x =>
|
||||
x.Split(Path.DirectorySeparatorChar).Last().Equals(string.Concat(GetTestFileName(type), FileExtension)));
|
||||
|
||||
fileOpenInfo.FilePath = fileName ?? string.Empty;
|
||||
}
|
||||
|
||||
if (!fileOpenInfo.FilePath.Contains("Assets"))
|
||||
{
|
||||
return fileOpenInfo;
|
||||
}
|
||||
fileOpenInfo.FilePath = FilePathToAssetsRelativeAndUnified(fileOpenInfo.FilePath);
|
||||
|
||||
return fileOpenInfo;
|
||||
}
|
||||
|
||||
internal static string GetTestFileName(Type type)
|
||||
{
|
||||
//This handles the case of a test in a nested class, getting the name of the base class
|
||||
if (type.FullName != null && type.Namespace!=null && type.FullName.Contains("+"))
|
||||
{
|
||||
var removedNamespace = type.FullName.Substring(type.Namespace.Length+1);
|
||||
return removedNamespace.Substring(0,removedNamespace.IndexOf("+", StringComparison.Ordinal));
|
||||
}
|
||||
return type.Name;
|
||||
}
|
||||
public string FilePathToAssetsRelativeAndUnified(string filePath)
|
||||
{
|
||||
if (string.IsNullOrEmpty(filePath))
|
||||
return string.Empty;
|
||||
|
||||
filePath = Paths.UnifyDirectorySeparator(filePath);
|
||||
var length = Paths.UnifyDirectorySeparator(Application.dataPath).Length - "Assets".Length;
|
||||
|
||||
return filePath.Substring(length);
|
||||
}
|
||||
|
||||
public bool OpenScriptInExternalEditor(string stacktrace)
|
||||
{
|
||||
if (string.IsNullOrEmpty(stacktrace))
|
||||
return false;
|
||||
|
||||
var regex = new Regex("in (?<path>.*):{1}(?<line>[0-9]+)");
|
||||
|
||||
var matchingLines = stacktrace.Split(new[] { Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries).Where(x => regex.IsMatch(x)).ToList();
|
||||
if (!matchingLines.Any())
|
||||
return false;
|
||||
|
||||
var fileOpenInfos = matchingLines
|
||||
.Select(x => regex.Match(x))
|
||||
.Select(x =>
|
||||
new FileOpenInfo
|
||||
{
|
||||
FilePath = x.Groups["path"].Value,
|
||||
LineNumber = int.Parse(x.Groups["line"].Value)
|
||||
}).ToList();
|
||||
|
||||
var fileOpenInfo = fileOpenInfos
|
||||
.FirstOrDefault(openInfo => !string.IsNullOrEmpty(openInfo.FilePath) && File.Exists(openInfo.FilePath));
|
||||
|
||||
if (fileOpenInfo == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var filePath = FilePathToAssetsRelativeAndUnified(fileOpenInfo.FilePath);
|
||||
AssetsDatabaseHelper.OpenAssetInItsDefaultExternalEditor(filePath, fileOpenInfo.LineNumber);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: d0138170d24533e47b8e6c250c6d7fbc
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,7 @@
|
|||
namespace UnityEditor.TestTools.TestRunner.GUI
|
||||
{
|
||||
internal interface IAssetsDatabaseHelper
|
||||
{
|
||||
void OpenAssetInItsDefaultExternalEditor(string assetPath, int line);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 208e46d59ff6e304db0318377d20f5a1
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,13 @@
|
|||
using System;
|
||||
using System.Reflection;
|
||||
|
||||
namespace UnityEditor.TestTools.TestRunner.GUI
|
||||
{
|
||||
internal interface IGuiHelper
|
||||
{
|
||||
bool OpenScriptInExternalEditor(string stacktrace);
|
||||
void OpenScriptInExternalEditor(Type type, MethodInfo method);
|
||||
IFileOpenInfo GetFileOpenInfo(Type type, MethodInfo method);
|
||||
string FilePathToAssetsRelativeAndUnified(string filePath);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: fd57cf917f61bbb42b8f030436426ddd
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,8 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 07ea0326ed848fb4489187cb58f96113
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,12 @@
|
|||
namespace UnityEditor.TestTools.TestRunner.GUI
|
||||
{
|
||||
internal class RenderingOptions
|
||||
{
|
||||
public string nameFilter;
|
||||
public bool showSucceeded;
|
||||
public bool showFailed;
|
||||
public bool showIgnored;
|
||||
public bool showNotRunned;
|
||||
public string[] categories;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 87357ff0dec4ef348a295235835c6ee4
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,174 @@
|
|||
// ****************************************************************
|
||||
// Based on nUnit 2.6.2 (http://www.nunit.org/)
|
||||
// ****************************************************************
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace UnityEditor.TestTools.TestRunner.GUI
|
||||
{
|
||||
/// <summary>
|
||||
/// Summary description for ResultSummarizer.
|
||||
/// </summary>
|
||||
internal class ResultSummarizer
|
||||
{
|
||||
private int m_ErrorCount = -1;
|
||||
private int m_FailureCount;
|
||||
private int m_IgnoreCount = -1;
|
||||
private int m_InconclusiveCount = -1;
|
||||
private int m_NotRunnable = -1;
|
||||
private int m_ResultCount;
|
||||
private int m_SkipCount;
|
||||
private int m_SuccessCount;
|
||||
private int m_TestsRun;
|
||||
|
||||
private TimeSpan m_Duration = TimeSpan.FromSeconds(0);
|
||||
|
||||
public ResultSummarizer(IEnumerable<TestRunnerResult> results)
|
||||
{
|
||||
foreach (var result in results)
|
||||
Summarize(result);
|
||||
}
|
||||
|
||||
public bool success
|
||||
{
|
||||
get { return m_FailureCount == 0; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the number of test cases for which results
|
||||
/// have been summarized. Any tests excluded by use of
|
||||
/// Category or Explicit attributes are not counted.
|
||||
/// </summary>
|
||||
public int ResultCount
|
||||
{
|
||||
get { return m_ResultCount; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the number of test cases actually run, which
|
||||
/// is the same as ResultCount, less any Skipped, Ignored
|
||||
/// or NonRunnable tests.
|
||||
/// </summary>
|
||||
public int TestsRun
|
||||
{
|
||||
get { return m_TestsRun; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the number of tests that passed
|
||||
/// </summary>
|
||||
public int Passed
|
||||
{
|
||||
get { return m_SuccessCount; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the number of test cases that had an error.
|
||||
/// </summary>
|
||||
public int errors
|
||||
{
|
||||
get { return m_ErrorCount; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the number of test cases that failed.
|
||||
/// </summary>
|
||||
public int failures
|
||||
{
|
||||
get { return m_FailureCount; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the number of test cases that failed.
|
||||
/// </summary>
|
||||
public int inconclusive
|
||||
{
|
||||
get { return m_InconclusiveCount; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the number of test cases that were not runnable
|
||||
/// due to errors in the signature of the class or method.
|
||||
/// Such tests are also counted as Errors.
|
||||
/// </summary>
|
||||
public int notRunnable
|
||||
{
|
||||
get { return m_NotRunnable; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the number of test cases that were skipped.
|
||||
/// </summary>
|
||||
public int Skipped
|
||||
{
|
||||
get { return m_SkipCount; }
|
||||
}
|
||||
|
||||
public int ignored
|
||||
{
|
||||
get { return m_IgnoreCount; }
|
||||
}
|
||||
|
||||
public double duration
|
||||
{
|
||||
get { return m_Duration.TotalSeconds; }
|
||||
}
|
||||
|
||||
public int testsNotRun
|
||||
{
|
||||
get { return m_SkipCount + m_IgnoreCount + m_NotRunnable; }
|
||||
}
|
||||
|
||||
public void Summarize(TestRunnerResult result)
|
||||
{
|
||||
m_Duration += TimeSpan.FromSeconds(result.duration);
|
||||
m_ResultCount++;
|
||||
|
||||
if (result.resultStatus != TestRunnerResult.ResultStatus.NotRun)
|
||||
{
|
||||
//TODO implement missing features
|
||||
// if(result.IsIgnored)
|
||||
// {
|
||||
// m_IgnoreCount++;
|
||||
// return;
|
||||
// }
|
||||
|
||||
m_SkipCount++;
|
||||
return;
|
||||
}
|
||||
|
||||
switch (result.resultStatus)
|
||||
{
|
||||
case TestRunnerResult.ResultStatus.Passed:
|
||||
m_SuccessCount++;
|
||||
m_TestsRun++;
|
||||
break;
|
||||
case TestRunnerResult.ResultStatus.Failed:
|
||||
m_FailureCount++;
|
||||
m_TestsRun++;
|
||||
break;
|
||||
//TODO implement missing features
|
||||
// case TestResultState.Error:
|
||||
// case TestResultState.Cancelled:
|
||||
// m_ErrorCount++;
|
||||
// m_TestsRun++;
|
||||
// break;
|
||||
// case TestResultState.Inconclusive:
|
||||
// m_InconclusiveCount++;
|
||||
// m_TestsRun++;
|
||||
// break;
|
||||
// case TestResultState.NotRunnable:
|
||||
// m_NotRunnable++;
|
||||
// // errorCount++;
|
||||
// break;
|
||||
// case TestResultState.Ignored:
|
||||
// m_IgnoreCount++;
|
||||
// break;
|
||||
default:
|
||||
m_SkipCount++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 95a2914724952ef40bb590d0607fc878
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,104 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using UnityEngine;
|
||||
|
||||
namespace UnityEditor.TestTools.TestRunner.GUI
|
||||
{
|
||||
internal class TestFilterSettings
|
||||
{
|
||||
public bool showSucceeded;
|
||||
public bool showFailed;
|
||||
public bool showIgnored;
|
||||
public bool showNotRun;
|
||||
|
||||
public string filterByName;
|
||||
public int filterByCategory;
|
||||
|
||||
private GUIContent m_SucceededBtn;
|
||||
private GUIContent m_FailedBtn;
|
||||
private GUIContent m_IgnoredBtn;
|
||||
private GUIContent m_NotRunBtn;
|
||||
|
||||
public string[] availableCategories;
|
||||
|
||||
private readonly string m_PrefsKey;
|
||||
|
||||
public TestFilterSettings(string prefsKey)
|
||||
{
|
||||
availableCategories = null;
|
||||
m_PrefsKey = prefsKey;
|
||||
Load();
|
||||
UpdateCounters(Enumerable.Empty<TestRunnerResult>());
|
||||
}
|
||||
|
||||
public void Load()
|
||||
{
|
||||
showSucceeded = EditorPrefs.GetBool(m_PrefsKey + ".ShowSucceeded", true);
|
||||
showFailed = EditorPrefs.GetBool(m_PrefsKey + ".ShowFailed", true);
|
||||
showIgnored = EditorPrefs.GetBool(m_PrefsKey + ".ShowIgnored", true);
|
||||
showNotRun = EditorPrefs.GetBool(m_PrefsKey + ".ShowNotRun", true);
|
||||
filterByName = EditorPrefs.GetString(m_PrefsKey + ".FilterByName", string.Empty);
|
||||
filterByCategory = EditorPrefs.GetInt(m_PrefsKey + ".FilterByCategory", 0);
|
||||
}
|
||||
|
||||
public void Save()
|
||||
{
|
||||
EditorPrefs.SetBool(m_PrefsKey + ".ShowSucceeded", showSucceeded);
|
||||
EditorPrefs.SetBool(m_PrefsKey + ".ShowFailed", showFailed);
|
||||
EditorPrefs.SetBool(m_PrefsKey + ".ShowIgnored", showIgnored);
|
||||
EditorPrefs.SetBool(m_PrefsKey + ".ShowNotRun", showNotRun);
|
||||
EditorPrefs.SetString(m_PrefsKey + ".FilterByName", filterByName);
|
||||
EditorPrefs.SetInt(m_PrefsKey + ".FilterByCategory", filterByCategory);
|
||||
}
|
||||
|
||||
public void UpdateCounters(IEnumerable<TestRunnerResult> results)
|
||||
{
|
||||
var summary = new ResultSummarizer(results);
|
||||
|
||||
m_SucceededBtn = new GUIContent(summary.Passed.ToString(), Icons.s_SuccessImg, "Show tests that succeeded");
|
||||
m_FailedBtn = new GUIContent((summary.errors + summary.failures + summary.inconclusive).ToString(), Icons.s_FailImg, "Show tests that failed");
|
||||
m_IgnoredBtn = new GUIContent((summary.ignored + summary.notRunnable).ToString(), Icons.s_IgnoreImg, "Show tests that are ignored");
|
||||
m_NotRunBtn = new GUIContent((summary.testsNotRun - summary.ignored - summary.notRunnable).ToString(), Icons.s_UnknownImg, "Show tests that didn't run");
|
||||
}
|
||||
|
||||
public string[] GetSelectedCategories()
|
||||
{
|
||||
if (availableCategories == null)
|
||||
return new string[0];
|
||||
|
||||
return availableCategories.Where((c, i) => (filterByCategory & (1 << i)) != 0).ToArray();
|
||||
}
|
||||
|
||||
public void OnGUI()
|
||||
{
|
||||
EditorGUI.BeginChangeCheck();
|
||||
|
||||
filterByName = GUILayout.TextField(filterByName, "ToolbarSeachTextField", GUILayout.MinWidth(100), GUILayout.MaxWidth(250), GUILayout.ExpandWidth(true));
|
||||
if (GUILayout.Button(GUIContent.none, string.IsNullOrEmpty(filterByName) ? "ToolbarSeachCancelButtonEmpty" : "ToolbarSeachCancelButton"))
|
||||
filterByName = string.Empty;
|
||||
|
||||
if (availableCategories != null && availableCategories.Length > 0)
|
||||
filterByCategory = EditorGUILayout.MaskField(filterByCategory, availableCategories, EditorStyles.toolbarDropDown, GUILayout.MaxWidth(90));
|
||||
|
||||
showSucceeded = GUILayout.Toggle(showSucceeded, m_SucceededBtn, EditorStyles.toolbarButton);
|
||||
showFailed = GUILayout.Toggle(showFailed, m_FailedBtn, EditorStyles.toolbarButton);
|
||||
showIgnored = GUILayout.Toggle(showIgnored, m_IgnoredBtn, EditorStyles.toolbarButton);
|
||||
showNotRun = GUILayout.Toggle(showNotRun, m_NotRunBtn, EditorStyles.toolbarButton);
|
||||
|
||||
if (EditorGUI.EndChangeCheck())
|
||||
Save();
|
||||
}
|
||||
|
||||
public RenderingOptions BuildRenderingOptions()
|
||||
{
|
||||
var options = new RenderingOptions();
|
||||
options.showSucceeded = showSucceeded;
|
||||
options.showFailed = showFailed;
|
||||
options.showIgnored = showIgnored;
|
||||
options.showNotRunned = showNotRun;
|
||||
options.nameFilter = filterByName;
|
||||
options.categories = GetSelectedCategories();
|
||||
return options;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 046c3854296c5ec48bac50da6ca248ec
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,110 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using UnityEditor.IMGUI.Controls;
|
||||
using UnityEditor.TestTools.TestRunner.Api;
|
||||
using UnityEngine.TestRunner.NUnitExtensions;
|
||||
using UnityEngine.TestRunner.NUnitExtensions.Filters;
|
||||
|
||||
namespace UnityEditor.TestTools.TestRunner.GUI
|
||||
{
|
||||
internal class TestTreeViewBuilder
|
||||
{
|
||||
public List<TestRunnerResult> results = new List<TestRunnerResult>();
|
||||
private readonly List<TestRunnerResult> m_OldTestResultList;
|
||||
private readonly TestRunnerUIFilter m_UIFilter;
|
||||
private readonly ITestAdaptor m_TestListRoot;
|
||||
|
||||
private readonly List<string> m_AvailableCategories = new List<string>();
|
||||
|
||||
public string[] AvailableCategories
|
||||
{
|
||||
get { return m_AvailableCategories.Distinct().OrderBy(a => a).ToArray(); }
|
||||
}
|
||||
|
||||
public TestTreeViewBuilder(ITestAdaptor tests, List<TestRunnerResult> oldTestResultResults, TestRunnerUIFilter uiFilter)
|
||||
{
|
||||
m_AvailableCategories.Add(CategoryFilterExtended.k_DefaultCategory);
|
||||
m_OldTestResultList = oldTestResultResults;
|
||||
m_TestListRoot = tests;
|
||||
m_UIFilter = uiFilter;
|
||||
}
|
||||
|
||||
public TreeViewItem BuildTreeView(TestFilterSettings settings, bool sceneBased, string sceneName)
|
||||
{
|
||||
var rootItem = new TreeViewItem(int.MaxValue, 0, null, "Invisible Root Item");
|
||||
ParseTestTree(0, rootItem, m_TestListRoot);
|
||||
return rootItem;
|
||||
}
|
||||
|
||||
private bool IsFilteredOutByUIFilter(ITestAdaptor test, TestRunnerResult result)
|
||||
{
|
||||
if (m_UIFilter.PassedHidden && result.resultStatus == TestRunnerResult.ResultStatus.Passed)
|
||||
return true;
|
||||
if (m_UIFilter.FailedHidden && (result.resultStatus == TestRunnerResult.ResultStatus.Failed || result.resultStatus == TestRunnerResult.ResultStatus.Inconclusive))
|
||||
return true;
|
||||
if (m_UIFilter.NotRunHidden && (result.resultStatus == TestRunnerResult.ResultStatus.NotRun || result.resultStatus == TestRunnerResult.ResultStatus.Skipped))
|
||||
return true;
|
||||
if (m_UIFilter.CategoryFilter.Length > 0)
|
||||
return !test.Categories.Any(category => m_UIFilter.CategoryFilter.Contains(category));
|
||||
return false;
|
||||
}
|
||||
|
||||
private void ParseTestTree(int depth, TreeViewItem rootItem, ITestAdaptor testElement)
|
||||
{
|
||||
m_AvailableCategories.AddRange(testElement.Categories);
|
||||
|
||||
var testElementId = testElement.UniqueName;
|
||||
if (!testElement.HasChildren)
|
||||
{
|
||||
var result = m_OldTestResultList.FirstOrDefault(a => a.uniqueId == testElementId);
|
||||
|
||||
if (result != null &&
|
||||
(result.ignoredOrSkipped
|
||||
|| result.notRunnable
|
||||
|| testElement.RunState == RunState.NotRunnable
|
||||
|| testElement.RunState == RunState.Ignored
|
||||
|| testElement.RunState == RunState.Skipped
|
||||
)
|
||||
)
|
||||
{
|
||||
//if the test was or becomes ignored or not runnable, we recreate the result in case it has changed
|
||||
result = null;
|
||||
}
|
||||
if (result == null)
|
||||
{
|
||||
result = new TestRunnerResult(testElement);
|
||||
}
|
||||
results.Add(result);
|
||||
|
||||
var test = new TestTreeViewItem(testElement, depth, rootItem);
|
||||
if (!IsFilteredOutByUIFilter(testElement, result))
|
||||
rootItem.AddChild(test);
|
||||
test.SetResult(result);
|
||||
return;
|
||||
}
|
||||
|
||||
var groupResult = m_OldTestResultList.FirstOrDefault(a => a.uniqueId == testElementId);
|
||||
if (groupResult == null)
|
||||
{
|
||||
groupResult = new TestRunnerResult(testElement);
|
||||
}
|
||||
|
||||
results.Add(groupResult);
|
||||
var group = new TestTreeViewItem(testElement, depth, rootItem);
|
||||
group.SetResult(groupResult);
|
||||
|
||||
depth++;
|
||||
foreach (var child in testElement.Children)
|
||||
{
|
||||
ParseTestTree(depth, group, child);
|
||||
}
|
||||
|
||||
|
||||
if (testElement.IsTestAssembly && !testElement.HasChildren)
|
||||
return;
|
||||
|
||||
if (group.hasChildren)
|
||||
rootItem.AddChild(group);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: e17c88b021c2a4c409b3f15b0d80ac62
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,135 @@
|
|||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using UnityEditor.ProjectWindowCallback;
|
||||
using UnityEditor.Scripting.ScriptCompilation;
|
||||
using UnityEngine;
|
||||
|
||||
namespace UnityEditor.TestTools.TestRunner.GUI
|
||||
{
|
||||
internal class TestListGUIHelper
|
||||
{
|
||||
private const string kResourcesTemplatePath = "Resources/ScriptTemplates";
|
||||
private const string kAssemblyDefinitionTestTemplate = "92-Assembly Definition-NewTestAssembly.asmdef.txt";
|
||||
|
||||
private const string kAssemblyDefinitionEditModeTestTemplate =
|
||||
"92-Assembly Definition-NewEditModeTestAssembly.asmdef.txt";
|
||||
|
||||
private const string kTestScriptTemplate = "83-C# Script-NewTestScript.cs.txt";
|
||||
private const string kNewTestScriptName = "NewTestScript.cs";
|
||||
private const string kNunit = "nunit.framework.dll";
|
||||
|
||||
[MenuItem("Assets/Create/Testing/Tests Assembly Folder", false, 83)]
|
||||
public static void MenuItemAddFolderAndAsmDefForTesting()
|
||||
{
|
||||
AddFolderAndAsmDefForTesting();
|
||||
}
|
||||
|
||||
[MenuItem("Assets/Create/Testing/Tests Assembly Folder", true, 83)]
|
||||
public static bool MenuItemAddFolderAndAsmDefForTestingWithValidation()
|
||||
{
|
||||
return !SelectedFolderContainsTestAssembly();
|
||||
}
|
||||
|
||||
public static void AddFolderAndAsmDefForTesting(bool isEditorOnly = false)
|
||||
{
|
||||
ProjectWindowUtil.CreateFolderWithTemplates("Tests",
|
||||
isEditorOnly ? kAssemblyDefinitionEditModeTestTemplate : kAssemblyDefinitionTestTemplate);
|
||||
}
|
||||
|
||||
public static bool SelectedFolderContainsTestAssembly()
|
||||
{
|
||||
var theNearestCustomScriptAssembly = GetTheNearestCustomScriptAssembly();
|
||||
if (theNearestCustomScriptAssembly != null)
|
||||
{
|
||||
return theNearestCustomScriptAssembly.PrecompiledReferences != null && theNearestCustomScriptAssembly.PrecompiledReferences.Any(x => Path.GetFileName(x) == kNunit);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
[MenuItem("Assets/Create/Testing/C# Test Script", false, 83)]
|
||||
public static void AddTest()
|
||||
{
|
||||
var basePath = Path.Combine(EditorApplication.applicationContentsPath, kResourcesTemplatePath);
|
||||
var destPath = Path.Combine(GetActiveFolderPath(), kNewTestScriptName);
|
||||
var templatePath = Path.Combine(basePath, kTestScriptTemplate);
|
||||
var icon = EditorGUIUtility.IconContent("cs Script Icon").image as Texture2D;
|
||||
ProjectWindowUtil.StartNameEditingIfProjectWindowExists(0,
|
||||
ScriptableObject.CreateInstance<DoCreateScriptAsset>(), destPath, icon, templatePath);
|
||||
|
||||
AssetDatabase.Refresh();
|
||||
}
|
||||
|
||||
[MenuItem("Assets/Create/Testing/C# Test Script", true, 83)]
|
||||
public static bool CanAddScriptAndItWillCompile()
|
||||
{
|
||||
return CanAddEditModeTestScriptAndItWillCompile() || CanAddPlayModeTestScriptAndItWillCompile();
|
||||
}
|
||||
|
||||
public static bool CanAddEditModeTestScriptAndItWillCompile()
|
||||
{
|
||||
var theNearestCustomScriptAssembly = GetTheNearestCustomScriptAssembly();
|
||||
if (theNearestCustomScriptAssembly != null)
|
||||
{
|
||||
return (theNearestCustomScriptAssembly.AssemblyFlags & AssemblyFlags.EditorOnly) ==
|
||||
AssemblyFlags.EditorOnly;
|
||||
}
|
||||
|
||||
var activeFolderPath = GetActiveFolderPath();
|
||||
return activeFolderPath.ToLower().Contains("/editor");
|
||||
}
|
||||
|
||||
public static bool CanAddPlayModeTestScriptAndItWillCompile()
|
||||
{
|
||||
if (PlayerSettings.playModeTestRunnerEnabled)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
var theNearestCustomScriptAssembly = GetTheNearestCustomScriptAssembly();
|
||||
|
||||
if (theNearestCustomScriptAssembly == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var hasTestAssemblyFlag = theNearestCustomScriptAssembly.PrecompiledReferences != null && theNearestCustomScriptAssembly.PrecompiledReferences.Any(x => Path.GetFileName(x) == kNunit);;
|
||||
var editorOnlyAssembly = (theNearestCustomScriptAssembly.AssemblyFlags & AssemblyFlags.EditorOnly) != 0;
|
||||
|
||||
return hasTestAssemblyFlag && !editorOnlyAssembly;
|
||||
}
|
||||
|
||||
public static string GetActiveFolderPath()
|
||||
{
|
||||
var path = "Assets";
|
||||
|
||||
foreach (var obj in Selection.GetFiltered(typeof(UnityEngine.Object), SelectionMode.Assets))
|
||||
{
|
||||
path = AssetDatabase.GetAssetPath(obj);
|
||||
if (!string.IsNullOrEmpty(path) && File.Exists(path))
|
||||
{
|
||||
path = Path.GetDirectoryName(path);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return path;
|
||||
}
|
||||
|
||||
private static CustomScriptAssembly GetTheNearestCustomScriptAssembly()
|
||||
{
|
||||
CustomScriptAssembly findCustomScriptAssemblyFromScriptPath;
|
||||
try
|
||||
{
|
||||
findCustomScriptAssemblyFromScriptPath =
|
||||
EditorCompilationInterface.Instance.FindCustomScriptAssemblyFromScriptPath(
|
||||
Path.Combine(GetActiveFolderPath(), "Foo.cs"));
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
return findCustomScriptAssemblyFromScriptPath;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 97a05971510726f438153cd4987526fb
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,8 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 68cb547af0187634aad591a09c01cd5b
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,24 @@
|
|||
using UnityEngine;
|
||||
|
||||
namespace UnityEditor.TestTools.TestRunner.GUI
|
||||
{
|
||||
internal static class Icons
|
||||
{
|
||||
public static readonly Texture2D s_FailImg;
|
||||
public static readonly Texture2D s_IgnoreImg;
|
||||
public static readonly Texture2D s_SuccessImg;
|
||||
public static readonly Texture2D s_UnknownImg;
|
||||
public static readonly Texture2D s_InconclusiveImg;
|
||||
public static readonly Texture2D s_StopwatchImg;
|
||||
|
||||
static Icons()
|
||||
{
|
||||
s_FailImg = EditorGUIUtility.IconContent("TestFailed").image as Texture2D;
|
||||
s_IgnoreImg = EditorGUIUtility.IconContent("TestIgnored").image as Texture2D;
|
||||
s_SuccessImg = EditorGUIUtility.IconContent("TestPassed").image as Texture2D;
|
||||
s_UnknownImg = EditorGUIUtility.IconContent("TestNormal").image as Texture2D;
|
||||
s_InconclusiveImg = EditorGUIUtility.IconContent("TestInconclusive").image as Texture2D;
|
||||
s_StopwatchImg = EditorGUIUtility.IconContent("TestStopwatch").image as Texture2D;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 27769e9b00b038d47aefe306a4d20bec
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,98 @@
|
|||
using System.Collections.Generic;
|
||||
using NUnit.Framework.Interfaces;
|
||||
using UnityEditor.IMGUI.Controls;
|
||||
using UnityEditor.TestTools.TestRunner.Api;
|
||||
using UnityEngine.SceneManagement;
|
||||
using UnityEngine.TestTools.TestRunner;
|
||||
|
||||
namespace UnityEditor.TestTools.TestRunner.GUI
|
||||
{
|
||||
internal class TestListTreeViewDataSource : TreeViewDataSource
|
||||
{
|
||||
private bool m_ExpandTreeOnCreation;
|
||||
private readonly TestListGUI m_TestListGUI;
|
||||
private ITestAdaptor m_RootTest;
|
||||
|
||||
public TestListTreeViewDataSource(TreeViewController testListTree, TestListGUI testListGUI, ITestAdaptor rootTest) : base(testListTree)
|
||||
{
|
||||
showRootItem = false;
|
||||
rootIsCollapsable = false;
|
||||
m_TestListGUI = testListGUI;
|
||||
m_RootTest = rootTest;
|
||||
}
|
||||
|
||||
public void UpdateRootTest(ITestAdaptor rootTest)
|
||||
{
|
||||
m_RootTest = rootTest;
|
||||
}
|
||||
|
||||
public override void FetchData()
|
||||
{
|
||||
var sceneName = SceneManager.GetActiveScene().name;
|
||||
if (sceneName.StartsWith("InitTestScene"))
|
||||
sceneName = PlaymodeTestsController.GetController().settings.originalScene;
|
||||
|
||||
var testListBuilder = new TestTreeViewBuilder(m_RootTest, m_TestListGUI.newResultList, m_TestListGUI.m_TestRunnerUIFilter);
|
||||
|
||||
m_RootItem = testListBuilder.BuildTreeView(null, false, sceneName);
|
||||
SetExpanded(m_RootItem, true);
|
||||
if (m_RootItem.hasChildren && m_RootItem.children.Count == 1)
|
||||
SetExpanded(m_RootItem.children[0], true);
|
||||
|
||||
if (m_ExpandTreeOnCreation)
|
||||
SetExpandedWithChildren(m_RootItem, true);
|
||||
|
||||
m_TestListGUI.newResultList = new List<TestRunnerResult>(testListBuilder.results);
|
||||
m_TestListGUI.m_TestRunnerUIFilter.availableCategories = testListBuilder.AvailableCategories;
|
||||
m_NeedRefreshRows = true;
|
||||
}
|
||||
|
||||
public override bool IsRenamingItemAllowed(TreeViewItem item)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
public void ExpandTreeOnCreation()
|
||||
{
|
||||
m_ExpandTreeOnCreation = true;
|
||||
}
|
||||
|
||||
public override bool IsExpandable(TreeViewItem item)
|
||||
{
|
||||
if (item is TestTreeViewItem)
|
||||
return ((TestTreeViewItem)item).IsGroupNode;
|
||||
return base.IsExpandable(item);
|
||||
}
|
||||
|
||||
protected override List<TreeViewItem> Search(TreeViewItem rootItem, string search)
|
||||
{
|
||||
var result = new List<TreeViewItem>();
|
||||
|
||||
if (rootItem.hasChildren)
|
||||
{
|
||||
foreach (var child in rootItem.children)
|
||||
{
|
||||
SearchTestTree(child, search, result);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
protected void SearchTestTree(TreeViewItem item, string search, IList<TreeViewItem> searchResult)
|
||||
{
|
||||
var testItem = item as TestTreeViewItem;
|
||||
if (!testItem.IsGroupNode)
|
||||
{
|
||||
if (testItem.FullName.ToLower().Contains(search))
|
||||
{
|
||||
searchResult.Add(item);
|
||||
}
|
||||
}
|
||||
else if (item.children != null)
|
||||
{
|
||||
foreach (var child in item.children)
|
||||
SearchTestTree(child, search, searchResult);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: ce87c287371edde43a4b5fcfdee7b9ef
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,11 @@
|
|||
using UnityEditor.IMGUI.Controls;
|
||||
|
||||
namespace UnityEditor.TestTools.TestRunner.GUI
|
||||
{
|
||||
internal class TestListTreeViewGUI : TreeViewGUI
|
||||
{
|
||||
public TestListTreeViewGUI(TreeViewController testListTree) : base(testListTree)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 52c907c81459f324497af504b84fd557
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,137 @@
|
|||
using System;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
using UnityEditor.IMGUI.Controls;
|
||||
using UnityEditor.TestTools.TestRunner.Api;
|
||||
|
||||
namespace UnityEditor.TestTools.TestRunner.GUI
|
||||
{
|
||||
internal sealed class TestTreeViewItem : TreeViewItem
|
||||
{
|
||||
public TestRunnerResult result;
|
||||
internal ITestAdaptor m_Test;
|
||||
|
||||
public Type type;
|
||||
public MethodInfo method;
|
||||
|
||||
private const int k_ResultTestMaxLength = 15000;
|
||||
|
||||
public bool IsGroupNode { get { return m_Test.IsSuite; } }
|
||||
|
||||
public string FullName { get { return m_Test.FullName; } }
|
||||
|
||||
public string GetAssemblyName()
|
||||
{
|
||||
var test = m_Test;
|
||||
while (test != null)
|
||||
{
|
||||
if (test.IsTestAssembly)
|
||||
{
|
||||
return test.FullName;
|
||||
}
|
||||
|
||||
test = test.Parent;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public TestTreeViewItem(ITestAdaptor test, int depth, TreeViewItem parent)
|
||||
: base(GetId(test), depth, parent, test.Name)
|
||||
{
|
||||
m_Test = test;
|
||||
|
||||
if (test.TypeInfo != null)
|
||||
{
|
||||
type = test.TypeInfo.Type;
|
||||
}
|
||||
if (test.Method != null)
|
||||
{
|
||||
method = test.Method.MethodInfo;
|
||||
}
|
||||
|
||||
displayName = test.Name.Replace("\n", "");
|
||||
icon = Icons.s_UnknownImg;
|
||||
}
|
||||
|
||||
private static int GetId(ITestAdaptor test)
|
||||
{
|
||||
return test.UniqueName.GetHashCode();
|
||||
}
|
||||
|
||||
public void SetResult(TestRunnerResult testResult)
|
||||
{
|
||||
result = testResult;
|
||||
result.SetResultChangedCallback(ResultUpdated);
|
||||
ResultUpdated(result);
|
||||
}
|
||||
|
||||
public string GetResultText()
|
||||
{
|
||||
if (result.resultStatus == TestRunnerResult.ResultStatus.NotRun)
|
||||
{
|
||||
return string.Empty;
|
||||
}
|
||||
var durationString = String.Format("{0:0.000}", result.duration);
|
||||
var sb = new StringBuilder(string.Format("{0} ({1}s)", displayName.Trim(), durationString));
|
||||
if (!string.IsNullOrEmpty(result.description))
|
||||
{
|
||||
sb.AppendFormat("\n{0}", result.description);
|
||||
}
|
||||
if (!string.IsNullOrEmpty(result.messages))
|
||||
{
|
||||
sb.Append("\n---\n");
|
||||
sb.Append(result.messages.Trim());
|
||||
}
|
||||
if (!string.IsNullOrEmpty(result.stacktrace))
|
||||
{
|
||||
sb.Append("\n---\n");
|
||||
sb.Append(result.stacktrace.Trim());
|
||||
}
|
||||
if (!string.IsNullOrEmpty(result.output))
|
||||
{
|
||||
sb.Append("\n---\n");
|
||||
sb.Append(result.output.Trim());
|
||||
}
|
||||
if (sb.Length > k_ResultTestMaxLength)
|
||||
{
|
||||
sb.Length = k_ResultTestMaxLength;
|
||||
sb.AppendFormat("...\n\n---MESSAGE TRUNCATED AT {0} CHARACTERS---", k_ResultTestMaxLength);
|
||||
}
|
||||
return sb.ToString().Trim();
|
||||
}
|
||||
|
||||
private void ResultUpdated(TestRunnerResult testResult)
|
||||
{
|
||||
switch (testResult.resultStatus)
|
||||
{
|
||||
case TestRunnerResult.ResultStatus.Passed:
|
||||
icon = Icons.s_SuccessImg;
|
||||
break;
|
||||
case TestRunnerResult.ResultStatus.Failed:
|
||||
icon = Icons.s_FailImg;
|
||||
break;
|
||||
case TestRunnerResult.ResultStatus.Inconclusive:
|
||||
icon = Icons.s_InconclusiveImg;
|
||||
break;
|
||||
case TestRunnerResult.ResultStatus.Skipped:
|
||||
icon = Icons.s_IgnoreImg;
|
||||
break;
|
||||
default:
|
||||
if (testResult.ignoredOrSkipped)
|
||||
{
|
||||
icon = Icons.s_IgnoreImg;
|
||||
}
|
||||
else if (testResult.notRunnable)
|
||||
{
|
||||
icon = Icons.s_FailImg;
|
||||
}
|
||||
else
|
||||
{
|
||||
icon = Icons.s_UnknownImg;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: ce567ddbf30368344bc7b80e20cac36e
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,148 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using UnityEditor.TestTools.TestRunner.Api;
|
||||
|
||||
namespace UnityEditor.TestTools.TestRunner.GUI
|
||||
{
|
||||
[Serializable]
|
||||
internal class TestRunnerResult : UITestRunnerFilter.IClearableResult
|
||||
{
|
||||
public string id;
|
||||
public string uniqueId;
|
||||
public string name;
|
||||
public string fullName;
|
||||
public ResultStatus resultStatus = ResultStatus.NotRun;
|
||||
public float duration;
|
||||
public string messages;
|
||||
public string output;
|
||||
public string stacktrace;
|
||||
public bool notRunnable;
|
||||
public bool ignoredOrSkipped;
|
||||
public string description;
|
||||
public bool isSuite;
|
||||
public List<string> categories;
|
||||
public string parentId;
|
||||
public string parentUniqueId;
|
||||
|
||||
//This field is suppose to mark results from before domain reload
|
||||
//Such result is outdated because the code might haev changed
|
||||
//This field will get reset every time a domain reload happens
|
||||
[NonSerialized]
|
||||
public bool notOutdated;
|
||||
|
||||
protected Action<TestRunnerResult> m_OnResultUpdate;
|
||||
|
||||
internal TestRunnerResult(ITestAdaptor test)
|
||||
{
|
||||
id = test.Id;
|
||||
uniqueId = test.UniqueName;
|
||||
|
||||
fullName = test.FullName;
|
||||
name = test.Name;
|
||||
description = test.Description;
|
||||
isSuite = test.IsSuite;
|
||||
|
||||
ignoredOrSkipped = test.RunState == RunState.Ignored || test.RunState == RunState.Skipped;
|
||||
notRunnable = test.RunState == RunState.NotRunnable;
|
||||
|
||||
if (ignoredOrSkipped)
|
||||
{
|
||||
messages = test.SkipReason;
|
||||
}
|
||||
if (notRunnable)
|
||||
{
|
||||
resultStatus = ResultStatus.Failed;
|
||||
messages = test.SkipReason;
|
||||
}
|
||||
categories = test.Categories.ToList();
|
||||
parentId = test.ParentId;
|
||||
parentUniqueId = test.ParentUniqueName;
|
||||
}
|
||||
|
||||
internal TestRunnerResult(ITestResultAdaptor testResult) : this(testResult.Test)
|
||||
{
|
||||
notOutdated = true;
|
||||
|
||||
messages = testResult.Message;
|
||||
output = testResult.Output;
|
||||
stacktrace = testResult.StackTrace;
|
||||
duration = (float)testResult.Duration;
|
||||
if (testResult.Test.IsSuite && testResult.ResultState == "Ignored")
|
||||
{
|
||||
resultStatus = ResultStatus.Passed;
|
||||
}
|
||||
else
|
||||
{
|
||||
resultStatus = ParseNUnitResultStatus(testResult.TestStatus);
|
||||
}
|
||||
}
|
||||
|
||||
public void Update(TestRunnerResult result)
|
||||
{
|
||||
if (ReferenceEquals(result, null))
|
||||
return;
|
||||
resultStatus = result.resultStatus;
|
||||
duration = result.duration;
|
||||
messages = result.messages;
|
||||
output = result.output;
|
||||
stacktrace = result.stacktrace;
|
||||
ignoredOrSkipped = result.ignoredOrSkipped;
|
||||
notRunnable = result.notRunnable;
|
||||
description = result.description;
|
||||
notOutdated = result.notOutdated;
|
||||
if (m_OnResultUpdate != null)
|
||||
m_OnResultUpdate(this);
|
||||
}
|
||||
|
||||
public void SetResultChangedCallback(Action<TestRunnerResult> resultUpdated)
|
||||
{
|
||||
m_OnResultUpdate = resultUpdated;
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
internal enum ResultStatus
|
||||
{
|
||||
NotRun,
|
||||
Passed,
|
||||
Failed,
|
||||
Inconclusive,
|
||||
Skipped
|
||||
}
|
||||
|
||||
private static ResultStatus ParseNUnitResultStatus(TestStatus status)
|
||||
{
|
||||
switch (status)
|
||||
{
|
||||
case TestStatus.Passed:
|
||||
return ResultStatus.Passed;
|
||||
case TestStatus.Failed:
|
||||
return ResultStatus.Failed;
|
||||
case TestStatus.Inconclusive:
|
||||
return ResultStatus.Inconclusive;
|
||||
case TestStatus.Skipped:
|
||||
return ResultStatus.Skipped;
|
||||
default:
|
||||
return ResultStatus.NotRun;
|
||||
}
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return string.Format("{0} ({1})", name, fullName);
|
||||
}
|
||||
|
||||
public string Id { get { return uniqueId; } }
|
||||
public string FullName { get { return fullName; } }
|
||||
public string ParentId { get { return parentUniqueId; } }
|
||||
public bool IsSuite { get { return isSuite; } }
|
||||
public List<string> Categories { get { return categories; } }
|
||||
|
||||
public void Clear()
|
||||
{
|
||||
resultStatus = ResultStatus.NotRun;
|
||||
if (m_OnResultUpdate != null)
|
||||
m_OnResultUpdate(this);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: a04a45bbed9e1714f9902fc9443669b9
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,177 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using UnityEngine;
|
||||
|
||||
namespace UnityEditor.TestTools.TestRunner.GUI
|
||||
{
|
||||
[Serializable]
|
||||
internal class TestRunnerUIFilter
|
||||
{
|
||||
private int m_PassedCount;
|
||||
private int m_FailedCount;
|
||||
private int m_NotRunCount;
|
||||
private int m_InconclusiveCount;
|
||||
private int m_SkippedCount;
|
||||
|
||||
public int PassedCount { get { return m_PassedCount; } }
|
||||
public int FailedCount { get { return m_FailedCount + m_InconclusiveCount; } }
|
||||
public int NotRunCount { get { return m_NotRunCount + m_SkippedCount; } }
|
||||
|
||||
[SerializeField]
|
||||
public bool PassedHidden;
|
||||
[SerializeField]
|
||||
public bool FailedHidden;
|
||||
[SerializeField]
|
||||
public bool NotRunHidden;
|
||||
|
||||
[SerializeField]
|
||||
private string m_SearchString;
|
||||
[SerializeField]
|
||||
private int selectedCategoryMask;
|
||||
|
||||
public string[] availableCategories = new string[0];
|
||||
|
||||
|
||||
private GUIContent m_SucceededBtn;
|
||||
private GUIContent m_FailedBtn;
|
||||
private GUIContent m_NotRunBtn;
|
||||
|
||||
public Action RebuildTestList;
|
||||
public Action<string> SearchStringChanged;
|
||||
public Action SearchStringCleared;
|
||||
public bool IsFiltering
|
||||
{
|
||||
get
|
||||
{
|
||||
return !string.IsNullOrEmpty(m_SearchString) || PassedHidden || FailedHidden || NotRunHidden ||
|
||||
selectedCategoryMask != 0;
|
||||
}
|
||||
}
|
||||
|
||||
public string[] CategoryFilter
|
||||
{
|
||||
get
|
||||
{
|
||||
var list = new List<string>();
|
||||
for (int i = 0; i < availableCategories.Length; i++)
|
||||
{
|
||||
if ((selectedCategoryMask & (1 << i)) != 0)
|
||||
{
|
||||
list.Add(availableCategories[i]);
|
||||
}
|
||||
}
|
||||
return list.ToArray();
|
||||
}
|
||||
}
|
||||
|
||||
public void UpdateCounters(List<TestRunnerResult> resultList)
|
||||
{
|
||||
m_PassedCount = m_FailedCount = m_NotRunCount = m_InconclusiveCount = m_SkippedCount = 0;
|
||||
foreach (var result in resultList)
|
||||
{
|
||||
if (result.isSuite)
|
||||
continue;
|
||||
switch (result.resultStatus)
|
||||
{
|
||||
case TestRunnerResult.ResultStatus.Passed:
|
||||
m_PassedCount++;
|
||||
break;
|
||||
case TestRunnerResult.ResultStatus.Failed:
|
||||
m_FailedCount++;
|
||||
break;
|
||||
case TestRunnerResult.ResultStatus.Inconclusive:
|
||||
m_InconclusiveCount++;
|
||||
break;
|
||||
case TestRunnerResult.ResultStatus.Skipped:
|
||||
m_SkippedCount++;
|
||||
break;
|
||||
case TestRunnerResult.ResultStatus.NotRun:
|
||||
default:
|
||||
m_NotRunCount++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
var succeededTooltip = string.Format("Show tests that succeeded\n{0} succeeded", m_PassedCount);
|
||||
m_SucceededBtn = new GUIContent(PassedCount.ToString(), Icons.s_SuccessImg, succeededTooltip);
|
||||
var failedTooltip = string.Format("Show tests that failed\n{0} failed\n{1} inconclusive", m_FailedCount, m_InconclusiveCount);
|
||||
m_FailedBtn = new GUIContent(FailedCount.ToString(), Icons.s_FailImg, failedTooltip);
|
||||
var notRunTooltip = string.Format("Show tests that didn't run\n{0} didn't run\n{1} skipped or ignored", m_NotRunCount, m_SkippedCount);
|
||||
m_NotRunBtn = new GUIContent(NotRunCount.ToString(), Icons.s_UnknownImg, notRunTooltip);
|
||||
}
|
||||
|
||||
public void Draw()
|
||||
{
|
||||
EditorGUI.BeginChangeCheck();
|
||||
if (m_SearchString == null)
|
||||
{
|
||||
m_SearchString = "";
|
||||
}
|
||||
m_SearchString = EditorGUILayout.ToolbarSearchField(m_SearchString);
|
||||
if (EditorGUI.EndChangeCheck() && SearchStringChanged != null)
|
||||
{
|
||||
SearchStringChanged(m_SearchString);
|
||||
if (String.IsNullOrEmpty(m_SearchString))
|
||||
SearchStringCleared();
|
||||
}
|
||||
|
||||
if (availableCategories != null && availableCategories.Any())
|
||||
{
|
||||
EditorGUI.BeginChangeCheck();
|
||||
selectedCategoryMask = EditorGUILayout.MaskField(selectedCategoryMask, availableCategories, EditorStyles.toolbarDropDown, GUILayout.MaxWidth(150));
|
||||
if (EditorGUI.EndChangeCheck() && RebuildTestList != null)
|
||||
{
|
||||
RebuildTestList();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
EditorGUILayout.Popup(0, new[] { "<No categories available>" }, EditorStyles.toolbarDropDown, GUILayout.MaxWidth(150));
|
||||
}
|
||||
|
||||
EditorGUI.BeginChangeCheck();
|
||||
if (m_SucceededBtn != null)
|
||||
{
|
||||
PassedHidden = !GUILayout.Toggle(!PassedHidden, m_SucceededBtn, EditorStyles.toolbarButton, GUILayout.MaxWidth(GetMaxWidth(PassedCount)));
|
||||
}
|
||||
if (m_FailedBtn != null)
|
||||
{
|
||||
FailedHidden = !GUILayout.Toggle(!FailedHidden, m_FailedBtn, EditorStyles.toolbarButton, GUILayout.MaxWidth(GetMaxWidth(FailedCount)));
|
||||
}
|
||||
if (m_NotRunBtn != null)
|
||||
{
|
||||
NotRunHidden = !GUILayout.Toggle(!NotRunHidden, m_NotRunBtn, EditorStyles.toolbarButton, GUILayout.MaxWidth(GetMaxWidth(NotRunCount)));
|
||||
}
|
||||
|
||||
if (EditorGUI.EndChangeCheck() && RebuildTestList != null)
|
||||
{
|
||||
RebuildTestList();
|
||||
}
|
||||
}
|
||||
|
||||
private static int GetMaxWidth(int count)
|
||||
{
|
||||
if (count < 10)
|
||||
return 33;
|
||||
return count < 100 ? 40 : 47;
|
||||
}
|
||||
|
||||
public void Clear()
|
||||
{
|
||||
PassedHidden = false;
|
||||
FailedHidden = false;
|
||||
NotRunHidden = false;
|
||||
selectedCategoryMask = 0;
|
||||
m_SearchString = "";
|
||||
if (SearchStringChanged != null)
|
||||
{
|
||||
SearchStringChanged(m_SearchString);
|
||||
}
|
||||
if (SearchStringCleared != null)
|
||||
{
|
||||
SearchStringCleared();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 15f870c6975ad6449b5b52514b90dc2b
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,164 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace UnityEditor.TestTools.TestRunner.GUI
|
||||
{
|
||||
[Serializable]
|
||||
internal class UITestRunnerFilter
|
||||
{
|
||||
#pragma warning disable 649
|
||||
public string[] assemblyNames;
|
||||
public string[] groupNames;
|
||||
public string[] categoryNames;
|
||||
public string[] testNames;
|
||||
public int testRepetitions = 1;
|
||||
public bool synchronousOnly = false;
|
||||
|
||||
public static string AssemblyNameFromPath(string path)
|
||||
{
|
||||
string output = Path.GetFileName(path);
|
||||
if (output != null && output.EndsWith(".dll", StringComparison.OrdinalIgnoreCase))
|
||||
return output.Substring(0, output.Length - 4);
|
||||
return output;
|
||||
}
|
||||
|
||||
private bool CategoryMatches(IEnumerable<string> categories)
|
||||
{
|
||||
if (categoryNames == null || categoryNames.Length == 0)
|
||||
return true;
|
||||
|
||||
foreach (string category in categories)
|
||||
{
|
||||
if (categoryNames.Contains(category))
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private bool IDMatchesAssembly(string id)
|
||||
{
|
||||
if (AreOptionalFiltersEmpty())
|
||||
return true;
|
||||
|
||||
if (assemblyNames == null || assemblyNames.Length == 0)
|
||||
return true;
|
||||
|
||||
int openingBracket = id.IndexOf('[');
|
||||
int closingBracket = id.IndexOf(']');
|
||||
if (openingBracket >= 0 && openingBracket < id.Length && closingBracket > openingBracket &&
|
||||
openingBracket < id.Length)
|
||||
{
|
||||
//Some assemblies are absolute and explicitly part of the test ID e.g.
|
||||
//"[/path/to/assembly-name.dll][rest of ID ...]"
|
||||
//While some are minimal assembly names e.g.
|
||||
//"[assembly-name][rest of ID ...]"
|
||||
//Strip them down to just the assembly name
|
||||
string assemblyNameFromID =
|
||||
AssemblyNameFromPath(id.Substring(openingBracket + 1, closingBracket - openingBracket - 1));
|
||||
foreach (string assemblyName in assemblyNames)
|
||||
{
|
||||
if (assemblyName.Equals(assemblyNameFromID, StringComparison.OrdinalIgnoreCase))
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private bool NameMatches(string name)
|
||||
{
|
||||
if (AreOptionalFiltersEmpty())
|
||||
return true;
|
||||
|
||||
if (groupNames == null || groupNames.Length == 0)
|
||||
return true;
|
||||
|
||||
foreach (var nameFromFilter in groupNames)
|
||||
{
|
||||
//Strict regex match for test group name on its own
|
||||
if (Regex.IsMatch(name, nameFromFilter))
|
||||
return true;
|
||||
//Match test names that end with parametrized test values and full nunit generated test names that have . separators
|
||||
var regex = nameFromFilter.TrimEnd('$') + @"[\.|\(.*\)]";
|
||||
if (Regex.IsMatch(name, regex))
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private bool AreOptionalFiltersEmpty()
|
||||
{
|
||||
if (assemblyNames != null && assemblyNames.Length != 0)
|
||||
return false;
|
||||
if (groupNames != null && groupNames.Length != 0)
|
||||
return false;
|
||||
if (testNames != null && testNames.Length != 0)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
private bool NameMatchesExactly(string name)
|
||||
{
|
||||
if (AreOptionalFiltersEmpty())
|
||||
return true;
|
||||
|
||||
if (testNames == null || testNames.Length == 0)
|
||||
return true;
|
||||
|
||||
foreach (var exactName in testNames)
|
||||
{
|
||||
if (name == exactName)
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private static void ClearAncestors(IEnumerable<IClearableResult> newResultList, string parentID)
|
||||
{
|
||||
if (string.IsNullOrEmpty(parentID))
|
||||
return;
|
||||
foreach (var result in newResultList)
|
||||
{
|
||||
if (result.Id == parentID)
|
||||
{
|
||||
result.Clear();
|
||||
ClearAncestors(newResultList, result.ParentId);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void ClearResults(List<IClearableResult> newResultList)
|
||||
{
|
||||
foreach (var result in newResultList)
|
||||
{
|
||||
if (!result.IsSuite && CategoryMatches(result.Categories))
|
||||
{
|
||||
if (IDMatchesAssembly(result.Id) && NameMatches(result.FullName) &&
|
||||
NameMatchesExactly(result.FullName))
|
||||
{
|
||||
result.Clear();
|
||||
ClearAncestors(newResultList, result.ParentId);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal interface IClearableResult
|
||||
{
|
||||
string Id { get; }
|
||||
string FullName { get; }
|
||||
string ParentId { get; }
|
||||
bool IsSuite { get; }
|
||||
List<string> Categories { get; }
|
||||
void Clear();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 8069e1fc631e461ababf11f19a9c0df3
|
||||
timeCreated: 1595586126
|
|
@ -0,0 +1,8 @@
|
|||
fileFormatVersion: 2
|
||||
guid: c5535d742ea2e4941850b421f9c70a1f
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,92 @@
|
|||
using System;
|
||||
using System.Linq;
|
||||
using UnityEditor.TestTools.TestRunner.Api;
|
||||
using UnityEngine;
|
||||
using UnityEngine.TestTools;
|
||||
|
||||
namespace UnityEditor.TestTools.TestRunner.GUI
|
||||
{
|
||||
[Serializable]
|
||||
internal class EditModeTestListGUI : TestListGUI
|
||||
{
|
||||
public override TestMode TestMode
|
||||
{
|
||||
get { return TestMode.EditMode; }
|
||||
}
|
||||
|
||||
public override void RenderNoTestsInfo()
|
||||
{
|
||||
if (!TestListGUIHelper.SelectedFolderContainsTestAssembly())
|
||||
{
|
||||
var noTestText = "No tests to show";
|
||||
|
||||
if (!PlayerSettings.playModeTestRunnerEnabled)
|
||||
{
|
||||
const string testsArePulledFromCustomAssemblies =
|
||||
"EditMode tests can be in Editor only Assemblies, either in the editor special folder or Editor only Assembly Definitions that references the \"nunit.framework.dll\" Assembly Reference or any of the Assembly Definition References \"UnityEngine.TestRunner\" or \"UnityEditor.TestRunner\"..";
|
||||
noTestText += Environment.NewLine + testsArePulledFromCustomAssemblies;
|
||||
}
|
||||
|
||||
EditorGUILayout.HelpBox(noTestText, MessageType.Info);
|
||||
if (GUILayout.Button("Create EditMode Test Assembly Folder"))
|
||||
{
|
||||
TestListGUIHelper.AddFolderAndAsmDefForTesting(isEditorOnly: true);
|
||||
}
|
||||
}
|
||||
|
||||
if (!TestListGUIHelper.CanAddEditModeTestScriptAndItWillCompile())
|
||||
{
|
||||
UnityEngine.GUI.enabled = false;
|
||||
EditorGUILayout.HelpBox("EditMode test scripts can only be created in editor test assemblies.", MessageType.Warning);
|
||||
}
|
||||
if (GUILayout.Button("Create Test Script in current folder"))
|
||||
{
|
||||
TestListGUIHelper.AddTest();
|
||||
}
|
||||
UnityEngine.GUI.enabled = true;
|
||||
}
|
||||
|
||||
public override void PrintHeadPanel()
|
||||
{
|
||||
base.PrintHeadPanel();
|
||||
DrawFilters();
|
||||
}
|
||||
|
||||
protected override void RunTests(params UITestRunnerFilter[] filters)
|
||||
{
|
||||
if (EditorUtility.scriptCompilationFailed)
|
||||
{
|
||||
Debug.LogError("Fix compilation issues before running tests");
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (var filter in filters)
|
||||
{
|
||||
filter.ClearResults(newResultList.OfType<UITestRunnerFilter.IClearableResult>().ToList());
|
||||
}
|
||||
|
||||
RerunCallbackData.instance.runFilters = filters;
|
||||
RerunCallbackData.instance.testMode = TestMode.EditMode;
|
||||
|
||||
var testRunnerApi = ScriptableObject.CreateInstance<TestRunnerApi>();
|
||||
testRunnerApi.Execute(new ExecutionSettings()
|
||||
{
|
||||
filters = filters.Select(filter => new Filter()
|
||||
{
|
||||
assemblyNames = filter.assemblyNames,
|
||||
categoryNames = filter.categoryNames,
|
||||
groupNames = filter.groupNames,
|
||||
testMode = TestMode,
|
||||
testNames = filter.testNames
|
||||
}).ToArray()
|
||||
});
|
||||
}
|
||||
|
||||
public override TestPlatform TestPlatform { get { return TestPlatform.EditMode; } }
|
||||
|
||||
protected override bool IsBusy()
|
||||
{
|
||||
return TestRunnerApi.IsRunActive() || EditorApplication.isCompiling || EditorApplication.isPlaying;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 0336a32a79bfaed43a3fd2d88b91e974
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,241 @@
|
|||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using UnityEditor.SceneManagement;
|
||||
using UnityEditor.TestTools.TestRunner.Api;
|
||||
using UnityEngine;
|
||||
using UnityEngine.TestTools;
|
||||
|
||||
namespace UnityEditor.TestTools.TestRunner.GUI
|
||||
{
|
||||
[Serializable]
|
||||
internal class PlayModeTestListGUI : TestListGUI
|
||||
{
|
||||
private struct PlayerMenuItem
|
||||
{
|
||||
public GUIContent name;
|
||||
public bool filterSelectedTestsOnly;
|
||||
public bool buildOnly;
|
||||
}
|
||||
|
||||
[SerializeField]
|
||||
private int m_SelectedOption;
|
||||
|
||||
public override TestMode TestMode
|
||||
{
|
||||
get { return TestMode.PlayMode; }
|
||||
}
|
||||
|
||||
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 ExecuteAction(PlayerMenuItem item)
|
||||
{
|
||||
var runSettings = new PlayerLauncherTestRunSettings();
|
||||
runSettings.buildOnly = item.buildOnly;
|
||||
if (runSettings.buildOnly)
|
||||
{
|
||||
runSettings.buildOnlyLocationPath = PickBuildLocation();
|
||||
if (string.IsNullOrEmpty(runSettings.buildOnlyLocationPath))
|
||||
{
|
||||
Debug.LogWarning("Aborting, build selection was canceled.");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (item.filterSelectedTestsOnly)
|
||||
RunTestsInPlayer(runSettings, SelectedTestsFilter);
|
||||
else
|
||||
{
|
||||
var filter = new UITestRunnerFilter { categoryNames = m_TestRunnerUIFilter.CategoryFilter };
|
||||
RunTestsInPlayer(runSettings, filter);
|
||||
}
|
||||
}
|
||||
|
||||
public override void PrintHeadPanel()
|
||||
{
|
||||
EditorGUILayout.BeginHorizontal(GUILayout.ExpandHeight(false));
|
||||
base.PrintHeadPanel();
|
||||
|
||||
PlayerMenuItem[] menuItems;
|
||||
|
||||
if (EditorUserBuildSettings.installInBuildFolder)
|
||||
{
|
||||
menuItems = new []
|
||||
{
|
||||
// Note: We select here buildOnly = false, so build location dialog won't show up
|
||||
// The player won't actually be ran when using together with EditorUserBuildSettings.installInBuildFolder
|
||||
new PlayerMenuItem()
|
||||
{
|
||||
name = new GUIContent("Install All Tests In Build Folder"), buildOnly = false, filterSelectedTestsOnly = false
|
||||
},
|
||||
new PlayerMenuItem()
|
||||
{
|
||||
name = new GUIContent("Install Selected Tests In Build Folder"), buildOnly = false, filterSelectedTestsOnly = true
|
||||
}
|
||||
};
|
||||
}
|
||||
else
|
||||
{
|
||||
menuItems = new []
|
||||
{
|
||||
new PlayerMenuItem()
|
||||
{
|
||||
name = new GUIContent("Run All Tests"), buildOnly = false, filterSelectedTestsOnly = false
|
||||
},
|
||||
new PlayerMenuItem()
|
||||
{
|
||||
name = new GUIContent("Run Selected Tests"), buildOnly = false, filterSelectedTestsOnly = true
|
||||
},
|
||||
new PlayerMenuItem()
|
||||
{
|
||||
name = new GUIContent($"{GetBuildText()} All Tests"), buildOnly = true, filterSelectedTestsOnly = false
|
||||
},
|
||||
new PlayerMenuItem()
|
||||
{
|
||||
name = new GUIContent($"{GetBuildText()} Selected Tests"), buildOnly = true, filterSelectedTestsOnly = true
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
m_SelectedOption = Math.Min(m_SelectedOption, menuItems.Length - 1);
|
||||
var selectedMenuItem = menuItems[m_SelectedOption];
|
||||
if (GUILayout.Button(
|
||||
new GUIContent($"{selectedMenuItem.name.text} ({EditorUserBuildSettings.activeBuildTarget})"),
|
||||
EditorStyles.toolbarButton))
|
||||
{
|
||||
ExecuteAction(selectedMenuItem);
|
||||
}
|
||||
|
||||
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) => m_SelectedOption = selected,
|
||||
menuItems);
|
||||
}
|
||||
|
||||
EditorGUILayout.EndHorizontal();
|
||||
DrawFilters();
|
||||
EditorGUILayout.BeginHorizontal(GUILayout.ExpandHeight(false));
|
||||
EditorGUILayout.EndHorizontal();
|
||||
}
|
||||
|
||||
public override void RenderNoTestsInfo()
|
||||
{
|
||||
if (!TestListGUIHelper.SelectedFolderContainsTestAssembly())
|
||||
{
|
||||
var noTestText = "No tests to show";
|
||||
if (!PlayerSettings.playModeTestRunnerEnabled)
|
||||
{
|
||||
const string testsArePulledFromCustomAssemblues = "Test Assemblies are defined by Assembly Definitions that references the \"nunit.framework.dll\" Assembly Reference or the Assembly Definition Reference \"UnityEngine.TestRunner\".";
|
||||
const string infoTextAboutTestsInAllAssemblies =
|
||||
"To have tests in all assemblies enable it in the Test Runner window context menu";
|
||||
noTestText += Environment.NewLine + testsArePulledFromCustomAssemblues + Environment.NewLine +
|
||||
infoTextAboutTestsInAllAssemblies;
|
||||
}
|
||||
|
||||
EditorGUILayout.HelpBox(noTestText, MessageType.Info);
|
||||
if (GUILayout.Button("Create PlayMode Test Assembly Folder"))
|
||||
{
|
||||
TestListGUIHelper.AddFolderAndAsmDefForTesting();
|
||||
}
|
||||
}
|
||||
|
||||
if (!TestListGUIHelper.CanAddPlayModeTestScriptAndItWillCompile())
|
||||
{
|
||||
UnityEngine.GUI.enabled = false;
|
||||
EditorGUILayout.HelpBox("PlayMode test scripts can only be created in non editor test assemblies.", MessageType.Warning);
|
||||
}
|
||||
if (GUILayout.Button("Create Test Script in current folder"))
|
||||
{
|
||||
TestListGUIHelper.AddTest();
|
||||
}
|
||||
UnityEngine.GUI.enabled = true;
|
||||
}
|
||||
|
||||
protected override void RunTests(UITestRunnerFilter[] filters)
|
||||
{
|
||||
foreach (var filter in filters)
|
||||
{
|
||||
filter.ClearResults(newResultList.OfType<UITestRunnerFilter.IClearableResult>().ToList());
|
||||
}
|
||||
|
||||
RerunCallbackData.instance.runFilters = filters;
|
||||
RerunCallbackData.instance.testMode = TestMode.PlayMode;
|
||||
|
||||
var testRunnerApi = ScriptableObject.CreateInstance<TestRunnerApi>();
|
||||
testRunnerApi.Execute(new ExecutionSettings()
|
||||
{
|
||||
filters = filters.Select(filter => new Filter()
|
||||
{
|
||||
assemblyNames = filter.assemblyNames,
|
||||
categoryNames = filter.categoryNames,
|
||||
groupNames = filter.groupNames,
|
||||
testMode = TestMode,
|
||||
testNames = filter.testNames
|
||||
}).ToArray()
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
protected void RunTestsInPlayer(PlayerLauncherTestRunSettings runSettings, params UITestRunnerFilter[] filters)
|
||||
{
|
||||
foreach (var filter in filters)
|
||||
{
|
||||
filter.ClearResults(newResultList.OfType<UITestRunnerFilter.IClearableResult>().ToList());
|
||||
}
|
||||
|
||||
var testRunnerApi = ScriptableObject.CreateInstance<TestRunnerApi>();
|
||||
testRunnerApi.Execute(new ExecutionSettings()
|
||||
{
|
||||
overloadTestRunSettings = runSettings,
|
||||
filters = filters.Select(filter => new Filter()
|
||||
{
|
||||
assemblyNames = filter.assemblyNames,
|
||||
categoryNames = filter.categoryNames,
|
||||
groupNames = filter.groupNames,
|
||||
testMode = TestMode,
|
||||
testNames = filter.testNames
|
||||
}).ToArray(),
|
||||
targetPlatform = EditorUserBuildSettings.activeBuildTarget
|
||||
});
|
||||
}
|
||||
|
||||
public override TestPlatform TestPlatform { get { return TestPlatform.PlayMode; } }
|
||||
|
||||
protected override bool IsBusy()
|
||||
{
|
||||
return TestRunnerApi.IsRunActive() || PlaymodeLauncher.IsRunning || EditorApplication.isCompiling || EditorApplication.isPlaying;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: c3efd39f2cfb43a4c830d4fd5689900f
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,540 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text.RegularExpressions;
|
||||
using UnityEditor.IMGUI.Controls;
|
||||
using UnityEditor.TestTools.TestRunner.Api;
|
||||
using UnityEngine;
|
||||
using UnityEngine.TestTools;
|
||||
|
||||
namespace UnityEditor.TestTools.TestRunner.GUI
|
||||
{
|
||||
internal abstract 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");
|
||||
|
||||
[SerializeField]
|
||||
protected TestRunnerWindow m_Window;
|
||||
[SerializeField]
|
||||
public List<TestRunnerResult> newResultList = new List<TestRunnerResult>();
|
||||
[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 string m_PreviousProjectPath;
|
||||
private List<TestRunnerResult> m_QueuedResults = new List<TestRunnerResult>();
|
||||
|
||||
protected TestListGUI()
|
||||
{
|
||||
MonoCecilHelper = new MonoCecilHelper();
|
||||
AssetsDatabaseHelper = new AssetsDatabaseHelper();
|
||||
|
||||
GuiHelper = new GuiHelper(MonoCecilHelper, AssetsDatabaseHelper);
|
||||
}
|
||||
|
||||
protected IMonoCecilHelper MonoCecilHelper { get; private set; }
|
||||
protected IAssetsDatabaseHelper AssetsDatabaseHelper { get; private set; }
|
||||
protected IGuiHelper GuiHelper { get; private set; }
|
||||
protected UITestRunnerFilter[] SelectedTestsFilter => GetSelectedTestsAsFilter(m_TestListTree.GetSelection());
|
||||
|
||||
public abstract TestMode TestMode { get; }
|
||||
|
||||
public virtual void PrintHeadPanel()
|
||||
{
|
||||
EditorGUILayout.BeginHorizontal(EditorStyles.toolbar);
|
||||
using (new EditorGUI.DisabledScope(IsBusy()))
|
||||
{
|
||||
if (GUILayout.Button(s_GUIRunAllTests, EditorStyles.toolbarButton))
|
||||
{
|
||||
var filter = new UITestRunnerFilter {categoryNames = m_TestRunnerUIFilter.CategoryFilter};
|
||||
RunTests(filter);
|
||||
GUIUtility.ExitGUI();
|
||||
}
|
||||
}
|
||||
using (new EditorGUI.DisabledScope(m_TestListTree == null || !m_TestListTree.HasSelection() || IsBusy()))
|
||||
{
|
||||
if (GUILayout.Button(s_GUIRunSelectedTests, EditorStyles.toolbarButton))
|
||||
{
|
||||
RunTests(SelectedTestsFilter);
|
||||
GUIUtility.ExitGUI();
|
||||
}
|
||||
}
|
||||
using (new EditorGUI.DisabledScope(m_TestRunnerUIFilter.FailedCount == 0 || IsBusy()))
|
||||
{
|
||||
if (GUILayout.Button(s_GUIRerunFailedTests, EditorStyles.toolbarButton))
|
||||
{
|
||||
var failedTestnames = new List<string>();
|
||||
foreach (var result in newResultList)
|
||||
{
|
||||
if (result.isSuite)
|
||||
continue;
|
||||
if (result.resultStatus == TestRunnerResult.ResultStatus.Failed ||
|
||||
result.resultStatus == TestRunnerResult.ResultStatus.Inconclusive)
|
||||
failedTestnames.Add(result.fullName);
|
||||
}
|
||||
RunTests(new UITestRunnerFilter() {testNames = failedTestnames.ToArray(), categoryNames = m_TestRunnerUIFilter.CategoryFilter});
|
||||
GUIUtility.ExitGUI();
|
||||
}
|
||||
}
|
||||
using (new EditorGUI.DisabledScope(IsBusy()))
|
||||
{
|
||||
if (GUILayout.Button(s_GUIClearResults, EditorStyles.toolbarButton))
|
||||
{
|
||||
foreach (var result in newResultList)
|
||||
{
|
||||
result.Clear();
|
||||
}
|
||||
m_TestRunnerUIFilter.UpdateCounters(newResultList);
|
||||
Reload();
|
||||
GUIUtility.ExitGUI();
|
||||
}
|
||||
}
|
||||
GUILayout.FlexibleSpace();
|
||||
EditorGUILayout.EndHorizontal();
|
||||
}
|
||||
|
||||
protected void DrawFilters()
|
||||
{
|
||||
EditorGUILayout.BeginHorizontal(EditorStyles.toolbar);
|
||||
m_TestRunnerUIFilter.Draw();
|
||||
EditorGUILayout.EndHorizontal();
|
||||
}
|
||||
|
||||
public bool HasTreeData()
|
||||
{
|
||||
return m_TestListTree != null;
|
||||
}
|
||||
|
||||
public virtual 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)
|
||||
{
|
||||
if (GUILayout.Button("Clear filters"))
|
||||
{
|
||||
m_TestRunnerUIFilter.Clear();
|
||||
m_TestListTree.ReloadData();
|
||||
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);
|
||||
}
|
||||
|
||||
EditorGUILayout.EndScrollView();
|
||||
}
|
||||
|
||||
public virtual void RenderNoTestsInfo()
|
||||
{
|
||||
EditorGUILayout.HelpBox("No tests to show", MessageType.Info);
|
||||
}
|
||||
|
||||
public void RenderDetails()
|
||||
{
|
||||
m_TestInfoScroll = EditorGUILayout.BeginScrollView(m_TestInfoScroll);
|
||||
var resultTextSize = TestRunnerWindow.Styles.info.CalcSize(new GUIContent(m_ResultText));
|
||||
EditorGUILayout.SelectableLabel(m_ResultText, TestRunnerWindow.Styles.info,
|
||||
GUILayout.ExpandHeight(true),
|
||||
GUILayout.ExpandWidth(true),
|
||||
GUILayout.MinWidth(resultTextSize.x),
|
||||
GUILayout.MinHeight(resultTextSize.y));
|
||||
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)
|
||||
{
|
||||
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, rootTest);
|
||||
|
||||
if (!newResultList.Any())
|
||||
testListTreeViewDataSource.ExpandTreeOnCreation();
|
||||
|
||||
m_TestListTree.Init(new Rect(),
|
||||
testListTreeViewDataSource,
|
||||
new TestListTreeViewGUI(m_TestListTree),
|
||||
null);
|
||||
}
|
||||
|
||||
EditorApplication.update += RepaintIfProjectPathChanged;
|
||||
|
||||
m_TestRunnerUIFilter.UpdateCounters(newResultList);
|
||||
m_TestRunnerUIFilter.RebuildTestList = () => m_TestListTree.ReloadData();
|
||||
m_TestRunnerUIFilter.SearchStringChanged = s => m_TestListTree.searchString = s;
|
||||
m_TestRunnerUIFilter.SearchStringCleared = () => FrameSelection();
|
||||
}
|
||||
|
||||
public void UpdateResult(TestRunnerResult result)
|
||||
{
|
||||
if (!HasTreeData())
|
||||
{
|
||||
m_QueuedResults.Add(result);
|
||||
return;
|
||||
}
|
||||
|
||||
if (newResultList.All(x => x.uniqueId != result.uniqueId))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var testRunnerResult = newResultList.FirstOrDefault(x => x.uniqueId == result.uniqueId);
|
||||
if (testRunnerResult != null)
|
||||
{
|
||||
testRunnerResult.Update(result);
|
||||
}
|
||||
|
||||
Repaint();
|
||||
m_Window.Repaint();
|
||||
}
|
||||
|
||||
public void UpdateTestTree(ITestAdaptor test)
|
||||
{
|
||||
if (!HasTreeData())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
(m_TestListTree.data as TestListTreeViewDataSource).UpdateRootTest(test);
|
||||
|
||||
m_TestListTree.ReloadData();
|
||||
Repaint();
|
||||
m_Window.Repaint();
|
||||
}
|
||||
|
||||
private void UpdateQueuedResults()
|
||||
{
|
||||
foreach (var testRunnerResult in m_QueuedResults)
|
||||
{
|
||||
var existingResult = newResultList.FirstOrDefault(x => x.uniqueId == testRunnerResult.uniqueId);
|
||||
if (existingResult != null)
|
||||
{
|
||||
existingResult.Update(testRunnerResult);
|
||||
}
|
||||
}
|
||||
m_QueuedResults.Clear();
|
||||
TestSelectionCallback(m_TestListState.selectedIDs.ToArray());
|
||||
m_TestRunnerUIFilter.UpdateCounters(newResultList);
|
||||
Repaint();
|
||||
m_Window.Repaint();
|
||||
}
|
||||
|
||||
internal void TestSelectionCallback(int[] selected)
|
||||
{
|
||||
if (m_TestListTree != null && selected.Length == 1)
|
||||
{
|
||||
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 = "";
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual void TestDoubleClickCallback(int id)
|
||||
{
|
||||
if (IsBusy())
|
||||
return;
|
||||
|
||||
RunTests(GetSelectedTestsAsFilter(new List<int> { id }));
|
||||
GUIUtility.ExitGUI();
|
||||
}
|
||||
|
||||
protected virtual void RunTests(params UITestRunnerFilter[] filters)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
protected virtual void TestContextClickCallback(int id)
|
||||
{
|
||||
if (id == 0)
|
||||
return;
|
||||
|
||||
var m = new GenericMenu();
|
||||
var testFilters = GetSelectedTestsAsFilter(m_TestListState.selectedIDs);
|
||||
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(testFilters),
|
||||
"");
|
||||
|
||||
if (EditorPrefs.GetBool("DeveloperMode", false))
|
||||
{
|
||||
m.AddItem(multilineSelection ? s_GUIRunSelectedTests : s_GUIRunUntilFailed,
|
||||
false,
|
||||
data =>
|
||||
{
|
||||
foreach (var filter in testFilters)
|
||||
{
|
||||
filter.testRepetitions = int.MaxValue;
|
||||
}
|
||||
|
||||
RunTests(testFilters);
|
||||
},
|
||||
"");
|
||||
|
||||
m.AddItem(multilineSelection ? s_GUIRunSelectedTests : s_GUIRun100Times,
|
||||
false,
|
||||
data =>
|
||||
{
|
||||
foreach (var filter in testFilters)
|
||||
{
|
||||
filter.testRepetitions = 100;
|
||||
}
|
||||
|
||||
RunTests(testFilters);
|
||||
},
|
||||
"");
|
||||
}
|
||||
}
|
||||
else
|
||||
m.AddDisabledItem(multilineSelection ? s_GUIRunSelectedTests : s_GUIRun, false);
|
||||
|
||||
m.ShowAsContext();
|
||||
}
|
||||
|
||||
private UITestRunnerFilter[] GetSelectedTestsAsFilter(IEnumerable<int> selectedIDs)
|
||||
{
|
||||
var namesToRun = new List<string>();
|
||||
var assembliesForNamesToRun = new List<string>();
|
||||
var exactNamesToRun = new List<string>();
|
||||
var assembliesToRun = new List<string>();
|
||||
foreach (var lineId in selectedIDs)
|
||||
{
|
||||
var line = m_TestListTree.FindItem(lineId);
|
||||
if (line is TestTreeViewItem)
|
||||
{
|
||||
var testLine = line as TestTreeViewItem;
|
||||
if (testLine.IsGroupNode && !testLine.FullName.Contains("+"))
|
||||
{
|
||||
if (testLine.parent != null && testLine.parent.displayName == "Invisible Root Item")
|
||||
{
|
||||
//Root node selected. Use an empty TestRunnerFilter to run every test
|
||||
return new[] {new UITestRunnerFilter()};
|
||||
}
|
||||
|
||||
if (testLine.FullName.EndsWith(".dll", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
assembliesToRun.Add(UITestRunnerFilter.AssemblyNameFromPath(testLine.FullName));
|
||||
}
|
||||
else
|
||||
{
|
||||
namesToRun.Add($"^{Regex.Escape(testLine.FullName)}$");
|
||||
var assembly = UITestRunnerFilter.AssemblyNameFromPath(testLine.GetAssemblyName());
|
||||
if (!string.IsNullOrEmpty(assembly) && !assembliesForNamesToRun.Contains(assembly))
|
||||
{
|
||||
assembliesForNamesToRun.Add(assembly);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
exactNamesToRun.Add(testLine.FullName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var filters = new List<UITestRunnerFilter>();
|
||||
|
||||
if (assembliesToRun.Count > 0)
|
||||
{
|
||||
filters.Add(new UITestRunnerFilter()
|
||||
{
|
||||
assemblyNames = assembliesToRun.ToArray()
|
||||
});
|
||||
}
|
||||
|
||||
if (namesToRun.Count > 0)
|
||||
{
|
||||
filters.Add(new UITestRunnerFilter()
|
||||
{
|
||||
groupNames = namesToRun.ToArray(),
|
||||
assemblyNames = assembliesForNamesToRun.ToArray()
|
||||
});
|
||||
}
|
||||
|
||||
if (exactNamesToRun.Count > 0)
|
||||
{
|
||||
filters.Add(new UITestRunnerFilter()
|
||||
{
|
||||
testNames = exactNamesToRun.ToArray()
|
||||
});
|
||||
}
|
||||
|
||||
if (filters.Count == 0)
|
||||
{
|
||||
filters.Add(new UITestRunnerFilter());
|
||||
}
|
||||
|
||||
var categories = m_TestRunnerUIFilter.CategoryFilter.ToArray();
|
||||
if (categories.Length > 0)
|
||||
{
|
||||
foreach (var filter in filters)
|
||||
{
|
||||
filter.categoryNames = categories;
|
||||
}
|
||||
}
|
||||
|
||||
return filters.ToArray();
|
||||
}
|
||||
|
||||
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<int>() == m_TestListState.lastClickedID ? m_TestListState.selectedIDs.Last<int>() : m_TestListState.selectedIDs.First<int>();
|
||||
m_TestListTree.Frame(firstClickedID, true, false);
|
||||
}
|
||||
}
|
||||
|
||||
public abstract TestPlatform TestPlatform { get; }
|
||||
|
||||
public void RebuildUIFilter()
|
||||
{
|
||||
m_TestRunnerUIFilter.UpdateCounters(newResultList);
|
||||
if (m_TestRunnerUIFilter.IsFiltering)
|
||||
{
|
||||
m_TestListTree.ReloadData();
|
||||
}
|
||||
}
|
||||
|
||||
public void RepaintIfProjectPathChanged()
|
||||
{
|
||||
var path = TestListGUIHelper.GetActiveFolderPath();
|
||||
if (path != m_PreviousProjectPath)
|
||||
{
|
||||
m_PreviousProjectPath = path;
|
||||
TestRunnerWindow.s_Instance.Repaint();
|
||||
}
|
||||
|
||||
EditorApplication.update -= RepaintIfProjectPathChanged;
|
||||
}
|
||||
|
||||
protected abstract bool IsBusy();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: b8abb41ceb6f62c45a00197ae59224c1
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
Loading…
Add table
Add a link
Reference in a new issue