Skip to content
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions src/libraries/System.Memory.Data/ref/System.Memory.Data.cs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,10 @@ public BinaryData(string data, string? mediaType) { }
public static System.BinaryData FromBytes(byte[] data, string? mediaType) { throw null; }
public static System.BinaryData FromBytes(System.ReadOnlyMemory<byte> data) { throw null; }
public static System.BinaryData FromBytes(System.ReadOnlyMemory<byte> data, string? mediaType) { throw null; }
public static System.BinaryData FromFile(string path) { throw null; }
public static System.BinaryData FromFile(string path, string? mediaType) { throw null; }
public static System.Threading.Tasks.Task<System.BinaryData> FromFileAsync(string path, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; }
public static System.Threading.Tasks.Task<System.BinaryData> FromFileAsync(string path, string? mediaType, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; }
[System.Diagnostics.CodeAnalysis.RequiresDynamicCodeAttribute("JSON serialization and deserialization might require types that cannot be statically analyzed and might need runtime code generation.")]
[System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("JSON serialization and deserialization might require types that cannot be statically analyzed.")]
public static System.BinaryData FromObjectAsJson<T>(T jsonSerializable, System.Text.Json.JsonSerializerOptions? options = null) { throw null; }
Expand Down
88 changes: 67 additions & 21 deletions src/libraries/System.Memory.Data/src/System/BinaryData.cs
Original file line number Diff line number Diff line change
Expand Up @@ -225,15 +225,7 @@ public static BinaryData FromString(string data, string? mediaType)
/// </summary>
/// <param name="stream">Stream containing the data.</param>
/// <returns>A value representing all of the data remaining in <paramref name="stream"/>.</returns>
public static BinaryData FromStream(Stream stream)
{
if (stream is null)
{
throw new ArgumentNullException(nameof(stream));
}

return FromStreamAsync(stream, async: false).GetAwaiter().GetResult();
}
public static BinaryData FromStream(Stream stream) => FromStream(stream, mediaType: null);

/// <summary>
/// Creates a <see cref="BinaryData"/> instance from the specified stream
Expand All @@ -251,7 +243,7 @@ public static BinaryData FromStream(Stream stream, string? mediaType)
throw new ArgumentNullException(nameof(stream));
}

return FromStreamAsync(stream, async: false, mediaType).GetAwaiter().GetResult();
return FromStreamAsync(stream, useAsync: false, mediaType).GetAwaiter().GetResult();
}

/// <summary>
Expand All @@ -262,14 +254,7 @@ public static BinaryData FromStream(Stream stream, string? mediaType)
/// <param name="cancellationToken">A token that may be used to cancel the operation.</param>
/// <returns>A value representing all of the data remaining in <paramref name="stream"/>.</returns>
public static Task<BinaryData> FromStreamAsync(Stream stream, CancellationToken cancellationToken = default)
{
if (stream is null)
{
throw new ArgumentNullException(nameof(stream));
}

return FromStreamAsync(stream, async: true, cancellationToken: cancellationToken);
}
=> FromStreamAsync(stream, mediaType: null, cancellationToken);

/// <summary>
/// Creates a <see cref="BinaryData"/> instance from the specified stream
Expand All @@ -289,10 +274,10 @@ public static Task<BinaryData> FromStreamAsync(Stream stream, string? mediaType,
throw new ArgumentNullException(nameof(stream));
}

return FromStreamAsync(stream, async: true, mediaType, cancellationToken);
return FromStreamAsync(stream, useAsync: true, mediaType, cancellationToken);
}

