244 lines
6.5 KiB
C#
244 lines
6.5 KiB
C#
using FluentAssertions;
|
|
using Xunit;
|
|
|
|
namespace StellaOps.FeatureFlags.Tests;
|
|
|
|
[Trait("Category", "Unit")]
|
|
public class InMemoryFeatureFlagProviderTests
|
|
{
|
|
[Fact]
|
|
public void Name_ReturnsInMemory()
|
|
{
|
|
// Arrange
|
|
var provider = new InMemoryFeatureFlagProvider(new Dictionary<string, bool>());
|
|
|
|
// Assert
|
|
provider.Name.Should().Be("InMemory");
|
|
}
|
|
|
|
[Fact]
|
|
public void Priority_ReturnsConfiguredValue()
|
|
{
|
|
// Arrange
|
|
var provider = new InMemoryFeatureFlagProvider(new Dictionary<string, bool>(), priority: 5);
|
|
|
|
// Assert
|
|
provider.Priority.Should().Be(5);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task TryGetFlagAsync_ReturnsTrueForEnabledFlag()
|
|
{
|
|
// Arrange
|
|
var flags = new Dictionary<string, bool>
|
|
{
|
|
{ "enabled-flag", true }
|
|
};
|
|
var provider = new InMemoryFeatureFlagProvider(flags);
|
|
|
|
// Act
|
|
var result = await provider.TryGetFlagAsync("enabled-flag", FeatureFlagEvaluationContext.Empty);
|
|
|
|
// Assert
|
|
result.Should().NotBeNull();
|
|
result!.Enabled.Should().BeTrue();
|
|
result.Key.Should().Be("enabled-flag");
|
|
}
|
|
|
|
[Fact]
|
|
public async Task TryGetFlagAsync_ReturnsFalseForDisabledFlag()
|
|
{
|
|
// Arrange
|
|
var flags = new Dictionary<string, bool>
|
|
{
|
|
{ "disabled-flag", false }
|
|
};
|
|
var provider = new InMemoryFeatureFlagProvider(flags);
|
|
|
|
// Act
|
|
var result = await provider.TryGetFlagAsync("disabled-flag", FeatureFlagEvaluationContext.Empty);
|
|
|
|
// Assert
|
|
result.Should().NotBeNull();
|
|
result!.Enabled.Should().BeFalse();
|
|
}
|
|
|
|
[Fact]
|
|
public async Task TryGetFlagAsync_ReturnsNullForUnknownFlag()
|
|
{
|
|
// Arrange
|
|
var provider = new InMemoryFeatureFlagProvider(new Dictionary<string, bool>());
|
|
|
|
// Act
|
|
var result = await provider.TryGetFlagAsync("unknown", FeatureFlagEvaluationContext.Empty);
|
|
|
|
// Assert
|
|
result.Should().BeNull();
|
|
}
|
|
|
|
[Fact]
|
|
public async Task TryGetFlagAsync_IsCaseInsensitive()
|
|
{
|
|
// Arrange
|
|
var flags = new Dictionary<string, bool>
|
|
{
|
|
{ "MyFlag", true }
|
|
};
|
|
var provider = new InMemoryFeatureFlagProvider(flags);
|
|
|
|
// Act
|
|
var result = await provider.TryGetFlagAsync("myflag", FeatureFlagEvaluationContext.Empty);
|
|
|
|
// Assert
|
|
result.Should().NotBeNull();
|
|
result!.Enabled.Should().BeTrue();
|
|
}
|
|
|
|
[Fact]
|
|
public void SetFlag_AddsNewFlag()
|
|
{
|
|
// Arrange
|
|
var provider = new InMemoryFeatureFlagProvider(new Dictionary<string, bool>());
|
|
|
|
// Act
|
|
provider.SetFlag("new-flag", true);
|
|
var result = provider.TryGetFlagAsync("new-flag", FeatureFlagEvaluationContext.Empty).Result;
|
|
|
|
// Assert
|
|
result.Should().NotBeNull();
|
|
result!.Enabled.Should().BeTrue();
|
|
}
|
|
|
|
[Fact]
|
|
public void SetFlag_UpdatesExistingFlag()
|
|
{
|
|
// Arrange
|
|
var flags = new Dictionary<string, bool>
|
|
{
|
|
{ "toggle-flag", false }
|
|
};
|
|
var provider = new InMemoryFeatureFlagProvider(flags);
|
|
|
|
// Act
|
|
provider.SetFlag("toggle-flag", true);
|
|
var result = provider.TryGetFlagAsync("toggle-flag", FeatureFlagEvaluationContext.Empty).Result;
|
|
|
|
// Assert
|
|
result.Should().NotBeNull();
|
|
result!.Enabled.Should().BeTrue();
|
|
}
|
|
|
|
[Fact]
|
|
public void SetFlag_WithVariant_SetsVariantValue()
|
|
{
|
|
// Arrange
|
|
var provider = new InMemoryFeatureFlagProvider(new Dictionary<string, bool>());
|
|
|
|
// Act
|
|
provider.SetFlag("variant-flag", true, "blue");
|
|
var result = provider.TryGetFlagAsync("variant-flag", FeatureFlagEvaluationContext.Empty).Result;
|
|
|
|
// Assert
|
|
result.Should().NotBeNull();
|
|
result!.Variant.Should().Be("blue");
|
|
}
|
|
|
|
[Fact]
|
|
public void RemoveFlag_RemovesExistingFlag()
|
|
{
|
|
// Arrange
|
|
var flags = new Dictionary<string, bool>
|
|
{
|
|
{ "to-remove", true }
|
|
};
|
|
var provider = new InMemoryFeatureFlagProvider(flags);
|
|
|
|
// Act
|
|
provider.RemoveFlag("to-remove");
|
|
var result = provider.TryGetFlagAsync("to-remove", FeatureFlagEvaluationContext.Empty).Result;
|
|
|
|
// Assert
|
|
result.Should().BeNull();
|
|
}
|
|
|
|
[Fact]
|
|
public void RemoveFlag_DoesNotThrowForNonexistentFlag()
|
|
{
|
|
// Arrange
|
|
var provider = new InMemoryFeatureFlagProvider(new Dictionary<string, bool>());
|
|
|
|
// Act & Assert
|
|
provider.Invoking(p => p.RemoveFlag("nonexistent"))
|
|
.Should().NotThrow();
|
|
}
|
|
|
|
[Fact]
|
|
public void Clear_RemovesAllFlags()
|
|
{
|
|
// Arrange
|
|
var flags = new Dictionary<string, bool>
|
|
{
|
|
{ "flag-1", true },
|
|
{ "flag-2", false }
|
|
};
|
|
var provider = new InMemoryFeatureFlagProvider(flags);
|
|
|
|
// Act
|
|
provider.Clear();
|
|
var result1 = provider.TryGetFlagAsync("flag-1", FeatureFlagEvaluationContext.Empty).Result;
|
|
var result2 = provider.TryGetFlagAsync("flag-2", FeatureFlagEvaluationContext.Empty).Result;
|
|
|
|
// Assert
|
|
result1.Should().BeNull();
|
|
result2.Should().BeNull();
|
|
}
|
|
|
|
[Fact]
|
|
public async Task ListFlagsAsync_ReturnsAllFlags()
|
|
{
|
|
// Arrange
|
|
var flags = new Dictionary<string, bool>
|
|
{
|
|
{ "flag-a", true },
|
|
{ "flag-b", false },
|
|
{ "flag-c", true }
|
|
};
|
|
var provider = new InMemoryFeatureFlagProvider(flags);
|
|
|
|
// Act
|
|
var result = await provider.ListFlagsAsync();
|
|
|
|
// Assert
|
|
result.Should().HaveCount(3);
|
|
result.Select(f => f.Key).Should().Contain(["flag-a", "flag-b", "flag-c"]);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task ListFlagsAsync_ReturnsEmptyWhenNoFlags()
|
|
{
|
|
// Arrange
|
|
var provider = new InMemoryFeatureFlagProvider(new Dictionary<string, bool>());
|
|
|
|
// Act
|
|
var result = await provider.ListFlagsAsync();
|
|
|
|
// Assert
|
|
result.Should().BeEmpty();
|
|
}
|
|
|
|
[Fact]
|
|
public async Task ListFlagsAsync_ReflectsCurrentStateAfterModifications()
|
|
{
|
|
// Arrange
|
|
var provider = new InMemoryFeatureFlagProvider(new Dictionary<string, bool>());
|
|
provider.SetFlag("dynamic-flag", true);
|
|
|
|
// Act
|
|
var result = await provider.ListFlagsAsync();
|
|
|
|
// Assert
|
|
result.Should().HaveCount(1);
|
|
result.Single().Key.Should().Be("dynamic-flag");
|
|
}
|
|
}
|