Uno.SkiaSharp/tests/Tests/SKManagedStreamTest.cs

525 строки
14 KiB
C#

using System;
using System.IO;
using System.Linq;
using Xunit;
using System.Collections.Generic;
namespace SkiaSharp.Tests
{
public class SKManagedStreamTest : SKTest
{
[SkippableFact]
public void DotNetStreamIsCollected()
{
var dotnet = CreateTestStream();
var stream = new SKManagedStream(dotnet, true);
Assert.Equal(0, dotnet.Position);
stream.Dispose();
Assert.Throws<ObjectDisposedException>(() => dotnet.Position);
}
[SkippableFact]
public void DotNetStreamIsNotCollected()
{
var dotnet = CreateTestStream();
var stream = new SKManagedStream(dotnet, false);
Assert.Equal(0, dotnet.Position);
stream.Dispose();
Assert.Equal(0, dotnet.Position);
}
[SkippableFact]
public unsafe void StreamLosesOwnershipToCodecButIsNotForgotten()
{
var bytes = File.ReadAllBytes(Path.Combine(PathToImages, "color-wheel.png"));
var dotnet = new MemoryStream(bytes);
var stream = new SKManagedStream(dotnet, true);
var handle = stream.Handle;
Assert.True(stream.OwnsHandle);
Assert.True(SKObject.GetInstance<SKManagedStream>(handle, out _));
var codec = SKCodec.Create(stream);
Assert.False(stream.OwnsHandle);
stream.Dispose();
Assert.True(SKObject.GetInstance<SKManagedStream>(handle, out _));
Assert.Equal(SKCodecResult.Success, codec.GetPixels(out var pixels));
Assert.NotEmpty(pixels);
}
[SkippableFact]
public unsafe void StreamThatHasLostOwnershipIsDisposed()
{
var bytes = File.ReadAllBytes(Path.Combine(PathToImages, "color-wheel.png"));
var dotnet = new MemoryStream(bytes);
var stream = new SKManagedStream(dotnet, true);
var handle = stream.Handle;
Assert.True(stream.OwnsHandle);
Assert.True(SKObject.GetInstance<SKManagedStream>(handle, out _));
var codec = SKCodec.Create(stream);
Assert.False(stream.OwnsHandle);
codec.Dispose();
Assert.False(SKObject.GetInstance<SKManagedStream>(handle, out _));
}
[SkippableFact]
public void StreamIsCollectedEvenWhenNotProperlyDisposed()
{
VerifyImmediateFinalizers();
var handle = DoWork();
CollectGarbage();
var exists = SKObject.GetInstance<SKManagedStream>(handle, out _);
Assert.False(exists);
IntPtr DoWork()
{
var dotnet = CreateTestStream();
var stream = new SKManagedStream(dotnet, true);
return stream.Handle;
}
}
[SkippableFact]
public void ManagedStreamReadsByteCorrectly()
{
var data = new byte[1024];
for (int i = 0; i < data.Length; i++)
{
data[i] = (byte)(i % byte.MaxValue);
}
var stream = new MemoryStream(data);
var skManagedStream = new SKManagedStream(stream);
skManagedStream.Rewind();
Assert.Equal(0, stream.Position);
Assert.Equal(0, skManagedStream.Position);
for (int i = 0; i < data.Length; i++)
{
skManagedStream.Position = i;
Assert.Equal(i, stream.Position);
Assert.Equal(i, skManagedStream.Position);
Assert.Equal((byte)(i % byte.MaxValue), data[i]);
Assert.Equal((byte)(i % byte.MaxValue), skManagedStream.ReadByte());
Assert.Equal(i + 1, stream.Position);
Assert.Equal(i + 1, skManagedStream.Position);
}
}
[SkippableTheory]
[InlineData(1024, 0, 0, 0)]
[InlineData(1024, 1, 1, 1)]
[InlineData(1024, 10, 10, 10)]
[InlineData(1024, 100, 100, 100)]
[InlineData(1024, 1000, 1000, 1000)]
[InlineData(1024, 10000, 1024, 1024)]
public void ReadIsCorrect(int dataSize, int readSize, int finalPos, int expectedReadSize)
{
var data = new byte[dataSize];
for (var i = 0; i < data.Length; i++)
{
data[i] = (byte)(i % byte.MaxValue);
}
var stream = new MemoryStream(data);
var managedStream = new SKManagedStream(stream);
var buffer = new byte[dataSize * 2];
var actualReadSize = managedStream.Read(buffer, readSize);
Assert.Equal(expectedReadSize, actualReadSize);
Assert.Equal(finalPos, managedStream.Position);
Assert.Equal(data.Take(readSize), buffer.Take(actualReadSize));
Assert.All(buffer.Skip(actualReadSize), i => Assert.Equal(0, i));
}
[SkippableFact]
public void ManagedStreamReadsChunkCorrectly()
{
var data = new byte[1024];
for (int i = 0; i < data.Length; i++)
{
data[i] = (byte)(i % byte.MaxValue);
}
var stream = new MemoryStream(data);
var skManagedStream = new SKManagedStream(stream);
skManagedStream.Rewind();
Assert.Equal(0, stream.Position);
Assert.Equal(0, skManagedStream.Position);
var buffer = new byte[data.Length / 2];
skManagedStream.Read(buffer, buffer.Length);
Assert.Equal(data.Take(buffer.Length), buffer);
}
[SkippableFact]
public void ManagedStreamReadsOffsetChunkCorrectly()
{
var data = new byte[1024];
for (int i = 0; i < data.Length; i++)
{
data[i] = (byte)(i % byte.MaxValue);
}
var stream = new MemoryStream(data);
var skManagedStream = new SKManagedStream(stream);
var offset = 768;
skManagedStream.Position = offset;
var buffer = new byte[data.Length];
var taken = skManagedStream.Read(buffer, buffer.Length);
Assert.Equal(data.Length - offset, taken);
var resultData = data.Skip(offset).Take(buffer.Length).ToArray();
resultData = resultData.Concat(Enumerable.Repeat<byte>(0, offset)).ToArray();
Assert.Equal(resultData, buffer);
}
[SkippableFact]
public void ManagedStreamIsNotCollectedPrematurely()
{
using (var document = CreateDocument(out var handle))
{
var paintList = new List<SKPaint>();
for (var index = 0; index < 10; index++)
{
var fontStream = File.OpenRead(Path.Combine(PathToFonts, "Roboto2-Regular_NoEmbed.ttf"));
var typeface = SKTypeface.FromStream(fontStream);
var paint = new SKPaint
{
Typeface = typeface
};
paintList.Add(paint);
}
using (var pageCanvas = document.BeginPage(792, 842))
{
foreach (var paint in paintList)
{
for (var i = 0; i < 100; i++)
pageCanvas.DrawText("Text", 0, 5 * i, paint);
}
document.EndPage();
}
CollectGarbage();
Assert.True(SKObject.GetInstance<SKDynamicMemoryWStream>(handle, out _));
document.Close();
}
SKDocument CreateDocument(out IntPtr streamHandle)
{
var stream = new SKDynamicMemoryWStream();
streamHandle = stream.Handle;
return SKDocument.CreatePdf(stream, new SKDocumentPdfMetadata());
}
}
[SkippableFact]
public unsafe void StreamLosesOwnershipAndCanBeDisposedButIsNotActually()
{
var path = Path.Combine(PathToImages, "color-wheel.png");
var bytes = File.ReadAllBytes(path);
var stream = new SKManagedStream(new MemoryStream(bytes), true);
var handle = stream.Handle;
Assert.True(stream.OwnsHandle);
Assert.False(stream.IgnorePublicDispose);
Assert.True(SKObject.GetInstance<SKManagedStream>(handle, out _));
var codec = SKCodec.Create(stream);
Assert.False(stream.OwnsHandle);
Assert.True(stream.IgnorePublicDispose);
stream.Dispose();
Assert.True(SKObject.GetInstance<SKManagedStream>(handle, out var inst));
Assert.Same(stream, inst);
Assert.Equal(SKCodecResult.Success, codec.GetPixels(out var pixels));
Assert.NotEmpty(pixels);
codec.Dispose();
Assert.False(SKObject.GetInstance<SKManagedStream>(handle, out _));
}
[SkippableFact]
public unsafe void InvalidStreamIsDisposedImmediately()
{
var stream = CreateTestSKStream();
var handle = stream.Handle;
Assert.True(stream.OwnsHandle);
Assert.False(stream.IgnorePublicDispose);
Assert.True(SKObject.GetInstance<SKStream>(handle, out _));
Assert.Null(SKCodec.Create(stream));
Assert.False(stream.OwnsHandle);
Assert.True(stream.IgnorePublicDispose);
Assert.False(SKObject.GetInstance<SKStream>(handle, out _));
}
[SkippableFact]
public unsafe void StreamLosesOwnershipAndCanBeGarbageCollected()
{
VerifyImmediateFinalizers();
var bytes = File.ReadAllBytes(Path.Combine(PathToImages, "color-wheel.png"));
DoWork(out var codecH, out var streamH);
CollectGarbage();
Assert.False(SKObject.GetInstance<SKManagedStream>(streamH, out _));
Assert.False(SKObject.GetInstance<SKCodec>(codecH, out _));
void DoWork(out IntPtr codecHandle, out IntPtr streamHandle)
{
var codec = CreateCodec(out streamHandle);
codecHandle = codec.Handle;
CollectGarbage();
Assert.Equal(SKCodecResult.Success, codec.GetPixels(out var pixels));
Assert.NotEmpty(pixels);
Assert.True(SKObject.GetInstance<SKManagedStream>(streamHandle, out var stream));
Assert.False(stream.OwnsHandle);
Assert.True(stream.IgnorePublicDispose);
}
SKCodec CreateCodec(out IntPtr streamHandle)
{
var stream = new SKManagedStream(new MemoryStream(bytes), true);
streamHandle = stream.Handle;
Assert.True(stream.OwnsHandle);
Assert.False(stream.IgnorePublicDispose);
Assert.True(SKObject.GetInstance<SKManagedStream>(streamHandle, out _));
return SKCodec.Create(stream);
}
}
[SkippableFact]
public void StreamCanBeDuplicatedButTheOriginalCannotBeRead()
{
VerifySupportsExceptionsInDelegates();
var dotnet = new MemoryStream(new byte[] { 1, 2, 3, 4, 5 });
var stream = new SKManagedStream(dotnet, true);
Assert.Equal(1, stream.ReadByte());
Assert.Equal(2, stream.ReadByte());
Assert.Equal(3, stream.ReadByte());
var dupe = stream.Duplicate();
Assert.NotSame(stream, dupe);
Assert.IsType<SKManagedStream>(dupe);
Assert.Equal(1, dupe.ReadByte());
Assert.Equal(2, dupe.ReadByte());
Assert.Equal(3, dupe.ReadByte());
Assert.Throws<InvalidOperationException>(() => stream.ReadByte());
}
[SkippableFact]
public void StreamCanBeForkedButTheOriginalCannotBeRead()
{
VerifySupportsExceptionsInDelegates();
var dotnet = new MemoryStream(new byte[] { 1, 2, 3, 4, 5 });
var stream = new SKManagedStream(dotnet, true);
Assert.Equal(1, stream.ReadByte());
Assert.Equal(2, stream.ReadByte());
var dupe = stream.Fork();
Assert.NotSame(stream, dupe);
Assert.IsType<SKManagedStream>(dupe);
Assert.Equal(3, dupe.ReadByte());
Assert.Equal(4, dupe.ReadByte());
Assert.Throws<InvalidOperationException>(() => stream.ReadByte());
}
[SkippableFact]
public void StreamCannotBeDuplicatedMultipleTimes()
{
VerifySupportsExceptionsInDelegates();
var dotnet = new MemoryStream(new byte[] { 1, 2, 3, 4, 5 });
var stream = new SKManagedStream(dotnet, true);
Assert.Equal(1, stream.ReadByte());
Assert.Equal(2, stream.ReadByte());
var dupe = stream.Duplicate();
Assert.Throws<InvalidOperationException>(() => stream.Duplicate());
Assert.Equal(1, dupe.ReadByte());
}
[SkippableFact]
public void StreamCanBeDuplicatedMultipleTimesIfTheChildIsDestroyed()
{
VerifySupportsExceptionsInDelegates();
var dotnet = new MemoryStream(new byte[] { 1, 2, 3, 4, 5 });
var stream = new SKManagedStream(dotnet, true);
Assert.Equal(1, stream.ReadByte());
Assert.Equal(2, stream.ReadByte());
var dupe1 = stream.Duplicate();
Assert.Equal(1, dupe1.ReadByte());
Assert.Equal(2, dupe1.ReadByte());
dupe1.Dispose();
var dupe2 = stream.Duplicate();
Assert.Equal(1, dupe2.ReadByte());
Assert.Equal(2, dupe2.ReadByte());
Assert.Throws<InvalidOperationException>(() => stream.Duplicate());
}
[SkippableFact]
public void FullOwnershipIsTransferredToTheChildIfTheParentIsDisposed()
{
VerifySupportsExceptionsInDelegates();
var dotnet = new MemoryStream(new byte[] { 1, 2, 3, 4, 5 });
var stream = new SKManagedStream(dotnet, true);
Assert.Equal(1, stream.ReadByte());
Assert.Equal(2, stream.ReadByte());
var dupe1 = stream.Duplicate();
Assert.Equal(1, dupe1.ReadByte());
Assert.Equal(2, dupe1.ReadByte());
Assert.Throws<InvalidOperationException>(() => stream.Duplicate());
stream.Dispose();
var dupe2 = dupe1.Duplicate();
Assert.Equal(1, dupe2.ReadByte());
Assert.Equal(2, dupe2.ReadByte());
Assert.Throws<InvalidOperationException>(() => dupe1.Duplicate());
dupe1.Dispose();
dupe2.Dispose();
Assert.Throws<ObjectDisposedException>(() => dotnet.Position);
}
[SkippableFact]
public void DuplicateStreamIsCollected()
{
VerifySupportsExceptionsInDelegates();
var handle = DoWork();
CollectGarbage();
Assert.False(SKObject.GetInstance<SKManagedStream>(handle, out _));
IntPtr DoWork()
{
var dotnet = new MemoryStream(new byte[] { 1, 2, 3, 4, 5 });
var stream = new SKManagedStream(dotnet, true);
Assert.Equal(1, stream.ReadByte());
Assert.Equal(2, stream.ReadByte());
var dupe1 = stream.Duplicate();
Assert.Equal(1, dupe1.ReadByte());
Assert.Equal(2, dupe1.ReadByte());
Assert.Throws<InvalidOperationException>(() => stream.Duplicate());
stream.Dispose();
var dupe2 = dupe1.Duplicate();
Assert.Equal(1, dupe2.ReadByte());
Assert.Equal(2, dupe2.ReadByte());
return dupe2.Handle;
}
}
[SkippableFact]
public void MiddleDuplicateCanBeRemoved()
{
VerifySupportsExceptionsInDelegates();
var dotnet = new MemoryStream(new byte[] { 1, 2, 3, 4, 5 });
var stream = new SKManagedStream(dotnet, true);
Assert.Equal(1, stream.ReadByte());
Assert.Equal(2, stream.ReadByte());
var dupe1 = stream.Duplicate();
Assert.Equal(1, dupe1.ReadByte());
Assert.Equal(2, dupe1.ReadByte());
Assert.Throws<InvalidOperationException>(() => stream.Duplicate());
var dupe2 = dupe1.Duplicate();
Assert.Equal(1, dupe2.ReadByte());
Assert.Equal(2, dupe2.ReadByte());
Assert.Throws<InvalidOperationException>(() => stream.Duplicate());
Assert.Throws<InvalidOperationException>(() => dupe1.Duplicate());
dupe1.Dispose();
Assert.Throws<InvalidOperationException>(() => stream.Duplicate());
dupe2.Dispose();
var dupe3 = stream.Duplicate();
Assert.Equal(1, dupe3.ReadByte());
Assert.Equal(2, dupe3.ReadByte());
Assert.Throws<InvalidOperationException>(() => stream.Duplicate());
}
[SkippableFact]
public void DotNetStreamIsNotClosedPrematurely()
{
var dotnet = CreateTestStream();
var stream = new SKManagedStream(dotnet, true);
Assert.Equal(0, stream.Position);
var dupe = stream.Duplicate();
Assert.Equal(0, dupe.Position);
stream.Dispose();
Assert.Equal(0, dupe.Position);
dupe.Dispose();
Assert.Throws<ObjectDisposedException>(() => dotnet.Position);
}
}
}