|
// 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.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Build.BackEnd.SdkResolution;
using Microsoft.Build.Definition;
using Microsoft.Build.Engine.UnitTests.TestComparers;
using Microsoft.Build.Evaluation.Context;
using Microsoft.Build.Execution;
using Microsoft.Build.Framework;
using Microsoft.Build.UnitTests;
using Microsoft.Build.UnitTests.BackEnd;
using Shouldly;
using SdkResolverContext = Microsoft.Build.Framework.SdkResolverContext;
using SdkResult = Microsoft.Build.BackEnd.SdkResolution.SdkResult;
using SdkResultFactory = Microsoft.Build.Framework.SdkResultFactory;
#nullable disable
namespace Microsoft.Build.Unittest
{
internal static class SdkUtilities
{
public static ProjectOptions CreateProjectOptionsWithResolver(SdkResolver resolver)
{
var context = EvaluationContext.Create(EvaluationContext.SharingPolicy.Isolated);
var sdkService = (SdkResolverService)context.SdkResolverService;
sdkService.InitializeForTests(null, new List<SdkResolver>() { resolver });
return new ProjectOptions
{
EvaluationContext = context
};
}
internal sealed class ConfigurableMockSdkResolver : SdkResolver
{
private readonly Dictionary<string, SdkResult> _resultMap;
private readonly Func<SdkReference, SdkResolverContext, SdkResultFactory, Framework.SdkResult> _resolveFunc;
public ConcurrentDictionary<string, int> ResolvedCalls { get; } = new ConcurrentDictionary<string, int>();
public ConfigurableMockSdkResolver(SdkResult result)
{
_resultMap = new Dictionary<string, SdkResult> { [result.SdkReference.Name] = result };
}
public ConfigurableMockSdkResolver(Dictionary<string, SdkResult> resultMap)
{
_resultMap = resultMap;
}
public ConfigurableMockSdkResolver(Func<SdkReference, SdkResolverContext, SdkResultFactory, Framework.SdkResult> resolveFunc)
{
_resolveFunc = resolveFunc;
}
public override string Name => nameof(ConfigurableMockSdkResolver);
public override int Priority => int.MaxValue;
public override Framework.SdkResult Resolve(SdkReference sdkReference, SdkResolverContext resolverContext, SdkResultFactory factory)
{
if (_resolveFunc != null)
{
return _resolveFunc(sdkReference, resolverContext, factory);
}
ResolvedCalls.AddOrUpdate(sdkReference.Name, k => 1, (k, c) => c + 1);
return _resultMap.TryGetValue(sdkReference.Name, out var result)
? CloneSdkResult(result)
: null;
}
private SdkResult CloneSdkResult(SdkResult sdkResult)
{
if (!sdkResult.Success)
{
return new SdkResult(sdkResult.SdkReference, sdkResult.Warnings, sdkResult.Errors);
}
IEnumerable<string> sdkResultPaths;
if (sdkResult.Path == null)
{
sdkResultPaths = Enumerable.Empty<string>();
}
else
{
List<string> pathList = new List<string>();
pathList.Add(sdkResult.Path);
if (sdkResult.AdditionalPaths != null)
{
pathList.AddRange(sdkResult.AdditionalPaths);
}
sdkResultPaths = pathList;
}
Dictionary<string, SdkResultItem> sdkResultItems;
if (sdkResult.ItemsToAdd == null)
{
sdkResultItems = null;
}
else
{
sdkResultItems = new Dictionary<string, SdkResultItem>(StringComparer.OrdinalIgnoreCase);
foreach (var item in sdkResult.ItemsToAdd)
{
Dictionary<string, string> newMetadata = null;
if (item.Value.Metadata != null)
{
newMetadata = new Dictionary<string, string>(item.Value.Metadata, StringComparer.OrdinalIgnoreCase);
}
sdkResultItems.Add(item.Key, new SdkResultItem(item.Value.ItemSpec, newMetadata));
}
}
return new SdkResult(sdkResult.SdkReference,
sdkResultPaths,
version: sdkResult.Version,
sdkResult.PropertiesToAdd == null ? null : new Dictionary<string, string>(sdkResult.PropertiesToAdd, StringComparer.OrdinalIgnoreCase),
sdkResultItems,
sdkResult.Warnings);
}
}
internal sealed class FileBasedMockSdkResolver : SdkResolver
{
private readonly Dictionary<string, string> _mapping;
public FileBasedMockSdkResolver(Dictionary<string, string> mapping)
{
_mapping = mapping;
}
public override string Name => "FileBasedMockSdkResolver";
public override int Priority => int.MinValue;
public override Framework.SdkResult Resolve(SdkReference sdkReference, SdkResolverContext resolverContext, SdkResultFactory factory)
{
resolverContext.Logger.LogMessage($"{nameof(resolverContext.ProjectFilePath)} = {resolverContext.ProjectFilePath}", MessageImportance.High);
resolverContext.Logger.LogMessage($"{nameof(resolverContext.SolutionFilePath)} = {resolverContext.SolutionFilePath}", MessageImportance.High);
resolverContext.Logger.LogMessage($"{nameof(resolverContext.MSBuildVersion)} = {resolverContext.MSBuildVersion}", MessageImportance.High);
return _mapping.ContainsKey(sdkReference.Name)
? factory.IndicateSuccess(_mapping[sdkReference.Name], null)
: factory.IndicateFailure(new[] { $"Not in {nameof(_mapping)}" });
}
}
internal static class EngineHelpers
{
internal static void AssertBuildResultsEqual(BuildResult actualBuildResult, BuildResult expectedBuildResult)
{
actualBuildResult.InitialTargets.ShouldBe(expectedBuildResult.InitialTargets);
actualBuildResult.DefaultTargets.ShouldBe(expectedBuildResult.DefaultTargets);
actualBuildResult.CircularDependency.ShouldBe(expectedBuildResult.CircularDependency);
actualBuildResult.Exception.ShouldBe(expectedBuildResult.Exception);
actualBuildResult.OverallResult.ShouldBe(expectedBuildResult.OverallResult);
actualBuildResult.ProjectStateAfterBuild.ShouldBe(expectedBuildResult.ProjectStateAfterBuild);
Helpers.AssertDictionariesEqual(
actualBuildResult.ResultsByTarget,
expectedBuildResult.ResultsByTarget,
(a, b) =>
{
a.Key.ShouldBe(b.Key);
AssertTargetResultsEqual(a.Value, b.Value);
});
}
internal static void AssertTargetResultsEqual(TargetResult a, TargetResult b)
{
TranslationHelpers.CompareExceptions(a.Exception, b.Exception, out string diffReason).ShouldBeTrue(diffReason);
TranslationHelpers.CompareCollections(a.Items, b.Items, TaskItemComparer.Instance).ShouldBeTrue();
a.ResultCode.ShouldBe(b.ResultCode);
a.WorkUnitResult.ActionCode.ShouldBe(b.WorkUnitResult.ActionCode);
a.WorkUnitResult.Exception.ShouldBe(b.WorkUnitResult.Exception);
a.WorkUnitResult.ResultCode.ShouldBe(b.WorkUnitResult.ResultCode);
}
}
}
}
|