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