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

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 37 additions & 9 deletions src/Ramstack.FileProviders.Composition/FileProviderComposer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,48 +8,76 @@ namespace Ramstack.FileProviders.Composition;
public static class FileProviderComposer
{
/// <summary>
/// Tries to flatten the specified <see cref="IFileProvider"/> into a flat list of file providers.
/// Attempts to flatten the specified <see cref="IFileProvider"/> into a flat list of file providers.
/// </summary>
/// <remarks>
/// If the <paramref name="provider"/> is not a <see cref="CompositeFileProvider"/>,
/// the same instance of the <paramref name="provider"/> is returned.
/// </remarks>
/// <param name="provider">The <see cref="IFileProvider"/> to flatten.</param>
/// <returns>
/// A <see cref="IFileProvider"/> that represents the flattened version of the specified <see cref="IFileProvider"/>.
/// An <see cref="IFileProvider"/> representing the flattened version from the specified <see cref="IFileProvider"/>.
/// </returns>
public static IFileProvider Flatten(this IFileProvider provider) =>
FlattenProvider(provider);

/// <summary>
/// Attempts to flatten the specified <see cref="IFileProvider"/> into a flat list of file providers.
/// </summary>
/// <remarks>
/// If the <paramref name="provider"/> is not a <see cref="CompositeFileProvider"/>,
/// the same instance of the <paramref name="provider"/> is returned.
/// </remarks>
/// <param name="provider">The <see cref="IFileProvider"/> to flatten.</param>
/// <returns>
/// An <see cref="IFileProvider"/> representing the flattened version from the specified <see cref="IFileProvider"/>.
/// </returns>
public static IFileProvider FlattenProvider(IFileProvider provider)
{
if (provider is CompositeFileProvider composite)
foreach (var p in composite.FileProviders)
while (provider is CompositeFileProvider composite)
{
var providers = composite.FileProviders as IFileProvider[] ?? composite.FileProviders.ToArray();
if (providers.Length == 0)
return new NullFileProvider();

if (providers.Length == 1)
{
provider = providers[0];
continue;
}

foreach (var p in providers)
if (p is CompositeFileProvider or NullFileProvider)
return ComposeProviders(composite.FileProviders);
return ComposeProviders(providers);

break;
}

return provider;
}

/// <summary>
/// Creates a provider from the specified list of <see cref="IFileProvider"/> and flattens it into a flat list of file providers.
/// Creates a provider from the specified list of <see cref="IFileProvider"/> instances and flattens it into a flat list of file providers.
/// </summary>
/// <remarks>
/// This method returns a <see cref="CompositeFileProvider"/> if more than one provider remains after flattening.
/// </remarks>
/// <param name="providers">The list of <see cref="IFileProvider"/> instances to compose and flatten.</param>
/// <returns>
/// A <see cref="IFileProvider"/> that represents the flattened version of the specified list of providers.
/// An <see cref="IFileProvider"/> representing the flattened version from the specified list of providers.
/// </returns>
public static IFileProvider ComposeProviders(params IFileProvider[] providers) =>
ComposeProviders(providers.AsEnumerable());

/// <summary>
/// Creates a provider from the specified list of <see cref="IFileProvider"/> and flattens it into a flat list of file providers.
/// Creates a provider from the specified list of <see cref="IFileProvider"/> instances and flattens it into a flat list of file providers.
/// </summary>
/// <remarks>
/// This method returns a <see cref="CompositeFileProvider"/> if more than one provider remains after flattening.
/// </remarks>
/// <param name="providers">The list of <see cref="IFileProvider"/> instances to compose and flatten.</param>
/// <returns>
/// A <see cref="IFileProvider"/> that represents the flattened version of the specified list of providers.
/// An <see cref="IFileProvider"/> representing the flattened version from the specified list of providers.
/// </returns>
public static IFileProvider ComposeProviders(IEnumerable<IFileProvider> providers)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,15 @@
public sealed class FileProviderComposerTests
{
[Test]
public void FlattenFileProvider_ReturnsAsIs_WhenNoComposite()
public void Flatten_ReturnsAsIs_WhenNoComposite()
{
var provider = new TestFileProvider();
var result = FileProviderComposer.FlattenProvider(provider);
Assert.That(result, Is.SameAs(provider));
}

[Test]
public void FlattenFileProvider_ReturnsCompositeProvider_WhenNeedComposite()
public void Flatten_ReturnsCompositeProvider_WhenNeedComposite()
{
var provider = new CompositeFileProvider(new TestFileProvider(), new TestFileProvider());

Expand All @@ -21,7 +21,7 @@ public void FlattenFileProvider_ReturnsCompositeProvider_WhenNeedComposite()
}

[Test]
public void FlattenFileProvider_ReturnsAsIs_WhenAlreadyFlat()
public void Flatten_ReturnsAsIs_WhenAlreadyFlat()
{
var provider = new CompositeFileProvider(new TestFileProvider(), new TestFileProvider());

Expand All @@ -30,7 +30,7 @@ public void FlattenFileProvider_ReturnsAsIs_WhenAlreadyFlat()
}

[Test]
public void FlattenFileProvider_ReturnsCompositeProvider_Flattened()
public void Flatten_ReturnsCompositeProvider_Flattened()
{
var provider = new CompositeFileProvider(
new TestFileProvider(),
Expand All @@ -48,7 +48,7 @@ public void FlattenFileProvider_ReturnsCompositeProvider_Flattened()
}

[Test]
public void FlattenFileProvider_RemovesNullFileProvider()
public void Flatten_RemovesNullFileProvider()
{
var provider = new CompositeFileProvider(
new TestFileProvider(),
Expand All @@ -66,7 +66,7 @@ public void FlattenFileProvider_RemovesNullFileProvider()
}

[Test]
public void FlattenFileProvider_ReturnsNullFileProvider_WhenNothingReturn()
public void Flatten_ReturnsNullFileProvider_WhenNothingReturn()
{
var provider = new CompositeFileProvider(
new CompositeFileProvider(
Expand Down Expand Up @@ -107,7 +107,7 @@ public void FlattenFileProvider_ReturnsNullFileProvider_WhenNothingReturn()
}

[Test]
public void FlattenFileProvider_ReturnsSingleProvider_WhenRemainOneProvider()
public void Flatten_ReturnsSingleProvider_WhenRemainOneProvider()
{
var provider = new CompositeFileProvider(
new CompositeFileProvider(
Expand Down Expand Up @@ -148,7 +148,7 @@ public void FlattenFileProvider_ReturnsSingleProvider_WhenRemainOneProvider()
}

[Test]
public void FlattenFileProvider_MaintainOrder_WhenComposite()
public void Flatten_MaintainOrder_WhenComposite()
{
var p1 = new TestFileProvider();
var p2 = new TestFileProvider();
Expand Down Expand Up @@ -208,6 +208,20 @@ public void FlattenFileProvider_MaintainOrder_WhenComposite()
Assert.That(composite.FileProviders, Is.EquivalentTo(providers));
}

[Test]
public void Flatten_ReturnsSingleProvider_WhenCompositeContainsOnlyOne()
{
var provider = new CompositeFileProvider(new TestFileProvider()).Flatten();
Assert.That(provider, Is.InstanceOf<TestFileProvider>());
}

[Test]
public void Flatten_EmptyComposite_ReturnsNullProvider()
{
var provider = new CompositeFileProvider().Flatten();
Assert.That(provider, Is.InstanceOf<NullFileProvider>());
}

private sealed class TestFileProvider : IFileProvider
{
public IFileInfo GetFileInfo(string subpath) =>
Expand Down