You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
137 lines
5.2 KiB
137 lines
5.2 KiB
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; |
|
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; |
|
|
|
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; |
|
} |
|
} |
|
}
|
|
|