From 7046f9891e21a4a49716160092747baf923ff6a1 Mon Sep 17 00:00:00 2001 From: Maryam Ariyan Date: Tue, 13 Mar 2018 17:35:19 -0700 Subject: [PATCH 1/3] Adding test for StringBuilder.Clear making sure Capacity wont grow unboundedly. Fixes #27625 --- .../tests/System/Text/StringBuilderTests.cs | 29 +++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/src/System.Runtime/tests/System/Text/StringBuilderTests.cs b/src/System.Runtime/tests/System/Text/StringBuilderTests.cs index e68d4046c2f7..e434f5caa344 100644 --- a/src/System.Runtime/tests/System/Text/StringBuilderTests.cs +++ b/src/System.Runtime/tests/System/Text/StringBuilderTests.cs @@ -979,6 +979,35 @@ public static void Clear() Assert.Same(string.Empty, builder.ToString()); } + [Fact] + public static void Clear_ClearEmptyStringBuilder_CapacityNotZero() + { + var builder = new StringBuilder(); + builder.Clear(); + Assert.NotEqual(0, builder.Capacity); + } + + [Theory] + [InlineData(1)] + [InlineData(10000)] + public static void Clear_AppendAndInsertBeforeClearManyTimes_CapacityStaysWithinRange(int times) + { + var builder = new StringBuilder(); + var s = new string(' ', 10); + int oldLength = 0; + for (int i = 0; i < times; i++) + { + builder.Append(s); + builder.Append(s); + builder.Append(s); + builder.Insert(0, s); + builder.Insert(0, s); + oldLength = builder.Length; + builder.Clear(); + } + Assert.InRange(builder.Capacity, 1, oldLength * 1.2); + } + [Theory] [InlineData("Hello", 0, new char[] { '\0', '\0', '\0', '\0', '\0' }, 0, 5, new char[] { 'H', 'e', 'l', 'l', 'o' })] [InlineData("Hello", 0, new char[] { '\0', '\0', '\0', '\0', '\0', '\0' }, 1, 5, new char[] { '\0', 'H', 'e', 'l', 'l', 'o' })] From feb947ddda6611f87bb495959535b92a70b741dc Mon Sep 17 00:00:00 2001 From: Maryam Ariyan Date: Fri, 16 Mar 2018 19:51:44 -0700 Subject: [PATCH 2/3] Adding more tests for StringBuilder.Clear --- .../tests/System/Text/StringBuilderTests.cs | 43 +++++++++++-------- .../Text/StringBuilderTests.netcoreapp.cs | 41 ++++++++++++++++++ 2 files changed, 65 insertions(+), 19 deletions(-) diff --git a/src/System.Runtime/tests/System/Text/StringBuilderTests.cs b/src/System.Runtime/tests/System/Text/StringBuilderTests.cs index e434f5caa344..d5e57a118e33 100644 --- a/src/System.Runtime/tests/System/Text/StringBuilderTests.cs +++ b/src/System.Runtime/tests/System/Text/StringBuilderTests.cs @@ -980,32 +980,37 @@ public static void Clear() } [Fact] - public static void Clear_ClearEmptyStringBuilder_CapacityNotZero() + public static void Clear_Empty_CapacityNotZero() { var builder = new StringBuilder(); builder.Clear(); Assert.NotEqual(0, builder.Capacity); } - [Theory] - [InlineData(1)] - [InlineData(10000)] - public static void Clear_AppendAndInsertBeforeClearManyTimes_CapacityStaysWithinRange(int times) + [Fact] + public static void Clear_Empty_CapacityStaysUnchanged() { - var builder = new StringBuilder(); - var s = new string(' ', 10); - int oldLength = 0; - for (int i = 0; i < times; i++) - { - builder.Append(s); - builder.Append(s); - builder.Append(s); - builder.Insert(0, s); - builder.Insert(0, s); - oldLength = builder.Length; - builder.Clear(); - } - Assert.InRange(builder.Capacity, 1, oldLength * 1.2); + var sb = new StringBuilder(14); + sb.Clear(); + Assert.Equal(14, sb.Capacity); + } + + [Fact] + public static void Clear_Full_CapacityStaysUnchanged() + { + var sb = new StringBuilder(14); + sb.Append("Hello World!!!"); + sb.Clear(); + Assert.Equal(14, sb.Capacity); + } + + [Fact] + public static void Clear_AtMaxCapacity_CapacityStaysUnchanged() + { + var builder = new StringBuilder(14, 14); + builder.Append("Hello World!!!"); + builder.Clear(); + Assert.Equal(14, builder.Capacity); } [Theory] diff --git a/src/System.Runtime/tests/System/Text/StringBuilderTests.netcoreapp.cs b/src/System.Runtime/tests/System/Text/StringBuilderTests.netcoreapp.cs index cff21e37eb3e..9dcf6b2eff40 100644 --- a/src/System.Runtime/tests/System/Text/StringBuilderTests.netcoreapp.cs +++ b/src/System.Runtime/tests/System/Text/StringBuilderTests.netcoreapp.cs @@ -141,6 +141,47 @@ public static void Append_CharSpan(string original, char[] value, string expecte Assert.Equal(expected, builder.ToString()); } + [Theory] + [InlineData(1)] + [InlineData(10000)] + public static void Clear_AppendAndInsertBeforeClearManyTimes_CapacityStaysWithinRange(int times) + { + var builder = new StringBuilder(); + var originalCapacity = builder.Capacity; + var s = new string(' ', 10); + int oldLength = 0; + for (int i = 0; i < times; i++) + { + builder.Append(s); + builder.Append(s); + builder.Append(s); + builder.Insert(0, s); + builder.Insert(0, s); + oldLength = builder.Length; + + builder.Clear(); + } + Assert.InRange(builder.Capacity, 1, oldLength * 1.2); + } + + [Fact] + public static void Clear_InitialCapacityMuchLargerThanLength_CapacityReducedToInitialCapacity() + { + var builder = new StringBuilder(100); + var initialCapacity = builder.Capacity; + builder.Append(new string('a', 40)); + builder.Insert(0, new string('a', 10)); + builder.Insert(0, new string('a', 10)); + builder.Insert(0, new string('a', 10)); + var oldCapacity = builder.Capacity; + var oldLength = builder.Length; + builder.Clear(); + Assert.NotEqual(oldCapacity, builder.Capacity); + Assert.Equal(initialCapacity, builder.Capacity); + Assert.NotInRange(builder.Capacity, 1, oldLength * 1.2); + Assert.InRange(builder.Capacity, 1, Math.Max(initialCapacity, oldLength * 1.2)); + } + [Theory] [InlineData("Hello", 0, new char[] { '\0', '\0', '\0', '\0', '\0' }, 5, new char[] { 'H', 'e', 'l', 'l', 'o' })] [InlineData("Hello", 0, new char[] { '\0', '\0', '\0', '\0' }, 4, new char[] { 'H', 'e', 'l', 'l' })] From e2335c5944b75c0dce7725811f7716cb135d10f2 Mon Sep 17 00:00:00 2001 From: Maryam Ariyan Date: Mon, 26 Mar 2018 13:02:34 -0700 Subject: [PATCH 3/3] Adding test for special case where the capacity corresponds to exactly chunk array size --- .../Text/StringBuilderTests.netcoreapp.cs | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/src/System.Runtime/tests/System/Text/StringBuilderTests.netcoreapp.cs b/src/System.Runtime/tests/System/Text/StringBuilderTests.netcoreapp.cs index 9dcf6b2eff40..848cd2888be6 100644 --- a/src/System.Runtime/tests/System/Text/StringBuilderTests.netcoreapp.cs +++ b/src/System.Runtime/tests/System/Text/StringBuilderTests.netcoreapp.cs @@ -182,6 +182,26 @@ public static void Clear_InitialCapacityMuchLargerThanLength_CapacityReducedToIn Assert.InRange(builder.Capacity, 1, Math.Max(initialCapacity, oldLength * 1.2)); } + [Fact] + public static void Clear_StringBuilderHasTwoChunks_OneChunkIsEmpty_ClearReducesCapacity() + { + var sb = new StringBuilder(string.Empty); + int initialCapacity = sb.Capacity; + for (int i = 0; i < initialCapacity; i++) + { + sb.Append('a'); + } + sb.Insert(0, 'a'); + while (sb.Length > 1) + { + sb.Remove(1, 1); + } + int oldCapacity = sb.Capacity; + sb.Clear(); + Assert.Equal(oldCapacity - 1, sb.Capacity); + Assert.Equal(initialCapacity, sb.Capacity); + } + [Theory] [InlineData("Hello", 0, new char[] { '\0', '\0', '\0', '\0', '\0' }, 5, new char[] { 'H', 'e', 'l', 'l', 'o' })] [InlineData("Hello", 0, new char[] { '\0', '\0', '\0', '\0' }, 4, new char[] { 'H', 'e', 'l', 'l' })]