From aad3acfa002870a3f42621bbc68de270df7796c0 Mon Sep 17 00:00:00 2001 From: Ladi Prosek Date: Tue, 5 Jan 2021 13:07:48 +0100 Subject: [PATCH] Remove old interning code tests --- ...Microsoft.Build.Engine.OM.UnitTests.csproj | 4 - .../OpportunisticIntern_Tests.cs | 217 ------------------ src/Build.UnitTests/WeakStringCache_Tests.cs | 185 --------------- ...Microsoft.Build.Framework.UnitTests.csproj | 4 - .../Microsoft.Build.UnitTests.Shared.csproj | 12 - 5 files changed, 422 deletions(-) delete mode 100644 src/Build.UnitTests/OpportunisticIntern_Tests.cs delete mode 100644 src/Build.UnitTests/WeakStringCache_Tests.cs diff --git a/src/Build.OM.UnitTests/Microsoft.Build.Engine.OM.UnitTests.csproj b/src/Build.OM.UnitTests/Microsoft.Build.Engine.OM.UnitTests.csproj index 5ec78a92068..18ad711bac4 100644 --- a/src/Build.OM.UnitTests/Microsoft.Build.Engine.OM.UnitTests.csproj +++ b/src/Build.OM.UnitTests/Microsoft.Build.Engine.OM.UnitTests.csproj @@ -99,10 +99,6 @@ True - - - - true diff --git a/src/Build.UnitTests/OpportunisticIntern_Tests.cs b/src/Build.UnitTests/OpportunisticIntern_Tests.cs deleted file mode 100644 index c47f751c349..00000000000 --- a/src/Build.UnitTests/OpportunisticIntern_Tests.cs +++ /dev/null @@ -1,217 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System; -using System.Text; -using Microsoft.Build.Shared; -using Xunit; -using Xunit.Abstractions; - -namespace Microsoft.Build.UnitTests -{ - public abstract class OpportunisticInternTestBase : IDisposable - { - protected TestEnvironment _env; - - public void Dispose() - { - _env.Dispose(); - } - - protected OpportunisticInternTestBase(ITestOutputHelper testOutput) - { - _env = TestEnvironment.Create(testOutput); - } - - private static bool IsInternable(IInternable internable) - { - string i1 = OpportunisticIntern.InternableToString(internable); - string i2 = OpportunisticIntern.InternableToString(internable); - Assert.Equal(i1, i2); // No matter what, the same string value should return. - return Object.ReferenceEquals(i1, i2); - } - - private static void AssertInternable(IInternable internable) - { - Assert.True(IsInternable(internable)); - } - - private static void AssertInternable(StringBuilder sb) - { - AssertInternable(new StringBuilderInternTarget(sb)); - } - - private static string AssertInternable(char[] ch, int startIndex, int count) - { - var target = new CharArrayInternTarget(ch, startIndex, count); - AssertInternable(target); - Assert.Equal(target.Length, count); - - return target.ExpensiveConvertToString(); - } - - private static void AssertInternable(string value) - { - AssertInternable(new StringBuilder(value)); - AssertInternable(value.ToCharArray(), 0, value.ToCharArray().Length); - } - - private static void AssertNotInternable(IInternable internable) - { - Assert.False(IsInternable(internable)); - } - - private static void AssertNotInternable(StringBuilder sb) - { - AssertNotInternable(new StringBuilderInternTarget(sb)); - } - - private static void AssertNotInternable(char[] ch) - { - AssertNotInternable(new CharArrayInternTarget(ch, ch.Length)); - } - - protected static void AssertNotInternable(string value) - { - AssertNotInternable(new StringBuilder(value)); - AssertNotInternable(value.ToCharArray()); - } - - /// - /// Test interning segment of char array - /// - [Fact] - public void SubArray() - { - var result = AssertInternable(new char[] { 'a', 't', 'r', 'u', 'e' }, 1, 4); - - Assert.Equal("true", result); - } - - /// - /// Test interning segment of char array - /// - [Fact] - public void SubArray2() - { - var result = AssertInternable(new char[] { 'a', 't', 'r', 'u', 'e', 'x' }, 1, 4); - - Assert.Equal("true", result); - } - - /// - /// Unique strings should not be interned - /// - [Fact] - public void NonInternableDummyGlobalVariable() - { - AssertNotInternable($"{MSBuildConstants.MSBuildDummyGlobalPropertyHeader}{new string('1', 100)}"); - } - - /// - /// This is the list of hard-coded interns. They should report interned even though they are too small for normal interning. - /// - [Fact] - public void KnownInternableTinyStrings() - { - AssertInternable("C#"); - AssertInternable("F#"); - AssertInternable("VB"); - AssertInternable("True"); - AssertInternable("TRUE"); - AssertInternable("Copy"); - AssertInternable("v4.0"); - AssertInternable("true"); - AssertInternable("FALSE"); - AssertInternable("false"); - AssertInternable("Debug"); - AssertInternable("Build"); - AssertInternable("''!=''"); - AssertInternable("AnyCPU"); - AssertInternable("Library"); - AssertInternable("MSBuild"); - AssertInternable("Release"); - AssertInternable("ResolveAssemblyReference"); - } - - /// - /// Test a set of strings that are similar to each other - /// - [Fact] - public void InternableDifferingOnlyByNthCharacter() - { - string test = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890!@#$%^&*()_+ABCDEFGHIJKLMNOPQRSTUVabcdefghijklmnopqrstuvwxyz0150"; - for (int i = 0; i < test.Length; ++i) - { - string mutated = test.Substring(0, i) + " " + test.Substring(i + 1); - AssertInternable(mutated); - } - } - - /// - /// Test The empty string - /// - [Fact] - public void StringDotEmpty() - { - AssertInternable(String.Empty); - } - - /// - /// Test an empty string. - /// - [Fact] - public void DoubleDoubleQuotes() - { - AssertInternable(""); - } - } - - /// - /// Tests the new (default) implementation of OpportunisticIntern. - /// - public class OpportunisticIntern_Tests : OpportunisticInternTestBase - { - public OpportunisticIntern_Tests(ITestOutputHelper testOutput) - : base(testOutput) - { - OpportunisticIntern.ResetForTests(); - } - } - - /// - /// Tests the legacy implementation of OpportunisticIntern. - /// - public class OpportunisticInternLegacy_Tests : OpportunisticInternTestBase - { - public OpportunisticInternLegacy_Tests(ITestOutputHelper testOutput) - : base(testOutput) - { - _env.SetEnvironmentVariable("MSBuildUseLegacyStringInterner", "1"); - OpportunisticIntern.ResetForTests(); - } - - /// - /// The legacy implementation does not intern tiny strings unless they are on the hard-coded list. - /// - [Fact] - public void NonInternableTinyString() - { - AssertNotInternable("1234"); - } - } - - /// - /// Tests the legacy implementation of OpportunisticIntern with simple concurrency enabled. - /// - public class OpportunisticInternLegacySimpleConcurrecy_Tests : OpportunisticInternTestBase - { - public OpportunisticInternLegacySimpleConcurrecy_Tests(ITestOutputHelper testOutput) - : base(testOutput) - { - _env.SetEnvironmentVariable("MSBuildUseLegacyStringInterner", "1"); - _env.SetEnvironmentVariable("MSBuildUseSimpleInternConcurrency", "1"); - OpportunisticIntern.ResetForTests(); - } - } -} diff --git a/src/Build.UnitTests/WeakStringCache_Tests.cs b/src/Build.UnitTests/WeakStringCache_Tests.cs deleted file mode 100644 index ece79899fd0..00000000000 --- a/src/Build.UnitTests/WeakStringCache_Tests.cs +++ /dev/null @@ -1,185 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System; -using System.Linq; -using System.Runtime.CompilerServices; -using System.Text; - -using Shouldly; -using Xunit; - -namespace Microsoft.Build.UnitTests -{ - public class WeakStringCache_Tests : IDisposable - { - /// - /// The weak string cache under test. - /// - private WeakStringCache _cache = new WeakStringCache(); - - public void Dispose() - { - _cache.Dispose(); - } - - /// - /// Adds a string to the cache under test. - /// - /// Part one of the string (split to prevent runtime interning and unintended GC roots). - /// Part two of the string (split to prevent runtime interning and unintended GC roots). - /// Callback to be invoked after the string has been added but before the strong GC ref is released. - /// The hash code of the string as calculated by WeakStringCache. - [MethodImpl(MethodImplOptions.NoInlining)] - private int AddString(string strPart1, string strPart2, Action callbackToRunWithTheStringAlive) - { - // Compose the string with SB so it doesn't get interned by the runtime. - string testString = new StringBuilder(strPart1).Append(strPart2).ToString(); - StringInternTarget testStringTarget = new StringInternTarget(testString); - - int hashCode = WeakStringCache.GetInternableHashCode(testStringTarget); - - string cachedString = _cache.GetOrCreateEntry(testStringTarget, out bool cacheHit); - cacheHit.ShouldBeFalse(); - cachedString.ShouldBeSameAs(testString); - - callbackToRunWithTheStringAlive(cachedString); - - // Verify that the string is really in the cache and the cache returns the interned instance. - string testStringCopy = new StringBuilder(strPart1).Append(strPart2).ToString(); - cachedString = _cache.GetOrCreateEntry(new StringInternTarget(testStringCopy), out cacheHit); - cacheHit.ShouldBeTrue(); - cachedString.ShouldBeSameAs(testString); - - // Trigger full GC and verify that nothing has changed since we're still keeping testString alive. - GC.Collect(); - - callbackToRunWithTheStringAlive(cachedString); - - cachedString = _cache.GetOrCreateEntry(new StringInternTarget(testStringCopy), out cacheHit); - cacheHit.ShouldBeTrue(); - cachedString.ShouldBeSameAs(testString); - - return hashCode; - } - - /// - /// Adds strings that are known to have a hash code collision to the cache under test. - /// - [MethodImpl(MethodImplOptions.NoInlining)] - private void AddStringsWithSameHashCode(int numberOfStrings) - { - string[] cachedStrings = new string[numberOfStrings]; - int[] hashCodes = new int[numberOfStrings]; - - for (int i = 0; i < numberOfStrings; i++) - { - string strPart2 = "1" + String.Concat(Enumerable.Repeat("4428939786", i)); - hashCodes[i] = AddString("Random string ", strPart2, (string cachedString) => - { - _cache.GetDebugInfo().ShouldBe(new WeakStringCache.DebugInfo() - { - LiveStringCount = 1, - CollectedStringCount = 0, - }); - cachedStrings[i] = cachedString; - }); - - if (i > 0) - { - // The strings have been carefully constructed to have the same hash code. - hashCodes[i].ShouldBe(hashCodes[i - 1]); - } - } - - // There are no cache hits when iterating over our strings again because the last one always wins and steals the slot. - for (int i = 0; i < numberOfStrings; i++) - { - StringBuilder sb = new StringBuilder(cachedStrings[i]); - string cachedStringFromCache =_cache.GetOrCreateEntry(new StringBuilderInternTarget(sb), out bool cacheHit); - cacheHit.ShouldBeFalse(); - cachedStringFromCache.ShouldNotBeSameAs(cachedStrings[i]); - } - } - - /// - /// Simple test case to verify that: - /// 1. A string added to the cache stays in the cache as long as it's alive. - /// 2. The string is no longer retrievable after all strong GC refs are gone. - /// 3. The cache completely removes the handle after calling Scavenge on it. - /// - /// - /// Disabled on MacOS Mono because it doesn't play well with conservative GC scanning. - /// https://www.mono-project.com/docs/advanced/garbage-collector/sgen/#precise-stack-marking - /// - [Fact] - [SkipOnTargetFramework(TargetFrameworkMonikers.Mono, "doesn't play well with conservative GC scanning")] - public void RetainsStringUntilCollected() - { - // Add a string to the cache using a non-inlinable method to make sure it's not reachable from a GC root. - AddString("Random string ", "test", (string cachedString) => - { - _cache.GetDebugInfo().ShouldBe(new WeakStringCache.DebugInfo() - { - LiveStringCount = 1, - CollectedStringCount = 0, - }); - }); - - // Trigger full GC. - GC.Collect(); - - // The handle is still in the cache but it's unused now as the string has been collected. - _cache.GetDebugInfo().ShouldBe(new WeakStringCache.DebugInfo() - { - LiveStringCount = 0, - CollectedStringCount = 1, - }); - - // Ask the cache to get rid of unused handles. - _cache.Scavenge(); - - // The cache should be empty now. - _cache.GetDebugInfo().ShouldBe(new WeakStringCache.DebugInfo() - { - LiveStringCount = 0, - CollectedStringCount = 0, - }); - } - - /// - /// Same as RetainsStringUntilCollected but with multiple strings sharing the same hash code. - /// - /// - /// Disabled on MacOS Mono because it doesn't play well with conservative GC scanning. - /// https://www.mono-project.com/docs/advanced/garbage-collector/sgen/#precise-stack-marking - /// - [Fact] - [Trait("Category", "mono-osx-failing")] - public void RetainsLastStringWithGivenHashCode() - { - // Add 3 strings with the same hash code. - AddStringsWithSameHashCode(3); - - // Trigger full GC. - GC.Collect(); - - // The handle is still in the cache but it's unused now as the strings have been collected. - _cache.GetDebugInfo().ShouldBe(new WeakStringCache.DebugInfo() - { - LiveStringCount = 0, - CollectedStringCount = 1, - }); - - // Ask the cache to get rid of unused handles. - _cache.Scavenge(); - - // The cache should be empty now. - _cache.GetDebugInfo().ShouldBe(new WeakStringCache.DebugInfo() - { - LiveStringCount = 0, - CollectedStringCount = 0, - }); - } - } -} diff --git a/src/Framework.UnitTests/Microsoft.Build.Framework.UnitTests.csproj b/src/Framework.UnitTests/Microsoft.Build.Framework.UnitTests.csproj index 83bcbfcf5c0..b73c360d59d 100644 --- a/src/Framework.UnitTests/Microsoft.Build.Framework.UnitTests.csproj +++ b/src/Framework.UnitTests/Microsoft.Build.Framework.UnitTests.csproj @@ -44,10 +44,6 @@ - - - - diff --git a/src/UnitTests.Shared/Microsoft.Build.UnitTests.Shared.csproj b/src/UnitTests.Shared/Microsoft.Build.UnitTests.Shared.csproj index 30db3703d9b..209e21d4d1e 100644 --- a/src/UnitTests.Shared/Microsoft.Build.UnitTests.Shared.csproj +++ b/src/UnitTests.Shared/Microsoft.Build.UnitTests.Shared.csproj @@ -63,18 +63,6 @@ NativeMethodsShared.cs - - IInternable.cs - - - WeakStringCache.cs - - - WeakStringCache.Concurrent.cs - - - OpportunisticIntern.cs - ResourceUtilities.cs