A game about forced loneliness, made by TACStudios
1using System;
2using System.Collections.Generic;
3using System.IO;
4using System.Linq;
5using System.Reflection;
6using UnityEditor;
7using UnityEditor.Scripting.ScriptCompilation;
8using UnityEngine.TestTools;
9using UnityEngine.TestTools.Utils;
10
11namespace UnityEditor.TestTools.TestRunner
12{
13 internal class EditorLoadedTestAssemblyProvider : IEditorLoadedTestAssemblyProvider
14 {
15 private const string k_NunitAssemblyName = "nunit.framework";
16 private const string k_TestRunnerAssemblyName = "UnityEngine.TestRunner";
17 internal const string k_PerformanceTestingAssemblyName = "Unity.PerformanceTesting";
18
19 private readonly IEditorAssembliesProxy m_EditorAssembliesProxy;
20 private readonly ScriptAssembly[] m_AllEditorScriptAssemblies;
21 private readonly PrecompiledAssembly[] m_AllPrecompiledAssemblies;
22
23 public EditorLoadedTestAssemblyProvider(IEditorCompilationInterfaceProxy compilationInterfaceProxy, IEditorAssembliesProxy editorAssembliesProxy)
24 {
25 m_EditorAssembliesProxy = editorAssembliesProxy;
26 m_AllEditorScriptAssemblies = compilationInterfaceProxy.GetAllEditorScriptAssemblies();
27 m_AllPrecompiledAssemblies = compilationInterfaceProxy.GetAllPrecompiledAssemblies();
28 }
29
30 public List<IAssemblyWrapper> GetAssembliesGroupedByType(TestPlatform mode)
31 {
32 var assemblies = GetAssembliesGroupedByTypeAsync(mode);
33 while (assemblies.MoveNext())
34 {
35 }
36
37 return assemblies.Current.Where(pair => mode.IsFlagIncluded(pair.Key)).SelectMany(pair => pair.Value).ToList();
38 }
39
40 public IEnumerator<IDictionary<TestPlatform, List<IAssemblyWrapper>>> GetAssembliesGroupedByTypeAsync(TestPlatform mode)
41 {
42 IAssemblyWrapper[] loadedAssemblies = m_EditorAssembliesProxy.loadedAssemblies;
43
44 IDictionary<TestPlatform, List<IAssemblyWrapper>> result = new Dictionary<TestPlatform, List<IAssemblyWrapper>>
45 {
46 {TestPlatform.EditMode, new List<IAssemblyWrapper>() },
47 {TestPlatform.PlayMode, new List<IAssemblyWrapper>() }
48 };
49 var filteredAssemblies = FilterAssembliesWithTestReference(loadedAssemblies);
50
51 foreach (var loadedAssembly in filteredAssemblies)
52 {
53 var assemblyName = new FileInfo(loadedAssembly.Location).Name;
54 var scriptAssemblies = m_AllEditorScriptAssemblies.Where(x => x.Filename == assemblyName).ToList();
55 var precompiledAssemblies = m_AllPrecompiledAssemblies.Where(x => new FileInfo(x.Path).Name == assemblyName).ToList();
56 if (scriptAssemblies.Count < 1 && precompiledAssemblies.Count < 1)
57 {
58 continue;
59 }
60
61 var assemblyFlags = scriptAssemblies.Any() ? scriptAssemblies.Single().Flags : precompiledAssemblies.Single().Flags;
62 var assemblyType = (assemblyFlags & AssemblyFlags.EditorOnly) == AssemblyFlags.EditorOnly ? TestPlatform.EditMode : TestPlatform.PlayMode;
63 result[assemblyType].Add(loadedAssembly);
64 yield return null;
65 }
66
67 yield return result;
68 }
69
70 private IAssemblyWrapper[] FilterAssembliesWithTestReference(IAssemblyWrapper[] loadedAssemblies)
71 {
72 var filteredResults = new Dictionary<IAssemblyWrapper, bool>();
73 foreach (var assembly in loadedAssemblies)
74 {
75 FilterAssemblyForTestReference(assembly, loadedAssemblies, filteredResults, new Dictionary<IAssemblyWrapper, bool>());
76 }
77
78 return filteredResults.Where(pair => pair.Value).Select(pair => pair.Key).ToArray();
79 }
80
81 private void FilterAssemblyForTestReference(IAssemblyWrapper assemblyToFilter, IAssemblyWrapper[] loadedAssemblies,
82 IDictionary<IAssemblyWrapper, bool> filterResults, IDictionary<IAssemblyWrapper, bool> resultsAlreadyAnalyzed)
83 {
84 if(resultsAlreadyAnalyzed.ContainsKey(assemblyToFilter))
85 {
86 return;
87 }
88
89 resultsAlreadyAnalyzed[assemblyToFilter] = true;
90
91 var references = assemblyToFilter.GetReferencedAssemblies();
92 if (references.Any(IsTestReference))
93 {
94 filterResults[assemblyToFilter] = true;
95 return;
96 }
97
98 foreach (var reference in references)
99 {
100 var referencedAssembly = loadedAssemblies.FirstOrDefault(a => a.Name.Name == reference.Name);
101 if (referencedAssembly == null)
102 {
103 continue;
104 }
105
106 FilterAssemblyForTestReference(referencedAssembly, loadedAssemblies, filterResults, resultsAlreadyAnalyzed);
107
108 if (filterResults.ContainsKey(referencedAssembly) && filterResults[referencedAssembly])
109 {
110 filterResults[assemblyToFilter] = true;
111 return;
112 }
113 }
114
115 filterResults[assemblyToFilter] = false;
116 }
117
118 private static bool IsTestReference(AssemblyName assemblyName)
119 {
120 return assemblyName.Name == k_NunitAssemblyName ||
121 assemblyName.Name == k_TestRunnerAssemblyName ||
122 assemblyName.Name == k_PerformanceTestingAssemblyName;
123 }
124 }
125}