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(), 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; } } }