blob: 59d42c7a94237e618bc7ae78f16fc8dfbc449de8 (
plain)
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
|
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using System;
using System.Linq;
using Mono.Cecil;
using Mono.Linker.Tests.Extensions;
using Mono.Linker.Tests.TestCases;
namespace Mono.Linker.Tests.TestCasesRunner
{
public abstract class BaseMetadataProvider
{
protected readonly TestCase _testCase;
protected readonly TypeDefinition _testCaseTypeDefinition;
protected BaseMetadataProvider (TestCase testCase, AssemblyDefinition fullTestCaseAssemblyDefinition)
{
_testCase = testCase;
// The test case types are never nested so we don't need to worry about that
_testCaseTypeDefinition = fullTestCaseAssemblyDefinition.MainModule.GetType (_testCase.ReconstructedFullTypeName);
if (_testCaseTypeDefinition == null)
throw new InvalidOperationException ($"Could not find the type definition for {_testCase.Name} in {_testCase.SourceFile}");
}
protected T GetOptionAttributeValue<T> (string attributeName, T defaultValue)
{
var attribute = _testCaseTypeDefinition.CustomAttributes.FirstOrDefault (attr => attr.AttributeType.Name == attributeName);
if (attribute != null)
return (T) attribute.ConstructorArguments.First ().Value;
return defaultValue;
}
protected NPath MakeSourceTreeFilePathAbsolute (string value)
{
return _testCase.SourceFile.Parent.Combine (value);
}
protected SourceAndDestinationPair GetSourceAndRelativeDestinationValue (CustomAttribute attribute)
{
var fullSource = SourceFileForAttributeArgumentValue (attribute.ConstructorArguments.First ().Value);
var destinationFileName = (string) attribute.ConstructorArguments[1].Value;
return new SourceAndDestinationPair {
Source = fullSource,
DestinationFileName = string.IsNullOrEmpty (destinationFileName) ? fullSource.FileName : destinationFileName
};
}
protected virtual NPath SourceFileForAttributeArgumentValue (object value)
{
if (value is TypeReference valueAsTypeRef) {
// Use the parent type for locating the source file
var parentType = ParentMostType (valueAsTypeRef);
var pathRelativeToAssembly = $"{parentType.FullName.Substring (parentType.Module.Name.Length - 3).Replace ('.', '/')}.cs".ToNPath ();
var pathElements = pathRelativeToAssembly.Elements.ToArray ();
var topMostDirectoryName = pathElements[0];
var topMostDirectory = _testCase.SourceFile.RecursiveParents.Reverse ().FirstOrDefault (d => !d.IsRoot && d.FileName == topMostDirectoryName);
if (topMostDirectory == null) {
// Before giving up, try and detect the naming scheme for tests that use a dot in the top level directory name.
// Ex:
// Attributes.Debugger
// + 1 because the file name is one of the elements
if (pathElements.Length >= 3) {
topMostDirectoryName = $"{pathElements[0]}.{pathElements[1]}";
topMostDirectory = _testCase.SourceFile.RecursiveParents.Reverse ().FirstOrDefault (d => !d.IsRoot && d.FileName == topMostDirectoryName);
pathRelativeToAssembly = topMostDirectoryName.ToNPath ().Combine (pathElements.Skip (2).Aggregate (new NPath (string.Empty), (path, s) => path.Combine (s)));
}
if (topMostDirectory == null)
throw new ArgumentException ($"Unable to locate the source file for type {valueAsTypeRef}. Could not locate directory {topMostDirectoryName}. Ensure the type name matches the file name. And the namespace match the directory structure on disk");
}
var fullPath = topMostDirectory.Parent.Combine (pathRelativeToAssembly);
if (!fullPath.Exists ())
throw new ArgumentException ($"Unable to locate the source file for type {valueAsTypeRef}. Expected {fullPath}. Ensure the type name matches the file name. And the namespace match the directory structure on disk");
return fullPath;
}
return MakeSourceTreeFilePathAbsolute (value.ToString ());
}
static TypeReference ParentMostType (TypeReference type)
{
if (!type.IsNested)
return type;
return ParentMostType (type.DeclaringType);
}
}
}
|