Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
41 changes: 41 additions & 0 deletions PolyShim.Tests/Net70/FileTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
using System.Collections.Generic;
using System.IO;
using System.Threading.Tasks;
using FluentAssertions;
using Xunit;

namespace PolyShim.Tests.Net70;

public class FileTests
{
[Fact]
public async Task ReadLinesAsync_Test()
{
// Arrange
var linesToWrite = new[] { "Line 1", "Line 2", "Line 3" };
var tempFilePath = Path.GetTempFileName();
await File.WriteAllLinesAsync(tempFilePath, linesToWrite);

try
{
// Act
var readLines = new List<string>();
await foreach (var line in File.ReadLinesAsync(tempFilePath))
readLines.Add(line);

// Assert
readLines.Should().Equal(linesToWrite);
}
finally
{
try
{
File.Delete(tempFilePath);
}
catch
{
// Ignore
}
}
}
}
77 changes: 77 additions & 0 deletions PolyShim.Tests/Net70/TextReaderTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
using System;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
using FluentAssertions;
using Xunit;

namespace PolyShim.Tests.Net70;

public class TextReaderTests
{
[Fact]
public async Task ReadLineAsync_Test()
{
// Arrange
using var stream = new MemoryStream("Line 1\nLine 2\nLine 3\n"u8.ToArray());
using var reader = new StreamReader(stream);

// Act
var line1 = await reader.ReadLineAsync(CancellationToken.None);
var line2 = await reader.ReadLineAsync(CancellationToken.None);
var line3 = await reader.ReadLineAsync(CancellationToken.None);
var line4 = await reader.ReadLineAsync(CancellationToken.None);

// Assert
line1.Should().Be("Line 1");
line2.Should().Be("Line 2");
line3.Should().Be("Line 3");
line4.Should().BeNull();
}

[Fact]
public async Task ReadLineAsync_Cancellation_Test()
{
// Arrange
using var stream = new MemoryStream("Line 1\nLine 2\nLine 3\n"u8.ToArray());
using var reader = new StreamReader(stream);
using var cts = new CancellationTokenSource();
await cts.CancelAsync();

// Act & Assert
await Assert.ThrowsAnyAsync<OperationCanceledException>(async () =>
{
await reader.ReadLineAsync(cts.Token);
});
}

[Fact]
public async Task ReadToEndAsync_Test()
{
// Arrange
using var stream = new MemoryStream("Hello, World!"u8.ToArray());
using var reader = new StreamReader(stream);

// Act
var content = await reader.ReadToEndAsync(CancellationToken.None);

// Assert
content.Should().Be("Hello, World!");
}

[Fact]
public async Task ReadToEndAsync_Cancellation_Test()
{
// Arrange
using var stream = new MemoryStream("Hello, World!"u8.ToArray());
using var reader = new StreamReader(stream);
using var cts = new CancellationTokenSource();
await cts.CancelAsync();

// Act & Assert
await Assert.ThrowsAnyAsync<OperationCanceledException>(async () =>
{
await reader.ReadToEndAsync(cts.Token);
});
}
}
79 changes: 79 additions & 0 deletions PolyShim/Net70/File.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
#if (NETCOREAPP && !NET7_0_OR_GREATER) || (NETFRAMEWORK) || (NETSTANDARD)
#nullable enable
// ReSharper disable RedundantUsingDirective
// ReSharper disable CheckNamespace
// ReSharper disable InconsistentNaming
// ReSharper disable PartialTypeWithSinglePart

using System.Collections.Generic;
using System.IO;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading;

internal static partial class PolyfillExtensions
{
// No file I/O on .NET Standard prior to 1.3
#if !NETSTANDARD || NETSTANDARD1_3_OR_GREATER
extension(File)
{
#if FEATURE_TASK && FEATURE_ASYNCINTERFACES
// https://learn.microsoft.com/dotnet/api/system.io.file.readlinesasync#system-io-file-readlinesasync(system-string-system-text-encoding-system-threading-cancellationtoken)
public static async IAsyncEnumerable<string> ReadLinesAsync(
string path,
Encoding encoding,
[EnumeratorCancellation] CancellationToken cancellationToken = default
)
{
using var stream = new FileStream(
path,
FileMode.Open,
FileAccess.Read,
FileShare.Read,
4096,
FileOptions.Asynchronous | FileOptions.SequentialScan
);

using var reader = new StreamReader(stream, encoding);

while (!reader.EndOfStream)
{
cancellationToken.ThrowIfCancellationRequested();

var line = await reader.ReadLineAsync(cancellationToken).ConfigureAwait(false);
if (line is not null)
yield return line;
}
}

// https://learn.microsoft.com/dotnet/api/system.io.file.readlinesasync#system-io-file-readlinesasync(system-string-system-threading-cancellationtoken)
public static async IAsyncEnumerable<string> ReadLinesAsync(
string path,
[EnumeratorCancellation] CancellationToken cancellationToken = default
)
{
using var stream = new FileStream(
path,
FileMode.Open,
FileAccess.Read,
FileShare.Read,
4096,
FileOptions.Asynchronous | FileOptions.SequentialScan
);

using var reader = new StreamReader(stream);

while (!reader.EndOfStream)
{
cancellationToken.ThrowIfCancellationRequested();

var line = await reader.ReadLineAsync(cancellationToken).ConfigureAwait(false);
if (line is not null)
yield return line;
}
}
#endif
}
#endif
}
#endif
50 changes: 50 additions & 0 deletions PolyShim/Net70/TextReader.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
#if (NETCOREAPP && !NET7_0_OR_GREATER) || (NETFRAMEWORK) || (NETSTANDARD)
#nullable enable
// ReSharper disable RedundantUsingDirective
// ReSharper disable CheckNamespace
// ReSharper disable InconsistentNaming
// ReSharper disable PartialTypeWithSinglePart

