diff --git a/PowerKit.Tests/AssemblyExtensionsTests.cs b/PowerKit.Tests/AssemblyExtensionsTests.cs index 1074520..f7cd0c0 100644 --- a/PowerKit.Tests/AssemblyExtensionsTests.cs +++ b/PowerKit.Tests/AssemblyExtensionsTests.cs @@ -1,5 +1,8 @@ +using System.IO; using System.Reflection; +using System.Threading.Tasks; using FluentAssertions; +using PowerKit; using PowerKit.Extensions; using Xunit; @@ -7,16 +10,65 @@ namespace PowerKit.Tests; public class AssemblyExtensionsTests { + private static readonly Assembly ThisAssembly = typeof(AssemblyExtensionsTests).Assembly; + + // The embedded resource name follows the default MSBuild convention: + // . with path separators replaced by dots. + private const string ResourceName = "PowerKit.Tests.TestData.TestResource.txt"; + [Fact] public void TryGetVersionString_Test() + { + // Act + var version = ThisAssembly.TryGetVersionString(); + + // Assert + version.Should().NotBeNullOrWhiteSpace(); + } + + [Fact] + public void GetManifestResourceString_Test() + { + // Act + var content = ThisAssembly.GetManifestResourceString(ResourceName); + + // Assert + content.Should().Be("hello"); + } + + [Fact] + public async Task GetManifestResourceStringAsync_Test() + { + // Act + var content = await ThisAssembly.GetManifestResourceStringAsync(ResourceName); + + // Assert + content.Should().Be("hello"); + } + + [Fact] + public void ExtractManifestResource_Test() { // Arrange - var assembly = typeof(AssemblyExtensionsTests).Assembly; + using var tempFile = TempFile.Create(); // Act - var version = assembly.TryGetVersionString(); + ThisAssembly.ExtractManifestResource(ResourceName, tempFile.Path); // Assert - version.Should().NotBeNullOrWhiteSpace(); + File.ReadAllText(tempFile.Path).Should().Be("hello"); + } + + [Fact] + public async Task ExtractManifestResourceAsync_Test() + { + // Arrange + using var tempFile = TempFile.Create(); + + // Act + await ThisAssembly.ExtractManifestResourceAsync(ResourceName, tempFile.Path); + + // Assert + (await File.ReadAllTextAsync(tempFile.Path)).Should().Be("hello"); } } diff --git a/PowerKit.Tests/PowerKit.Tests.csproj b/PowerKit.Tests/PowerKit.Tests.csproj index 8026c37..a4158eb 100644 --- a/PowerKit.Tests/PowerKit.Tests.csproj +++ b/PowerKit.Tests/PowerKit.Tests.csproj @@ -11,6 +11,10 @@ + + + + diff --git a/PowerKit.Tests/TestData/TestResource.txt b/PowerKit.Tests/TestData/TestResource.txt new file mode 100644 index 0000000..b6fc4c6 --- /dev/null +++ b/PowerKit.Tests/TestData/TestResource.txt @@ -0,0 +1 @@ +hello \ No newline at end of file diff --git a/PowerKit/Extensions/AssemblyExtensions.cs b/PowerKit/Extensions/AssemblyExtensions.cs index a123680..4264bb0 100644 --- a/PowerKit/Extensions/AssemblyExtensions.cs +++ b/PowerKit/Extensions/AssemblyExtensions.cs @@ -1,4 +1,9 @@ +using System.IO; using System.Reflection; +using System.Resources; +using System.Text; +using System.Threading; +using System.Threading.Tasks; namespace PowerKit.Extensions; @@ -15,5 +20,106 @@ internal static class AssemblyExtensions assembly .GetCustomAttribute() ?.InformationalVersion ?? assembly.GetName().Version?.ToString(); + + /// + /// Reads the specified manifest resource as a string using the specified encoding. + /// Throws if the resource is not found. + /// + public string GetManifestResourceString(string resourceName, Encoding encoding) + { + using var stream = + assembly.GetManifestResourceStream(resourceName) + ?? throw new MissingManifestResourceException( + $"Failed to find resource '{resourceName}'." + ); + + using var reader = new StreamReader(stream, encoding); + return reader.ReadToEnd(); + } + + /// + /// Reads the specified manifest resource as a UTF-8 string. + /// Throws if the resource is not found. + /// + public string GetManifestResourceString(string resourceName) => + assembly.GetManifestResourceString(resourceName, Encoding.UTF8); + + /// + /// Reads the specified manifest resource as a string using the specified encoding asynchronously. + /// Throws if the resource is not found. + /// + public async Task GetManifestResourceStringAsync( + string resourceName, + Encoding encoding, + CancellationToken cancellationToken = default + ) + { + using var stream = + assembly.GetManifestResourceStream(resourceName) + ?? throw new MissingManifestResourceException( + $"Failed to find resource '{resourceName}'." + ); + + using var reader = new StreamReader(stream, encoding); + return await reader.ReadToEndAsync(cancellationToken).ConfigureAwait(false); + } + + /// + /// Reads the specified manifest resource as a UTF-8 string asynchronously. + /// Throws if the resource is not found. + /// + public async Task GetManifestResourceStringAsync( + string resourceName, + CancellationToken cancellationToken = default + ) => + await assembly + .GetManifestResourceStringAsync(resourceName, Encoding.UTF8, cancellationToken) + .ConfigureAwait(false); + + /// + /// Extracts the specified manifest resource to a file at the given path. + /// Throws if the resource is not found. + /// + public void ExtractManifestResource(string resourceName, string filePath) + { + using var source = + assembly.GetManifestResourceStream(resourceName) + ?? throw new MissingManifestResourceException( + $"Failed to find resource '{resourceName}'." + ); + + using var destination = File.Create(filePath); + source.CopyTo(destination); + destination.Flush(); + } + + /// + /// Extracts the specified manifest resource to a file at the given path asynchronously. + /// Throws if the resource is not found. + /// + public async Task ExtractManifestResourceAsync( + string resourceName, + string filePath, + CancellationToken cancellationToken = default + ) + { + using var source = + assembly.GetManifestResourceStream(resourceName) + ?? throw new MissingManifestResourceException( + $"Failed to find resource '{resourceName}'." + ); + + using var destination = new FileStream( + filePath, + FileMode.Create, + FileAccess.Write, + FileShare.None, + 81920, + FileOptions.Asynchronous + ); + + await source.CopyToAsync(destination, 81920, cancellationToken).ConfigureAwait(false); + await destination.FlushAsync(cancellationToken).ConfigureAwait(false); + } } }