PO/Library/PackageCache/com.unity.test-framework@1..../UnityEditor.TestRunner/GUI/GuiHelper.cs

139 lines
5.2 KiB
C#

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;
}
}
}