using System;
using System.IO;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

internal static partial class PolyfillExtensions
{
extension(TextReader reader)
{
#if FEATURE_TASK
// https://learn.microsoft.com/dotnet/api/system.io.textreader.readlineasync#system-io-textreader-readlineasync(system-threading-cancellationtoken)
public Task<string?> ReadLineAsync(CancellationToken cancellationToken)
{
// Impossible to polyfill this properly as it requires to track the buffer's state
cancellationToken.ThrowIfCancellationRequested();
return reader.ReadLineAsync();
}

// https://learn.microsoft.com/dotnet/api/system.io.textreader.readtoendasync#system-io-textreader-readtoendasync(system-threading-cancellationtoken)
public async Task<string> ReadToEndAsync(CancellationToken cancellationToken)
{
var result = new StringBuilder();
var buffer = new char[4096];

while (true)
{
var charsRead = await reader
.ReadAsync(buffer, cancellationToken)
.ConfigureAwait(false);

if (charsRead <= 0)
break;

result.Append(buffer, 0, charsRead);
}

return result.ToString();
}
#endif
}
}
#endif
8 changes: 6 additions & 2 deletions PolyShim/Signatures.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
# Signatures

- **Total:** 335
- **Total:** 339
- **Types:** 74
- **Members:** 261
- **Members:** 265

___

Expand Down Expand Up @@ -89,6 +89,8 @@ ___
- `FeatureSwitchDefinitionAttribute`
- [**[class]**](https://learn.microsoft.com/dotnet/api/system.diagnostics.codeanalysis.featureswitchdefinitionattribute) <sup><sub>.NET 9.0</sub></sup>
- `File`
- [`IAsyncEnumerable<string> ReadLinesAsync(string, CancellationToken)`](https://learn.microsoft.com/dotnet/api/system.io.file.readlinesasync#system-io-file-readlinesasync(system-string-system-threading-cancellationtoken)) <sup><sub>.NET 7.0</sub></sup>
- [`IAsyncEnumerable<string> ReadLinesAsync(string, Encoding, CancellationToken)`](https://learn.microsoft.com/dotnet/api/system.io.file.readlinesasync#system-io-file-readlinesasync(system-string-system-text-encoding-system-threading-cancellationtoken)) <sup><sub>.NET 7.0</sub></sup>
- [`Task AppendAllBytesAsync(string, byte[], CancellationToken)`](https://learn.microsoft.com/dotnet/api/system.io.file.appendallbytesasync#system-io-file-appendallbytesasync(system-string-system-byte()-system-threading-cancellationtoken)) <sup><sub>.NET 9.0</sub></sup>
- [`Task AppendAllLinesAsync(string, IEnumerable<string>, CancellationToken)`](https://learn.microsoft.com/dotnet/api/system.io.file.appendalllinesasync#system-io-file-appendalllinesasync(system-string-system-collections-generic-ienumerable((system-string))-system-threading-cancellationtoken)) <sup><sub>.NET Core 2.0</sub></sup>
- [`Task AppendAllLinesAsync(string, IEnumerable<string>, Encoding, CancellationToken)`](https://learn.microsoft.com/dotnet/api/system.io.file.appendalllinesasync#system-io-file-appendalllinesasync(system-string-system-collections-generic-ienumerable((system-string))-system-text-encoding-system-threading-cancellationtoken)) <sup><sub>.NET Core 2.0</sub></sup>
Expand Down Expand Up @@ -413,6 +415,8 @@ ___
- `TextReader`
- [`int Read(Span<char>)`](https://learn.microsoft.com/dotnet/api/system.io.textreader.read#system-io-textreader-read(system-span((system-char)))) <sup><sub>.NET Core 2.1</sub></sup>
- [`Task<int> ReadAsync(Memory<char>, CancellationToken)`](https://learn.microsoft.com/dotnet/api/system.io.textreader.readasync#system-io-textreader-readasync(system-memory((system-char))-system-threading-cancellationtoken)) <sup><sub>.NET Core 2.1</sub></sup>
- [`Task<string?> ReadLineAsync(CancellationToken)`](https://learn.microsoft.com/dotnet/api/system.io.textreader.readlineasync#system-io-textreader-readlineasync(system-threading-cancellationtoken)) <sup><sub>.NET 7.0</sub></sup>
- [`Task<string> ReadToEndAsync(CancellationToken)`](https://learn.microsoft.com/dotnet/api/system.io.textreader.readtoendasync#system-io-textreader-readtoendasync(system-threading-cancellationtoken)) <sup><sub>.NET 7.0</sub></sup>
- `TextWriter`
- [`Task DisposeAsync()`](https://learn.microsoft.com/dotnet/api/system.io.textwriter.disposeasync) <sup><sub>.NET Core 3.0</sub></sup>
- [`Task WriteAsync(ReadOnlyMemory<char>, CancellationToken)`](https://learn.microsoft.com/dotnet/api/system.io.textwriter.writeasync#system-io-textwriter-writeasync(system-readonlymemory((system-char))-system-threading-cancellationtoken)) <sup><sub>.NET Core 2.1</sub></sup>
Expand Down
Loading