142 lines
		
	
	
		
			5.3 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
			
		
		
	
	
			142 lines
		
	
	
		
			5.3 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
| using System;
 | |
| 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;
 | |
|             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 ?? CodeEditor.CurrentEditor).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;
 | |
| 
 | |
| #if UNITY_2021_3_OR_NEWER
 | |
|             return Path.GetRelativePath(Directory.GetCurrentDirectory(), filePath);
 | |
| #else
 | |
|             filePath = Paths.UnifyDirectorySeparator(filePath);
 | |
|             var length = Paths.UnifyDirectorySeparator(Application.dataPath).Length - "Assets".Length;
 | |
| 
 | |
|             return filePath.Substring(length);
 | |
| #endif
 | |
|         }
 | |
| 
 | |
|         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;
 | |
|         }
 | |
|     }
 | |
| }
 |