using System; using System.Collections.Generic; using System.Linq; using UnityEditor; using UnityEngine; using UnityEditor.Callbacks; namespace UnityTest { [Serializable] public partial class UnitTestView : EditorWindow, IHasCustomMenu { private static UnitTestView s_Instance; private static readonly IUnitTestEngine k_TestEngine = new NUnitTestEngine(); [SerializeField] private List m_ResultList = new List(); [SerializeField] private List m_FoldMarkers = new List(); [SerializeField] private List m_SelectedLines = new List(); UnitTestRendererLine m_TestLines; private TestFilterSettings m_FilterSettings; #region runner steering vars private Vector2 m_TestListScroll, m_TestInfoScroll; private float m_HorizontalSplitBarPosition = 200; private float m_VerticalSplitBarPosition = 300; #endregion private UnitTestsRunnerSettings m_Settings; #region GUI Contents private readonly GUIContent m_GUIRunSelectedTestsIcon = new GUIContent("Run Selected", "Run selected tests"); private readonly GUIContent m_GUIRunAllTestsIcon = new GUIContent("Run All", "Run all tests"); private readonly GUIContent m_GUIRerunFailedTestsIcon = new GUIContent("Rerun Failed", "Rerun failed tests"); private readonly GUIContent m_GUIRunOnRecompile = new GUIContent("Run on recompile", "Run all tests after recompilation"); private readonly GUIContent m_GUIShowDetailsBelowTests = new GUIContent("Show details below tests", "Show run details below test list"); private readonly GUIContent m_GUIRunTestsOnNewScene = new GUIContent("Run tests on a new scene", "Run tests on a new scene"); private readonly GUIContent m_GUIAutoSaveSceneBeforeRun = new GUIContent("Autosave scene", "The runner will automatically save the current scene changes before it starts"); #endregion public UnitTestView() { m_ResultList.Clear(); } public void OnEnable() { titleContent = new GUIContent("Unit Tests"); s_Instance = this; m_Settings = ProjectSettingsBase.Load(); m_FilterSettings = new TestFilterSettings("UnityTest.UnitTestView"); RefreshTests(); } [DidReloadScripts] public static void OnDidReloadScripts() { if (s_Instance != null && s_Instance.m_Settings.runOnRecompilation) { s_Instance.RunTests(); s_Instance.Repaint(); } } public void OnDestroy() { s_Instance = null; } public void OnGUI() { EditorGUILayout.BeginVertical(); EditorGUILayout.BeginHorizontal(EditorStyles.toolbar); if (GUILayout.Button(m_GUIRunAllTestsIcon, EditorStyles.toolbarButton)) { RunTests(); GUIUtility.ExitGUI(); } EditorGUI.BeginDisabledGroup(!m_TestLines.IsAnySelected); if (GUILayout.Button(m_GUIRunSelectedTestsIcon, EditorStyles.toolbarButton)) { m_TestLines.RunSelectedTests(); } EditorGUI.EndDisabledGroup(); if (GUILayout.Button(m_GUIRerunFailedTestsIcon, EditorStyles.toolbarButton)) { m_TestLines.RunTests(m_ResultList.Where(result => result.IsFailure || result.IsError).Select(l => l.FullName).ToArray()); } GUILayout.FlexibleSpace(); m_FilterSettings.OnGUI (); EditorGUILayout.EndHorizontal(); if (m_Settings.horizontalSplit) EditorGUILayout.BeginVertical(); else EditorGUILayout.BeginHorizontal(GUILayout.ExpandWidth(true)); RenderTestList(); RenderTestInfo(); if (m_Settings.horizontalSplit) EditorGUILayout.EndVertical(); else EditorGUILayout.EndHorizontal(); EditorGUILayout.EndVertical(); } private void RenderTestList() { EditorGUILayout.BeginVertical(Styles.testList); m_TestListScroll = EditorGUILayout.BeginScrollView(m_TestListScroll, GUILayout.ExpandWidth(true), GUILayout.MaxWidth(2000)); if (m_TestLines != null) { if (m_TestLines.Render(m_FilterSettings.BuildRenderingOptions())) Repaint(); } EditorGUILayout.EndScrollView(); EditorGUILayout.EndVertical(); } private void RenderTestInfo() { var ctrlId = GUIUtility.GetControlID(FocusType.Passive); var rect = GUILayoutUtility.GetLastRect(); if (m_Settings.horizontalSplit) { rect.y = rect.height + rect.y - 1; rect.height = 3; } else { rect.x = rect.width + rect.x - 1; rect.width = 3; } EditorGUIUtility.AddCursorRect(rect, m_Settings.horizontalSplit ? MouseCursor.ResizeVertical : MouseCursor.ResizeHorizontal); var e = Event.current; switch (e.type) { case EventType.MouseDown: if (GUIUtility.hotControl == 0 && rect.Contains(e.mousePosition)) GUIUtility.hotControl = ctrlId; break; case EventType.MouseDrag: if (GUIUtility.hotControl == ctrlId) { m_HorizontalSplitBarPosition -= e.delta.y; if (m_HorizontalSplitBarPosition < 20) m_HorizontalSplitBarPosition = 20; m_VerticalSplitBarPosition -= e.delta.x; if (m_VerticalSplitBarPosition < 20) m_VerticalSplitBarPosition = 20; Repaint(); } break; case EventType.MouseUp: if (GUIUtility.hotControl == ctrlId) GUIUtility.hotControl = 0; break; } m_TestInfoScroll = EditorGUILayout.BeginScrollView(m_TestInfoScroll, m_Settings.horizontalSplit ? GUILayout.MinHeight(m_HorizontalSplitBarPosition) : GUILayout.Width(m_VerticalSplitBarPosition)); var text = ""; if (m_SelectedLines.Any()) { text = m_SelectedLines.First().GetResultText(); } var resultTextSize = Styles.info.CalcSize(new GUIContent(text)); EditorGUILayout.SelectableLabel(text, Styles.info, GUILayout.ExpandHeight(true), GUILayout.ExpandWidth(true), GUILayout.MinWidth(resultTextSize.x), GUILayout.MinHeight(resultTextSize.y)); EditorGUILayout.EndScrollView(); } private void ToggleRunOnRecompilation() { m_Settings.runOnRecompilation = !m_Settings.runOnRecompilation; } public void AddItemsToMenu (GenericMenu menu) { menu.AddItem(m_GUIRunOnRecompile, m_Settings.runOnRecompilation, ToggleRunOnRecompilation); menu.AddItem(m_GUIRunTestsOnNewScene, m_Settings.runTestOnANewScene, m_Settings.ToggleRunTestOnANewScene); if(!m_Settings.runTestOnANewScene) menu.AddDisabledItem(m_GUIAutoSaveSceneBeforeRun); else menu.AddItem(m_GUIAutoSaveSceneBeforeRun, m_Settings.autoSaveSceneBeforeRun, m_Settings.ToggleAutoSaveSceneBeforeRun); menu.AddItem(m_GUIShowDetailsBelowTests, m_Settings.horizontalSplit, m_Settings.ToggleHorizontalSplit); } private void RefreshTests() { UnitTestResult[] newResults; m_TestLines = k_TestEngine.GetTests(out newResults, out m_FilterSettings.AvailableCategories); foreach (var newResult in newResults) { var result = m_ResultList.Where(t => t.Test == newResult.Test && t.FullName == newResult.FullName).ToArray(); if (result.Count() != 1) continue; newResult.Update(result.Single(), true); } UnitTestRendererLine.SelectedLines = m_SelectedLines; UnitTestRendererLine.RunTest = RunTests; GroupLine.FoldMarkers = m_FoldMarkers; TestLine.GetUnitTestResult = FindTestResult; m_ResultList = new List(newResults); m_FilterSettings.UpdateCounters(m_ResultList.Cast()); Repaint(); } } }