1 // Copyright (c) Microsoft. All rights reserved.
2 // Licensed under the MIT license. See LICENSE file in the project root for full license information.
3 
4 using System;
5 using System.Collections.Concurrent;
6 using System.Collections.Generic;
7 using System.Linq;
8 using System.Text;
9 using Microsoft.Build.BackEnd;
10 using Microsoft.Build.BackEnd.SdkResolution;
11 using Microsoft.Build.Definition;
12 using Microsoft.Build.Evaluation.Context;
13 using Microsoft.Build.Execution;
14 using Microsoft.Build.Framework;
15 using SdkResolverContext = Microsoft.Build.Framework.SdkResolverContext;
16 using SdkResult = Microsoft.Build.BackEnd.SdkResolution.SdkResult;
17 using SdkResultFactory = Microsoft.Build.Framework.SdkResultFactory;
18 
19 namespace Microsoft.Build.Unittest
20 {
21     internal static class SdkUtilities
22     {
CreateProjectOptionsWithResolverFileMapping(Dictionary<string, string> mapping)23         public static ProjectOptions CreateProjectOptionsWithResolverFileMapping(Dictionary<string, string> mapping)
24         {
25             var resolver = new FileBasedMockSdkResolver(mapping);
26 
27             var context = EvaluationContext.Create(EvaluationContext.SharingPolicy.Isolated);
28             var sdkService = (SdkResolverService)context.SdkResolverService;
29             sdkService.InitializeForTests(null, new List<SdkResolver>(){resolver});
30 
31             return new ProjectOptions
32             {
33                 EvaluationContext = context
34             };
35         }
36 
37         internal class ConfigurableMockSdkResolver : SdkResolver
38         {
39             private readonly Dictionary<string, SdkResult> _resultMap;
40 
41             public ConcurrentDictionary<string, int> ResolvedCalls { get; } = new ConcurrentDictionary<string, int>();
42 
ConfigurableMockSdkResolver(SdkResult result)43             public ConfigurableMockSdkResolver(SdkResult result)
44             {
45                 _resultMap = new Dictionary<string, SdkResult> { [result.Sdk.Name] = result };
46             }
47 
ConfigurableMockSdkResolver(Dictionary<string, SdkResult> resultMap)48             public ConfigurableMockSdkResolver(Dictionary<string, SdkResult> resultMap)
49             {
50                 _resultMap = resultMap;
51             }
52 
53             public override string Name => nameof(ConfigurableMockSdkResolver);
54 
55             public override int Priority => int.MaxValue;
56 
Resolve(SdkReference sdkReference, SdkResolverContext resolverContext, SdkResultFactory factory)57             public override Framework.SdkResult Resolve(SdkReference sdkReference, SdkResolverContext resolverContext, SdkResultFactory factory)
58             {
59                 ResolvedCalls.AddOrUpdate(sdkReference.Name, k => 1, (k, c) => c + 1);
60 
61                 return _resultMap.TryGetValue(sdkReference.Name, out var result)
62                     ? new SdkResult(sdkReference, result.Path, result.Version, null)
63                     : null;
64             }
65         }
66 
67         internal class FileBasedMockSdkResolver : SdkResolver
68         {
69             private readonly Dictionary<string, string> _mapping;
70 
FileBasedMockSdkResolver(Dictionary<string, string> mapping)71             public FileBasedMockSdkResolver(Dictionary<string, string> mapping)
72             {
73                 _mapping = mapping;
74             }
75             public override string Name => "FileBasedMockSdkResolver";
76             public override int Priority => int.MinValue;
77 
Resolve(SdkReference sdkReference, SdkResolverContext resolverContext, SdkResultFactory factory)78             public override Framework.SdkResult Resolve(SdkReference sdkReference, SdkResolverContext resolverContext, SdkResultFactory factory)
79             {
80                 resolverContext.Logger.LogMessage($"{nameof(resolverContext.ProjectFilePath)} = {resolverContext.ProjectFilePath}", MessageImportance.High);
81                 resolverContext.Logger.LogMessage($"{nameof(resolverContext.SolutionFilePath)} = {resolverContext.SolutionFilePath}", MessageImportance.High);
82                 resolverContext.Logger.LogMessage($"{nameof(resolverContext.MSBuildVersion)} = {resolverContext.MSBuildVersion}", MessageImportance.High);
83 
84                 return _mapping.ContainsKey(sdkReference.Name)
85                     ? factory.IndicateSuccess(_mapping[sdkReference.Name], null)
86                     : factory.IndicateFailure(new[] { $"Not in {nameof(_mapping)}" });
87             }
88         }
89     }
90 }
91