Welcome to mirror list, hosted at ThFree Co, Russian Federation.

BaseMetadataProvider.cs « TestCasesRunner « Mono.Linker.Tests « test - github.com/mono/linker.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
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);
		}
	}
}