private static async Task<BinaryData> FromStreamAsync(Stream stream, bool async,
private static async Task<BinaryData> FromStreamAsync(Stream stream, bool useAsync,
string? mediaType = default, CancellationToken cancellationToken = default)
{
const int CopyToBufferSize = 81920; // the default used by Stream.CopyToAsync
Expand All @@ -318,7 +303,7 @@ private static async Task<BinaryData> FromStreamAsync(Stream stream, bool async,

using (memoryStream)
{
if (async)
if (useAsync)
{
await stream.CopyToAsync(memoryStream, bufferSize, cancellationToken).ConfigureAwait(false);
}
Expand All @@ -330,6 +315,67 @@ private static async Task<BinaryData> FromStreamAsync(Stream stream, bool async,
}
}

/// <summary>
/// Creates a <see cref="BinaryData"/> instance from the specified file.
/// </summary>
/// <param name="path">The path to the file.</param>
/// <returns>A value representing all of the data from the file.</returns>
public static BinaryData FromFile(string path) => FromFile(path, mediaType: null);

/// <summary>
/// Creates a <see cref="BinaryData"/> instance from the specified file
/// and sets <see cref="MediaType"/> to <see pref="mediaType"/> value.
/// </summary>
/// <param name="path">The path to the file.</param>
/// <param name="mediaType">MIME type of this data, e.g. <see cref="MediaTypeNames.Application.Octet"/>.</param>
/// <returns>A value representing all of the data from the file.</returns>
/// <seealso cref="MediaTypeNames"/>
public static BinaryData FromFile(string path, string? mediaType)
{
if (path is null)
{
throw new ArgumentNullException(nameof(path));
}

return new BinaryData(File.ReadAllBytes(path), mediaType);
}

/// <summary>
/// Creates a <see cref="BinaryData"/> instance from the specified file.
/// </summary>
/// <param name="path">The path to the file.</param>
/// <param name="cancellationToken">A token that may be used to cancel the operation.</param>
/// <returns>A value representing all of the data from the file.</returns>
public static Task<BinaryData> FromFileAsync(string path, CancellationToken cancellationToken = default)
=> FromFileAsync(path, mediaType: null, cancellationToken);

/// <summary>
/// Creates a <see cref="BinaryData"/> instance from the specified file
/// and sets <see cref="MediaType"/> to <see pref="mediaType"/> value.
/// </summary>
/// <param name="path">The path to the file.</param>
/// <param name="mediaType">MIME type of this data, e.g. <see cref="MediaTypeNames.Application.Octet"/>.</param>
/// <param name="cancellationToken">A token that may be used to cancel the operation.</param>
/// <returns>A value representing all of the data from the file.</returns>
/// <seealso cref="MediaTypeNames"/>
public static async Task<BinaryData> FromFileAsync(string path, string? mediaType,
CancellationToken cancellationToken = default)
{
if (path is null)
{
throw new ArgumentNullException(nameof(path));
}

#if NET
return new BinaryData(
await File.ReadAllBytesAsync(path, cancellationToken).ConfigureAwait(false),
mediaType);
#else
using FileStream fileStream = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read, 1, useAsync: true);
return await FromStreamAsync(fileStream, mediaType, cancellationToken).ConfigureAwait(false);
#endif
}

/// <summary>
/// Creates a <see cref="BinaryData"/> instance by serializing the provided object using
/// the <see cref="JsonSerializer"/>
Expand Down
67 changes: 67 additions & 0 deletions src/libraries/System.Memory.Data/tests/BinaryDataFromFileTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System.IO;
using System.Net.Mime;
using System.Threading.Tasks;
using Xunit;

namespace System.Tests
{
public partial class BinaryDataFromFileTests : FileCleanupTestBase
{
[Fact]
public async Task CanCreateBinaryDataFromFile()
{
byte[] buffer = "some data"u8.ToArray();
string path = GetRandomFilePath();
File.WriteAllBytes(path, buffer);
BinaryData data = BinaryData.FromFile(path);
Assert.Equal(buffer, data.ToArray());

byte[] output = new byte[buffer.Length];
var outputStream = data.ToStream();
outputStream.Read(output, 0, (int)outputStream.Length);
Assert.Equal(buffer, output);

data = await BinaryData.FromFileAsync(path);
Assert.Equal(buffer, data.ToArray());

outputStream = data.ToStream();
outputStream.Read(output, 0, (int)outputStream.Length);
Assert.Equal(buffer, output);
}

[Theory]
[InlineData(null)]
[InlineData("")]
[InlineData(MediaTypeNames.Application.Soap)]
public async Task CanCreateBinaryDataFromFileWithMediaType(string? mediaType)
{
byte[] buffer = "some data"u8.ToArray();
string path = GetRandomFilePath();

File.WriteAllBytes(path, buffer);
BinaryData data = BinaryData.FromFile(path, mediaType);
Assert.Equal(buffer, data.ToArray());
Assert.Equal(mediaType, data.MediaType);

byte[] output = new byte[buffer.Length];
var outputStream = data.ToStream();
outputStream.Read(output, 0, (int)outputStream.Length);
Assert.Equal(buffer, output);

data = await BinaryData.FromFileAsync(path, mediaType);
Assert.Equal(buffer, data.ToArray());
Assert.Equal(mediaType, data.MediaType);

outputStream = data.ToStream();
outputStream.Read(output, 0, (int)outputStream.Length);
Assert.Equal(buffer, output);

//changing the backing buffer should not affect the BD instance
buffer[3] = (byte)'z';
Assert.NotEqual(buffer, data.ToMemory().ToArray());
}
}
}
47 changes: 13 additions & 34 deletions src/libraries/System.Memory.Data/tests/BinaryDataTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -352,7 +352,7 @@ public async Task CanCreateBinaryDataFromNonSeekableStream()
public async Task CanCreateBinaryDataFromFileStream()
{
byte[] buffer = "some data"u8.ToArray();
using FileStream stream = new FileStream(Path.GetTempFileName(), FileMode.Open);
using FileStream stream = new FileStream(Path.GetTempFileName(), FileMode.Open, FileAccess.ReadWrite, FileShare.None, 4096, FileOptions.DeleteOnClose);
stream.Write(buffer, 0, buffer.Length);
stream.Position = 0;
BinaryData data = BinaryData.FromStream(stream);
Expand Down Expand Up @@ -497,51 +497,30 @@ public void CanSerializeNullData()
[Fact]
public async Task CreateThrowsOnNullStream()
{
var ex = Assert.Throws<ArgumentNullException>(() => BinaryData.FromStream(null));
Assert.Contains("stream", ex.Message);

ex = Assert.Throws<ArgumentNullException>(() => BinaryData.FromStream(null, null));
Assert.Contains("stream", ex.Message);

ex = await Assert.ThrowsAsync<ArgumentNullException>(() => BinaryData.FromStreamAsync(null));
Assert.Contains("stream", ex.Message);

ex = await Assert.ThrowsAsync<ArgumentNullException>(() => BinaryData.FromStreamAsync(null, null));
Assert.Contains("stream", ex.Message);
AssertExtensions.Throws<ArgumentNullException>("stream", () => BinaryData.FromStream(null));
AssertExtensions.Throws<ArgumentNullException>("stream", () => BinaryData.FromStream(null, null));
await AssertExtensions.ThrowsAsync<ArgumentNullException>("stream", () => BinaryData.FromStreamAsync(null));
await AssertExtensions.ThrowsAsync<ArgumentNullException>("stream", () => BinaryData.FromStreamAsync(null, null));
}

[Fact]
public void CreateThrowsOnNullString()
{
string payload = null;
var ex = Assert.Throws<ArgumentNullException>(() => new BinaryData(payload));
Assert.Contains("data", ex.Message);

ex = Assert.Throws<ArgumentNullException>(() => new BinaryData(payload, null));
Assert.Contains("data", ex.Message);

ex = Assert.Throws<ArgumentNullException>(() => BinaryData.FromString(payload));
Assert.Contains("data", ex.Message);

ex = Assert.Throws<ArgumentNullException>(() => BinaryData.FromString(payload, null));
Assert.Contains("data", ex.Message);
var ex = AssertExtensions.Throws<ArgumentNullException>("data", () => new BinaryData(payload));
AssertExtensions.Throws<ArgumentNullException>("data", () => new BinaryData(payload, null));
AssertExtensions.Throws<ArgumentNullException>("data", () => BinaryData.FromString(payload));
AssertExtensions.Throws<ArgumentNullException>("data", () => BinaryData.FromString(payload, null));
}

[Fact]
public void CreateThrowsOnNullArray()
{
byte[] payload = null;
var ex = Assert.Throws<ArgumentNullException>(() => new BinaryData(payload));
Assert.Contains("data", ex.Message);

ex = Assert.Throws<ArgumentNullException>(() => new BinaryData(payload, null));
Assert.Contains("data", ex.Message);

ex = Assert.Throws<ArgumentNullException>(() => BinaryData.FromBytes(null));
Assert.Contains("data", ex.Message);

ex = Assert.Throws<ArgumentNullException>(() => BinaryData.FromBytes(null, null));
Assert.Contains("data", ex.Message);
var ex = AssertExtensions.Throws<ArgumentNullException>("data", () => new BinaryData(payload));
AssertExtensions.Throws<ArgumentNullException>("data", () => new BinaryData(payload, null));
AssertExtensions.Throws<ArgumentNullException>("data", () => BinaryData.FromBytes(payload));
AssertExtensions.Throws<ArgumentNullException>("data", () => BinaryData.FromBytes(payload, null));
}

[ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotBuiltWithAggressiveTrimming))]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,12 @@
</PropertyGroup>

<ItemGroup>
<Compile Include="BinaryDataFromFileTests.cs" />
<Compile Include="BinaryDataTests.cs" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\src\System.Memory.Data.csproj"/>
<ProjectReference Include="..\src\System.Memory.Data.csproj" />
</ItemGroup>

<ItemGroup Condition="'$(TargetFrameworkIdentifier)' == '.NETFramework'">
Expand Down