TestRunnerFilter.cs 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text.RegularExpressions;
  5. using System.IO;
  6. using NUnit.Framework.Interfaces;
  7. using NUnit.Framework.Internal;
  8. using NUnit.Framework.Internal.Filters;
  9. using UnityEngine.TestRunner.NUnitExtensions.Filters;
  10. namespace UnityEngine.TestTools.TestRunner.GUI
  11. {
  12. [Serializable]
  13. internal class TestRunnerFilter
  14. {
  15. #pragma warning disable 649
  16. public string[] assemblyNames;
  17. public string[] groupNames;
  18. public string[] categoryNames;
  19. public static TestRunnerFilter empty = new TestRunnerFilter();
  20. public string[] testNames;
  21. public int testRepetitions = 1;
  22. public bool synchronousOnly = false;
  23. public static string AssemblyNameFromPath(string path)
  24. {
  25. string output = Path.GetFileName(path);
  26. if (output != null && output.EndsWith(".dll", StringComparison.OrdinalIgnoreCase))
  27. return output.Substring(0, output.Length - 4);
  28. return output;
  29. }
  30. private bool CategoryMatches(IEnumerable<string> categories)
  31. {
  32. if (categoryNames == null || categoryNames.Length == 0)
  33. return true;
  34. foreach (string category in categories)
  35. {
  36. if (categoryNames.Contains(category))
  37. return true;
  38. }
  39. return false;
  40. }
  41. private bool IDMatchesAssembly(string id)
  42. {
  43. if (AreOptionalFiltersEmpty())
  44. return true;
  45. if (assemblyNames == null || assemblyNames.Length == 0)
  46. return true;
  47. int openingBracket = id.IndexOf('[');
  48. int closingBracket = id.IndexOf(']');
  49. if (openingBracket >= 0 && openingBracket < id.Length && closingBracket > openingBracket && openingBracket < id.Length)
  50. {
  51. //Some assemblies are absolute and explicitly part of the test ID e.g.
  52. //"[/path/to/assembly-name.dll][rest of ID ...]"
  53. //While some are minimal assembly names e.g.
  54. //"[assembly-name][rest of ID ...]"
  55. //Strip them down to just the assembly name
  56. string assemblyNameFromID = AssemblyNameFromPath(id.Substring(openingBracket + 1, closingBracket - openingBracket - 1));
  57. foreach (string assemblyName in assemblyNames)
  58. {
  59. if (assemblyName.Equals(assemblyNameFromID, StringComparison.OrdinalIgnoreCase))
  60. return true;
  61. }
  62. }
  63. return false;
  64. }
  65. private bool NameMatches(string name)
  66. {
  67. if (AreOptionalFiltersEmpty())
  68. return true;
  69. if (groupNames == null || groupNames.Length == 0)
  70. return true;
  71. foreach (var nameFromFilter in groupNames)
  72. {
  73. //Strict regex match for test group name on its own
  74. if (Regex.IsMatch(name, nameFromFilter))
  75. return true;
  76. //Match test names that end with parametrized test values and full nunit generated test names that have . separators
  77. var regex = nameFromFilter.TrimEnd('$') + @"[\.|\(.*\)]";
  78. if (Regex.IsMatch(name, regex))
  79. return true;
  80. }
  81. return false;
  82. }
  83. private bool AreOptionalFiltersEmpty()
  84. {
  85. if (assemblyNames != null && assemblyNames.Length != 0)
  86. return false;
  87. if (groupNames != null && groupNames.Length != 0)
  88. return false;
  89. if (testNames != null && testNames.Length != 0)
  90. return false;
  91. return true;
  92. }
  93. private bool NameMatchesExactly(string name)
  94. {
  95. if (AreOptionalFiltersEmpty())
  96. return true;
  97. if (testNames == null || testNames.Length == 0)
  98. return true;
  99. foreach (var exactName in testNames)
  100. {
  101. if (name == exactName)
  102. return true;
  103. }
  104. return false;
  105. }
  106. private static void ClearAncestors(IEnumerable<IClearableResult> newResultList, string parentID)
  107. {
  108. if (string.IsNullOrEmpty(parentID))
  109. return;
  110. foreach (var result in newResultList)
  111. {
  112. if (result.Id == parentID)
  113. {
  114. result.Clear();
  115. ClearAncestors(newResultList, result.ParentId);
  116. break;
  117. }
  118. }
  119. }
  120. public void ClearResults(List<IClearableResult> newResultList)
  121. {
  122. foreach (var result in newResultList)
  123. {
  124. if (!result.IsSuite && CategoryMatches(result.Categories))
  125. {
  126. if (IDMatchesAssembly(result.Id) && NameMatches(result.FullName) && NameMatchesExactly(result.FullName))
  127. {
  128. result.Clear();
  129. ClearAncestors(newResultList, result.ParentId);
  130. }
  131. }
  132. }
  133. }
  134. public ITestFilter BuildNUnitFilter()
  135. {
  136. var filters = new List<ITestFilter>();
  137. if (testNames != null && testNames.Length != 0)
  138. {
  139. var nameFilter = new OrFilter(testNames.Select(n => new FullNameFilter(n)).ToArray());
  140. filters.Add(nameFilter);
  141. }
  142. if (groupNames != null && groupNames.Length != 0)
  143. {
  144. var exactNamesFilter = new OrFilter(groupNames.Select(n =>
  145. {
  146. var f = new FullNameFilter(n);
  147. f.IsRegex = true;
  148. return f;
  149. }).ToArray());
  150. filters.Add(exactNamesFilter);
  151. }
  152. if (assemblyNames != null && assemblyNames.Length != 0)
  153. {
  154. var assemblyFilter = new OrFilter(assemblyNames.Select(c => new AssemblyNameFilter(c)).ToArray());
  155. filters.Add(assemblyFilter);
  156. }
  157. if (categoryNames != null && categoryNames.Length != 0)
  158. {
  159. var categoryFilter = new OrFilter(categoryNames.Select(c => new CategoryFilterExtended(c) {IsRegex = true}).ToArray());
  160. filters.Add(categoryFilter);
  161. }
  162. if (synchronousOnly)
  163. {
  164. filters.Add(new SynchronousFilter());
  165. }
  166. return filters.Count == 0 ? TestFilter.Empty : new AndFilter(filters.ToArray());
  167. }
  168. internal interface IClearableResult
  169. {
  170. string Id { get; }
  171. string FullName { get; }
  172. string ParentId { get; }
  173. bool IsSuite { get; }
  174. List<string> Categories { get; }
  175. void Clear();
  176. }
  177. }
  178. }