diff --git a/UniversalFiles.sln.DotSettings b/UniversalFiles.sln.DotSettings index 6f96f68..92a3c6e 100644 --- a/UniversalFiles.sln.DotSettings +++ b/UniversalFiles.sln.DotSettings @@ -13,4 +13,5 @@ See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with UniversalFiles. If not, see <https://www.gnu.org/licenses/>. True - True \ No newline at end of file + True + True \ No newline at end of file diff --git a/src/UniversalFiles.Swarm/Extensions/UniversalUriProviderExtensions.cs b/src/UniversalFiles.Swarm/Extensions/UFileProviderExtension.cs similarity index 51% rename from src/UniversalFiles.Swarm/Extensions/UniversalUriProviderExtensions.cs rename to src/UniversalFiles.Swarm/Extensions/UFileProviderExtension.cs index 3a6df97..62c95a4 100644 --- a/src/UniversalFiles.Swarm/Extensions/UniversalUriProviderExtensions.cs +++ b/src/UniversalFiles.Swarm/Extensions/UFileProviderExtension.cs @@ -13,31 +13,28 @@ // If not, see . using Etherna.BeeNet; -using Etherna.BeeNet.Models; -using Etherna.UniversalFiles.Handlers; using System; namespace Etherna.UniversalFiles.Extensions { - public static class UniversalUriProviderExtensions + public static class UFileProviderExtension { - public static UniversalUri GetNewUri( - this IUniversalUriProvider uriProvider, - SwarmUri swarmUri, - IBeeClient beeClient, - UniversalUriKind allowedUriKinds = UniversalUriKind.Online, - SwarmAddress? defaultBaseAddress = null) + public static SwarmUFile BuildNewUFile( + this IUFileProvider fileProvider, + SwarmUUri uuri) { - ArgumentNullException.ThrowIfNull(uriProvider, nameof(uriProvider)); - - if ((allowedUriKinds & UniversalUriKind.Local) != 0) - throw new ArgumentException("Swarm uri can't be local"); + ArgumentNullException.ThrowIfNull(fileProvider, nameof(fileProvider)); + return (SwarmUFile)fileProvider.BuildNewUFile(uuri); + } - return new( - swarmUri.ToString(), - new SwarmHandler(beeClient), - allowedUriKinds, - defaultBaseAddress.ToString()); + public static UFileProvider UseSwarmUFiles( + this UFileProvider fileProvider, + IBeeClient beeClient) + { + ArgumentNullException.ThrowIfNull(fileProvider, nameof(fileProvider)); + + fileProvider.RegisterUUriType(uuri => new SwarmUFile(beeClient, uuri)); + return fileProvider; } } } \ No newline at end of file diff --git a/src/UniversalFiles.Swarm/Handlers/SwarmHandler.cs b/src/UniversalFiles.Swarm/Handlers/SwarmHandler.cs deleted file mode 100644 index 238c99b..0000000 --- a/src/UniversalFiles.Swarm/Handlers/SwarmHandler.cs +++ /dev/null @@ -1,142 +0,0 @@ -// Copyright 2023-present Etherna SA -// This file is part of UniversalFiles. -// -// UniversalFiles is free software: you can redistribute it and/or modify it under the terms of the -// GNU Lesser General Public License as published by the Free Software Foundation, -// either version 3 of the License, or (at your option) any later version. -// -// UniversalFiles is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; -// without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -// See the GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License along with UniversalFiles. -// If not, see . - -using Etherna.BeeNet; -using Etherna.BeeNet.Models; -using System; -using System.IO; -using System.Text; -using System.Threading.Tasks; - -namespace Etherna.UniversalFiles.Handlers -{ - /// - /// Supports swarm files - /// - public class SwarmHandler( - IBeeClient beeClient) - : IHandler - { - public async Task<(bool Result, (byte[] ByteArray, Encoding? Encoding)? ContentCache)> ExistsAsync( - string absoluteUri, - UniversalUriKind absoluteUriKind) - { - if (absoluteUriKind != UniversalUriKind.OnlineAbsolute) - throw new InvalidOperationException( - "Invalid online absolute uri kind. It can't be casted to SwarmAddress"); - - // Try to get file head. - try - { - var headers = await beeClient.TryGetFileHeadersAsync(absoluteUri).ConfigureAwait(false); - if (headers is null) - return (false, null); - } - catch { return (false, null); } - - return (true, null); - } - - public async Task<(long Result, (byte[] ByteArray, Encoding? Encoding)? ContentCache)> GetByteSizeAsync( - string absoluteUri, - UniversalUriKind absoluteUriKind) - { - var size = await beeClient.TryGetFileSizeAsync(absoluteUri).ConfigureAwait(false); - if (size is null) - throw new InvalidOperationException(); - return (size.Value, null); - } - - public UniversalUriKind GetUriKind(string uri) - { - ArgumentNullException.ThrowIfNull(uri, nameof(uri)); - return SwarmHash.IsValidHash(uri.Split(SwarmAddress.Separator)[0]) - ? UniversalUriKind.OnlineAbsolute - : UniversalUriKind.OnlineRelative; - } - - public async Task<(byte[] ByteArray, Encoding? Encoding)> ReadToByteArrayAsync( - string absoluteUri, - UniversalUriKind absoluteUriKind) - { - var (contentStream, encoding) = await ReadToStreamAsync(absoluteUri, absoluteUriKind).ConfigureAwait(false); - - // Copy stream to memory stream. - using var memoryStream = new MemoryStream(); - await contentStream.CopyToAsync(memoryStream).ConfigureAwait(false); - memoryStream.Position = 0; - - var byteArrayContent = memoryStream.ToArray(); - await contentStream.DisposeAsync().ConfigureAwait(false); - - return (byteArrayContent, encoding); - } - - public async Task<(Stream Stream, Encoding? Encoding)> ReadToStreamAsync( - string absoluteUri, - UniversalUriKind absoluteUriKind) - { - var result = await beeClient.GetFileAsync(absoluteUri).ConfigureAwait(false); - - // Try to extract the encoding from the Content-Type header. - Encoding? contentEncoding = null; - if (result.ContentHeaders?.ContentType?.CharSet != null) - { - try { contentEncoding = Encoding.GetEncoding(result.ContentHeaders.ContentType.CharSet); } - catch (ArgumentException) { } - } - - return (result.Stream, contentEncoding); - } - - public Task TryGetFileNameAsync(string originalUri) => - beeClient.TryGetFileNameAsync(originalUri); - - public (string AbsoluteUri, UniversalUriKind UriKind)? TryGetParentDirectoryAsAbsoluteUri( - string absoluteUri, - UniversalUriKind absoluteUriKind) => - throw new InvalidOperationException("Swarm doesn't implement concept of directories"); - - public (string AbsoluteUri, UniversalUriKind UriKind) UriToAbsoluteUri( - string originalUri, - string? baseDirectory, - UniversalUriKind uriKind) - { - ArgumentNullException.ThrowIfNull(originalUri, nameof(originalUri)); - - // Resolve absolute url. - switch (uriKind) - { - case UniversalUriKind.OnlineAbsolute: - return (new SwarmAddress(originalUri).ToString(), UniversalUriKind.OnlineAbsolute); - - case UniversalUriKind.OnlineRelative: - if (baseDirectory is null) - throw new ArgumentNullException(nameof(baseDirectory), - "Base directory can't be null with relative original uri"); - - if ((GetUriKind(baseDirectory) & UniversalUriKind.Absolute) == 0) - throw new InvalidOperationException( - "If uri kind is relative, base directory must be absolute"); - - var swarmUri = new SwarmUri(originalUri, UriKind.Relative); - var swarmAddress = swarmUri.ToSwarmAddress(baseDirectory); - - return (swarmAddress.ToString(), UniversalUriKind.OnlineAbsolute); - - default: throw new InvalidOperationException("Can't find a valid uri kind"); - } - } - } -} \ No newline at end of file diff --git a/src/UniversalFiles.Swarm/SwarmUFile.cs b/src/UniversalFiles.Swarm/SwarmUFile.cs new file mode 100644 index 0000000..37c1b5c --- /dev/null +++ b/src/UniversalFiles.Swarm/SwarmUFile.cs @@ -0,0 +1,95 @@ +// Copyright 2023-present Etherna SA +// This file is part of UniversalFiles. +// +// UniversalFiles is free software: you can redistribute it and/or modify it under the terms of the +// GNU Lesser General Public License as published by the Free Software Foundation, +// either version 3 of the License, or (at your option) any later version. +// +// UniversalFiles is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; +// without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License along with UniversalFiles. +// If not, see . + +using Etherna.BeeNet; +using System; +using System.IO; +using System.Text; +using System.Threading.Tasks; + +namespace Etherna.UniversalFiles +{ + public class SwarmUFile( + IBeeClient beeClient, + UUri fileUri) + : UFile(fileUri) + { + protected override async Task<(bool Result, (byte[] ByteArray, Encoding? Encoding)? ContentCache)> ExistsAsync( + string absoluteUri, + UUriKind absoluteUriKind) + { + if (absoluteUriKind != UUriKind.OnlineAbsolute) + throw new InvalidOperationException( + "Invalid online absolute uri kind. It can't be casted to SwarmAddress"); + + // Try to get file head. + try + { + var headers = await beeClient.TryGetFileHeadersAsync(absoluteUri).ConfigureAwait(false); + if (headers is null) + return (false, null); + } + catch { return (false, null); } + + return (true, null); + } + + protected override async Task<(long Result, (byte[] ByteArray, Encoding? Encoding)? ContentCache)> GetByteSizeAsync( + string absoluteUri, + UUriKind absoluteUriKind) + { + var size = await beeClient.TryGetFileSizeAsync(absoluteUri).ConfigureAwait(false); + if (size is null) + throw new InvalidOperationException(); + return (size.Value, null); + } + + protected override async Task<(byte[] ByteArray, Encoding? Encoding)> ReadToByteArrayAsync( + string absoluteUri, + UUriKind absoluteUriKind) + { + var (contentStream, encoding) = await ReadToStreamAsync(absoluteUri, absoluteUriKind).ConfigureAwait(false); + + // Copy stream to memory stream. + using var memoryStream = new MemoryStream(); + await contentStream.CopyToAsync(memoryStream).ConfigureAwait(false); + memoryStream.Position = 0; + + var byteArrayContent = memoryStream.ToArray(); + await contentStream.DisposeAsync().ConfigureAwait(false); + + return (byteArrayContent, encoding); + } + + protected override async Task<(Stream Stream, Encoding? Encoding)> ReadToStreamAsync( + string absoluteUri, + UUriKind absoluteUriKind) + { + var result = await beeClient.GetFileAsync(absoluteUri).ConfigureAwait(false); + + // Try to extract the encoding from the Content-Type header. + Encoding? contentEncoding = null; + if (result.ContentHeaders?.ContentType?.CharSet != null) + { + try { contentEncoding = Encoding.GetEncoding(result.ContentHeaders.ContentType.CharSet); } + catch (ArgumentException) { } + } + + return (result.Stream, contentEncoding); + } + + protected override Task TryGetFileNameAsync(string originalUri) => + beeClient.TryGetFileNameAsync(originalUri); + } +} \ No newline at end of file diff --git a/src/UniversalFiles.Swarm/SwarmUUri.cs b/src/UniversalFiles.Swarm/SwarmUUri.cs new file mode 100644 index 0000000..6867e1a --- /dev/null +++ b/src/UniversalFiles.Swarm/SwarmUUri.cs @@ -0,0 +1,74 @@ +// Copyright 2023-present Etherna SA +// This file is part of UniversalFiles. +// +// UniversalFiles is free software: you can redistribute it and/or modify it under the terms of the +// GNU Lesser General Public License as published by the Free Software Foundation, +// either version 3 of the License, or (at your option) any later version. +// +// UniversalFiles is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; +// without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License along with UniversalFiles. +// If not, see . + +using Etherna.BeeNet.Models; +using System; + +namespace Etherna.UniversalFiles +{ + public class SwarmUUri( + SwarmUri uri, + UUriKind allowedUriKinds = UUriKind.All, + string? defaultBaseDirectory = null) + : UUri(uri.ToString(), GetUriKind(uri.ToString()) & allowedUriKinds, defaultBaseDirectory) + { + // Public static methods. + public static UUriKind GetUriKind(string uri) + { + ArgumentNullException.ThrowIfNull(uri, nameof(uri)); + return SwarmHash.IsValidHash(uri.Split(SwarmAddress.Separator)[0]) + ? UUriKind.OnlineAbsolute + : UUriKind.OnlineRelative; + } + + // Protected methods. + protected internal override UUriKind GetUriKindHelper(string uri) => GetUriKind(uri); + + protected internal override (string AbsoluteUri, UUriKind UriKind)? TryGetParentDirectoryAsAbsoluteUri( + string absoluteUri, + UUriKind absoluteUriKind) => + throw new InvalidOperationException("Swarm doesn't implement concept of directories"); + + protected internal override (string AbsoluteUri, UUriKind UriKind) UriToAbsoluteUri( + string originalUri, + string? baseDirectory, + UUriKind uriKind) + { + ArgumentNullException.ThrowIfNull(originalUri, nameof(originalUri)); + + // Resolve absolute url. + switch (uriKind) + { + case UUriKind.OnlineAbsolute: + return (new SwarmAddress(originalUri).ToString(), UUriKind.OnlineAbsolute); + + case UUriKind.OnlineRelative: + if (baseDirectory is null) + throw new ArgumentNullException(nameof(baseDirectory), + "Base directory can't be null with relative original uri"); + + if ((GetUriKind(baseDirectory) & UUriKind.Absolute) == 0) + throw new InvalidOperationException( + "If uri kind is relative, base directory must be absolute"); + + var swarmUri = new SwarmUri(originalUri, System.UriKind.Relative); + var swarmAddress = swarmUri.ToSwarmAddress(baseDirectory); + + return (swarmAddress.ToString(), UUriKind.OnlineAbsolute); + + default: throw new InvalidOperationException("Can't find a valid uri kind"); + } + } + } +} \ No newline at end of file diff --git a/src/UniversalFiles/Handlers/BasicHandler.cs b/src/UniversalFiles/BasicUFile.cs similarity index 54% rename from src/UniversalFiles/Handlers/BasicHandler.cs rename to src/UniversalFiles/BasicUFile.cs index 5c7a0ef..8a9eb34 100644 --- a/src/UniversalFiles/Handlers/BasicHandler.cs +++ b/src/UniversalFiles/BasicUFile.cs @@ -16,30 +16,27 @@ using System.IO; using System.Linq; using System.Net.Http; -using System.Runtime.InteropServices; using System.Text; using System.Threading.Tasks; -namespace Etherna.UniversalFiles.Handlers +namespace Etherna.UniversalFiles { - /// - /// Supports local and online files with http protocol - /// - public class BasicHandler( + public class BasicUFile( + BasicUUri fileUri, IHttpClientFactory httpClientFactory) - : IHandler + : UFile(fileUri) { - // Methods. - public async Task<(bool Result, (byte[] ByteArray, Encoding? Encoding)? ContentCache)> ExistsAsync( + // Protected methods. + protected override async Task<(bool Result, (byte[] ByteArray, Encoding? Encoding)? ContentCache)> ExistsAsync( string absoluteUri, - UniversalUriKind absoluteUriKind) + UUriKind absoluteUriKind) { switch (absoluteUriKind) { - case UniversalUriKind.LocalAbsolute: + case UUriKind.LocalAbsolute: return (File.Exists(absoluteUri) || Directory.Exists(absoluteUri), null); - case UniversalUriKind.OnlineAbsolute: + case UUriKind.OnlineAbsolute: // Try to get resource byte size with an HEAD request. var byteSyze = await TryGetOnlineByteSizeWithHeadRequestAsync(absoluteUri).ConfigureAwait(false); if (byteSyze.HasValue) @@ -54,16 +51,16 @@ public class BasicHandler( } } - public async Task<(long Result, (byte[] ByteArray, Encoding? Encoding)? ContentCache)> GetByteSizeAsync( + protected override async Task<(long Result, (byte[] ByteArray, Encoding? Encoding)? ContentCache)> GetByteSizeAsync( string absoluteUri, - UniversalUriKind absoluteUriKind) + UUriKind absoluteUriKind) { switch (absoluteUriKind) { - case UniversalUriKind.LocalAbsolute: + case UUriKind.LocalAbsolute: return (new FileInfo(absoluteUri).Length, null); - case UniversalUriKind.OnlineAbsolute: + case UUriKind.OnlineAbsolute: // Try to get resource byte size with an HEAD request. var byteSyze = await TryGetOnlineByteSizeWithHeadRequestAsync(absoluteUri).ConfigureAwait(false); if (byteSyze.HasValue) @@ -79,45 +76,16 @@ public class BasicHandler( } } - public UniversalUriKind GetUriKind(string uri) - { - ArgumentNullException.ThrowIfNull(uri, nameof(uri)); - - var uriKind = UniversalUriKind.None; - - if (uri.Length > 0) - { - //test online absolute - if (Uri.TryCreate(uri, UriKind.Absolute, out var onlineAbsUriResult) && - (onlineAbsUriResult.Scheme == Uri.UriSchemeHttp || onlineAbsUriResult.Scheme == Uri.UriSchemeHttps)) - uriKind |= UniversalUriKind.OnlineAbsolute; - - //test online relative - if (Uri.TryCreate(uri, UriKind.Relative, out var _)) - uriKind |= UniversalUriKind.OnlineRelative; - - //test local absolute and relative - if ((uriKind & UniversalUriKind.OnlineAbsolute) == 0) - { - uriKind |= Path.IsPathRooted(uri) ? - UniversalUriKind.LocalAbsolute : - UniversalUriKind.LocalRelative; - } - } - - return uriKind; - } - - public async Task<(byte[] ByteArray, Encoding? Encoding)> ReadToByteArrayAsync( + protected override async Task<(byte[] ByteArray, Encoding? Encoding)> ReadToByteArrayAsync( string absoluteUri, - UniversalUriKind absoluteUriKind) + UUriKind absoluteUriKind) { switch (absoluteUriKind) { - case UniversalUriKind.LocalAbsolute: + case UUriKind.LocalAbsolute: return (await File.ReadAllBytesAsync(absoluteUri).ConfigureAwait(false), null); - case UniversalUriKind.OnlineAbsolute: + case UUriKind.OnlineAbsolute: return await TryGetOnlineAsByteArrayAsync(absoluteUri).ConfigureAwait(false) ?? throw new IOException($"Can't retrieve online resource at {absoluteUri}"); @@ -126,16 +94,16 @@ public UniversalUriKind GetUriKind(string uri) } } - public async Task<(Stream Stream, Encoding? Encoding)> ReadToStreamAsync( + protected override async Task<(Stream Stream, Encoding? Encoding)> ReadToStreamAsync( string absoluteUri, - UniversalUriKind absoluteUriKind) + UUriKind absoluteUriKind) { switch (absoluteUriKind) { - case UniversalUriKind.LocalAbsolute: + case UUriKind.LocalAbsolute: return (File.OpenRead(absoluteUri), null); - case UniversalUriKind.OnlineAbsolute: + case UUriKind.OnlineAbsolute: return await TryGetOnlineAsStreamAsync(absoluteUri).ConfigureAwait(false) ?? throw new IOException($"Can't retrieve online resource at {absoluteUri}"); @@ -144,7 +112,7 @@ public UniversalUriKind GetUriKind(string uri) } } - public Task TryGetFileNameAsync(string originalUri) + protected override Task TryGetFileNameAsync(string originalUri) { ArgumentNullException.ThrowIfNull(originalUri, nameof(originalUri)); @@ -154,67 +122,6 @@ public UniversalUriKind GetUriKind(string uri) return Task.FromResult(originalUri.Split('/', '\\').Last()); } - public (string AbsoluteUri, UniversalUriKind UriKind)? TryGetParentDirectoryAsAbsoluteUri( - string absoluteUri, - UniversalUriKind absoluteUriKind) - { - switch (absoluteUriKind) - { - case UniversalUriKind.LocalAbsolute: - var dirName = Path.GetDirectoryName(absoluteUri); - return dirName is null ? null : - (dirName, UniversalUriKind.LocalAbsolute); - - case UniversalUriKind.OnlineAbsolute: - var segments = new Uri(absoluteUri, UriKind.Absolute).Segments; - return segments.Length == 1 ? null : //if it's already root, return null - (absoluteUri[..^segments.Last().Length], UniversalUriKind.OnlineAbsolute); - - default: throw new InvalidOperationException("Invalid absolute uri kind. It should be well defined and absolute"); - } - } - - public (string AbsoluteUri, UniversalUriKind UriKind) UriToAbsoluteUri( - string originalUri, - string? baseDirectory, - UniversalUriKind uriKind) - { - ArgumentNullException.ThrowIfNull(originalUri, nameof(originalUri)); - - // Verify base directory is absolute. - if ((uriKind & UniversalUriKind.Relative) != 0 && - baseDirectory != null && - (GetUriKind(baseDirectory) & UniversalUriKind.Absolute) == 0) - throw new InvalidOperationException("If uri kind can be relative and base directory is present, it must be absolute"); - - // Resolve absolute url. - return uriKind switch - { - UniversalUriKind.LocalAbsolute => - RuntimeInformation.IsOSPlatform(OSPlatform.Windows) && - !Path.IsPathFullyQualified(originalUri) && //Ex: "/test" - baseDirectory is not null && Path.IsPathFullyQualified(baseDirectory) ? - (Path.GetFullPath(originalUri, baseDirectory), UniversalUriKind.LocalAbsolute) : //take unit from base directory - (Path.GetFullPath(originalUri), UniversalUriKind.LocalAbsolute), - - UniversalUriKind.LocalRelative => - (Path.GetFullPath( - originalUri, - baseDirectory is not null ? - Path.GetFullPath(baseDirectory) : //GetFullPath is required when on windows baseDirectory is a root path without unit name. Ex: "/test" - Directory.GetCurrentDirectory()), - UniversalUriKind.LocalAbsolute), - - UniversalUriKind.OnlineAbsolute => (new Uri(originalUri, System.UriKind.Absolute).ToString(), UniversalUriKind.OnlineAbsolute), - - UniversalUriKind.OnlineRelative => (new Uri( - new Uri(baseDirectory!, UriKind.Absolute), - string.Join('/', originalUri.Split('/', '\\').Select(Uri.EscapeDataString))).ToString(), UniversalUriKind.OnlineAbsolute), - - _ => throw new InvalidOperationException("Can't find a valid uri kind") - }; - } - // Helpers. private async Task<(byte[] ByteArray, Encoding? Encoding)?> TryGetOnlineAsByteArrayAsync( string onlineAbsoluteUri) @@ -275,8 +182,8 @@ baseDirectory is not null ? if (response.Headers.TryGetValues("Content-Length", out var values)) { - string contentLength = values.GetEnumerator().Current; - if (long.TryParse(contentLength, out var byteSize)) + using var enumerator = values.GetEnumerator(); + if (long.TryParse(enumerator.Current, out var byteSize)) return byteSize; } } diff --git a/src/UniversalFiles/BasicUUri.cs b/src/UniversalFiles/BasicUUri.cs new file mode 100644 index 0000000..71d628e --- /dev/null +++ b/src/UniversalFiles/BasicUUri.cs @@ -0,0 +1,122 @@ +// Copyright 2023-present Etherna SA +// This file is part of UniversalFiles. +// +// UniversalFiles is free software: you can redistribute it and/or modify it under the terms of the +// GNU Lesser General Public License as published by the Free Software Foundation, +// either version 3 of the License, or (at your option) any later version. +// +// UniversalFiles is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; +// without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License along with UniversalFiles. +// If not, see . + +using System; +using System.IO; +using System.Linq; +using System.Runtime.InteropServices; + +namespace Etherna.UniversalFiles +{ + public class BasicUUri( + string uri, + UUriKind allowedUriKinds = UUriKind.All, + string? defaultBaseDirectory = null) + : UUri(uri, GetUriKind(uri) & allowedUriKinds, defaultBaseDirectory) + { + // Public static methods. + public static UUriKind GetUriKind(string uri) + { + ArgumentNullException.ThrowIfNull(uri, nameof(uri)); + + var uriKind = UUriKind.None; + + if (uri.Length > 0) + { + //test online absolute + if (Uri.TryCreate(uri, System.UriKind.Absolute, out var onlineAbsUriResult) && + (onlineAbsUriResult.Scheme == Uri.UriSchemeHttp || onlineAbsUriResult.Scheme == Uri.UriSchemeHttps)) + uriKind |= UUriKind.OnlineAbsolute; + + //test online relative + if (Uri.TryCreate(uri, System.UriKind.Relative, out _)) + uriKind |= UUriKind.OnlineRelative; + + //test local absolute and relative + if ((uriKind & UUriKind.OnlineAbsolute) == 0) + { + uriKind |= Path.IsPathRooted(uri) ? + UUriKind.LocalAbsolute : + UUriKind.LocalRelative; + } + } + + return uriKind; + } + + // Protected methods. + protected internal override UUriKind GetUriKindHelper(string uri) => GetUriKind(uri); + + protected internal override (string AbsoluteUri, UUriKind UriKind)? TryGetParentDirectoryAsAbsoluteUri( + string absoluteUri, + UUriKind absoluteUriKind) + { + switch (absoluteUriKind) + { + case UUriKind.LocalAbsolute: + var dirName = Path.GetDirectoryName(absoluteUri); + return dirName is null ? null : + (dirName, UUriKind.LocalAbsolute); + + case UUriKind.OnlineAbsolute: + var segments = new Uri(absoluteUri, System.UriKind.Absolute).Segments; + return segments.Length == 1 ? null : //if it's already root, return null + (absoluteUri[..^segments.Last().Length], UUriKind.OnlineAbsolute); + + default: throw new InvalidOperationException("Invalid absolute uri kind. It should be well defined and absolute"); + } + } + + protected internal override (string AbsoluteUri, UUriKind UriKind) UriToAbsoluteUri( + string originalUri, + string? baseDirectory, + UUriKind uriKind) + { + ArgumentNullException.ThrowIfNull(originalUri, nameof(originalUri)); + + // Verify base directory is absolute. + if ((uriKind & UUriKind.Relative) != 0 && + baseDirectory != null && + (GetUriKind(baseDirectory) & UUriKind.Absolute) == 0) + throw new InvalidOperationException("If uri kind can be relative and base directory is present, it must be absolute"); + + // Resolve absolute url. + return uriKind switch + { + UUriKind.LocalAbsolute => + RuntimeInformation.IsOSPlatform(OSPlatform.Windows) && + !Path.IsPathFullyQualified(originalUri) && //Ex: "/test" + baseDirectory is not null && Path.IsPathFullyQualified(baseDirectory) ? + (Path.GetFullPath(originalUri, baseDirectory), UUriKind.LocalAbsolute) : //take unit from base directory + (Path.GetFullPath(originalUri), UUriKind.LocalAbsolute), + + UUriKind.LocalRelative => + (Path.GetFullPath( + originalUri, + baseDirectory is not null ? + Path.GetFullPath(baseDirectory) : //GetFullPath is required when on windows baseDirectory is a root path without unit name. Ex: "/test" + Directory.GetCurrentDirectory()), + UUriKind.LocalAbsolute), + + UUriKind.OnlineAbsolute => (new Uri(originalUri, System.UriKind.Absolute).ToString(), UUriKind.OnlineAbsolute), + + UUriKind.OnlineRelative => (new Uri( + new Uri(baseDirectory!, System.UriKind.Absolute), + string.Join('/', originalUri.Split('/', '\\').Select(Uri.EscapeDataString))).ToString(), UUriKind.OnlineAbsolute), + + _ => throw new InvalidOperationException("Can't find a valid uri kind") + }; + } + } +} \ No newline at end of file diff --git a/src/UniversalFiles/Handlers/IHandler.cs b/src/UniversalFiles/Handlers/IHandler.cs deleted file mode 100644 index 2819119..0000000 --- a/src/UniversalFiles/Handlers/IHandler.cs +++ /dev/null @@ -1,58 +0,0 @@ -// Copyright 2023-present Etherna SA -// This file is part of UniversalFiles. -// -// UniversalFiles is free software: you can redistribute it and/or modify it under the terms of the -// GNU Lesser General Public License as published by the Free Software Foundation, -// either version 3 of the License, or (at your option) any later version. -// -// UniversalFiles is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; -// without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -// See the GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License along with UniversalFiles. -// If not, see . - -using System.IO; -using System.Text; -using System.Threading.Tasks; - -namespace Etherna.UniversalFiles.Handlers -{ - public interface IHandler - { - Task<(bool Result, (byte[] ByteArray, Encoding? Encoding)? ContentCache)> ExistsAsync( - string absoluteUri, - UniversalUriKind absoluteUriKind); - - Task<(long Result, (byte[] ByteArray, Encoding? Encoding)? ContentCache)> GetByteSizeAsync( - string absoluteUri, - UniversalUriKind absoluteUriKind); - - /// - /// Try to identify the uri kind, doesn't validate paths - /// - /// The input uri - /// Identified uri kind - UniversalUriKind GetUriKind(string uri); - - Task<(byte[] ByteArray, Encoding? Encoding)> ReadToByteArrayAsync( - string absoluteUri, - UniversalUriKind absoluteUriKind); - - Task<(Stream Stream, Encoding? Encoding)> ReadToStreamAsync( - string absoluteUri, - UniversalUriKind absoluteUriKind); - - Task TryGetFileNameAsync( - string originalUri); - - (string AbsoluteUri, UniversalUriKind UriKind)? TryGetParentDirectoryAsAbsoluteUri( - string absoluteUri, - UniversalUriKind absoluteUriKind); - - (string AbsoluteUri, UniversalUriKind UriKind) UriToAbsoluteUri( - string originalUri, - string? baseDirectory, - UniversalUriKind uriKind); - } -} \ No newline at end of file diff --git a/src/UniversalFiles/IUniversalUriProvider.cs b/src/UniversalFiles/IUFileProvider.cs similarity index 68% rename from src/UniversalFiles/IUniversalUriProvider.cs rename to src/UniversalFiles/IUFileProvider.cs index d2f5fea..b0b00fe 100644 --- a/src/UniversalFiles/IUniversalUriProvider.cs +++ b/src/UniversalFiles/IUFileProvider.cs @@ -12,13 +12,20 @@ // You should have received a copy of the GNU Lesser General Public License along with UniversalFiles. // If not, see . +using System.Threading.Tasks; + namespace Etherna.UniversalFiles { - public interface IUniversalUriProvider + public interface IUFileProvider { - UniversalUri GetNewUri( - string uri, - UniversalUriKind allowedUriKinds = UniversalUriKind.All, - string? defaultBaseDirectory = null); + BasicUFile BuildNewUFile(BasicUUri uuri); + + UFile BuildNewUFile(UUri uuri); + + Task ToLocalUFileAsync( + UFile inputUFile, + UUriKind allowedUriKinds = UUriKind.All, + string? baseDirectory = null, + BasicUUri? outputUUri = null); } } \ No newline at end of file diff --git a/src/UniversalFiles/Properties/AssemblyInfo.cs b/src/UniversalFiles/Properties/AssemblyInfo.cs index 1568faa..71c880b 100644 --- a/src/UniversalFiles/Properties/AssemblyInfo.cs +++ b/src/UniversalFiles/Properties/AssemblyInfo.cs @@ -14,4 +14,5 @@ using System.Runtime.CompilerServices; -[assembly: InternalsVisibleTo("UniversalFiles.Swarm")] \ No newline at end of file +[assembly: InternalsVisibleTo("UniversalFiles.Swarm")] +[assembly: InternalsVisibleTo("UniversalFiles.Tests")] \ No newline at end of file diff --git a/src/UniversalFiles/UniversalFile.cs b/src/UniversalFiles/UFile.cs similarity index 67% rename from src/UniversalFiles/UniversalFile.cs rename to src/UniversalFiles/UFile.cs index fdf1033..327d9ed 100644 --- a/src/UniversalFiles/UniversalFile.cs +++ b/src/UniversalFiles/UFile.cs @@ -19,14 +19,14 @@ namespace Etherna.UniversalFiles { - public class UniversalFile + public abstract class UFile { // Fields. private (byte[], Encoding?)? onlineResourceCache; // Constructor. - public UniversalFile( - UniversalUri fileUri) + protected UFile( + UUri fileUri) { ArgumentNullException.ThrowIfNull(fileUri, nameof(fileUri)); @@ -34,14 +34,14 @@ public UniversalFile( } // Properties. - public UniversalUri FileUri { get; } + public UUri FileUri { get; } // Methods. public void ClearOnlineCache() => onlineResourceCache = null; public async Task ExistsAsync( bool useCacheIfOnline = false, - UniversalUriKind allowedUriKinds = UniversalUriKind.All, + UUriKind allowedUriKinds = UUriKind.All, string? baseDirectory = null) { // Use cache if enabled and available. @@ -50,10 +50,10 @@ public async Task ExistsAsync( // Get result from handler. var (absoluteUri, absoluteUriKind) = FileUri.ToAbsoluteUri(allowedUriKinds, baseDirectory); - var (result, resultCache) = await FileUri.Handler.ExistsAsync(absoluteUri, absoluteUriKind).ConfigureAwait(false); + var (result, resultCache) = await ExistsAsync(absoluteUri, absoluteUriKind).ConfigureAwait(false); // Update cache if required. - if (absoluteUriKind == UniversalUriKind.OnlineAbsolute && + if (absoluteUriKind == UUriKind.OnlineAbsolute && resultCache != null && useCacheIfOnline) onlineResourceCache = resultCache; @@ -63,7 +63,7 @@ public async Task ExistsAsync( public async Task GetByteSizeAsync( bool useCacheIfOnline = false, - UniversalUriKind allowedUriKinds = UniversalUriKind.All, + UUriKind allowedUriKinds = UUriKind.All, string? baseDirectory = null) { // Use cache if enabled and available. @@ -72,10 +72,10 @@ public async Task GetByteSizeAsync( // Get result from handler. var (absoluteUri, absoluteUriKind) = FileUri.ToAbsoluteUri(allowedUriKinds, baseDirectory); - var (result, resultCache) = await FileUri.Handler.GetByteSizeAsync(absoluteUri, absoluteUriKind).ConfigureAwait(false); + var (result, resultCache) = await GetByteSizeAsync(absoluteUri, absoluteUriKind).ConfigureAwait(false); // Update cache if required. - if (absoluteUriKind == UniversalUriKind.OnlineAbsolute && + if (absoluteUriKind == UUriKind.OnlineAbsolute && resultCache != null && useCacheIfOnline) onlineResourceCache = resultCache; @@ -85,7 +85,7 @@ public async Task GetByteSizeAsync( public async Task<(byte[] ByteArray, Encoding? Encoding)> ReadToByteArrayAsync( bool useCacheIfOnline = false, - UniversalUriKind allowedUriKinds = UniversalUriKind.All, + UUriKind allowedUriKinds = UUriKind.All, string? baseDirectory = null) { // Use cache if enabled and available. @@ -94,10 +94,10 @@ public async Task GetByteSizeAsync( // Get resource. var (absoluteUri, absoluteUriKind) = FileUri.ToAbsoluteUri(allowedUriKinds, baseDirectory); - var result = await FileUri.Handler.ReadToByteArrayAsync(absoluteUri, absoluteUriKind).ConfigureAwait(false); + var result = await ReadToByteArrayAsync(absoluteUri, absoluteUriKind).ConfigureAwait(false); // Update cache if required. - if (absoluteUriKind == UniversalUriKind.OnlineAbsolute && + if (absoluteUriKind == UUriKind.OnlineAbsolute && useCacheIfOnline) onlineResourceCache = result; @@ -105,17 +105,17 @@ public async Task GetByteSizeAsync( } public Task<(Stream Stream, Encoding? Encoding)> ReadToStreamAsync( - UniversalUriKind allowedUriKinds = UniversalUriKind.All, + UUriKind allowedUriKinds = UUriKind.All, string? baseDirectory = null) { // Get resource. var (absoluteUri, absoluteUriKind) = FileUri.ToAbsoluteUri(allowedUriKinds, baseDirectory); - return FileUri.Handler.ReadToStreamAsync(absoluteUri, absoluteUriKind); + return ReadToStreamAsync(absoluteUri, absoluteUriKind); } public async Task ReadToStringAsync( bool useCacheIfOnline = false, - UniversalUriKind allowedUriKinds = UniversalUriKind.All, + UUriKind allowedUriKinds = UUriKind.All, string? baseDirectory = null) { var (content, encoding) = await ReadToByteArrayAsync( @@ -125,8 +125,26 @@ public async Task ReadToStringAsync( encoding ??= Encoding.UTF8; return encoding.GetString(content); } - - public Task TryGetFileNameAsync() => - FileUri.TryGetFileNameAsync(); + + public Task TryGetFileNameAsync() => TryGetFileNameAsync(FileUri.OriginalUri); + + // Protected methods. + protected abstract Task<(bool Result, (byte[] ByteArray, Encoding? Encoding)? ContentCache)> ExistsAsync( + string absoluteUri, + UUriKind absoluteUriKind); + + protected abstract Task<(long Result, (byte[] ByteArray, Encoding? Encoding)? ContentCache)> GetByteSizeAsync( + string absoluteUri, + UUriKind absoluteUriKind); + + protected abstract Task<(byte[] ByteArray, Encoding? Encoding)> ReadToByteArrayAsync( + string absoluteUri, + UUriKind absoluteUriKind); + + protected abstract Task<(Stream Stream, Encoding? Encoding)> ReadToStreamAsync( + string absoluteUri, + UUriKind absoluteUriKind); + + protected abstract Task TryGetFileNameAsync(string originalUri); } } diff --git a/src/UniversalFiles/UFileProvider.cs b/src/UniversalFiles/UFileProvider.cs new file mode 100644 index 0000000..6f78222 --- /dev/null +++ b/src/UniversalFiles/UFileProvider.cs @@ -0,0 +1,79 @@ +// Copyright 2023-present Etherna SA +// This file is part of UniversalFiles. +// +// UniversalFiles is free software: you can redistribute it and/or modify it under the terms of the +// GNU Lesser General Public License as published by the Free Software Foundation, +// either version 3 of the License, or (at your option) any later version. +// +// UniversalFiles is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; +// without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License along with UniversalFiles. +// If not, see . + +using System; +using System.Collections.Generic; +using System.IO; +using System.Net.Http; +using System.Threading.Tasks; + +namespace Etherna.UniversalFiles +{ + public class UFileProvider : IUFileProvider + { + // Fields. + private readonly Dictionary> uFileBuilders = new(); // + + public UFileProvider(IHttpClientFactory httpClientFactory) + { + uFileBuilders[typeof(BasicUUri)] = uuri => new BasicUFile((BasicUUri)uuri, httpClientFactory); + } + + // Methods. + public BasicUFile BuildNewUFile(BasicUUri uuri) => + (BasicUFile)BuildNewUFile((UUri)uuri); + + public UFile BuildNewUFile(UUri uuri) + { + ArgumentNullException.ThrowIfNull(uuri, nameof(uuri)); + + var builder = uFileBuilders[uuri.GetType()]; + return builder(uuri); + } + + public void RegisterUUriType(Func builder) where TUUri : UUri => + uFileBuilders[typeof(TUUri)] = uuri => builder((TUUri)uuri); + + public async Task ToLocalUFileAsync( + UFile inputUFile, + UUriKind allowedUriKinds = UUriKind.All, + string? baseDirectory = null, + BasicUUri? outputUUri = null) + { + ArgumentNullException.ThrowIfNull(inputUFile, nameof(inputUFile)); + + // If it's already a local file, skip file retrieve. + if (inputUFile is BasicUFile basicUFile && + (basicUFile.FileUri.UriKind & allowedUriKinds & UUriKind.Local) != 0) + return basicUFile; + + if (outputUUri != null && outputUUri.UriKind != UUriKind.LocalAbsolute) + throw new InvalidOperationException("If provided, output uuri must be local and absolute"); + + if (outputUUri is null) + { + var fileName = await inputUFile.TryGetFileNameAsync().ConfigureAwait(false); + outputUUri = fileName is null ? + new BasicUUri(Path.GetTempFileName()) : + new BasicUUri(Path.Join(Path.GetTempPath(), fileName)); + } + + using var inputFileStream = (await inputUFile.ReadToStreamAsync(allowedUriKinds, baseDirectory).ConfigureAwait(false)).Stream; + using var outputFileStream = new FileStream(outputUUri.ToAbsoluteUri().Item1, FileMode.Create); + await inputFileStream.CopyToAsync(outputFileStream).ConfigureAwait(false); + + return (BasicUFile)BuildNewUFile(outputUUri); + } + } +} \ No newline at end of file diff --git a/src/UniversalFiles/UniversalUri.cs b/src/UniversalFiles/UUri.cs similarity index 68% rename from src/UniversalFiles/UniversalUri.cs rename to src/UniversalFiles/UUri.cs index 1167b47..349c5cb 100644 --- a/src/UniversalFiles/UniversalUri.cs +++ b/src/UniversalFiles/UUri.cs @@ -12,42 +12,34 @@ // You should have received a copy of the GNU Lesser General Public License along with UniversalFiles. // If not, see . -using Etherna.UniversalFiles.Handlers; using System; -using System.Threading.Tasks; namespace Etherna.UniversalFiles { - public class UniversalUri + public abstract class UUri { - // Fields. - private readonly string? defaultBaseDirectory; - // Constructor. - public UniversalUri( + protected UUri( string uri, - IHandler handler, - UniversalUriKind allowedUriKinds = UniversalUriKind.All, + UUriKind uriKind, string? defaultBaseDirectory = null) { - ArgumentNullException.ThrowIfNull(handler, nameof(handler)); if (string.IsNullOrWhiteSpace(uri)) throw new ArgumentException("Uri cannot be null or white spaces", nameof(uri)); - this.defaultBaseDirectory = defaultBaseDirectory; - Handler = handler; + DefaultBaseDirectory = defaultBaseDirectory; OriginalUri = uri; - UriKind = handler.GetUriKind(uri) & allowedUriKinds; + UriKind = uriKind; // Final check. - if (UriKind == UniversalUriKind.None) + if (UriKind == UUriKind.None) throw new ArgumentException("Invalid uri with allowed uri types", nameof(uri)); } // Properties. - public IHandler Handler { get; } + public string? DefaultBaseDirectory { get; } public string OriginalUri { get; } - public UniversalUriKind UriKind { get; } + public UUriKind UriKind { get; } // Methods. /// @@ -56,40 +48,40 @@ public UniversalUri( /// Optional restrictions for original uri kind /// Optional base directory, required for online relative uri /// Absolute uri and uri kind - public (string, UniversalUriKind) ToAbsoluteUri( - UniversalUriKind allowedUriKinds = UniversalUriKind.All, + public (string, UUriKind) ToAbsoluteUri( + UUriKind allowedUriKinds = UUriKind.All, string? baseDirectory = null) { // Define actual allowed uri kinds. var actualAllowedUriKinds = UriKind & allowedUriKinds; // Check with base directory. - baseDirectory ??= defaultBaseDirectory; - if ((actualAllowedUriKinds & UniversalUriKind.Relative) != 0 && + baseDirectory ??= DefaultBaseDirectory; + if ((actualAllowedUriKinds & UUriKind.Relative) != 0 && baseDirectory is not null) { - var baseDirectoryUriKind = Handler.GetUriKind(baseDirectory) & UniversalUriKind.Absolute; + var baseDirectoryUriKind = GetUriKindHelper(baseDirectory) & UUriKind.Absolute; actualAllowedUriKinds &= baseDirectoryUriKind switch { - UniversalUriKind.LocalAbsolute => UniversalUriKind.Local, - UniversalUriKind.OnlineAbsolute => UniversalUriKind.Online, + UUriKind.LocalAbsolute => UUriKind.Local, + UUriKind.OnlineAbsolute => UUriKind.Online, _ => throw new InvalidOperationException("Base directory can only be absolute"), }; } // Checks. //none allowed uri kinds. - if (actualAllowedUriKinds == UniversalUriKind.None) + if (actualAllowedUriKinds == UUriKind.None) throw new InvalidOperationException("Can't identify a valid uri kind"); //local and online ambiguity - if ((actualAllowedUriKinds & UniversalUriKind.Local) != 0 && - (actualAllowedUriKinds & UniversalUriKind.Online) != 0) + if ((actualAllowedUriKinds & UUriKind.Local) != 0 && + (actualAllowedUriKinds & UUriKind.Online) != 0) throw new InvalidOperationException("Unable to distinguish between local and online uri. Try to restrict allowed uri kinds"); //check if it could be an online relative uri, and base directory is null - if ((actualAllowedUriKinds & UniversalUriKind.OnlineRelative) != 0 && + if ((actualAllowedUriKinds & UUriKind.OnlineRelative) != 0 && baseDirectory is null) throw new InvalidOperationException("Can't resolve online relative uri. Specify a base directory"); @@ -104,24 +96,33 @@ public UniversalUri( * - if uri can be online relative, then it can't be an absoulute or a local relative. * It implies that a base directory must be present, and this implies same previous considerations. */ - return Handler.UriToAbsoluteUri(OriginalUri, baseDirectory, actualAllowedUriKinds); + return UriToAbsoluteUri(OriginalUri, baseDirectory, actualAllowedUriKinds); } - public Task TryGetFileNameAsync() => - Handler.TryGetFileNameAsync(OriginalUri); - /// /// Get parent directory as an absolute uri /// /// Optional restrictions for original uri kind /// Optional base directory, required for online relative uri /// Parent directory absolute uri and its kind - public (string, UniversalUriKind)? TryGetParentDirectoryAsAbsoluteUri( - UniversalUriKind allowedUriKinds = UniversalUriKind.All, + public (string, UUriKind)? TryGetParentDirectoryAsAbsoluteUri( + UUriKind allowedUriKinds = UUriKind.All, string? baseDirectory = null) { var (absoluteUri, absoluteUriKind) = ToAbsoluteUri(allowedUriKinds, baseDirectory); - return Handler.TryGetParentDirectoryAsAbsoluteUri(absoluteUri, absoluteUriKind); + return TryGetParentDirectoryAsAbsoluteUri(absoluteUri, absoluteUriKind); } + + // Protected methods. + protected internal abstract UUriKind GetUriKindHelper(string uri); + + protected internal abstract (string AbsoluteUri, UUriKind UriKind)? TryGetParentDirectoryAsAbsoluteUri( + string absoluteUri, + UUriKind absoluteUriKind); + + protected internal abstract (string AbsoluteUri, UUriKind UriKind) UriToAbsoluteUri( + string originalUri, + string? baseDirectory, + UUriKind uriKind); } } diff --git a/src/UniversalFiles/UniversalUriKind.cs b/src/UniversalFiles/UUriKind.cs similarity index 97% rename from src/UniversalFiles/UniversalUriKind.cs rename to src/UniversalFiles/UUriKind.cs index 127b704..db8ff98 100644 --- a/src/UniversalFiles/UniversalUriKind.cs +++ b/src/UniversalFiles/UUriKind.cs @@ -17,7 +17,7 @@ namespace Etherna.UniversalFiles { [Flags] - public enum UniversalUriKind + public enum UUriKind { None = 0, LocalAbsolute = 1, diff --git a/src/UniversalFiles/UniversalUriProvider.cs b/src/UniversalFiles/UniversalUriProvider.cs deleted file mode 100644 index b940846..0000000 --- a/src/UniversalFiles/UniversalUriProvider.cs +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright 2023-present Etherna SA -// This file is part of UniversalFiles. -// -// UniversalFiles is free software: you can redistribute it and/or modify it under the terms of the -// GNU Lesser General Public License as published by the Free Software Foundation, -// either version 3 of the License, or (at your option) any later version. -// -// UniversalFiles is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; -// without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -// See the GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License along with UniversalFiles. -// If not, see . - -using Etherna.UniversalFiles.Handlers; -using System.Net.Http; - -namespace Etherna.UniversalFiles -{ - public class UniversalUriProvider( - IHttpClientFactory httpClientFactory) - : IUniversalUriProvider - { - // Fields. - private readonly BasicHandler basicHandler = new(httpClientFactory); - - // Methods. - public UniversalUri GetNewUri( - string uri, - UniversalUriKind allowedUriKinds = UniversalUriKind.All, - string? defaultBaseDirectory = null) => - new(uri, basicHandler, allowedUriKinds, defaultBaseDirectory); - } -} \ No newline at end of file diff --git a/test/UniversalFiles.Tests/Handlers/BasicHandlerTest.cs b/test/UniversalFiles.Tests/BasicUUriTest.cs similarity index 50% rename from test/UniversalFiles.Tests/Handlers/BasicHandlerTest.cs rename to test/UniversalFiles.Tests/BasicUUriTest.cs index e33c384..9845036 100644 --- a/test/UniversalFiles.Tests/Handlers/BasicHandlerTest.cs +++ b/test/UniversalFiles.Tests/BasicUUriTest.cs @@ -1,4 +1,4 @@ -// Copyright 2023-present Etherna SA +// Copyright 2023-present Etherna SA // This file is part of UniversalFiles. // // UniversalFiles is free software: you can redistribute it and/or modify it under the terms of the @@ -12,55 +12,50 @@ // You should have received a copy of the GNU Lesser General Public License along with UniversalFiles. // If not, see . -using Moq; using System; using System.Collections.Generic; using System.IO; using System.Linq; -using System.Net.Http; using System.Runtime.InteropServices; using Xunit; -namespace Etherna.UniversalFiles.Handlers +namespace Etherna.UniversalFiles { - public class BasicHandlerTest + public class BasicUUriTest { - // Fields. - private static BasicHandler handler = new(new Mock().Object); - // Classes. public class GetUriKindTestElement( string uri, - UniversalUriKind expectedUriKind) + UUriKind expectedUriKind) { public string Uri { get; } = uri; - public UniversalUriKind ExpectedUriKind { get; } = expectedUriKind; + public UUriKind ExpectedUriKind { get; } = expectedUriKind; } public class TryGetParentDirectoryAsAbsoluteUriTestElement( string absoluteUri, - UniversalUriKind absoluteUriKind, - (string, UniversalUriKind)? expectedResult) + UUriKind absoluteUriKind, + (string, UUriKind)? expectedResult) { public string AbsoluteUri { get; } = absoluteUri; - public UniversalUriKind AbsoluteUriKind { get; } = absoluteUriKind; - public (string, UniversalUriKind)? ExpectedResult { get; } = expectedResult; + public UUriKind AbsoluteUriKind { get; } = absoluteUriKind; + public (string, UUriKind)? ExpectedResult { get; } = expectedResult; } - + public class UriToAbsoluteUriTestElement( string originalUri, string? baseDirectory, - UniversalUriKind uriKind, - (string, UniversalUriKind)? expectedResult = null, + UUriKind uriKind, + (string, UUriKind)? expectedResult = null, Type? expectedExceptionType = null) { public string OriginalUri { get; } = originalUri; public string? BaseDirectory { get; } = baseDirectory; - public UniversalUriKind UriKind { get; } = uriKind; - public (string, UniversalUriKind)? ExpectedResult { get; } = expectedResult; + public UUriKind UriKind { get; } = uriKind; + public (string, UUriKind)? ExpectedResult { get; } = expectedResult; public Type? ExpectedExceptionType { get; } = expectedExceptionType; } - + // Data. public static IEnumerable GetUriKindTests { @@ -69,67 +64,73 @@ public static IEnumerable GetUriKindTests var tests = new List { new("", - UniversalUriKind.None), - + UUriKind.None), + new("test.txt", - UniversalUriKind.Relative), - + UUriKind.Relative), + new("dir/test.txt", - UniversalUriKind.Relative), - + UUriKind.Relative), + new("dir\\test.txt", - UniversalUriKind.Relative), - + UUriKind.Relative), + new("/test.txt", - UniversalUriKind.LocalAbsolute | UniversalUriKind.OnlineRelative), - + UUriKind.LocalAbsolute | UUriKind.OnlineRelative), + new("\\test.txt", - RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? //different behavior on windows host - UniversalUriKind.LocalAbsolute | UniversalUriKind.OnlineRelative : - UniversalUriKind.Relative), - + RuntimeInformation.IsOSPlatform(OSPlatform.Windows) + ? //different behavior on windows host + UUriKind.LocalAbsolute | UUriKind.OnlineRelative + : UUriKind.Relative), + new("C:/dir/", - RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? //different behavior on windows host - UniversalUriKind.LocalAbsolute | UniversalUriKind.OnlineRelative : - UniversalUriKind.Relative), - + RuntimeInformation.IsOSPlatform(OSPlatform.Windows) + ? //different behavior on windows host + UUriKind.LocalAbsolute | UUriKind.OnlineRelative + : UUriKind.Relative), + new("C:\\dir\\", - RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? //different behavior on windows host - UniversalUriKind.LocalAbsolute | UniversalUriKind.OnlineRelative : - UniversalUriKind.Relative), - + RuntimeInformation.IsOSPlatform(OSPlatform.Windows) + ? //different behavior on windows host + UUriKind.LocalAbsolute | UUriKind.OnlineRelative + : UUriKind.Relative), + new("C:\\dir/file.txt", - RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? //different behavior on windows host - UniversalUriKind.LocalAbsolute | UniversalUriKind.OnlineRelative : - UniversalUriKind.Relative), - + RuntimeInformation.IsOSPlatform(OSPlatform.Windows) + ? //different behavior on windows host + UUriKind.LocalAbsolute | UUriKind.OnlineRelative + : UUriKind.Relative), + new("/dir/", - UniversalUriKind.LocalAbsolute | UniversalUriKind.OnlineRelative), - + UUriKind.LocalAbsolute | UUriKind.OnlineRelative), + new("\\dir\\", - RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? //different behavior on windows host - UniversalUriKind.LocalAbsolute | UniversalUriKind.OnlineRelative : - UniversalUriKind.Relative), - + RuntimeInformation.IsOSPlatform(OSPlatform.Windows) + ? //different behavior on windows host + UUriKind.LocalAbsolute | UUriKind.OnlineRelative + : UUriKind.Relative), + new("\\dir/file.txt", - RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? //different behavior on windows host - UniversalUriKind.LocalAbsolute | UniversalUriKind.OnlineRelative : - UniversalUriKind.Relative), - + RuntimeInformation.IsOSPlatform(OSPlatform.Windows) + ? //different behavior on windows host + UUriKind.LocalAbsolute | UUriKind.OnlineRelative + : UUriKind.Relative), + new("https://example.com", - UniversalUriKind.OnlineAbsolute), - + UUriKind.OnlineAbsolute), + new("https://example.com/dir/", - UniversalUriKind.OnlineAbsolute), - + UUriKind.OnlineAbsolute), + new("http://example.com/dir/file.txt", - UniversalUriKind.OnlineAbsolute), + UUriKind.OnlineAbsolute), }; - + return tests.Select(t => new object[] { t }); } } - + public static IEnumerable TryGetParentDirectoryAsAbsoluteUriTests { get @@ -138,44 +139,45 @@ public static IEnumerable TryGetParentDirectoryAsAbsoluteUriTests { //local without parent new("/", - UniversalUriKind.LocalAbsolute, - ((string, UniversalUriKind)?)null), - + UUriKind.LocalAbsolute, + null), + //local with parent new("/parent/test", - UniversalUriKind.LocalAbsolute, - (RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? //different behavior on windows host - "\\parent" : - "/parent", - UniversalUriKind.LocalAbsolute)), - + UUriKind.LocalAbsolute, + (RuntimeInformation.IsOSPlatform(OSPlatform.Windows) + ? //different behavior on windows host + "\\parent" + : "/parent", + UUriKind.LocalAbsolute)), + //online without parent new("https://example.com", - UniversalUriKind.OnlineAbsolute, - ((string, UniversalUriKind)?)null), - + UUriKind.OnlineAbsolute, + null), + new("https://example.com/", - UniversalUriKind.OnlineAbsolute, - ((string, UniversalUriKind)?)null), - + UUriKind.OnlineAbsolute, + null), + //online with parent new("https://example.com/test", - UniversalUriKind.OnlineAbsolute, - ("https://example.com/", UniversalUriKind.OnlineAbsolute)), - + UUriKind.OnlineAbsolute, + ("https://example.com/", UUriKind.OnlineAbsolute)), + new("https://example.com/test/", - UniversalUriKind.OnlineAbsolute, - ("https://example.com/", UniversalUriKind.OnlineAbsolute)), - + UUriKind.OnlineAbsolute, + ("https://example.com/", UUriKind.OnlineAbsolute)), + new("https://example.com/parent/test", - UniversalUriKind.OnlineAbsolute, - ("https://example.com/parent/", UniversalUriKind.OnlineAbsolute)), + UUriKind.OnlineAbsolute, + ("https://example.com/parent/", UUriKind.OnlineAbsolute)), }; - + return tests.Select(t => new object[] { t }); } } - + public static IEnumerable UriToAbsoluteUriTests { get @@ -185,178 +187,218 @@ public static IEnumerable UriToAbsoluteUriTests //local absolute unix-like, no base directory new("/test", null, - UniversalUriKind.LocalAbsolute, - (RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? //different behavior on windows host - Path.Combine(Path.GetPathRoot(Directory.GetCurrentDirectory())!, "test") : //ex: "C:\\test" - "/test", - UniversalUriKind.LocalAbsolute)), - + UUriKind.LocalAbsolute, + (RuntimeInformation.IsOSPlatform(OSPlatform.Windows) + ? //different behavior on windows host + Path.Combine(Path.GetPathRoot(Directory.GetCurrentDirectory())!, "test") + : //ex: "C:\\test" + "/test", + UUriKind.LocalAbsolute)), + //local absolute windows-like, no base directory new("D:\\test", null, - RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? - UniversalUriKind.LocalAbsolute : - UniversalUriKind.LocalRelative, - (RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? //different behavior on windows host - "D:\\test" : - Path.Combine(Directory.GetCurrentDirectory(), "D:\\test"), - UniversalUriKind.LocalAbsolute)), - + RuntimeInformation.IsOSPlatform(OSPlatform.Windows) + ? UUriKind.LocalAbsolute + : UUriKind.LocalRelative, + (RuntimeInformation.IsOSPlatform(OSPlatform.Windows) + ? //different behavior on windows host + "D:\\test" + : Path.Combine(Directory.GetCurrentDirectory(), "D:\\test"), + UUriKind.LocalAbsolute)), + //local absolute unix-like, with local base directory unix-like new("/test", "/absolute/local", - UniversalUriKind.LocalAbsolute, - (RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? //different behavior on windows host - Path.Combine(Path.GetPathRoot(Directory.GetCurrentDirectory())!, "test") : //ex: "C:\\test" - "/test", UniversalUriKind.LocalAbsolute)), - + UUriKind.LocalAbsolute, + (RuntimeInformation.IsOSPlatform(OSPlatform.Windows) + ? //different behavior on windows host + Path.Combine(Path.GetPathRoot(Directory.GetCurrentDirectory())!, "test") + : //ex: "C:\\test" + "/test", UUriKind.LocalAbsolute)), + //local absolute windows-like, with local base directory unix-like new("D:\\test", "/absolute/local", - RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? - UniversalUriKind.LocalAbsolute : - UniversalUriKind.LocalRelative, - (RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? //different behavior on windows host - "D:\\test" : - "/absolute/local/D:\\test", - UniversalUriKind.LocalAbsolute)), - + RuntimeInformation.IsOSPlatform(OSPlatform.Windows) + ? UUriKind.LocalAbsolute + : UUriKind.LocalRelative, + (RuntimeInformation.IsOSPlatform(OSPlatform.Windows) + ? //different behavior on windows host + "D:\\test" + : "/absolute/local/D:\\test", + UUriKind.LocalAbsolute)), + //local absolute unix-like, with local base directory windows-like new("/test", "E:\\absolute\\local", - UniversalUriKind.LocalAbsolute, - expectedResult: RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? //different behavior on windows host - ("E:\\test", UniversalUriKind.LocalAbsolute) : - ("/test", UniversalUriKind.LocalAbsolute)), - + UUriKind.LocalAbsolute, + expectedResult: RuntimeInformation.IsOSPlatform(OSPlatform.Windows) + ? //different behavior on windows host + ("E:\\test", UUriKind.LocalAbsolute) + : ("/test", UUriKind.LocalAbsolute)), + //local absolute windows-like, with local base directory windows-like new("D:\\test", "E:\\absolute\\local", - RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? - UniversalUriKind.LocalAbsolute : - UniversalUriKind.LocalRelative, - expectedResult: RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? //different behavior on windows host - ("D:\\test", UniversalUriKind.LocalAbsolute) : - null, - expectedExceptionType: RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? //different behavior on windows host - null : - typeof(InvalidOperationException)), //throws exception because base directory is not absolute - + RuntimeInformation.IsOSPlatform(OSPlatform.Windows) + ? UUriKind.LocalAbsolute + : UUriKind.LocalRelative, + expectedResult: RuntimeInformation.IsOSPlatform(OSPlatform.Windows) + ? //different behavior on windows host + ("D:\\test", UUriKind.LocalAbsolute) + : null, + expectedExceptionType: RuntimeInformation.IsOSPlatform(OSPlatform.Windows) + ? //different behavior on windows host + null + : typeof(InvalidOperationException)), //throws exception because base directory is not absolute + //rooted online relative, with online base directory new("/test", "https://example.com/dir/", - UniversalUriKind.OnlineRelative, - ("https://example.com/test", UniversalUriKind.OnlineAbsolute)), - + UUriKind.OnlineRelative, + ("https://example.com/test", UUriKind.OnlineAbsolute)), + //not rooted online relative, with online base directory new("my/test", "https://example.com/dir/", - UniversalUriKind.OnlineRelative, - ("https://example.com/dir/my/test", UniversalUriKind.OnlineAbsolute)), - + UUriKind.OnlineRelative, + ("https://example.com/dir/my/test", UUriKind.OnlineAbsolute)), + //local relative (or online relative) with local restriction new("test", null, - UniversalUriKind.LocalRelative, - (Path.Combine(Directory.GetCurrentDirectory(), "test"), UniversalUriKind.LocalAbsolute)), - + UUriKind.LocalRelative, + (Path.Combine(Directory.GetCurrentDirectory(), "test"), UUriKind.LocalAbsolute)), + //local relative (or online relative), with local base directory unix-like new("test", "/absolute/local", - UniversalUriKind.LocalRelative, - (RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? //different behavior on windows host - Path.Combine(Path.GetPathRoot(Directory.GetCurrentDirectory())!, "absolute\\local\\test") : - "/absolute/local/test", UniversalUriKind.LocalAbsolute)), - + UUriKind.LocalRelative, + (RuntimeInformation.IsOSPlatform(OSPlatform.Windows) + ? //different behavior on windows host + Path.Combine(Path.GetPathRoot(Directory.GetCurrentDirectory())!, "absolute\\local\\test") + : "/absolute/local/test", UUriKind.LocalAbsolute)), + //local relative (or online relative), with local base directory windows-like new("test", "D:\\absolute\\local", - UniversalUriKind.LocalRelative, - expectedResult: RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? //different behavior on windows host - ("D:\\absolute\\local\\test", UniversalUriKind.LocalAbsolute) : - null, - expectedExceptionType: RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? //different behavior on windows host - null : - typeof(InvalidOperationException)), //throws exception because is ambiguous, and anyway base directory is not absolute + UUriKind.LocalRelative, + expectedResult: RuntimeInformation.IsOSPlatform(OSPlatform.Windows) + ? //different behavior on windows host + ("D:\\absolute\\local\\test", UUriKind.LocalAbsolute) + : null, + expectedExceptionType: RuntimeInformation.IsOSPlatform(OSPlatform.Windows) + ? //different behavior on windows host + null + : typeof(InvalidOperationException)), //throws exception because is ambiguous, and anyway base directory is not absolute //local relative (or online relative) with online base directory new("test", "https://example.com/dir/", - UniversalUriKind.OnlineRelative, - ("https://example.com/dir/test", UniversalUriKind.OnlineAbsolute)), - + UUriKind.OnlineRelative, + ("https://example.com/dir/test", UUriKind.OnlineAbsolute)), + //online absolute without restrictions new("https://example.com/", null, - UniversalUriKind.OnlineAbsolute, - ("https://example.com/", UniversalUriKind.OnlineAbsolute)), - + UUriKind.OnlineAbsolute, + ("https://example.com/", UUriKind.OnlineAbsolute)), + //online absolute, with local base directory unix-like new("https://example.com/", "/absolute/local", - UniversalUriKind.OnlineAbsolute, - ("https://example.com/", UniversalUriKind.OnlineAbsolute)), - + UUriKind.OnlineAbsolute, + ("https://example.com/", UUriKind.OnlineAbsolute)), + //online absolute, with local base directory windows-like new("https://example.com/", "C:\\absolute\\local", - UniversalUriKind.OnlineAbsolute, - ("https://example.com/", UniversalUriKind.OnlineAbsolute)), - + UUriKind.OnlineAbsolute, + ("https://example.com/", UUriKind.OnlineAbsolute)), + //online absolute with online base directory new("https://example.com/", "https://other-site.com/", - UniversalUriKind.OnlineAbsolute, - ("https://example.com/", UniversalUriKind.OnlineAbsolute)), - + UUriKind.OnlineAbsolute, + ("https://example.com/", UUriKind.OnlineAbsolute)), + //online absolute with relative base directory new("https://example.com/", "not/absolute", - UniversalUriKind.All, + UUriKind.All, expectedExceptionType: typeof(InvalidOperationException)), }; - + return tests.Select(t => new object[] { t }); } } - + // Tests. + [Theory] + [InlineData("relativeUri", UUriKind.All, "relativeUri", UUriKind.Relative, null)] + [InlineData("relativeUri", UUriKind.Local, "relativeUri", UUriKind.LocalRelative, null)] + [InlineData("http://test.com", UUriKind.All, "http://test.com", UUriKind.OnlineAbsolute, null)] + [InlineData("relativeUri", UUriKind.Absolute, null, null, typeof(ArgumentException))] //no valid uri kind found + public void ConstructorEvaluateUriKind( + string uri, + UUriKind allowedUriKinds, + string? expectedOriginalUri, + UUriKind? expectedUriKind, + Type? expectedExceptionType) + { + if (expectedExceptionType is null) + { + var universalUri = new BasicUUri(uri, allowedUriKinds); + + Assert.Equal(expectedOriginalUri, universalUri.OriginalUri); + Assert.Equal(expectedUriKind, universalUri.UriKind); + } + else + { + Assert.Throws(expectedExceptionType, + () => new BasicUUri(uri, allowedUriKinds)); + } + } + [Theory, MemberData(nameof(GetUriKindTests))] public void GetUriKind(GetUriKindTestElement test) { - var result = handler.GetUriKind(test.Uri); - + var result = BasicUUri.GetUriKind(test.Uri); + Assert.Equal(test.ExpectedUriKind, result); } - + [Theory, MemberData(nameof(TryGetParentDirectoryAsAbsoluteUriTests))] public void TryGetParentDirectoryAsAbsoluteUri(TryGetParentDirectoryAsAbsoluteUriTestElement test) { - var result = handler.TryGetParentDirectoryAsAbsoluteUri(test.AbsoluteUri, test.AbsoluteUriKind); - + var basicUUri = new BasicUUri("test"); + var result = basicUUri.TryGetParentDirectoryAsAbsoluteUri(test.AbsoluteUri, test.AbsoluteUriKind); + Assert.Equal(test.ExpectedResult, result); } - + [Theory, MemberData(nameof(UriToAbsoluteUriTests))] public void UriToAbsoluteUri(UriToAbsoluteUriTestElement test) { + var basicUUri = new BasicUUri("test"); if (test.ExpectedExceptionType is null) { - var result = handler.UriToAbsoluteUri( + var result = basicUUri.UriToAbsoluteUri( test.OriginalUri, test.BaseDirectory, test.UriKind); - + Assert.Equal(test.ExpectedResult, result); } else { Assert.Throws(test.ExpectedExceptionType, - () => handler.UriToAbsoluteUri( + () => basicUUri.UriToAbsoluteUri( test.OriginalUri, test.BaseDirectory, test.UriKind)); } } } -} \ No newline at end of file +} diff --git a/test/UniversalFiles.Tests/UniversalUriTest.cs b/test/UniversalFiles.Tests/UUriTest.cs similarity index 58% rename from test/UniversalFiles.Tests/UniversalUriTest.cs rename to test/UniversalFiles.Tests/UUriTest.cs index 6b5ce80..9f18352 100644 --- a/test/UniversalFiles.Tests/UniversalUriTest.cs +++ b/test/UniversalFiles.Tests/UUriTest.cs @@ -12,16 +12,16 @@ // You should have received a copy of the GNU Lesser General Public License along with UniversalFiles. // If not, see . -using Etherna.UniversalFiles.Handlers; using Moq; using System; using System.Collections.Generic; using System.Linq; +using System.Reflection; using Xunit; namespace Etherna.UniversalFiles { - public class UniversalUriTest + public class UUriTest { // Consts. private const string LocalAbsOrOnlineRelUri = "LocalAbsOrOnlineRelUri"; @@ -34,122 +34,116 @@ public class UniversalUriTest public class ToAbsoluteUriTestElement { // Fields. - private readonly Action>? assertHandlerMock; - + private readonly Action>? assertUUriMock; + private readonly Mock uuriMock; + // Constructor. public ToAbsoluteUriTestElement( string uri, - UniversalUriKind allowedUriKinds, + UUriKind uuriKind, string? baseDirectory, - Action>? assertHandlerMock = null, + Action>? assertUUriMock = null, Type? expectedExceptionType = null) { - // Setup handler mock. - HandlerMock = new Mock(); - HandlerMock.Setup(h => h.GetUriKind(LocalAbsOrOnlineRelUri)) - .Returns(() => UniversalUriKind.LocalAbsolute | UniversalUriKind.OnlineRelative); - HandlerMock.Setup(h => h.GetUriKind(LocalAbsUri)) - .Returns(() => UniversalUriKind.LocalAbsolute); - HandlerMock.Setup(h => h.GetUriKind(OnlineAbsUri)) - .Returns(() => UniversalUriKind.OnlineAbsolute); - HandlerMock.Setup(h => h.GetUriKind(OnlineAbsUri2)) - .Returns(() => UniversalUriKind.OnlineAbsolute); - HandlerMock.Setup(h => h.GetUriKind(RelativeUri)) - .Returns(() => UniversalUriKind.Relative); - // Set properties. - this.assertHandlerMock = assertHandlerMock; - UniversalUri = new UniversalUri(uri, HandlerMock.Object); - AllowedUriKinds = allowedUriKinds; + this.assertUUriMock = assertUUriMock; BaseDirectory = baseDirectory; ExpectedExceptionType = expectedExceptionType; + UuriKind = uuriKind; + uuriMock = new Mock( + uri, + UUriToUUriKind(uri), + null!); + + // Setup uuri mock. + uuriMock.Setup(u => u.GetUriKindHelper(It.IsAny())) + .Returns(UUriToUUriKind); } - + // Properties. - public UniversalUri UniversalUri { get; } - public UniversalUriKind AllowedUriKinds { get; } + public UUriKind UuriKind { get; } public string? BaseDirectory { get; } - public Mock HandlerMock { get; } public Type? ExpectedExceptionType { get; } + public UUri UUri => uuriMock.Object; // Methods. public void Assert() => - assertHandlerMock?.Invoke(HandlerMock); + assertUUriMock?.Invoke(uuriMock); } - - public class ToAbsoluteUriUsesBaseDirectoryTestElement + + public class ToAbsoluteUriUsesAllowedUriKindsTestElement { // Fields. - private readonly Action>? assertHandlerMock; - + private readonly Action>? assertUUriMock; + private readonly Mock uuriMock; + // Constructor. - public ToAbsoluteUriUsesBaseDirectoryTestElement( + public ToAbsoluteUriUsesAllowedUriKindsTestElement( string uri, - string? defaultBaseDirectory, - string? argBaseDirectory, - Action>? assertHandlerMock = null, + UUriKind uriKind, + UUriKind argAllowedUriKinds, + Action>? assertUUriMock = null, Type? expectedExceptionType = null) { - // Setup handler mock. - HandlerMock = new Mock(); - HandlerMock.Setup(h => h.GetUriKind(OnlineAbsUri)) - .Returns(() => UniversalUriKind.OnlineAbsolute); - HandlerMock.Setup(h => h.GetUriKind(OnlineAbsUri2)) - .Returns(() => UniversalUriKind.OnlineAbsolute); - HandlerMock.Setup(h => h.GetUriKind(RelativeUri)) - .Returns(() => UniversalUriKind.Relative); - // Set properties. - this.assertHandlerMock = assertHandlerMock; - UniversalUri = new UniversalUri(uri, HandlerMock.Object, defaultBaseDirectory: defaultBaseDirectory); - ArgBaseDirectory = argBaseDirectory; + this.assertUUriMock = assertUUriMock; + ArgAllowedUriKinds = argAllowedUriKinds; ExpectedExceptionType = expectedExceptionType; + uuriMock = new Mock( + uri, + uriKind, + null!); + + // Setup uuri mock. + uuriMock.Setup(u => u.GetUriKindHelper(It.IsAny())) + .Returns(UUriToUUriKind); } - - // Properties. - public UniversalUri UniversalUri { get; } - public string? ArgBaseDirectory { get; } + + public UUriKind ArgAllowedUriKinds { get; } public Type? ExpectedExceptionType { get; } - public Mock HandlerMock { get; } + public UUri UUri => uuriMock.Object; // Methods. public void Assert() => - assertHandlerMock?.Invoke(HandlerMock); + assertUUriMock?.Invoke(uuriMock); } - - public class ToAbsoluteUriUsesAllowedUriKindsTestElement + + public class ToAbsoluteUriUsesBaseDirectoryTestElement { // Fields. - private readonly Action>? assertHandlerMock; - + private readonly Action>? assertUUriMock; + private readonly Mock uuriMock; + // Constructor. - public ToAbsoluteUriUsesAllowedUriKindsTestElement( + public ToAbsoluteUriUsesBaseDirectoryTestElement( string uri, - UniversalUriKind allowedUriKinds, - UniversalUriKind argAllowedUriKinds, - Action>? assertHandlerMock = null, + string? defaultBaseDirectory, + string? argBaseDirectory, + Action>? assertUUriMock = null, Type? expectedExceptionType = null) { - // Setup handler mock. - HandlerMock = new Mock(); - HandlerMock.Setup(h => h.GetUriKind(RelativeUri)) - .Returns(() => UniversalUriKind.Relative); - // Set properties. - this.assertHandlerMock = assertHandlerMock; - UniversalUri = new UniversalUri(uri, HandlerMock.Object, allowedUriKinds); - ArgAllowedUriKinds = argAllowedUriKinds; + this.assertUUriMock = assertUUriMock; + ArgBaseDirectory = argBaseDirectory; ExpectedExceptionType = expectedExceptionType; + uuriMock = new Mock( + uri, + UUriToUUriKind(uri), + defaultBaseDirectory!); + + // Setup uuri mock. + uuriMock.Setup(u => u.GetUriKindHelper(It.IsAny())) + .Returns(UUriToUUriKind); } - - public UniversalUri UniversalUri { get; } - public UniversalUriKind ArgAllowedUriKinds { get; } + + // Properties. + public string? ArgBaseDirectory { get; } public Type? ExpectedExceptionType { get; } - public Mock HandlerMock { get; } + public UUri UUri => uuriMock.Object; // Methods. public void Assert() => - assertHandlerMock?.Invoke(HandlerMock); + assertUUriMock?.Invoke(uuriMock); } // Data. @@ -161,361 +155,361 @@ public static IEnumerable ToAbsoluteUriTests { //local absolute (or online relative), without restrictions. Throws exception because is ambiguous new(LocalAbsOrOnlineRelUri, - UniversalUriKind.All, + UUriKind.All, null, expectedExceptionType: typeof(InvalidOperationException)), //local absolute (or online relative), with local restriction new(LocalAbsOrOnlineRelUri, - UniversalUriKind.Local, + UUriKind.Local, null, - assertHandlerMock: mock => mock.Verify(h => h.UriToAbsoluteUri( - LocalAbsOrOnlineRelUri, null, UniversalUriKind.LocalAbsolute), Times.Once)), + assertUUriMock: mock => mock.Verify(h => h.UriToAbsoluteUri( + LocalAbsOrOnlineRelUri, null, UUriKind.LocalAbsolute), Times.Once)), //local absolute (or online relative), with online restriction. Throws exception because base directory is null new(LocalAbsOrOnlineRelUri, - UniversalUriKind.Online, + UUriKind.Online, null, expectedExceptionType: typeof(InvalidOperationException)), //local absolute (or online relative), with directory, without restrictions. Throws exception because is ambiguous new(LocalAbsOrOnlineRelUri, - UniversalUriKind.All, + UUriKind.All, LocalAbsOrOnlineRelUri, - assertHandlerMock: mock => mock.Verify(h => h.UriToAbsoluteUri( - LocalAbsOrOnlineRelUri, LocalAbsOrOnlineRelUri, UniversalUriKind.LocalAbsolute), Times.Once)), + assertUUriMock: mock => mock.Verify(h => h.UriToAbsoluteUri( + LocalAbsOrOnlineRelUri, LocalAbsOrOnlineRelUri, UUriKind.LocalAbsolute), Times.Once)), //local absolute (or online relative), with directory, with local restriction new(LocalAbsOrOnlineRelUri, - UniversalUriKind.Local, + UUriKind.Local, LocalAbsOrOnlineRelUri, - assertHandlerMock: mock => mock.Verify(h => h.UriToAbsoluteUri( - LocalAbsOrOnlineRelUri, LocalAbsOrOnlineRelUri, UniversalUriKind.LocalAbsolute), Times.Once)), + assertUUriMock: mock => mock.Verify(h => h.UriToAbsoluteUri( + LocalAbsOrOnlineRelUri, LocalAbsOrOnlineRelUri, UUriKind.LocalAbsolute), Times.Once)), //local absolute (or online relative), with directory, with online restriction. Throws exception because can't find a valid uri kind new(LocalAbsOrOnlineRelUri, - UniversalUriKind.Online, + UUriKind.Online, LocalAbsOrOnlineRelUri, expectedExceptionType: typeof(InvalidOperationException)), //local absolute (or online relative), with local base directory, without restrictions new(LocalAbsOrOnlineRelUri, - UniversalUriKind.All, + UUriKind.All, LocalAbsUri, - assertHandlerMock: mock => mock.Verify(h => h.UriToAbsoluteUri( - LocalAbsOrOnlineRelUri, LocalAbsUri, UniversalUriKind.LocalAbsolute), Times.Once)), + assertUUriMock: mock => mock.Verify(h => h.UriToAbsoluteUri( + LocalAbsOrOnlineRelUri, LocalAbsUri, UUriKind.LocalAbsolute), Times.Once)), //local absolute (or online relative), with local base directory, with local restriction new(LocalAbsOrOnlineRelUri, - UniversalUriKind.Local, + UUriKind.Local, LocalAbsUri, - assertHandlerMock: mock => mock.Verify(h => h.UriToAbsoluteUri( - LocalAbsOrOnlineRelUri, LocalAbsUri, UniversalUriKind.LocalAbsolute), Times.Once)), + assertUUriMock: mock => mock.Verify(h => h.UriToAbsoluteUri( + LocalAbsOrOnlineRelUri, LocalAbsUri, UUriKind.LocalAbsolute), Times.Once)), //local absolute (or online relative), with local base directory, with online restriction new(LocalAbsOrOnlineRelUri, - UniversalUriKind.Online, + UUriKind.Online, LocalAbsUri, expectedExceptionType: typeof(InvalidOperationException)), //local absolute (or online relative), with online base directory, without restrictions new(LocalAbsOrOnlineRelUri, - UniversalUriKind.All, + UUriKind.All, OnlineAbsUri, - assertHandlerMock: mock => mock.Verify(h => h.UriToAbsoluteUri( - LocalAbsOrOnlineRelUri, OnlineAbsUri, UniversalUriKind.OnlineRelative), Times.Once)), + assertUUriMock: mock => mock.Verify(h => h.UriToAbsoluteUri( + LocalAbsOrOnlineRelUri, OnlineAbsUri, UUriKind.OnlineRelative), Times.Once)), //local absolute (or online relative), with online base directory, with local restriction new(LocalAbsOrOnlineRelUri, - UniversalUriKind.Local, + UUriKind.Local, OnlineAbsUri, - assertHandlerMock: mock => mock.Verify(h => h.UriToAbsoluteUri( - LocalAbsOrOnlineRelUri, OnlineAbsUri, UniversalUriKind.LocalAbsolute), Times.Once)), + assertUUriMock: mock => mock.Verify(h => h.UriToAbsoluteUri( + LocalAbsOrOnlineRelUri, OnlineAbsUri, UUriKind.LocalAbsolute), Times.Once)), //local absolute (or online relative), with online base directory, with online restriction new(LocalAbsOrOnlineRelUri, - UniversalUriKind.Online, + UUriKind.Online, OnlineAbsUri, - assertHandlerMock: mock => mock.Verify(h => h.UriToAbsoluteUri( - LocalAbsOrOnlineRelUri, OnlineAbsUri, UniversalUriKind.OnlineRelative), Times.Once)), + assertUUriMock: mock => mock.Verify(h => h.UriToAbsoluteUri( + LocalAbsOrOnlineRelUri, OnlineAbsUri, UUriKind.OnlineRelative), Times.Once)), //local absolute (or online relative), with relative base directory. Throws exception because is ambiguous and base directory is not absolute new(LocalAbsOrOnlineRelUri, - UniversalUriKind.All, + UUriKind.All, RelativeUri, expectedExceptionType: typeof(InvalidOperationException)), //local absolute (or online relative), with relative base directory. Throws exception because is ambiguous and base directory is not absolute new(LocalAbsOrOnlineRelUri, - UniversalUriKind.Local, + UUriKind.Local, RelativeUri, - assertHandlerMock: mock => mock.Verify(h => h.UriToAbsoluteUri( - LocalAbsOrOnlineRelUri, RelativeUri, UniversalUriKind.LocalAbsolute), Times.Once)), + assertUUriMock: mock => mock.Verify(h => h.UriToAbsoluteUri( + LocalAbsOrOnlineRelUri, RelativeUri, UUriKind.LocalAbsolute), Times.Once)), //local absolute (or online relative), with relative base directory. Throws exception because is ambiguous and base directory is not absolute new(LocalAbsOrOnlineRelUri, - UniversalUriKind.Online, + UUriKind.Online, RelativeUri, expectedExceptionType: typeof(InvalidOperationException)), //local relative (or online relative) without restrictions. Throws exception because is ambiguous new(RelativeUri, - UniversalUriKind.All, + UUriKind.All, null, expectedExceptionType: typeof(InvalidOperationException)), //local relative (or online relative), with local restriction new(RelativeUri, - UniversalUriKind.Local, + UUriKind.Local, null, - assertHandlerMock: mock => mock.Verify(h => h.UriToAbsoluteUri( - RelativeUri, null, UniversalUriKind.LocalRelative), Times.Once)), + assertUUriMock: mock => mock.Verify(h => h.UriToAbsoluteUri( + RelativeUri, null, UUriKind.LocalRelative), Times.Once)), //local relative (or online relative), with online restriction. Throws exception because base directory is null new(RelativeUri, - UniversalUriKind.Online, + UUriKind.Online, null, expectedExceptionType: typeof(InvalidOperationException)), //local relative (or online relative) with local base directory new(RelativeUri, - UniversalUriKind.All, + UUriKind.All, LocalAbsOrOnlineRelUri, - assertHandlerMock: mock => mock.Verify(h => h.UriToAbsoluteUri( - RelativeUri, LocalAbsOrOnlineRelUri, UniversalUriKind.LocalRelative), Times.Once)), + assertUUriMock: mock => mock.Verify(h => h.UriToAbsoluteUri( + RelativeUri, LocalAbsOrOnlineRelUri, UUriKind.LocalRelative), Times.Once)), //local relative (or online relative), with local base directory, with local restriction new(RelativeUri, - UniversalUriKind.Local, + UUriKind.Local, LocalAbsOrOnlineRelUri, - assertHandlerMock: mock => mock.Verify(h => h.UriToAbsoluteUri( - RelativeUri, LocalAbsOrOnlineRelUri, UniversalUriKind.LocalRelative), Times.Once)), + assertUUriMock: mock => mock.Verify(h => h.UriToAbsoluteUri( + RelativeUri, LocalAbsOrOnlineRelUri, UUriKind.LocalRelative), Times.Once)), //local relative (or online relative), with local base directory, with online restriction. Throws exception because can't identify valid uri kind new(RelativeUri, - UniversalUriKind.Online, + UUriKind.Online, LocalAbsOrOnlineRelUri, expectedExceptionType: typeof(InvalidOperationException)), //local relative (or online relative), with online base directory new(RelativeUri, - UniversalUriKind.All, + UUriKind.All, OnlineAbsUri, - assertHandlerMock: mock => mock.Verify(h => h.UriToAbsoluteUri( - RelativeUri, OnlineAbsUri, UniversalUriKind.OnlineRelative), Times.Once)), + assertUUriMock: mock => mock.Verify(h => h.UriToAbsoluteUri( + RelativeUri, OnlineAbsUri, UUriKind.OnlineRelative), Times.Once)), //local relative (or online relative), with online base directory, with local restriction. Throws exception because can't identify valid uri kind new(RelativeUri, - UniversalUriKind.Local, + UUriKind.Local, OnlineAbsUri, expectedExceptionType: typeof(InvalidOperationException)), //local relative (or online relative), with online base directory, with online restriction new(RelativeUri, - UniversalUriKind.Online, + UUriKind.Online, OnlineAbsUri, - assertHandlerMock: mock => mock.Verify(h => h.UriToAbsoluteUri( - RelativeUri, OnlineAbsUri, UniversalUriKind.OnlineRelative), Times.Once)), + assertUUriMock: mock => mock.Verify(h => h.UriToAbsoluteUri( + RelativeUri, OnlineAbsUri, UUriKind.OnlineRelative), Times.Once)), //local relative (or online relative), with local base directory new(RelativeUri, - UniversalUriKind.All, + UUriKind.All, LocalAbsUri, - assertHandlerMock: mock => mock.Verify(h => h.UriToAbsoluteUri( - RelativeUri, LocalAbsUri, UniversalUriKind.LocalRelative), Times.Once)), + assertUUriMock: mock => mock.Verify(h => h.UriToAbsoluteUri( + RelativeUri, LocalAbsUri, UUriKind.LocalRelative), Times.Once)), //local relative (or online relative), with local base directory, with local restriction new(RelativeUri, - UniversalUriKind.Local, + UUriKind.Local, LocalAbsUri, - assertHandlerMock: mock => mock.Verify(h => h.UriToAbsoluteUri( - RelativeUri, LocalAbsUri, UniversalUriKind.LocalRelative), Times.Once)), + assertUUriMock: mock => mock.Verify(h => h.UriToAbsoluteUri( + RelativeUri, LocalAbsUri, UUriKind.LocalRelative), Times.Once)), //local relative (or online relative), with local base directory, with online restriction. Throws exception because can't identify valid uri kind new(RelativeUri, - UniversalUriKind.Online, + UUriKind.Online, LocalAbsUri, expectedExceptionType: typeof(InvalidOperationException)), //local relative (or online relative), with relative base directory. Throws exception because is ambiguous and base directory is not absolute new(RelativeUri, - UniversalUriKind.All, + UUriKind.All, RelativeUri, expectedExceptionType: typeof(InvalidOperationException)), //local relative (or online relative), with relative base directory, with local restriction. Throws exception because is ambiguous and base directory is not absolute new(RelativeUri, - UniversalUriKind.Local, + UUriKind.Local, RelativeUri, expectedExceptionType: typeof(InvalidOperationException)), //local relative (or online relative), with relative base directory, with online restriction. Throws exception because is ambiguous and base directory is not absolute new(RelativeUri, - UniversalUriKind.Online, + UUriKind.Online, RelativeUri, expectedExceptionType: typeof(InvalidOperationException)), //local absolute, with local base directory, without restrictions new(LocalAbsUri, - UniversalUriKind.All, + UUriKind.All, LocalAbsUri, - assertHandlerMock: mock => mock.Verify(h => h.UriToAbsoluteUri( - LocalAbsUri, LocalAbsUri, UniversalUriKind.LocalAbsolute), Times.Once)), + assertUUriMock: mock => mock.Verify(h => h.UriToAbsoluteUri( + LocalAbsUri, LocalAbsUri, UUriKind.LocalAbsolute), Times.Once)), //local absolute, with local base directory, with local restriction new(LocalAbsUri, - UniversalUriKind.Local, + UUriKind.Local, LocalAbsUri, - assertHandlerMock: mock => mock.Verify(h => h.UriToAbsoluteUri( - LocalAbsUri, LocalAbsUri, UniversalUriKind.LocalAbsolute), Times.Once)), + assertUUriMock: mock => mock.Verify(h => h.UriToAbsoluteUri( + LocalAbsUri, LocalAbsUri, UUriKind.LocalAbsolute), Times.Once)), //local absolute, with local base directory, with online restriction new(LocalAbsUri, - UniversalUriKind.Online, + UUriKind.Online, LocalAbsUri, expectedExceptionType: typeof(InvalidOperationException)), //online absolute without restrictions new(OnlineAbsUri, - UniversalUriKind.All, + UUriKind.All, null, - assertHandlerMock: mock => mock.Verify(h => h.UriToAbsoluteUri( - OnlineAbsUri, null, UniversalUriKind.OnlineAbsolute), Times.Once)), + assertUUriMock: mock => mock.Verify(h => h.UriToAbsoluteUri( + OnlineAbsUri, null, UUriKind.OnlineAbsolute), Times.Once)), //online absolute with local restriction. Throws exception because can't find valid uri kind new(OnlineAbsUri, - UniversalUriKind.Local, + UUriKind.Local, null, expectedExceptionType: typeof(InvalidOperationException)), //online absolute with online restriction new(OnlineAbsUri, - UniversalUriKind.Online, + UUriKind.Online, null, - assertHandlerMock: mock => mock.Verify(h => h.UriToAbsoluteUri( - OnlineAbsUri, null, UniversalUriKind.OnlineAbsolute), Times.Once)), + assertUUriMock: mock => mock.Verify(h => h.UriToAbsoluteUri( + OnlineAbsUri, null, UUriKind.OnlineAbsolute), Times.Once)), //online absolute with local base directory new(OnlineAbsUri, - UniversalUriKind.All, + UUriKind.All, LocalAbsOrOnlineRelUri, - assertHandlerMock: mock => mock.Verify(h => h.UriToAbsoluteUri( - OnlineAbsUri, LocalAbsOrOnlineRelUri, UniversalUriKind.OnlineAbsolute), Times.Once)), + assertUUriMock: mock => mock.Verify(h => h.UriToAbsoluteUri( + OnlineAbsUri, LocalAbsOrOnlineRelUri, UUriKind.OnlineAbsolute), Times.Once)), //online absolute with local base directory, with local restriction. Throws exception because can't find valid uri kind new(OnlineAbsUri, - UniversalUriKind.Local, + UUriKind.Local, LocalAbsOrOnlineRelUri, expectedExceptionType: typeof(InvalidOperationException)), //online absolute with local base directory, with online restriction new(OnlineAbsUri, - UniversalUriKind.Online, + UUriKind.Online, LocalAbsOrOnlineRelUri, - assertHandlerMock: mock => mock.Verify(h => h.UriToAbsoluteUri( - OnlineAbsUri, LocalAbsOrOnlineRelUri, UniversalUriKind.OnlineAbsolute), Times.Once)), + assertUUriMock: mock => mock.Verify(h => h.UriToAbsoluteUri( + OnlineAbsUri, LocalAbsOrOnlineRelUri, UUriKind.OnlineAbsolute), Times.Once)), //online absolute with absolute online base directory, but different new(OnlineAbsUri, - UniversalUriKind.All, + UUriKind.All, OnlineAbsUri2, - assertHandlerMock: mock => mock.Verify(h => h.UriToAbsoluteUri( - OnlineAbsUri, OnlineAbsUri2, UniversalUriKind.OnlineAbsolute), Times.Once)), + assertUUriMock: mock => mock.Verify(h => h.UriToAbsoluteUri( + OnlineAbsUri, OnlineAbsUri2, UUriKind.OnlineAbsolute), Times.Once)), //online absolute, with relative base directory new(OnlineAbsUri, - UniversalUriKind.All, + UUriKind.All, RelativeUri, - assertHandlerMock: mock => mock.Verify(h => h.UriToAbsoluteUri( - OnlineAbsUri, RelativeUri, UniversalUriKind.OnlineAbsolute), Times.Once)), + assertUUriMock: mock => mock.Verify(h => h.UriToAbsoluteUri( + OnlineAbsUri, RelativeUri, UUriKind.OnlineAbsolute), Times.Once)), //online absolute, with relative base directory, with local restriction. Throws exception because can't find valid uri kind new(OnlineAbsUri, - UniversalUriKind.Local, + UUriKind.Local, RelativeUri, expectedExceptionType: typeof(InvalidOperationException)), //online absolute, with relative base directory, with online restriction new(OnlineAbsUri, - UniversalUriKind.Online, + UUriKind.Online, RelativeUri, - assertHandlerMock: mock => mock.Verify(h => h.UriToAbsoluteUri( - OnlineAbsUri, RelativeUri, UniversalUriKind.OnlineAbsolute), Times.Once)), + assertUUriMock: mock => mock.Verify(h => h.UriToAbsoluteUri( + OnlineAbsUri, RelativeUri, UUriKind.OnlineAbsolute), Times.Once)), }; - + return tests.Select(t => new object[] { t }); } } - - public static IEnumerable ToAbsoluteUriUsesBaseDirectoryTests + + public static IEnumerable ToAbsoluteUriUsesAllowedUriKindsTests { get { - var tests = new List + var tests = new List { - //null constructor, null method + //all constructor, all method. new(RelativeUri, - null, - null, - expectedExceptionType: typeof(InvalidOperationException)), + UUriKind.Relative, + UUriKind.All, + expectedExceptionType: typeof(InvalidOperationException)), //throws exception because is ambiguous - //set constructor, null method + //limit constructor, all method new(RelativeUri, - OnlineAbsUri, - null, - assertHandlerMock: mock => mock.Verify(h => h.UriToAbsoluteUri( - RelativeUri, OnlineAbsUri, UniversalUriKind.OnlineRelative), Times.Once)), + UUriKind.LocalRelative, + UUriKind.All, + assertUUriMock: mock => mock.Verify(h => h.UriToAbsoluteUri( + RelativeUri, null, UUriKind.LocalRelative), Times.Once)), - //null constructor, set method + //all constructor, limit method new(RelativeUri, - null, - OnlineAbsUri, - assertHandlerMock: mock => mock.Verify(h => h.UriToAbsoluteUri( - RelativeUri, OnlineAbsUri, UniversalUriKind.OnlineRelative), Times.Once)), + UUriKind.Relative, + UUriKind.Local, + assertUUriMock: mock => mock.Verify(h => h.UriToAbsoluteUri( + RelativeUri, null, UUriKind.LocalRelative), Times.Once)), - //set constructor, set method + //limit constructor, limit method new(RelativeUri, - OnlineAbsUri, - OnlineAbsUri2, - assertHandlerMock: mock => mock.Verify(h => h.UriToAbsoluteUri( - RelativeUri, OnlineAbsUri2, UniversalUriKind.OnlineRelative), Times.Once)), + UUriKind.LocalRelative, + UUriKind.Online, + expectedExceptionType: typeof(InvalidOperationException)), //throws exception because can't find a valid uri kind }; return tests.Select(t => new object[] { t }); } } - public static IEnumerable ToAbsoluteUriUsesAllowedUriKindsTests + public static IEnumerable ToAbsoluteUriUsesBaseDirectoryTests { get { - var tests = new List + var tests = new List { - //all constructor, all method. + //null constructor, null method new(RelativeUri, - UniversalUriKind.Relative, - UniversalUriKind.All, - expectedExceptionType: typeof(InvalidOperationException)), //throws exception because is ambiguous + null, + null, + expectedExceptionType: typeof(InvalidOperationException)), - //limit constructor, all method + //set constructor, null method new(RelativeUri, - UniversalUriKind.Local, - UniversalUriKind.All, - assertHandlerMock: mock => mock.Verify(h => h.UriToAbsoluteUri( - RelativeUri, null, UniversalUriKind.LocalRelative), Times.Once)), + OnlineAbsUri, + null, + assertUUriMock: mock => mock.Verify(h => h.UriToAbsoluteUri( + RelativeUri, OnlineAbsUri, UUriKind.OnlineRelative), Times.Once)), - //all constructor, limit method + //null constructor, set method new(RelativeUri, - UniversalUriKind.Relative, - UniversalUriKind.Local, - assertHandlerMock: mock => mock.Verify(h => h.UriToAbsoluteUri( - RelativeUri, null, UniversalUriKind.LocalRelative), Times.Once)), + null, + OnlineAbsUri, + assertUUriMock: mock => mock.Verify(h => h.UriToAbsoluteUri( + RelativeUri, OnlineAbsUri, UUriKind.OnlineRelative), Times.Once)), - //limit constructor, limit method + //set constructor, set method new(RelativeUri, - UniversalUriKind.Local, - UniversalUriKind.Online, - expectedExceptionType: typeof(InvalidOperationException)), //throws exception because can't find a valid uri kind + OnlineAbsUri, + OnlineAbsUri2, + assertUUriMock: mock => mock.Verify(h => h.UriToAbsoluteUri( + RelativeUri, OnlineAbsUri2, UUriKind.OnlineRelative), Times.Once)), }; return tests.Select(t => new object[] { t }); @@ -524,35 +518,17 @@ public static IEnumerable ToAbsoluteUriUsesAllowedUriKindsTests // Tests. [Theory] - [InlineData(RelativeUri, UniversalUriKind.All, RelativeUri, UniversalUriKind.Relative, null)] - [InlineData(RelativeUri, UniversalUriKind.Local, RelativeUri, UniversalUriKind.LocalRelative, null)] - [InlineData(OnlineAbsUri, UniversalUriKind.All, OnlineAbsUri, UniversalUriKind.OnlineAbsolute, null)] - [InlineData(RelativeUri, UniversalUriKind.Absolute, null, null, typeof(ArgumentException))] // throws because uri is relative - public void ConstructorEvaluateProperties( - string uri, - UniversalUriKind allowedUriKinds, - string? expectedOriginalUri, - UniversalUriKind? expectedUriKind, - Type? expectedExceptionType) + [InlineData(UUriKind.Absolute)] + [InlineData(UUriKind.Relative)] + [InlineData(UUriKind.LocalRelative)] + [InlineData(UUriKind.OnlineAbsolute)] + public void CanConstruct(UUriKind uriKind) { - // Setup handler mock. - var handlerMock = new Mock(); - handlerMock.Setup(h => h.GetUriKind(OnlineAbsUri)) - .Returns(() => UniversalUriKind.OnlineAbsolute); - handlerMock.Setup(h => h.GetUriKind(RelativeUri)) - .Returns(() => UniversalUriKind.Relative); - - if (expectedExceptionType is null) - { - var universalUri = new UniversalUri(uri, handlerMock.Object, allowedUriKinds); + var uuriMock = new Mock("testUri", uriKind, "defaultDir"); - Assert.Equal(expectedOriginalUri, universalUri.OriginalUri); - Assert.Equal(expectedUriKind, universalUri.UriKind); - } - else - { - Assert.Throws(expectedExceptionType, () => new UniversalUri(uri, handlerMock.Object, allowedUriKinds)); - } + Assert.Equal("testUri", uuriMock.Object.OriginalUri); + Assert.Equal(uriKind, uuriMock.Object.UriKind); + Assert.Equal("defaultDir", uuriMock.Object.DefaultBaseDirectory); } [Theory] @@ -560,19 +536,16 @@ public void ConstructorEvaluateProperties( [InlineData(" ")] public void EmptyUriThrowsException(string? uri) { - var handlerMock = new Mock(); - Assert.Throws(() => new UniversalUri(uri!, handlerMock.Object)); - } - - [Theory] - [InlineData(OnlineAbsUri, UniversalUriKind.None)] - [InlineData(OnlineAbsUri, UniversalUriKind.Local)] - public void TooRestrictiveUriKindThrowsException(string uri, UniversalUriKind allowedUriKinds) - { - var handlerMock = new Mock(); - handlerMock.Setup(h => h.GetUriKind(OnlineAbsUri)) - .Returns(() => UniversalUriKind.OnlineAbsolute); - Assert.Throws(() => new UniversalUri(uri, handlerMock.Object, allowedUriKinds)); + Assert.Throws( + () => + { + var uuidMock = new Mock(uri!, UUriKind.All, null!); + try { _ = uuidMock.Object; } + catch(TargetInvocationException e) //unwrap from Moq + { + throw e.InnerException!; + } + }); } [Theory, MemberData(nameof(ToAbsoluteUriTests))] @@ -580,55 +553,82 @@ public void ToAbsoluteUri(ToAbsoluteUriTestElement test) { if (test.ExpectedExceptionType is null) { - test.UniversalUri.ToAbsoluteUri( - test.AllowedUriKinds, + test.UUri.ToAbsoluteUri( + test.UuriKind, test.BaseDirectory); - + test.Assert(); } else { Assert.Throws(test.ExpectedExceptionType, - () => test.UniversalUri.ToAbsoluteUri( - test.AllowedUriKinds, + () => test.UUri.ToAbsoluteUri( + test.UuriKind, test.BaseDirectory)); } } - [Theory, MemberData(nameof(ToAbsoluteUriUsesBaseDirectoryTests))] - public void ToAbsoluteUriUsesBaseDirectory(ToAbsoluteUriUsesBaseDirectoryTestElement test) + [Theory, MemberData(nameof(ToAbsoluteUriUsesAllowedUriKindsTests))] + public void ToAbsoluteUriUsesAllowedUriKinds(ToAbsoluteUriUsesAllowedUriKindsTestElement test) { if (test.ExpectedExceptionType is null) { - test.UniversalUri.ToAbsoluteUri( - baseDirectory: test.ArgBaseDirectory); - + test.UUri.ToAbsoluteUri( + test.ArgAllowedUriKinds); + test.Assert(); } else { Assert.Throws(test.ExpectedExceptionType!, - () => test.UniversalUri.ToAbsoluteUri( - baseDirectory: test.ArgBaseDirectory)); + () => test.UUri.ToAbsoluteUri( + test.ArgAllowedUriKinds)); } } - [Theory, MemberData(nameof(ToAbsoluteUriUsesAllowedUriKindsTests))] - public void ToAbsoluteUriUsesAllowedUriKinds(ToAbsoluteUriUsesAllowedUriKindsTestElement test) + [Theory, MemberData(nameof(ToAbsoluteUriUsesBaseDirectoryTests))] + public void ToAbsoluteUriUsesBaseDirectory(ToAbsoluteUriUsesBaseDirectoryTestElement test) { if (test.ExpectedExceptionType is null) { - test.UniversalUri.ToAbsoluteUri( - test.ArgAllowedUriKinds); - + test.UUri.ToAbsoluteUri( + baseDirectory: test.ArgBaseDirectory); + test.Assert(); } else { Assert.Throws(test.ExpectedExceptionType!, - () => test.UniversalUri.ToAbsoluteUri( - test.ArgAllowedUriKinds)); + () => test.UUri.ToAbsoluteUri( + baseDirectory: test.ArgBaseDirectory)); } } + + [Fact] + public void UriKindNoneThrowsException() + { + Assert.Throws( + () => + { + var uuidMock = new Mock("myUri", UUriKind.None, null!); + try { _ = uuidMock.Object; } + catch(TargetInvocationException e) //unwrap from Moq + { + throw e.InnerException!; + } + }); + } + + // Helpers. + private static UUriKind UUriToUUriKind(string uri) => + uri switch + { + LocalAbsOrOnlineRelUri => UUriKind.LocalAbsolute | UUriKind.OnlineRelative, + LocalAbsUri => UUriKind.LocalAbsolute, + OnlineAbsUri => UUriKind.OnlineAbsolute, + OnlineAbsUri2 => UUriKind.OnlineAbsolute, + RelativeUri => UUriKind.Relative, + _ => throw new ArgumentException(nameof(uri)) + }; } }