|
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
#nullable disable
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using Microsoft.CodeAnalysis.Collections;
using Xunit;
namespace Microsoft.CodeAnalysis.UnitTests.Collections
{
public class SegmentedArrayTests
{
public static IEnumerable<object[]> TestLengths
{
get
{
yield return new object[] { 1 };
yield return new object[] { 10 };
yield return new object[] { 100 };
yield return new object[] { SegmentedArray<IntPtr>.TestAccessor.SegmentSize / 2 };
yield return new object[] { SegmentedArray<IntPtr>.TestAccessor.SegmentSize };
yield return new object[] { SegmentedArray<IntPtr>.TestAccessor.SegmentSize * 2 };
yield return new object[] { 100000 };
}
}
private static void ResetToSequence(SegmentedArray<IntPtr> array)
{
for (var i = 0; i < array.Length; i++)
{
array[i] = (IntPtr)i;
}
}
[Fact]
public void TestDefaultInstance()
{
var data = default(SegmentedArray<IntPtr>);
Assert.Null(SegmentedCollectionsMarshal.AsSegments(data));
Assert.True(data.IsFixedSize);
Assert.True(data.IsReadOnly);
Assert.False(data.IsSynchronized);
Assert.Equal(0, data.Length);
Assert.Null(data.SyncRoot);
Assert.Throws<NullReferenceException>(() => data[0]);
Assert.Throws<NullReferenceException>(() => ((IReadOnlyList<IntPtr>)data)[0]);
Assert.Throws<NullReferenceException>(() => ((IList<IntPtr>)data)[0]);
Assert.Throws<NullReferenceException>(() => ((IList<IntPtr>)data)[0] = IntPtr.Zero);
Assert.Throws<NullReferenceException>(() => ((IList)data)[0]);
Assert.Throws<NullReferenceException>(() => ((IList)data)[0] = IntPtr.Zero);
Assert.Equal(0, ((ICollection)data).Count);
Assert.Equal(0, ((ICollection<IntPtr>)data).Count);
Assert.Equal(0, ((IReadOnlyCollection<IntPtr>)data).Count);
Assert.Throws<NullReferenceException>(() => data.Clone());
Assert.Throws<NullReferenceException>(() => data.CopyTo(Array.Empty<IntPtr>(), 0));
Assert.Throws<NullReferenceException>(() => ((ICollection<IntPtr>)data).CopyTo(Array.Empty<IntPtr>(), 0));
var enumerator1 = data.GetEnumerator();
Assert.Throws<NullReferenceException>(() => enumerator1.MoveNext());
var enumerator2 = ((IEnumerable)data).GetEnumerator();
Assert.Throws<NullReferenceException>(() => enumerator1.MoveNext());
var enumerator3 = ((IEnumerable<IntPtr>)data).GetEnumerator();
Assert.Throws<NullReferenceException>(() => enumerator1.MoveNext());
Assert.Throws<NotSupportedException>(() => ((IList)data).Add(IntPtr.Zero));
Assert.Throws<NotSupportedException>(() => ((ICollection<IntPtr>)data).Add(IntPtr.Zero));
Assert.Throws<NotSupportedException>(() => ((ICollection<IntPtr>)data).Clear());
Assert.Throws<NotSupportedException>(() => ((IList)data).Insert(0, IntPtr.Zero));
Assert.Throws<NotSupportedException>(() => ((IList<IntPtr>)data).Insert(0, IntPtr.Zero));
Assert.Throws<NotSupportedException>(() => ((IList)data).Remove(IntPtr.Zero));
Assert.Throws<NotSupportedException>(() => ((ICollection<IntPtr>)data).Remove(IntPtr.Zero));
Assert.Throws<NotSupportedException>(() => ((IList)data).RemoveAt(0));
Assert.Throws<NotSupportedException>(() => ((IList<IntPtr>)data).RemoveAt(0));
Assert.Throws<NullReferenceException>(() => ((IList)data).Clear());
Assert.Throws<NullReferenceException>(() => ((IList)data).Contains(IntPtr.Zero));
Assert.Throws<NullReferenceException>(() => ((ICollection<IntPtr>)data).Contains(IntPtr.Zero));
Assert.Throws<NullReferenceException>(() => ((IList)data).IndexOf(IntPtr.Zero));
Assert.Throws<NullReferenceException>(() => ((IList<IntPtr>)data).IndexOf(IntPtr.Zero));
}
[Fact]
public void TestConstructor1()
{
Assert.Throws<ArgumentOutOfRangeException>("length", () => new SegmentedArray<byte>(-1));
Assert.Empty(new SegmentedArray<byte>(0));
Assert.Same(Array.Empty<byte[]>(), SegmentedCollectionsMarshal.AsSegments(new SegmentedArray<byte>(0)));
}
[Theory]
[MemberData(nameof(TestLengths))]
public void TestConstructor2(int length)
{
var data = new SegmentedArray<IntPtr>(length);
Assert.Equal(length, data.Length);
var items = SegmentedCollectionsMarshal.AsSegments(data);
Assert.Equal(length, items.Sum(item => item.Length));
for (var i = 0; i < items.Length - 1; i++)
{
Assert.Equal(SegmentedArray<IntPtr>.TestAccessor.SegmentSize, items[i].Length);
Assert.True(items[i].Length <= SegmentedArray<IntPtr>.TestAccessor.SegmentSize);
}
}
[Theory]
[MemberData(nameof(TestLengths))]
public void TestBasicProperties(int length)
{
var data = new SegmentedArray<IntPtr>(length);
Assert.True(data.IsFixedSize);
Assert.True(data.IsReadOnly);
Assert.False(data.IsSynchronized);
Assert.Equal(length, data.Length);
Assert.Same(SegmentedCollectionsMarshal.AsSegments(data), data.SyncRoot);
Assert.Equal(length, ((ICollection)data).Count);
Assert.Equal(length, ((ICollection<IntPtr>)data).Count);
Assert.Equal(length, ((IReadOnlyCollection<IntPtr>)data).Count);
}
[Theory]
[MemberData(nameof(TestLengths))]
public void TestIndexer(int length)
{
var data = new SegmentedArray<IntPtr>(length);
ResetToSequence(data);
for (var i = 0; i < length; i++)
{
data[i] = (IntPtr)i;
}
for (var i = 0; i < length; i++)
{
Assert.Equal((IntPtr)i, data[i]);
}
for (var i = 0; i < length; i++)
{
ref var value = ref data[i];
Assert.Equal((IntPtr)i, data[i]);
value = IntPtr.Add(value, 1);
Assert.Equal((IntPtr)(i + 1), value);
Assert.Equal((IntPtr)(i + 1), data[i]);
}
ResetToSequence(data);
for (var i = 0; i < length; i++)
{
Assert.Equal((IntPtr)i, ((IReadOnlyList<IntPtr>)data)[i]);
data[i] = IntPtr.Add(data[i], 1);
Assert.Equal((IntPtr)(i + 1), ((IReadOnlyList<IntPtr>)data)[i]);
}
ResetToSequence(data);
for (var i = 0; i < length; i++)
{
Assert.Equal((IntPtr)i, ((IList<IntPtr>)data)[i]);
((IList<IntPtr>)data)[i] = IntPtr.Add(data[i], 1);
Assert.Equal((IntPtr)(i + 1), ((IList<IntPtr>)data)[i]);
}
ResetToSequence(data);
for (var i = 0; i < length; i++)
{
Assert.Equal((IntPtr)i, ((IList)data)[i]);
((IList)data)[i] = IntPtr.Add(data[i], 1);
Assert.Equal((IntPtr)(i + 1), ((IList)data)[i]);
}
}
/// <summary>
/// Verify that indexing and iteration match for an array with many segments.
/// </summary>
[Fact]
public void TestIterateLargeArray()
{
var data = new SegmentedArray<Guid>(1000000);
Assert.True(SegmentedCollectionsMarshal.AsSegments(data).Length > 10);
for (var i = 0; i < data.Length; i++)
{
data[i] = Guid.NewGuid();
Assert.NotEqual(Guid.Empty, data[i]);
}
var index = 0;
foreach (var guid in data)
{
Assert.Equal(guid, data[index++]);
}
Assert.Equal(data.Length, index);
}
[Fact]
public void CopyOverlappingEndOfSegment()
{
var array = new int[2 * SegmentedArray<int>.TestAccessor.SegmentSize];
var segmented = new SegmentedArray<int>(2 * SegmentedArray<int>.TestAccessor.SegmentSize);
initialize(array, segmented);
Assert.Equal(array, segmented);
var sourceStart = SegmentedArray<int>.TestAccessor.SegmentSize - 128;
var destinationStart = SegmentedArray<int>.TestAccessor.SegmentSize - 60;
var length = 256;
Array.Copy(array, sourceStart, array, destinationStart, length);
SegmentedArray.Copy(segmented, sourceStart, segmented, destinationStart, length);
Assert.Equal(array, segmented);
initialize(array, segmented);
sourceStart = SegmentedArray<int>.TestAccessor.SegmentSize - 60;
destinationStart = SegmentedArray<int>.TestAccessor.SegmentSize - 128;
length = 256;
Array.Copy(array, sourceStart, array, destinationStart, length);
SegmentedArray.Copy(segmented, sourceStart, segmented, destinationStart, length);
Assert.Equal(array, segmented);
static void initialize(int[] array, SegmentedArray<int> segmented)
{
for (int i = 0; i < array.Length; i++)
{
array[i] = i;
segmented[i] = i;
}
}
}
}
}
|