// ReSharper disable InconsistentNaming namespace ImageSharp.Tests.Common { using System; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Threading.Tasks; using ImageSharp.Memory; using Xunit; using static TestStructs; public unsafe class BufferTests { // ReSharper disable once ClassNeverInstantiated.Local private class Assert : Xunit.Assert { public static void SpanPointsTo(Span span, Buffer buffer, int bufferOffset = 0) where T : struct { ref T actual = ref span.DangerousGetPinnableReference(); ref T expected = ref Unsafe.Add(ref buffer[0], bufferOffset); Assert.True(Unsafe.AreSame(ref expected, ref actual), "span does not point to the expected position"); } public static void Equal(void* expected, void* actual) { Assert.Equal((IntPtr)expected, (IntPtr)actual); } } [Theory] [InlineData(42)] [InlineData(1111)] public void ConstructWithOwnArray(int count) { using (Buffer buffer = new Buffer(count)) { Assert.False(buffer.IsDisposedOrLostArrayOwnership); Assert.NotNull(buffer.Array); Assert.Equal(count, buffer.Length); Assert.True(buffer.Array.Length >= count); } } [Theory] [InlineData(42)] [InlineData(1111)] public void ConstructWithExistingArray(int count) { Foo[] array = new Foo[count]; using (Buffer buffer = new Buffer(array)) { Assert.False(buffer.IsDisposedOrLostArrayOwnership); Assert.Equal(array, buffer.Array); Assert.Equal(count, buffer.Length); } } [Fact] public void Clear() { Foo[] a = { new Foo() { A = 1, B = 2 }, new Foo() { A = 3, B = 4 } }; using (Buffer buffer = new Buffer(a)) { buffer.Clear(); Assert.Equal(default(Foo), a[0]); Assert.Equal(default(Foo), a[1]); } } [Fact] public void CreateClean() { for (int i = 0; i < 100; i++) { using (Buffer buffer = Buffer.CreateClean(42)) { for (int j = 0; j < buffer.Length; j++) { Assert.Equal(0, buffer.Array[j]); buffer.Array[j] = 666; } } } } public class Indexer { public static readonly TheoryData IndexerData = new TheoryData() { { 10, 0 }, { 16, 3 }, { 10, 9 } }; [Theory] [MemberData(nameof(IndexerData))] public void Read(int length, int index) { Foo[] a = Foo.CreateArray(length); using (Buffer buffer = new Buffer(a)) { Foo element = buffer[index]; Assert.Equal(a[index], element); } } [Theory] [MemberData(nameof(IndexerData))] public void Write(int length, int index) { Foo[] a = Foo.CreateArray(length); using (Buffer buffer = new Buffer(a)) { buffer[index] = new Foo(666, 666); Assert.Equal(new Foo(666, 666), a[index]); } } } [Fact] public void Dispose() { Buffer buffer = new Buffer(42); buffer.Dispose(); Assert.True(buffer.IsDisposedOrLostArrayOwnership); } [Theory] [InlineData(7)] [InlineData(123)] public void CastToSpan(int bufferLength) { using (Buffer buffer = new Buffer(bufferLength)) { Span span = buffer; //Assert.Equal(buffer.Array, span.ToArray()); //Assert.Equal(0, span.Start); Assert.SpanPointsTo(span, buffer); Assert.Equal(span.Length, bufferLength); } } [Fact] public void Span() { using (Buffer buffer = new Buffer(42)) { Span span = buffer.Span; // Assert.Equal(buffer.Array, span.ToArray()); // Assert.Equal(0, span.Start); Assert.SpanPointsTo(span, buffer); Assert.Equal(42, span.Length); } } public class Slice { [Theory] [InlineData(7, 2)] [InlineData(123, 17)] public void WithStartOnly(int bufferLength, int start) { using (Buffer buffer = new Buffer(bufferLength)) { Span span = buffer.Slice(start); Assert.SpanPointsTo(span, buffer, start); Assert.Equal(span.Length, bufferLength - start); } } [Theory] [InlineData(7, 2, 5)] [InlineData(123, 17, 42)] public void WithStartAndLength(int bufferLength, int start, int spanLength) { using (Buffer buffer = new Buffer(bufferLength)) { Span span = buffer.Slice(start, spanLength); Assert.SpanPointsTo(span, buffer, start); Assert.Equal(span.Length, spanLength); } } } [Fact] public void UnPinAndTakeArrayOwnership() { Foo[] data = null; using (Buffer buffer = new Buffer(42)) { data = buffer.TakeArrayOwnership(); Assert.True(buffer.IsDisposedOrLostArrayOwnership); } Assert.NotNull(data); Assert.True(data.Length >= 42); } public class Pin { [Fact] public void ReturnsPinnedPointerToTheBeginningOfArray() { using (Buffer buffer = new Buffer(42)) { Foo* actual = (Foo*)buffer.Pin(); fixed (Foo* expected = buffer.Array) { Assert.Equal(expected, actual); } } } [Fact] public void SecondCallReturnsTheSamePointer() { using (Buffer buffer = new Buffer(42)) { IntPtr ptr1 = buffer.Pin(); IntPtr ptr2 = buffer.Pin(); Assert.Equal(ptr1, ptr2); } } [Fact] public void WhenCalledOnDisposedBuffer_ThrowsInvalidOperationException() { Buffer buffer = new Buffer(42); buffer.Dispose(); Assert.Throws(() => buffer.Pin()); } } } }