mirror of https://github.com/SixLabors/ImageSharp
16 changed files with 511 additions and 88 deletions
@ -0,0 +1,109 @@ |
|||
// Copyright (c) Six Labors and contributors.
|
|||
// Licensed under the GNU Affero General Public License, Version 3.
|
|||
|
|||
using System; |
|||
using System.IO; |
|||
|
|||
using Moq; |
|||
|
|||
using SixLabors.ImageSharp.Formats.Png; |
|||
using SixLabors.ImageSharp.PixelFormats; |
|||
using Xunit; |
|||
|
|||
// ReSharper disable InconsistentNaming
|
|||
namespace SixLabors.ImageSharp.Tests |
|||
{ |
|||
using System.Runtime.CompilerServices; |
|||
using System.Threading.Tasks; |
|||
using SixLabors.ImageSharp.Advanced; |
|||
using SixLabors.ImageSharp.Formats; |
|||
using SixLabors.ImageSharp.Tests.TestUtilities; |
|||
|
|||
public partial class ImageTests |
|||
{ |
|||
public class SaveAsync |
|||
{ |
|||
|
|||
[Fact] |
|||
public async Task DetectedEncoding() |
|||
{ |
|||
string dir = TestEnvironment.CreateOutputDirectory(nameof(ImageTests)); |
|||
string file = System.IO.Path.Combine(dir, "DetectedEncodingAsync.png"); |
|||
|
|||
using (var image = new Image<Rgba32>(10, 10)) |
|||
{ |
|||
await image.SaveAsync(file); |
|||
} |
|||
|
|||
using (Image.Load(file, out IImageFormat mime)) |
|||
{ |
|||
Assert.Equal("image/png", mime.DefaultMimeType); |
|||
} |
|||
} |
|||
|
|||
[Fact] |
|||
public async Task WhenExtensionIsUnknown_Throws() |
|||
{ |
|||
string dir = TestEnvironment.CreateOutputDirectory(nameof(ImageTests)); |
|||
string file = System.IO.Path.Combine(dir, "UnknownExtensionsEncoding_Throws.tmp"); |
|||
|
|||
await Assert.ThrowsAsync<NotSupportedException>( |
|||
async () => |
|||
{ |
|||
using (var image = new Image<Rgba32>(10, 10)) |
|||
{ |
|||
await image.SaveAsync(file); |
|||
} |
|||
}); |
|||
} |
|||
|
|||
[Fact] |
|||
public async Task SetEncoding() |
|||
{ |
|||
string dir = TestEnvironment.CreateOutputDirectory(nameof(ImageTests)); |
|||
string file = System.IO.Path.Combine(dir, "SetEncoding.dat"); |
|||
|
|||
using (var image = new Image<Rgba32>(10, 10)) |
|||
{ |
|||
await image.SaveAsync(file, new PngEncoder()); |
|||
} |
|||
|
|||
using (Image.Load(file, out var mime)) |
|||
{ |
|||
Assert.Equal("image/png", mime.DefaultMimeType); |
|||
} |
|||
} |
|||
|
|||
[Fact] |
|||
public async Task ThrowsWhenDisposed() |
|||
{ |
|||
var image = new Image<Rgba32>(5, 5); |
|||
image.Dispose(); |
|||
IImageEncoder encoder = Mock.Of<IImageEncoder>(); |
|||
using (var stream = new MemoryStream()) |
|||
{ |
|||
await Assert.ThrowsAsync<ObjectDisposedException>(async () => await image.SaveAsync(stream, encoder)); |
|||
} |
|||
} |
|||
|
|||
[Theory] |
|||
[InlineData("test.png")] |
|||
[InlineData("test.tga")] |
|||
[InlineData("test.bmp")] |
|||
[InlineData("test.jpg")] |
|||
[InlineData("test.gif")] |
|||
public async Task SaveNeverCallsSyncMethods(string filename) |
|||
{ |
|||
using (var image = new Image<Rgba32>(5, 5)) |
|||
{ |
|||
IImageEncoder encoder = image.FindEncoded(filename); |
|||
using (var stream = new MemoryStream()) |
|||
{ |
|||
var asyncStream = new AsyncStreamWrapper(stream, () => false); |
|||
await image.SaveAsync(asyncStream, encoder); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,117 @@ |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.IO; |
|||
using System.Text; |
|||
using System.Threading; |
|||
using System.Threading.Tasks; |
|||
|
|||
namespace SixLabors.ImageSharp.Tests.TestUtilities |
|||
{ |
|||
// https://github.com/dotnet/aspnetcore/blob/620c673705bb17b33cbc5ff32872d85a5fbf82b9/src/Hosting/TestHost/src/AsyncStreamWrapper.cs
|
|||
internal class AsyncStreamWrapper : Stream |
|||
{ |
|||
private Stream inner; |
|||
private Func<bool> allowSynchronousIO; |
|||
|
|||
internal AsyncStreamWrapper(Stream inner, Func<bool> allowSynchronousIO) |
|||
{ |
|||
this.inner = inner; |
|||
this.allowSynchronousIO = allowSynchronousIO; |
|||
} |
|||
|
|||
public override bool CanRead => this.inner.CanRead; |
|||
|
|||
public override bool CanSeek => false; |
|||
|
|||
public override bool CanWrite => this.inner.CanWrite; |
|||
|
|||
public override long Length => throw new NotSupportedException("The stream is not seekable."); |
|||
|
|||
public override long Position |
|||
{ |
|||
get => throw new NotSupportedException("The stream is not seekable."); |
|||
set => throw new NotSupportedException("The stream is not seekable."); |
|||
} |
|||
|
|||
public override void Flush() |
|||
{ |
|||
// Not blocking Flush because things like StreamWriter.Dispose() always call it.
|
|||
this.inner.Flush(); |
|||
} |
|||
|
|||
public override Task FlushAsync(CancellationToken cancellationToken) |
|||
{ |
|||
return this.inner.FlushAsync(cancellationToken); |
|||
} |
|||
|
|||
public override int Read(byte[] buffer, int offset, int count) |
|||
{ |
|||
if (!this.allowSynchronousIO()) |
|||
{ |
|||
throw new InvalidOperationException("Synchronous operations are disallowed. Call ReadAsync or set AllowSynchronousIO to true."); |
|||
} |
|||
|
|||
return this.inner.Read(buffer, offset, count); |
|||
} |
|||
|
|||
public override Task<int> ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken) |
|||
{ |
|||
return this.inner.ReadAsync(buffer, offset, count, cancellationToken); |
|||
} |
|||
|
|||
public override IAsyncResult BeginRead(byte[] buffer, int offset, int count, AsyncCallback callback, object state) |
|||
{ |
|||
return this.inner.BeginRead(buffer, offset, count, callback, state); |
|||
} |
|||
|
|||
public override int EndRead(IAsyncResult asyncResult) |
|||
{ |
|||
return this.inner.EndRead(asyncResult); |
|||
} |
|||
|
|||
public override long Seek(long offset, SeekOrigin origin) |
|||
{ |
|||
throw new NotSupportedException("The stream is not seekable."); |
|||
} |
|||
|
|||
public override void SetLength(long value) |
|||
{ |
|||
throw new NotSupportedException("The stream is not seekable."); |
|||
} |
|||
|
|||
public override void Write(byte[] buffer, int offset, int count) |
|||
{ |
|||
if (!this.allowSynchronousIO()) |
|||
{ |
|||
throw new InvalidOperationException("Synchronous operations are disallowed. Call WriteAsync or set AllowSynchronousIO to true."); |
|||
} |
|||
|
|||
this.inner.Write(buffer, offset, count); |
|||
} |
|||
|
|||
public override IAsyncResult BeginWrite(byte[] buffer, int offset, int count, AsyncCallback callback, object state) |
|||
{ |
|||
return this.inner.BeginWrite(buffer, offset, count, callback, state); |
|||
} |
|||
|
|||
public override void EndWrite(IAsyncResult asyncResult) |
|||
{ |
|||
this.inner.EndWrite(asyncResult); |
|||
} |
|||
|
|||
public override Task WriteAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken) |
|||
{ |
|||
return this.inner.WriteAsync(buffer, offset, count, cancellationToken); |
|||
} |
|||
|
|||
public override void Close() |
|||
{ |
|||
// Don't dispose the inner stream, we don't want to impact the client stream
|
|||
} |
|||
|
|||
protected override void Dispose(bool disposing) |
|||
{ |
|||
// Don't dispose the inner stream, we don't want to impact the client stream
|
|||
} |
|||
} |
|||
} |
|||
Loading…
Reference in new issue