Nessuna descrizione
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.

GuiHelper.cs 5.2KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137
  1. using System;
  2. using System.Collections;
  3. using System.Collections.Generic;
  4. using System.IO;
  5. using System.Linq;
  6. using System.Reflection;
  7. using System.Text.RegularExpressions;
  8. using Unity.CodeEditor;
  9. using UnityEditor.Utils;
  10. using UnityEngine;
  11. namespace UnityEditor.TestTools.TestRunner.GUI
  12. {
  13. internal class GuiHelper : IGuiHelper
  14. {
  15. public GuiHelper(IMonoCecilHelper monoCecilHelper, IAssetsDatabaseHelper assetsDatabaseHelper)
  16. {
  17. MonoCecilHelper = monoCecilHelper;
  18. AssetsDatabaseHelper = assetsDatabaseHelper;
  19. GetCSFiles = (dirPath, fileExtension) =>
  20. {
  21. return Directory.GetFiles(dirPath, $"*{fileExtension}", SearchOption.AllDirectories)
  22. .Select(Paths.UnifyDirectorySeparator);
  23. };
  24. }
  25. internal Func<string, string, IEnumerable<string>> GetCSFiles;
  26. protected IMonoCecilHelper MonoCecilHelper { get; private set; }
  27. public IAssetsDatabaseHelper AssetsDatabaseHelper { get; private set; }
  28. public IExternalCodeEditor Editor { get; internal set; }
  29. private const string FileExtension = ".cs";
  30. public void OpenScriptInExternalEditor(Type type, MethodInfo method)
  31. {
  32. var fileOpenInfo = GetFileOpenInfo(type, method);
  33. if (string.IsNullOrEmpty(fileOpenInfo.FilePath))
  34. {
  35. Debug.LogWarning("Failed to open test method source code in external editor. Inconsistent filename and yield return operator in target method.");
  36. return;
  37. }
  38. if (fileOpenInfo.LineNumber == 1)
  39. {
  40. Debug.LogWarning("Failed to get a line number for unity test method. So please find it in opened file in external editor.");
  41. }
  42. if (!fileOpenInfo.FilePath.Contains("Assets"))
  43. {
  44. (Editor ?? CodeEditor.CurrentEditor).OpenProject(fileOpenInfo.FilePath, fileOpenInfo.LineNumber, 1);
  45. }
  46. else
  47. {
  48. AssetsDatabaseHelper.OpenAssetInItsDefaultExternalEditor(fileOpenInfo.FilePath, fileOpenInfo.LineNumber);
  49. }
  50. }
  51. public IFileOpenInfo GetFileOpenInfo(Type type, MethodInfo method)
  52. {
  53. var fileOpenInfo = MonoCecilHelper.TryGetCecilFileOpenInfo(type, method);
  54. if (string.IsNullOrEmpty(fileOpenInfo.FilePath))
  55. {
  56. var dirPath = Paths.UnifyDirectorySeparator(Application.dataPath);
  57. var allCsFiles = GetCSFiles(dirPath, FileExtension);
  58. var fileName = allCsFiles.FirstOrDefault(x =>
  59. x.Split(Path.DirectorySeparatorChar).Last().Equals(string.Concat(GetTestFileName(type), FileExtension)));
  60. fileOpenInfo.FilePath = fileName ?? string.Empty;
  61. }
  62. if (!fileOpenInfo.FilePath.Contains("Assets"))
  63. {
  64. return fileOpenInfo;
  65. }
  66. fileOpenInfo.FilePath = FilePathToAssetsRelativeAndUnified(fileOpenInfo.FilePath);
  67. return fileOpenInfo;
  68. }
  69. internal static string GetTestFileName(Type type)
  70. {
  71. //This handles the case of a test in a nested class, getting the name of the base class
  72. if (type.FullName != null && type.Namespace!=null && type.FullName.Contains("+"))
  73. {
  74. var removedNamespace = type.FullName.Substring(type.Namespace.Length+1);
  75. return removedNamespace.Substring(0,removedNamespace.IndexOf("+", StringComparison.Ordinal));
  76. }
  77. return type.Name;
  78. }
  79. public string FilePathToAssetsRelativeAndUnified(string filePath)
  80. {
  81. if (string.IsNullOrEmpty(filePath))
  82. return string.Empty;
  83. filePath = Paths.UnifyDirectorySeparator(filePath);
  84. var length = Paths.UnifyDirectorySeparator(Application.dataPath).Length - "Assets".Length;
  85. return filePath.Substring(length);
  86. }
  87. public bool OpenScriptInExternalEditor(string stacktrace)
  88. {
  89. if (string.IsNullOrEmpty(stacktrace))
  90. return false;
  91. var regex = new Regex("in (?<path>.*):{1}(?<line>[0-9]+)");
  92. var matchingLines = stacktrace.Split(new[] { Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries).Where(x => regex.IsMatch(x)).ToList();
  93. if (!matchingLines.Any())
  94. return false;
  95. var fileOpenInfos = matchingLines
  96. .Select(x => regex.Match(x))
  97. .Select(x =>
  98. new FileOpenInfo
  99. {
  100. FilePath = x.Groups["path"].Value,
  101. LineNumber = int.Parse(x.Groups["line"].Value)
  102. }).ToList();
  103. var fileOpenInfo = fileOpenInfos
  104. .FirstOrDefault(openInfo => !string.IsNullOrEmpty(openInfo.FilePath) && File.Exists(openInfo.FilePath));
  105. if (fileOpenInfo == null)
  106. {
  107. return false;
  108. }
  109. var filePath = FilePathToAssetsRelativeAndUnified(fileOpenInfo.FilePath);
  110. AssetsDatabaseHelper.OpenAssetInItsDefaultExternalEditor(filePath, fileOpenInfo.LineNumber);
  111. return true;
  112. }
  113. }
  114. }