CoverageUtils.cs 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372
  1. using System;
  2. using System.Collections.Generic;
  3. using System.IO;
  4. using System.Linq;
  5. using System.Text;
  6. using UnityEditor.Networking.PlayerConnection;
  7. using UnityEngine;
  8. using UnityEngine.TestTools;
  9. namespace UnityEditor.TestTools.CodeCoverage.Utils
  10. {
  11. internal static class CoverageUtils
  12. {
  13. public static bool IsConnectedToPlayer
  14. {
  15. get
  16. {
  17. return EditorConnection.instance.ConnectedPlayers.Count > 0;
  18. }
  19. }
  20. public static string NormaliseFolderSeparators(string folderPath, bool stripTrailingSlash = false)
  21. {
  22. if (folderPath != null)
  23. {
  24. folderPath = folderPath.Replace('\\', '/');
  25. if (stripTrailingSlash)
  26. {
  27. folderPath = folderPath.TrimEnd('/');
  28. }
  29. }
  30. return folderPath;
  31. }
  32. public static bool EnsureFolderExists(string folderPath)
  33. {
  34. if (string.IsNullOrEmpty(folderPath))
  35. return false;
  36. if (!Directory.Exists(folderPath))
  37. {
  38. try
  39. {
  40. Directory.CreateDirectory(folderPath);
  41. }
  42. catch (Exception)
  43. {
  44. return false;
  45. }
  46. }
  47. return true;
  48. }
  49. public static string GetProjectFolderName()
  50. {
  51. string[] projectPathArray = GetProjectPath().Split('/');
  52. Debug.Assert(projectPathArray.Length > 0);
  53. string folderName = projectPathArray[projectPathArray.Length - 1];
  54. char[] invalidChars = Path.GetInvalidPathChars();
  55. StringBuilder folderNameStringBuilder = new StringBuilder();
  56. foreach (char c in folderName)
  57. {
  58. if (invalidChars.Contains(c))
  59. {
  60. folderNameStringBuilder.Append('_');
  61. }
  62. else
  63. {
  64. folderNameStringBuilder.Append(c);
  65. }
  66. }
  67. return folderNameStringBuilder.ToString();
  68. }
  69. public static string StripAssetsFolderIfExists(string folderPath)
  70. {
  71. if (folderPath != null)
  72. {
  73. string toTrim = "Assets";
  74. folderPath = folderPath.TrimEnd(toTrim.ToCharArray());
  75. }
  76. return folderPath;
  77. }
  78. public static string GetProjectPath()
  79. {
  80. return NormaliseFolderSeparators(StripAssetsFolderIfExists(Application.dataPath), true);
  81. }
  82. public static string GetRootFolderPath(CoverageSettings coverageSettings)
  83. {
  84. string rootFolderPath = string.Empty;
  85. string coverageFolderPath = string.Empty;
  86. if (CommandLineManager.instance.batchmode)
  87. {
  88. if (coverageSettings.resultsPathFromCommandLine.Length > 0)
  89. {
  90. coverageFolderPath = coverageSettings.resultsPathFromCommandLine;
  91. EnsureFolderExists(coverageFolderPath);
  92. }
  93. }
  94. else
  95. {
  96. if (CommandLineManager.instance.runFromCommandLine && coverageSettings.resultsPathFromCommandLine.Length > 0)
  97. {
  98. coverageFolderPath = coverageSettings.resultsPathFromCommandLine;
  99. EnsureFolderExists(coverageFolderPath);
  100. }
  101. else
  102. {
  103. coverageFolderPath = CoveragePreferences.instance.GetStringForPaths("Path", string.Empty);
  104. }
  105. }
  106. string projectPath = GetProjectPath();
  107. if (EnsureFolderExists(coverageFolderPath))
  108. {
  109. coverageFolderPath = NormaliseFolderSeparators(coverageFolderPath, true);
  110. // Add 'CodeCoverage' directory if coverageFolderPath is projectPath
  111. if (string.Equals(coverageFolderPath, projectPath, StringComparison.InvariantCultureIgnoreCase))
  112. rootFolderPath = JoinPaths(coverageFolderPath, coverageSettings.rootFolderName);
  113. // else user coverageFolderPath as the root folder
  114. else
  115. rootFolderPath = coverageFolderPath;
  116. }
  117. else
  118. {
  119. // Add 'CodeCoverage' directory to projectPath if coverageFolderPath is not valid
  120. rootFolderPath = JoinPaths(projectPath, coverageSettings.rootFolderName);
  121. }
  122. return rootFolderPath;
  123. }
  124. public static string GetHistoryFolderPath(CoverageSettings coverageSettings)
  125. {
  126. string historyFolderPath = string.Empty;
  127. string rootFolderPath = coverageSettings.rootFolderPath;
  128. if (CommandLineManager.instance.batchmode)
  129. {
  130. if (coverageSettings.historyPathFromCommandLine.Length > 0)
  131. {
  132. historyFolderPath = coverageSettings.historyPathFromCommandLine;
  133. EnsureFolderExists(historyFolderPath);
  134. }
  135. }
  136. else
  137. {
  138. if (CommandLineManager.instance.runFromCommandLine && coverageSettings.historyPathFromCommandLine.Length > 0)
  139. {
  140. historyFolderPath = coverageSettings.historyPathFromCommandLine;
  141. EnsureFolderExists(historyFolderPath);
  142. }
  143. else
  144. {
  145. historyFolderPath = CoveragePreferences.instance.GetStringForPaths("HistoryPath", string.Empty);
  146. }
  147. }
  148. bool addHistorySubDir = false;
  149. string projectPath = GetProjectPath();
  150. if (EnsureFolderExists(historyFolderPath))
  151. {
  152. historyFolderPath = NormaliseFolderSeparators(historyFolderPath, true);
  153. // If historyFolderPath == rootFolderPath, add 'Report-history' sub directory in rootFolderPath
  154. if (string.Equals(historyFolderPath, rootFolderPath, StringComparison.InvariantCultureIgnoreCase))
  155. {
  156. addHistorySubDir = true;
  157. }
  158. // If historyFolderPath == projectPath, add 'CodeCoverage' directory to projectPath
  159. // and add 'Report-history' sub directory in rootFolderPath
  160. else if (string.Equals(historyFolderPath, projectPath, StringComparison.InvariantCultureIgnoreCase))
  161. {
  162. rootFolderPath = JoinPaths(projectPath, coverageSettings.rootFolderName);
  163. addHistorySubDir = true;
  164. }
  165. // otherwise keep the original historyFolderPath
  166. }
  167. else
  168. {
  169. // If historyFolderPath is not valid, add 'CodeCoverage' directory to projectPath
  170. // and add 'Report-history' sub directory in rootFolderPath
  171. rootFolderPath = JoinPaths(projectPath, coverageSettings.rootFolderName);
  172. addHistorySubDir = true;
  173. }
  174. if (addHistorySubDir)
  175. {
  176. historyFolderPath = JoinPaths(rootFolderPath, CoverageSettings.ReportHistoryFolderName);
  177. }
  178. return historyFolderPath;
  179. }
  180. public static string JoinPaths(string pathLeft, string pathRight)
  181. {
  182. string[] pathsToJoin = new string[] { pathLeft, pathRight };
  183. return string.Join("/", pathsToJoin);
  184. }
  185. public static int GetNumberOfFilesInFolder(string folderPath, string filePattern, SearchOption searchOption)
  186. {
  187. if (folderPath == null)
  188. return 0;
  189. string[] files = Directory.GetFiles(folderPath, filePattern, searchOption);
  190. return files.Length;
  191. }
  192. public static void ClearFolderIfExists(string folderPath, string filePattern)
  193. {
  194. if (folderPath != null)
  195. {
  196. if (Directory.Exists(folderPath))
  197. {
  198. DirectoryInfo dirInfo = new DirectoryInfo(folderPath);
  199. foreach (FileInfo file in dirInfo.GetFiles(filePattern))
  200. {
  201. try
  202. {
  203. file.Delete();
  204. }
  205. catch (Exception)
  206. {
  207. ResultsLogger.Log(ResultID.Warning_FailedToDeleteFile, file.FullName);
  208. }
  209. }
  210. foreach (DirectoryInfo dir in dirInfo.GetDirectories())
  211. {
  212. try
  213. {
  214. dir.Delete(true);
  215. }
  216. catch (Exception)
  217. {
  218. ResultsLogger.Log(ResultID.Warning_FailedToDeleteDir, dir.FullName);
  219. }
  220. }
  221. }
  222. }
  223. }
  224. public static bool DoesFolderExistAndNotEmpty(string folderPath)
  225. {
  226. if (folderPath != null)
  227. {
  228. if (Directory.Exists(folderPath))
  229. {
  230. DirectoryInfo dirInfo = new DirectoryInfo(folderPath);
  231. return dirInfo.GetFiles().Length > 0 || dirInfo.GetDirectories().Length > 0;
  232. }
  233. }
  234. return false;
  235. }
  236. public static bool IsValidFolder(string folderPath)
  237. {
  238. return !string.IsNullOrEmpty(folderPath) && Directory.Exists(folderPath);
  239. }
  240. public static bool IsValidFile(string filePath)
  241. {
  242. return !string.IsNullOrEmpty(filePath) && File.Exists(filePath);
  243. }
  244. private static HashSet<char> regexSpecialChars = new HashSet<char>(new[] { '[', '\\', '^', '$', '.', '|', '?', '*', '+', '(', ')' });
  245. public static string GlobToRegex(string glob)
  246. {
  247. var regex = new StringBuilder();
  248. var characterClass = false;
  249. regex.Append("^");
  250. foreach (var c in glob)
  251. {
  252. if (characterClass)
  253. {
  254. if (c == ']')
  255. {
  256. characterClass = false;
  257. }
  258. regex.Append(c);
  259. continue;
  260. }
  261. switch (c)
  262. {
  263. case '*':
  264. regex.Append(".*");
  265. break;
  266. case '?':
  267. regex.Append(".");
  268. break;
  269. case '[':
  270. characterClass = true;
  271. regex.Append(c);
  272. break;
  273. default:
  274. if (regexSpecialChars.Contains(c))
  275. {
  276. regex.Append('\\');
  277. }
  278. regex.Append(c);
  279. break;
  280. }
  281. }
  282. regex.Append("$");
  283. return regex.ToString();
  284. }
  285. [ExcludeFromCoverage]
  286. public static string BrowseForDir(string directory, string title)
  287. {
  288. if (string.IsNullOrEmpty(directory))
  289. {
  290. string variable = "ProgramFiles";
  291. #if UNITY_EDITOR_OSX
  292. variable = "HOME";
  293. #endif
  294. string candidateDirectory = Environment.GetEnvironmentVariable(variable);
  295. if (IsValidFolder(candidateDirectory))
  296. directory = candidateDirectory;
  297. }
  298. directory = EditorUtility.OpenFolderPanel(title, directory, string.Empty);
  299. EditorWindow.FocusWindowIfItsOpen(typeof(CodeCoverageWindow));
  300. if (!IsValidFolder(directory))
  301. return string.Empty;
  302. return directory;
  303. }
  304. [ExcludeFromCoverage]
  305. public static string BrowseForFile(string directory, string title)
  306. {
  307. if (string.IsNullOrEmpty(directory))
  308. {
  309. string variable = "ProgramFiles";
  310. #if UNITY_EDITOR_OSX
  311. variable = "HOME";
  312. #endif
  313. string candidateDirectory = Environment.GetEnvironmentVariable(variable);
  314. if (IsValidFolder(candidateDirectory))
  315. directory = candidateDirectory;
  316. }
  317. string file = EditorUtility.OpenFilePanel(title, directory, "cs");
  318. EditorWindow.FocusWindowIfItsOpen(typeof(CodeCoverageWindow));
  319. if (!IsValidFile(file))
  320. return string.Empty;
  321. return file;
  322. }
  323. }
  324. }