forked from DynamoDS/RevitTestFramework
-
Notifications
You must be signed in to change notification settings - Fork 5
/
AssemblyLoader.cs
224 lines (188 loc) · 8.35 KB
/
AssemblyLoader.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using NUnit.Framework;
namespace RTF.Framework
{
/// <summary>
/// The AssemblyLoader class is used during reflection only load
/// in an RTF app domain to allow non-locking loading of assemblies.
/// </summary>
[Serializable]
public class AssemblyLoader : MarshalByRefObject
{
public AssemblyLoader(RTFAssemblyResolver resolver)
{
AppDomain.CurrentDomain.ReflectionOnlyAssemblyResolve += resolver.Resolve;
}
public AssemblyData ReadAssembly(string assemblyPath, GroupingType groupType, string workingDirectory)
{
// NOTE: We use reflection only load here so that we don't have to resolve all binaries
// This is an assumption by Dynamo tests which reference assemblies that can be resolved
// at runtime inside Revit.
var assembly = Assembly.ReflectionOnlyLoadFrom(assemblyPath);
var data = new AssemblyData(assemblyPath, assembly.GetName().Name, groupType);
try
{
var revitReference = assembly.GetReferencedAssemblies().FirstOrDefault(x => x.Name.Contains("RevitAPI"));
if (revitReference != null)
{
data.ReferencedRevitVersion = $"{(revitReference.Version.Major + 2000)}";
}
foreach (var fixtureType in assembly.GetTypes())
{
if (!ReadFixture(fixtureType, data, workingDirectory))
{
//Console.WriteLine(string.Format("Journals could not be created for {0}", fixtureType.Name));
}
}
data.Fixtures = data.Fixtures.Sorted(x => x.Name);
return data;
}
catch (ReflectionTypeLoadException ex)
{
Console.WriteLine($"ERROR: Failed to resolve assembly:");
Console.WriteLine($"ERROR: {ex.Message}");
Console.WriteLine($"ERROR: {ex.LoaderExceptions}");
throw new Exception("A referenced type could not be loaded.");
}
}
public static bool ReadFixture(Type fixtureType, IAssemblyData data, string workingDirectory)
{
var fixtureAttribs = CustomAttributeData.GetCustomAttributes(fixtureType);
if (!fixtureAttribs.Any(x => x.Constructor.DeclaringType.Name == nameof(TestFixtureAttribute)))
{
//Console.WriteLine("Specified fixture does not have the required TestFixture attribute.");
return false;
}
var fixData = new FixtureData(data, fixtureType.Name);
data.Fixtures.Add(fixData);
foreach (var test in fixtureType.GetMethods())
{
var testAttribs = CustomAttributeData.GetCustomAttributes(test);
if (!testAttribs.Any(x => x.Constructor.DeclaringType.Name == nameof(TestAttribute)))
{
// skip this method
continue;
}
if (!ReadTest(test, fixData, workingDirectory))
{
//Console.WriteLine(string.Format("Journal could not be created for test:{0} in fixture:{1}", _test,_fixture));
continue;
}
}
// sort the collection
fixData.Tests = fixData.Tests.Sorted(x => x.Name);
return true;
}
public static bool ReadTest(MethodInfo test, IFixtureData data, string workingDirectory)
{
List<string> modelPaths = new List<string>();
var testAttribs = CustomAttributeData.GetCustomAttributes(test);
if (testAttribs.Any(x => x.Constructor.DeclaringType.Name == nameof(IgnoreAttribute)))
{
return false;
}
var testModelAttrib = testAttribs.FirstOrDefault(x => x.Constructor.DeclaringType.Name == nameof(TestModelAttribute));
if (testModelAttrib != null)
{
string absolutePath;
// We can't get the instantiated attribute from the assembly because we performed a ReflectionOnly load
TestModelAttribute testModelAttribute = new TestModelAttribute((string)testModelAttrib.ConstructorArguments.First().Value);
if (Path.IsPathRooted(testModelAttribute.Path))
{
absolutePath = testModelAttribute.Path;
}
else
{
if (workingDirectory == null)
{
// If the working directory is not specified.
// Add the relative path to the assembly's path.
absolutePath = Path.GetFullPath(
Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), testModelAttribute.Path));
}
else
{
absolutePath = Path.GetFullPath(Path.Combine(workingDirectory, testModelAttribute.Path));
}
}
if (testModelAttribute.IsWildcard)
{
string[] modelFiles = null;
try
{
modelFiles = Directory.GetFiles(Path.GetDirectoryName(absolutePath), Path.GetFileName(absolutePath), SearchOption.AllDirectories);
}
catch
{
// Means folder doesn't exist
}
if (modelFiles == null || modelFiles.Length == 0)
{
modelFiles = new string[] { absolutePath };
}
modelPaths.AddRange(modelFiles);
}
else
{
modelPaths.Add(absolutePath);
}
}
else
{
//set the default modelPath to the empty.rfa file that will live in the build directory
modelPaths.Add(Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "empty.rfa"));
}
var runDynamoAttrib = testAttribs.FirstOrDefault(x => x.Constructor.DeclaringType.Name == nameof(RunDynamoAttribute));
var runDynamo = false;
if (runDynamoAttrib != null)
{
runDynamo = (bool)runDynamoAttrib.ConstructorArguments.FirstOrDefault().Value;
}
foreach (string modelPath in modelPaths)
{
var testData = new TestData(data, test.Name, modelPath, runDynamo);
data.Tests.Add(testData);
const string EmptyCategory = "[NO CATEGORY]";
var category = string.Empty;
var categoryAttribs =
testAttribs.Where(x => x.Constructor.DeclaringType.Name == nameof(CategoryAttribute));
if (categoryAttribs.Any())
{
foreach (var categoryAttrib in categoryAttribs)
{
category = categoryAttrib.ConstructorArguments.FirstOrDefault().Value.ToString();
if (String.IsNullOrEmpty(category))
{
category = EmptyCategory;
}
AddWithCategory(data, category, testData);
}
}
else
{
AddWithCategory(data, EmptyCategory, testData);
}
Console.WriteLine($"Loaded test: {testData} ({modelPath})");
}
return true;
}
private static void AddWithCategory(IFixtureData data, string category, TestData testData)
{
var cat = data.Assembly.Categories.FirstOrDefault(x => x.Name == category);
if (cat != null)
{
cat.Tests.Add(testData);
}
else
{
var catData = new CategoryData(data.Assembly, category);
catData.Tests.Add(testData);
data.Assembly.Categories.Add(catData);
}
}
}
}