1 using System.IO;
2 using Microsoft.Build.Framework;
3 using Microsoft.Build.Tasks;
4 using Microsoft.Build.Utilities;
5 using Xunit;
6 
7 namespace Microsoft.Build.UnitTests.ResolveAssemblyReference_Tests
8 {
9     /// <summary>
10     /// Unit test the cases where we need to determine if the target framework is greater than the current target framework through the use of the target framework attribute
11     /// </summary>
12     public sealed class VerifyTargetFrameworkAttribute : ResolveAssemblyReferenceTestFixture
13     {
14         /// <summary>
15         /// Verify there are no warnings if the target framework identifier passed to rar and the target framework identifier in the dll do not match.
16         /// </summary>
17         [Fact]
FrameworksDoNotMatch()18         public void FrameworksDoNotMatch()
19         {
20             MockEngine e = new MockEngine();
21 
22             ITaskItem[] items = new ITaskItem[]
23             {
24                 new TaskItem("DependsOnFoo4Framework"),
25             };
26 
27             ResolveAssemblyReference t = new ResolveAssemblyReference();
28             t.BuildEngine = e;
29             t.Assemblies = items;
30             t.TargetFrameworkMoniker = "BAR, Version=4.0";
31             t.TargetFrameworkMonikerDisplayName = "BAR";
32             t.SearchPaths = new string[] { s_frameworksPath + Path.DirectorySeparatorChar };
33             Execute(t);
34 
35             Assert.Equal(0, e.Warnings); // "No warnings expected in this scenario."
36             Assert.Equal(0, e.Errors); // "No errors expected in this scenario."
37             Assert.Equal(1, t.ResolvedFiles.Length);
38             Assert.True(ContainsItem(t.ResolvedFiles, Path.Combine(s_frameworksPath, "DependsOnFoo4Framework.dll"))); // "Expected to find assembly, but didn't."
39         }
40 
41         /// <summary>
42         /// Verify there are no warnings if it is the same framework but we are a lower version. With a primary reference in the project.
43         /// </summary>
44         [Fact]
LowerVersionSameFrameworkDirect()45         public void LowerVersionSameFrameworkDirect()
46         {
47             MockEngine e = new MockEngine();
48 
49             ITaskItem[] items = new ITaskItem[]
50             {
51                 new TaskItem("DependsOnFoo35Framework"),
52             };
53 
54             ResolveAssemblyReference t = new ResolveAssemblyReference();
55             t.BuildEngine = e;
56             t.Assemblies = items;
57             t.TargetFrameworkMoniker = "Foo, Version=v4.0";
58             t.TargetFrameworkMonikerDisplayName = "Foo";
59             t.SearchPaths = new string[] { s_frameworksPath + Path.DirectorySeparatorChar };
60             Execute(t);
61 
62             Assert.Equal(0, e.Warnings); // "No warnings expected in this scenario."
63             Assert.Equal(0, e.Errors); // "No errors expected in this scenario."
64             Assert.Equal(1, t.ResolvedFiles.Length);
65             Assert.True(ContainsItem(t.ResolvedFiles, Path.Combine(s_frameworksPath, "DependsOnFoo35Framework.dll"))); // "Expected to find assembly, but didn't."
66         }
67 
68         /// <summary>
69         /// Verify there are no warnings if it is the same framework and the same version and a direct reference
70         /// </summary>
71         [Fact]
SameVersionSameFrameworkDirect()72         public void SameVersionSameFrameworkDirect()
73         {
74             MockEngine e = new MockEngine();
75 
76             ITaskItem[] items = new ITaskItem[]
77             {
78                 new TaskItem("DependsOnFoo4Framework"),
79             };
80 
81             ResolveAssemblyReference t = new ResolveAssemblyReference();
82             t.BuildEngine = e;
83             t.Assemblies = items;
84             t.TargetFrameworkMoniker = "Foo, Version=4.0";
85             t.TargetFrameworkMonikerDisplayName = "Foo";
86             t.SearchPaths = new string[] { s_frameworksPath + Path.DirectorySeparatorChar };
87             Execute(t);
88 
89             Assert.Equal(0, e.Warnings); // "No warnings expected in this scenario."
90             Assert.Equal(0, e.Errors); // "No errors expected in this scenario."
91             Assert.Equal(1, t.ResolvedFiles.Length);
92             Assert.True(ContainsItem(t.ResolvedFiles, Path.Combine(s_frameworksPath, "DependsOnFoo4Framework.dll"))); // "Expected to find assembly, but didn't."
93         }
94 
95         /// <summary>
96         /// Verify there are no warnings if the reference was built for a higher framework but specific version is true
97         /// </summary>
98         [Fact]
HigherVersionButSpecificVersionDirect()99         public void HigherVersionButSpecificVersionDirect()
100         {
101             MockEngine e = new MockEngine();
102 
103             TaskItem item = new TaskItem("DependsOnFoo45Framework, Version=4.5.0.0, PublicKeyToken=null, Culture=Neutral");
104             item.SetMetadata("SpecificVersion", "true");
105 
106             ITaskItem[] items = new ITaskItem[]
107             {
108                 item
109             };
110 
111             ResolveAssemblyReference t = new ResolveAssemblyReference();
112             t.BuildEngine = e;
113             t.Assemblies = items;
114             t.TargetFrameworkMoniker = "Foo, Version=4.0";
115             t.TargetFrameworkMonikerDisplayName = "Foo";
116             t.SearchPaths = new string[] { s_frameworksPath + Path.DirectorySeparatorChar };
117             Execute(t);
118 
119             Assert.Equal(0, e.Warnings); // "No warnings expected in this scenario."
120             Assert.Equal(0, e.Errors); // "No errors expected in this scenario."
121             Assert.Equal(1, t.ResolvedFiles.Length);
122             Assert.True(ContainsItem(t.ResolvedFiles, Path.Combine(s_frameworksPath, "DependsOnFoo45Framework.dll"))); // "Expected to find assembly, but didn't."
123         }
124 
125         /// <summary>
126         /// Verify there are no warnings if it is the same framework but we are a lower version.
127         /// </summary>
128         [Fact]
LowerVersionSameFrameworkInDirect()129         public void LowerVersionSameFrameworkInDirect()
130         {
131             MockEngine e = new MockEngine();
132 
133             ITaskItem[] items = new ITaskItem[]
134             {
135                 new TaskItem("IndirectDependsOnFoo35Framework"),
136             };
137 
138             ResolveAssemblyReference t = new ResolveAssemblyReference();
139             t.BuildEngine = e;
140             t.Assemblies = items;
141             t.TargetFrameworkMoniker = "Foo, Version=v4.0";
142             t.TargetFrameworkMonikerDisplayName = "Foo";
143             t.SearchPaths = new string[] { s_frameworksPath + Path.DirectorySeparatorChar };
144             Execute(t);
145 
146             Assert.Equal(0, e.Warnings); // "No warnings expected in this scenario."
147             Assert.Equal(0, e.Errors); // "No errors expected in this scenario."
148             Assert.Equal(1, t.ResolvedFiles.Length);
149             Assert.Equal(1, t.ResolvedDependencyFiles.Length);
150             Assert.True(ContainsItem(t.ResolvedFiles, Path.Combine(s_frameworksPath, "IndirectDependsOnFoo35Framework.dll"))); // "Expected to find assembly, but didn't."
151             Assert.True(ContainsItem(t.ResolvedDependencyFiles, Path.Combine(s_frameworksPath, "DependsOnFoo35Framework.dll"))); // "Expected to find assembly, but didn't."
152         }
153 
154         /// <summary>
155         /// Verify there are no warnings if it is the same framework and the same version.
156         /// </summary>
157         [Fact]
SameVersionSameFrameworkInDirect()158         public void SameVersionSameFrameworkInDirect()
159         {
160             MockEngine e = new MockEngine();
161 
162             ITaskItem[] items = new ITaskItem[]
163             {
164                 new TaskItem("IndirectDependsOnFoo4Framework"),
165             };
166 
167             ResolveAssemblyReference t = new ResolveAssemblyReference();
168             t.BuildEngine = e;
169             t.Assemblies = items;
170             t.TargetFrameworkMoniker = "Foo, Version=4.0";
171             t.TargetFrameworkMonikerDisplayName = "Foo";
172             t.SearchPaths = new string[] { s_frameworksPath + Path.DirectorySeparatorChar };
173             Execute(t);
174 
175             Assert.Equal(0, e.Warnings); // "No warnings expected in this scenario."
176             Assert.Equal(0, e.Errors); // "No errors expected in this scenario."
177             Assert.Equal(1, t.ResolvedFiles.Length);
178             Assert.Equal(1, t.ResolvedDependencyFiles.Length);
179             Assert.True(ContainsItem(t.ResolvedFiles, Path.Combine(s_frameworksPath, "IndirectDependsOnFoo4Framework.dll"))); // "Expected to find assembly, but didn't."
180             Assert.True(ContainsItem(t.ResolvedDependencyFiles, Path.Combine(s_frameworksPath, "DependsOnFoo4Framework.dll"))); // "Expected to find assembly, but didn't."
181         }
182 
183         /// <summary>
184         /// Verify there are no warnings if it is the same framework and a higher version but specific version is true.
185         /// </summary>
186         [Fact]
HigherVersionButSpecificVersionInDirect()187         public void HigherVersionButSpecificVersionInDirect()
188         {
189             MockEngine e = new MockEngine();
190 
191             TaskItem item = new TaskItem("IndirectDependsOnFoo45Framework, Version=0.0.0.0, PublicKeyToken=null, Culture=Neutral");
192             item.SetMetadata("SpecificVersion", "true");
193 
194             ITaskItem[] items = new ITaskItem[]
195             {
196                 item
197             };
198 
199             ResolveAssemblyReference t = new ResolveAssemblyReference();
200             t.BuildEngine = e;
201             t.Assemblies = items;
202             t.TargetFrameworkMoniker = "Foo, Version=4.0";
203             t.TargetFrameworkMonikerDisplayName = "Foo";
204             t.SearchPaths = new string[] { s_frameworksPath + Path.DirectorySeparatorChar };
205             Execute(t);
206 
207             Assert.Equal(0, e.Warnings); // "No warnings expected in this scenario."
208             Assert.Equal(0, e.Errors); // "No errors expected in this scenario."
209             Assert.Equal(1, t.ResolvedFiles.Length);
210             Assert.Equal(1, t.ResolvedDependencyFiles.Length);
211             Assert.True(ContainsItem(t.ResolvedFiles, Path.Combine(s_frameworksPath, "IndirectDependsOnFoo45Framework.dll"))); // "Expected to find assembly, but didn't."
212             Assert.True(ContainsItem(t.ResolvedDependencyFiles, Path.Combine(s_frameworksPath, "DependsOnFoo45Framework.dll"))); // "Expected to find assembly, but didn't."
213         }
214 
215         /// <summary>
216         /// Verify there are warnings if there is an indirect reference to a dll that is higher that what the current target framework is.
217         /// </summary>
218         [Fact]
HigherVersionInDirect()219         public void HigherVersionInDirect()
220         {
221             MockEngine e = new MockEngine();
222 
223             TaskItem item = new TaskItem("IndirectDependsOnFoo45Framework, Version=0.0.0.0, PublicKeyToken=null, Culture=Neutral");
224 
225             ITaskItem[] items = new ITaskItem[]
226             {
227                 item
228             };
229 
230             ResolveAssemblyReference t = new ResolveAssemblyReference();
231             t.BuildEngine = e;
232             t.Assemblies = items;
233             t.TargetFrameworkMoniker = "Foo, Version=4.0";
234             t.TargetFrameworkMonikerDisplayName = "Foo";
235             t.SearchPaths = new string[] { s_frameworksPath + Path.DirectorySeparatorChar };
236             Execute(t, false);
237 
238             Assert.Equal(1, e.Warnings); // "One warning expected in this scenario."
239             e.AssertLogContains("MSB3275");
240             Assert.Equal(0, e.Errors); // "No errors expected in this scenario."
241             Assert.Equal(0, t.ResolvedFiles.Length);
242             Assert.Equal(0, t.ResolvedDependencyFiles.Length);
243         }
244 
245         /// <summary>
246         /// Verify there are no warnings if there is an indirect reference to a dll that is higher that what the current target framework is but IgnoreFrameworkAttributeVersionMismatch is true.
247         /// </summary>
248         [Fact]
HigherVersionInDirectIgnoreMismatch()249         public void HigherVersionInDirectIgnoreMismatch()
250         {
251             MockEngine e = new MockEngine();
252 
253             TaskItem item = new TaskItem("IndirectDependsOnFoo45Framework, Version=0.0.0.0, PublicKeyToken=null, Culture=Neutral");
254 
255             ITaskItem[] items = new ITaskItem[]
256             {
257                 item
258             };
259 
260             ResolveAssemblyReference t = new ResolveAssemblyReference();
261             t.BuildEngine = e;
262             t.Assemblies = items;
263             t.TargetFrameworkMoniker = "Foo, Version=4.0";
264             t.TargetFrameworkMonikerDisplayName = "Foo";
265             t.SearchPaths = new string[] { s_frameworksPath + Path.DirectorySeparatorChar };
266             t.IgnoreTargetFrameworkAttributeVersionMismatch = true;
267             Execute(t);
268 
269             Assert.Equal(0, e.Warnings); // "No warnings expected in this scenario."
270             Assert.Equal(0, e.Errors); // "No errors expected in this scenario."
271             Assert.Equal(1, t.ResolvedFiles.Length);
272             Assert.Equal(1, t.ResolvedDependencyFiles.Length);
273             Assert.True(ContainsItem(t.ResolvedFiles, Path.Combine(s_frameworksPath, "IndirectDependsOnFoo45Framework.dll"))); // "Expected to find assembly, but didn't."
274             Assert.True(ContainsItem(t.ResolvedDependencyFiles, Path.Combine(s_frameworksPath, "DependsOnFoo45Framework.dll"))); // "Expected to find assembly, but didn't."
275         }
276 
277         /// <summary>
278         /// Verify there are no warnings if there is a direct reference to a dll that is higher that what the current target framework is but the property IgnoreFrameworkAttributeVersionMismatch is true.
279         /// </summary>
280         [Fact]
HigherVersionDirectIgnoreMismatch()281         public void HigherVersionDirectIgnoreMismatch()
282         {
283             MockEngine e = new MockEngine();
284 
285             TaskItem item = new TaskItem("DependsOnFoo45Framework");
286 
287             ITaskItem[] items = new ITaskItem[]
288             {
289                 item
290             };
291 
292             ResolveAssemblyReference t = new ResolveAssemblyReference();
293             t.BuildEngine = e;
294             t.Assemblies = items;
295             t.TargetFrameworkMoniker = "Foo, Version=4.0";
296             t.TargetFrameworkMonikerDisplayName = "Foo";
297             t.SearchPaths = new string[] { s_frameworksPath + Path.DirectorySeparatorChar };
298             t.IgnoreTargetFrameworkAttributeVersionMismatch = true;
299 
300             Execute(t);
301 
302             Assert.Equal(0, e.Warnings); // "No warnings expected in this scenario."
303             Assert.Equal(0, e.Errors); // "No errors expected in this scenario."
304             Assert.Equal(1, t.ResolvedFiles.Length);
305             Assert.True(ContainsItem(t.ResolvedFiles, Path.Combine(s_frameworksPath, "DependsOnFoo45Framework.dll"))); // "Expected to find assembly, but didn't."
306         }
307 
308 
309         /// <summary>
310         /// Verify there are warnings if there is a direct reference to a dll that is higher that what the current target framework is.
311         /// </summary>
312         [Fact]
HigherVersionDirect()313         public void HigherVersionDirect()
314         {
315             MockEngine e = new MockEngine();
316 
317             TaskItem item = new TaskItem("DependsOnFoo45Framework");
318 
319             ITaskItem[] items = new ITaskItem[]
320             {
321                 item
322             };
323 
324             ResolveAssemblyReference t = new ResolveAssemblyReference();
325             t.BuildEngine = e;
326             t.Assemblies = items;
327             t.TargetFrameworkMoniker = "Foo, Version=4.0";
328             t.TargetFrameworkMonikerDisplayName = "Foo";
329             t.SearchPaths = new string[] { s_frameworksPath + Path.DirectorySeparatorChar };
330             Execute(t, false);
331 
332             Assert.Equal(1, e.Warnings); // "One warning expected in this scenario."
333             e.AssertLogContains("MSB3274");
334             Assert.Equal(0, e.Errors); // "No errors expected in this scenario."
335             Assert.Equal(0, t.ResolvedFiles.Length);
336             Assert.Equal(0, t.ResolvedDependencyFiles.Length);
337         }
338 
339         /// <summary>
340         /// Verify there are no warnings if there is a direct reference to a dll that is higher that what the current target framework is but
341         /// find dependencies is false. This is because we do not want to add an extra read for this attribute during the project load phase.
342         /// which has dependencies set to false.  A regular build or design time build has this set to true so we do the correct check.
343         /// </summary>
344         [Fact]
345         [Trait("Category", "mono-osx-failing")]
HigherVersionDirectDependenciesFalse()346         public void HigherVersionDirectDependenciesFalse()
347         {
348             MockEngine e = new MockEngine();
349 
350             TaskItem item = new TaskItem("DependsOnFoo45Framework");
351 
352             ITaskItem[] items = new ITaskItem[]
353             {
354                 item
355             };
356 
357             ResolveAssemblyReference t = new ResolveAssemblyReference();
358             t.BuildEngine = e;
359             t.Assemblies = items;
360             t.FindDependencies = false;
361             t.TargetFrameworkMoniker = "Foo, Version=4.0";
362             t.TargetFrameworkMonikerDisplayName = "Foo";
363             t.SearchPaths = new string[] { @"c:\Frameworks\" };
364             Assert.True(
365                 t.Execute
366                 (
367                     fileExists,
368                     directoryExists,
369                     getDirectories,
370                     getAssemblyName,
371                     getAssemblyMetadata,
372 #if FEATURE_WIN32_REGISTRY
373                     getRegistrySubKeyNames,
374                     getRegistrySubKeyDefaultValue,
375 #endif
376                     getLastWriteTime,
377                     getRuntimeVersion,
378 #if FEATURE_WIN32_REGISTRY
379                     openBaseKey,
380 #endif
381                     checkIfAssemblyIsInGac,
382                     isWinMDFile,
383                     readMachineTypeFromPEHeader
384                 )
385             );
386 
387 
388             Assert.Equal(0, e.Warnings); // "No warning expected in this scenario."
389             Assert.Equal(0, e.Errors); // "No errors expected in this scenario."
390             Assert.Equal(1, t.ResolvedFiles.Length);
391             Assert.Equal(0, t.ResolvedDependencyFiles.Length);
392             Assert.True(ContainsItem(t.ResolvedFiles, Path.Combine(s_frameworksPath, "DependsOnFoo45Framework.dll"))); // "Expected to find assembly, but didn't."
393         }
394     }
395 }