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++) { InternableString stringCopy = new InternableString(new string(cachedStrings[i].ToCharArray())); string cachedStringFromCache = _cache.GetOrCreateEntry(ref stringCopy, out bool cacheHit); cacheHit.ShouldBeFalse(); cachedStringFromCache.ShouldNotBeSameAs(cachedStrings[i]); } }
private int AddString(string strPart1, string strPart2, Action <string> callbackToRunWithTheStringAlive) { // Compose the string with SB so it doesn't get interned by the runtime. string testString = new StringBuilder(strPart1).Append(strPart2).ToString(); InternableString testStringTarget = new InternableString(testString); int hashCode = testStringTarget.GetHashCode(); string cachedString = _cache.GetOrCreateEntry(ref 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(); InternableString testStringCopyTarget = new InternableString(testStringCopy); cachedString = _cache.GetOrCreateEntry(ref testStringCopyTarget, 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); testStringCopyTarget = new InternableString(testStringCopy); cachedString = _cache.GetOrCreateEntry(ref testStringCopyTarget, out cacheHit); cacheHit.ShouldBeTrue(); cachedString.ShouldBeSameAs(testString); return(hashCode); }
public void ReferenceEqualsReturnsExpectedValue() { string str = "Test"; InternableString internableString = new InternableString(str); internableString.ReferenceEquals(str).ShouldBeTrue(); internableString = new InternableString(new string(str.ToCharArray())); internableString.ReferenceEquals(str).ShouldBeFalse(); }
[InlineData("0123456789")] // even number of characters public void GetHashCodeIsStableRegardlessOfSpanLength(string testString) { int hashCode = new InternableString(testString).GetHashCode(); // Chop the string into 2-3 parts and verify that the hash code is unchanged. for (int i = 0; i < testString.Length - 1; i++) { for (int j = i + 1; j < testString.Length; j++) { SpanBasedStringBuilder stringBuilder = new SpanBasedStringBuilder(); stringBuilder.Append(testString.Substring(0, i)); stringBuilder.Append(testString.Substring(i, j - i)); stringBuilder.Append(testString.Substring(j)); InternableString internableString = new InternableString(stringBuilder); internableString.GetHashCode().ShouldBe(hashCode); } } }
public void EqualsReturnsExpectedValue(InterningTestData.TestDatum datum) { InternableString internableString = new InternableString(MakeSpanBasedStringBuilder(datum)); internableString.Equals(string.Empty).ShouldBe(internableString.Length == 0); string substr = datum.Fragments[0] ?? string.Empty; internableString.Equals(substr).ShouldBe(substr.Length == internableString.Length); if (datum.Fragments.Length > 1) { substr += datum.Fragments[1]; internableString.Equals(substr).ShouldBe(substr.Length == internableString.Length); internableString.Equals(datum.ToString()).ShouldBeTrue(); } internableString.Equals("Things").ShouldBeFalse(); }