Skip to content

Commit

Permalink
Merge settings safely (#771)
Browse files Browse the repository at this point in the history
  • Loading branch information
nohwnd committed Feb 15, 2021
1 parent 7f89665 commit f55dc39
Show file tree
Hide file tree
Showing 5 changed files with 179 additions and 1 deletion.
61 changes: 61 additions & 0 deletions src/Adapter/MSTest.CoreAdapter/Helpers/DictionaryHelper.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

namespace Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Helpers
{
using System;
using System.Collections.Generic;
using System.Linq;

internal static class DictionaryHelper
{
public static IDictionary<TKey, TValue> ConcatWithOverwrites<TKey, TValue>(
this IDictionary<TKey, TValue> source,
IDictionary<TKey, TValue> overwrite,
string sourceFriendlyName = "source",
string overwriteFriendlyName = "overwrite")
where TKey : IEquatable<TKey>
{
if ((source == null || source?.Count == 0) && (overwrite == null || overwrite?.Count == 0))
{
PlatformServiceProvider.Instance.AdapterTraceLogger.LogInfo("DictionaryHelper.ConcatWithOverwrites: Both {0} and {1} dictionaries are null or empty, returning empty dictionary.", sourceFriendlyName, overwriteFriendlyName);
return new Dictionary<TKey, TValue>();
}

if (overwrite == null || overwrite?.Count == 0)
{
PlatformServiceProvider.Instance.AdapterTraceLogger.LogInfo("DictionaryHelper.ConcatWithOverwrites: The {0} is null or empty, returning the {1} dictionary.", overwriteFriendlyName, sourceFriendlyName);
return source.ToDictionary(p => p.Key, p => p.Value);
}

if (source == null || source?.Count == 0)
{
PlatformServiceProvider.Instance.AdapterTraceLogger.LogInfo("DictionaryHelper.ConcatWithOverwrites: The {0} is null or empty, returning the {1} dictionary.", sourceFriendlyName, overwriteFriendlyName);
return overwrite.ToDictionary(p => p.Key, p => p.Value);
}

PlatformServiceProvider.Instance.AdapterTraceLogger.LogInfo("DictionaryHelper.ConcatWithOverwrites: The {0} has {1} keys. And {2} has {3} keys. Merging them.", sourceFriendlyName, source.Count, overwriteFriendlyName, overwrite.Count);
var destination = source.ToDictionary(p => p.Key, p => p.Value);
PlatformServiceProvider.Instance.AdapterTraceLogger.LogInfo("DictionaryHelper.ConcatWithOverwrites: Taking all keys from {0}: {1}.", sourceFriendlyName, string.Join(", ", source.Keys));
var overwrites = new List<TKey>();
foreach (var k in overwrite.Keys)
{
if (destination.ContainsKey(k))
{
PlatformServiceProvider.Instance.AdapterTraceLogger.LogInfo("DictionaryHelper.ConcatWithOverwrites: The {0} already contains key {1}. Overwriting it with value from {2}.", sourceFriendlyName, k, overwriteFriendlyName);
destination[k] = overwrite[k];
overwrites.Add(k);
}
else
{
PlatformServiceProvider.Instance.AdapterTraceLogger.LogInfo("DictionaryHelper.ConcatWithOverwrites: The {0} does not contain key {1}. Adding it from {2}.", sourceFriendlyName, k, overwriteFriendlyName);
destination.Add(k, overwrite[k]);
}
}

PlatformServiceProvider.Instance.AdapterTraceLogger.LogInfo("DictionaryHelper.ConcatWithOverwrites: Merging done: Resulting dictionary has keys {0}, overwrites {1}.", string.Join(", ", destination.Keys), string.Join(", ", overwrites));

return destination;
}
}
}
1 change: 1 addition & 0 deletions src/Adapter/MSTest.CoreAdapter/MSTest.CoreAdapter.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
<Compile Include="Extensions\TestContextExtensions.cs" />
<Compile Include="Extensions\TestResultExtensions.cs" />
<Compile Include="Extensions\UnitTestOutcomeExtensions.cs" />
<Compile Include="Helpers\DictionaryHelper.cs" />
<Compile Include="Helpers\RunSettingsUtilities.cs" />
<Compile Include="Helpers\TestRunParameters.cs" />
<Compile Include="MSTestDiscoverer.cs" />
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

namespace Microsoft.VisualStudio.TestPlatform.MSTestAdapter.UnitTests
{
extern alias FrameworkV1;
extern alias FrameworkV2;

using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using FluentAssertions;
using Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter;
using Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Helpers;
using Moq;

using TestableImplementations;
using Assert = FrameworkV1::Microsoft.VisualStudio.TestTools.UnitTesting.Assert;
using CollectionAssert = FrameworkV1::Microsoft.VisualStudio.TestTools.UnitTesting.CollectionAssert;
using TestClass = FrameworkV1::Microsoft.VisualStudio.TestTools.UnitTesting.TestClassAttribute;
using TestCleanup = FrameworkV1::Microsoft.VisualStudio.TestTools.UnitTesting.TestCleanupAttribute;
using TestInitialize = FrameworkV1::Microsoft.VisualStudio.TestTools.UnitTesting.TestInitializeAttribute;
using TestMethod = FrameworkV1::Microsoft.VisualStudio.TestTools.UnitTesting.TestMethodAttribute;
using UTF = FrameworkV2::Microsoft.VisualStudio.TestTools.UnitTesting;

[TestClass]
public class DictionaryHelperTests
{
[TestMethod]
public void ConcatenatingDictionariesReturnsEmptyDictionaryWhenBothSidesAreNullOrEmpty()
{
Dictionary<string, string> source = null;

var overwrite = new Dictionary<string, string>();

var actual = source.ConcatWithOverwrites(overwrite, nameof(source), nameof(overwrite));
var expected = new Dictionary<string, string>();

actual.Should().BeEquivalentTo(expected);
}

[TestMethod]
public void ConcatenatingDictionariesReturnsSourceSideWhenOverwriteIsNullOrEmpty()
{
var source = new Dictionary<string, string>
{
["aaa"] = "source",
["bbb"] = "source",
};

Dictionary<string, string> overwrite = null;

var actual = source.ConcatWithOverwrites(overwrite, nameof(source), nameof(overwrite));

actual.Should().BeEquivalentTo(source);
}

[TestMethod]
public void ConcatenatingDictionariesReturnsOverwriteSideWhenSourceIsNullOrEmpty()
{
Dictionary<string, string> source = null;

var overwrite = new Dictionary<string, string>
{
["bbb"] = "overwrite",
["ccc"] = "overwrite",
};

var actual = source.ConcatWithOverwrites(overwrite, nameof(source), nameof(overwrite));

actual.Should().BeEquivalentTo(overwrite);
}

[TestMethod]
public void ConcatenatingDictionariesShouldMergeThemAndTakeDuplicateKeysFromOverwrite()
{
var source = new Dictionary<string, string>
{
["aaa"] = "source",
["bbb"] = "source",
};

var overwrite = new Dictionary<string, string>
{
["bbb"] = "overwrite",
["ccc"] = "overwrite",
};

var actual = source.ConcatWithOverwrites(overwrite, nameof(source), nameof(overwrite));
var expected = new Dictionary<string, string>
{
// this is only present in source, take it
["aaa"] = "source",

// this is present in source and overwrite, take it from overwrite
["bbb"] = "overwrite",

// this is present only in overwrite, take it from overwrite
["ccc"] = "overwrite",
};

actual.Should().BeEquivalentTo(expected);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,9 @@
<HintPath>$(TestFxRoot)packages\Castle.Core.3.3.3\lib\net45\Castle.Core.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="FluentAssertions, Version=5.10.3.0, Culture=neutral, PublicKeyToken=33f2691a05b67b6a, processorArchitecture=MSIL">
<HintPath>..\..\..\packages\FluentAssertions.5.10.3\lib\net45\FluentAssertions.dll</HintPath>
</Reference>
<Reference Include="Microsoft.TestPlatform.CoreUtilities, Version=15.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>..\..\..\packages\Microsoft.TestPlatform.ObjectModel.$(TestPlatformVersion)\lib\net451\Microsoft.TestPlatform.CoreUtilities.dll</HintPath>
</Reference>
Expand All @@ -62,9 +65,13 @@
<Reference Include="System.Collections.Immutable, Version=1.2.3.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>..\..\..\packages\System.Collections.Immutable.1.5.0\lib\portable-net45+win8+wp8+wpa81\System.Collections.Immutable.dll</HintPath>
</Reference>
<Reference Include="System.Configuration" />
<Reference Include="System.Reflection.Metadata, Version=1.4.3.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>..\..\..\packages\System.Reflection.Metadata.1.6.0\lib\portable-net45+win8\System.Reflection.Metadata.dll</HintPath>
</Reference>
<Reference Include="System.ValueTuple, Version=4.0.2.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
<HintPath>..\..\..\packages\System.ValueTuple.4.4.0\lib\netstandard1.0\System.ValueTuple.dll</HintPath>
</Reference>
<Reference Include="System.Xml" />
<Reference Include="System.Xml.Linq" />
<Reference Include="Microsoft.VisualStudio.QualityTools.UnitTestFramework, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
Expand Down Expand Up @@ -99,6 +106,7 @@
<Compile Include="Extensions\TestContextExtensionsTests.cs" />
<Compile Include="Extensions\TestResultExtensionsTests.cs" />
<Compile Include="Extensions\UnitTestOutcomeExtensionsTests.cs" />
<Compile Include="Helpers\DictionaryHelperTests.cs" />
<Compile Include="Helpers\ReflectHelperTests.cs" />
<Compile Include="Helpers\RunSettingsUtilitiesTests.cs" />
<Compile Include="Helpers\UnitTestOutcomeHelperTests.cs" />
Expand Down
4 changes: 3 additions & 1 deletion test/UnitTests/MSTest.CoreAdapter.Unit.Tests/packages.config
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="Castle.Core" version="3.3.3" targetFramework="net452" />
<package id="Microsoft.TestPlatform.ObjectModel" version="16.10.0-preview-20210204-01" targetFramework="net452" />
<package id="FluentAssertions" version="5.10.3" targetFramework="net452" />
<package id="Microsoft.TestPlatform.AdapterUtilities" version="16.10.0-preview-20210204-01" targetFramework="net452" />
<package id="Microsoft.TestPlatform.ObjectModel" version="16.10.0-preview-20210204-01" targetFramework="net452" />
<package id="Moq" version="4.5.21" targetFramework="net452" />
<package id="NuGet.Frameworks" version="5.0.0" targetFramework="net452" />
<package id="StyleCop.Analyzers" version="1.0.0" targetFramework="net452" developmentDependency="true" />
<package id="System.Collections.Immutable" version="1.5.0" targetFramework="net452" />
<package id="System.Reflection.Metadata" version="1.6.0" targetFramework="net452" />
<package id="System.ValueTuple" version="4.4.0" targetFramework="net452" />
</packages>

0 comments on commit f55dc39

Please sign in to comment.