1 using System;
2 using System.Collections.Generic;
3 using System.Linq;
4 using Mono.Cecil;
5 using Mono.Linker.Tests.Cases.Expectations.Assertions;
6 using Mono.Linker.Tests.Cases.Expectations.Metadata;
7 using Mono.Linker.Tests.Extensions;
8 using Mono.Linker.Tests.TestCases;
9 
10 namespace Mono.Linker.Tests.TestCasesRunner {
11 	public class TestCaseMetadaProvider {
12 		protected readonly TestCase _testCase;
13 		protected readonly AssemblyDefinition _fullTestCaseAssemblyDefinition;
14 		protected readonly TypeDefinition _testCaseTypeDefinition;
15 
TestCaseMetadaProvider(TestCase testCase, AssemblyDefinition fullTestCaseAssemblyDefinition)16 		public TestCaseMetadaProvider (TestCase testCase, AssemblyDefinition fullTestCaseAssemblyDefinition)
17 		{
18 			_testCase = testCase;
19 			_fullTestCaseAssemblyDefinition = fullTestCaseAssemblyDefinition;
20 			// The test case types are never nested so we don't need to worry about that
21 			_testCaseTypeDefinition = fullTestCaseAssemblyDefinition.MainModule.GetType (_testCase.ReconstructedFullTypeName);
22 
23 			if (_testCaseTypeDefinition == null)
24 				throw new InvalidOperationException ($"Could not find the type definition for {_testCase.Name} in {_testCase.SourceFile}");
25 		}
26 
GetLinkerOptions()27 		public virtual TestCaseLinkerOptions GetLinkerOptions ()
28 		{
29 			var tclo = new TestCaseLinkerOptions {
30 				Il8n = GetOptionAttributeValue (nameof (Il8nAttribute), "none"),
31 				IncludeBlacklistStep = GetOptionAttributeValue (nameof (IncludeBlacklistStepAttribute), false),
32 				KeepTypeForwarderOnlyAssemblies = GetOptionAttributeValue (nameof (KeepTypeForwarderOnlyAssembliesAttribute), string.Empty),
33 				CoreAssembliesAction = GetOptionAttributeValue<string> (nameof (SetupLinkerCoreActionAttribute), null)
34 			};
35 
36 			foreach (var assemblyAction in _testCaseTypeDefinition.CustomAttributes.Where (attr => attr.AttributeType.Name == nameof (SetupLinkerActionAttribute)))
37 			{
38 				var ca = assemblyAction.ConstructorArguments;
39 				tclo.AssembliesAction.Add (new KeyValuePair<string, string> ((string)ca [0].Value, (string)ca [1].Value));
40 			}
41 
42 			foreach (var additionalArgumentAttr in _testCaseTypeDefinition.CustomAttributes.Where (attr => attr.AttributeType.Name == nameof (SetupLinkerArgumentAttribute)))
43 			{
44 				var ca = additionalArgumentAttr.ConstructorArguments;
45 				var values = ((CustomAttributeArgument [])ca [1].Value)?.Select (arg => arg.Value.ToString ()).ToArray ();
46 				tclo.AdditionalArguments.Add (new KeyValuePair<string, string []> ((string)ca [0].Value, values));
47 			}
48 
49 			return tclo;
50 		}
51 
GetReferencedAssemblies(NPath workingDirectory)52 		public virtual IEnumerable<string> GetReferencedAssemblies (NPath workingDirectory)
53 		{
54 			yield return workingDirectory.Combine ("Mono.Linker.Tests.Cases.Expectations.dll").ToString ();
55 			yield return "mscorlib.dll";
56 
57 			foreach (var referenceAttr in _testCaseTypeDefinition.CustomAttributes.Where (attr => attr.AttributeType.Name == nameof (ReferenceAttribute))) {
58 				yield return (string) referenceAttr.ConstructorArguments.First ().Value;
59 			}
60 		}
61 
GetResources()62 		public virtual IEnumerable<SourceAndDestinationPair> GetResources ()
63 		{
64 			return _testCaseTypeDefinition.CustomAttributes
65 				.Where (attr => attr.AttributeType.Name == nameof (SetupCompileResourceAttribute))
66 				.Select (GetSourceAndRelativeDestinationValue);
67 		}
68 
GetExtraLinkerSearchDirectories()69 		public virtual IEnumerable<NPath> GetExtraLinkerSearchDirectories ()
70 		{
71 			yield break;
72 		}
73 
IsIgnored(out string reason)74 		public bool IsIgnored (out string reason)
75 		{
76 			var ignoreAttribute = _testCaseTypeDefinition.CustomAttributes.FirstOrDefault (attr => attr.AttributeType.Name == nameof (IgnoreTestCaseAttribute));
77 			if (ignoreAttribute != null) {
78 				reason = (string)ignoreAttribute.ConstructorArguments.First ().Value;
79 				return true;
80 			}
81 
82 			reason = null;
83 			return false;
84 		}
85 
AdditionalFilesToSandbox()86 		public virtual IEnumerable<SourceAndDestinationPair> AdditionalFilesToSandbox ()
87 		{
88 			return _testCaseTypeDefinition.CustomAttributes
89 				.Where (attr => attr.AttributeType.Name == nameof (SandboxDependencyAttribute))
90 				.Select (GetSourceAndRelativeDestinationValue);
91 		}
92 
GetSetupCompileAssembliesBefore()93 		public virtual IEnumerable<SetupCompileInfo> GetSetupCompileAssembliesBefore ()
94 		{
95 			return _testCaseTypeDefinition.CustomAttributes
96 				.Where (attr => attr.AttributeType.Name == nameof (SetupCompileBeforeAttribute))
97 				.Select (CreateSetupCompileAssemblyInfo);
98 		}
99 
GetSetupCompileAssembliesAfter()100 		public virtual IEnumerable<SetupCompileInfo> GetSetupCompileAssembliesAfter ()
101 		{
102 			return _testCaseTypeDefinition.CustomAttributes
103 				.Where (attr => attr.AttributeType.Name == nameof (SetupCompileAfterAttribute))
104 				.Select (CreateSetupCompileAssemblyInfo);
105 		}
106 
GetDefines()107 		public virtual IEnumerable<string> GetDefines ()
108 		{
109 			return _testCaseTypeDefinition.CustomAttributes
110 				.Where (attr => attr.AttributeType.Name == nameof (DefineAttribute))
111 				.Select (attr => (string) attr.ConstructorArguments.First ().Value);
112 		}
113 
GetAssemblyName()114 		public virtual string GetAssemblyName ()
115 		{
116 			return GetOptionAttributeValue (nameof (SetupCompileAssemblyNameAttribute), "test.exe");
117 		}
118 
GetSetupCompilerArguments()119 		public virtual IEnumerable<string> GetSetupCompilerArguments ()
120 		{
121 			return _testCaseTypeDefinition.CustomAttributes
122 				.Where (attr => attr.AttributeType.Name == nameof (SetupCompileArgumentAttribute))
123 				.Select (attr => (string) attr.ConstructorArguments.First ().Value);
124 		}
125 
GetOptionAttributeValue(string attributeName, T defaultValue)126 		T GetOptionAttributeValue<T> (string attributeName, T defaultValue)
127 		{
128 			var attribute = _testCaseTypeDefinition.CustomAttributes.FirstOrDefault (attr => attr.AttributeType.Name == attributeName);
129 			if (attribute != null)
130 				return (T) attribute.ConstructorArguments.First ().Value;
131 
132 			return defaultValue;
133 		}
134 
GetSourceAndRelativeDestinationValue(CustomAttribute attribute)135 		SourceAndDestinationPair GetSourceAndRelativeDestinationValue (CustomAttribute attribute)
136 		{
137 			var relativeSource = (string) attribute.ConstructorArguments.First ().Value;
138 			var destinationFileName = (string) attribute.ConstructorArguments [1].Value;
139 			var fullSource = _testCase.SourceFile.Parent.Combine (relativeSource);
140 			return new SourceAndDestinationPair
141 			{
142 				Source = fullSource,
143 				DestinationFileName = string.IsNullOrEmpty (destinationFileName) ? fullSource.FileName : destinationFileName
144 			};
145 		}
146 
CreateSetupCompileAssemblyInfo(CustomAttribute attribute)147 		private SetupCompileInfo CreateSetupCompileAssemblyInfo (CustomAttribute attribute)
148 		{
149 			var ctorArguments = attribute.ConstructorArguments;
150 			return new SetupCompileInfo
151 			{
152 				OutputName = (string) ctorArguments [0].Value,
153 				SourceFiles = ((CustomAttributeArgument []) ctorArguments [1].Value).Select (arg => _testCase.SourceFile.Parent.Combine (arg.Value.ToString ())).ToArray (),
154 				References = ((CustomAttributeArgument []) ctorArguments [2].Value)?.Select (arg => arg.Value.ToString ()).ToArray (),
155 				Defines = ((CustomAttributeArgument []) ctorArguments [3].Value)?.Select (arg => arg.Value.ToString ()).ToArray (),
156 				AddAsReference = ctorArguments.Count >= 5 ? (bool) ctorArguments [4].Value : true
157 			};
158 		}
159 	}
160 }