diff --git a/src/libraries/System.Collections/tests/BitArray/BitArray_OperatorsTests.cs b/src/libraries/System.Collections/tests/BitArray/BitArray_OperatorsTests.cs index 888c523ef7e86e..b9396e21cde539 100644 --- a/src/libraries/System.Collections/tests/BitArray/BitArray_OperatorsTests.cs +++ b/src/libraries/System.Collections/tests/BitArray/BitArray_OperatorsTests.cs @@ -387,5 +387,76 @@ public static void PopCount(BitArray array, int expected) { Assert.Equal(expected, array.PopCount()); } + + public static IEnumerable Shift_PopCount_TestData() + { + // Test lengths that cover edge cases around int32 boundaries + int[] lengths = [1, BitsPerByte, BitsPerInt32 - 1, BitsPerInt32, BitsPerInt32 + 1, 2 * BitsPerInt32, 2 * BitsPerInt32 + 1]; + + foreach (int length in lengths) + { + // Generate valid shift amounts based on array length + int[] shifts = [1, length / 2, length - 1, length, length + 1]; + + // Test with bit set at start, middle, and end positions + int[] bitPositions = length > 1 ? [0, length / 2, length - 1] : [0]; + + foreach (int shift in shifts.Where(s => s > 0).Distinct()) + { + foreach (int bitPosition in bitPositions.Distinct()) + { + yield return new object[] { length, bitPosition, shift }; + } + } + } + } + + [Theory] + [MemberData(nameof(Shift_PopCount_TestData))] + public static void LeftShift_PopCount(int length, int bitPosition, int shift) + { + BitArray ba = new(length); + ba[bitPosition] = true; + + int expectedPopCount = bitPosition + shift < length ? 1 : 0; + ba.LeftShift(shift); + Assert.Equal(expectedPopCount, ba.PopCount()); + } + + [Theory] + [MemberData(nameof(Shift_PopCount_TestData))] + public static void RightShift_PopCount(int length, int bitPosition, int shift) + { + BitArray ba = new(length); + ba[bitPosition] = true; + + int expectedPopCount = bitPosition - shift >= 0 ? 1 : 0; + ba.RightShift(shift); + Assert.Equal(expectedPopCount, ba.PopCount()); + } + + [Theory] + [MemberData(nameof(Shift_PopCount_TestData))] + public static void LeftShift_HasAnySet(int length, int bitPosition, int shift) + { + BitArray ba = new(length); + ba[bitPosition] = true; + + bool expectedHasAny = bitPosition + shift < length; + ba.LeftShift(shift); + Assert.Equal(expectedHasAny, ba.HasAnySet()); + } + + [Theory] + [MemberData(nameof(Shift_PopCount_TestData))] + public static void RightShift_HasAnySet(int length, int bitPosition, int shift) + { + BitArray ba = new(length); + ba[bitPosition] = true; + + bool expectedHasAny = bitPosition - shift >= 0; + ba.RightShift(shift); + Assert.Equal(expectedHasAny, ba.HasAnySet()); + } } } diff --git a/src/libraries/System.Private.CoreLib/src/System/Collections/BitArray.cs b/src/libraries/System.Private.CoreLib/src/System/Collections/BitArray.cs index 015985a464f8f9..a325147a8f0bc5 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Collections/BitArray.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Collections/BitArray.cs @@ -98,6 +98,8 @@ private BitArray(SerializationInfo info, StreamingContext context) { BinaryPrimitives.ReverseEndianness(array, MemoryMarshal.Cast((Span)_array)); } + + ClearHighExtraBits(); } /// Generates serialization data for the BitArray in a way that's compatible with the original .NET Framework implementation. @@ -603,6 +605,8 @@ public BitArray LeftShift(int count) } intSpan[lastIndex] = ReverseIfBE(ReverseIfBE(intSpan[fromindex]) << shiftCount); } + + ClearHighExtraBits(); } else {