Skip to content

Commit 5c93a37

Browse files
committed
Feat: HasFlag
1 parent ded9822 commit 5c93a37

File tree

10 files changed

+61
-12
lines changed

10 files changed

+61
-12
lines changed

src/CodeOfChaos.Extensions/EnumExtensions.cs

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,8 @@ namespace System;
1010
// ---------------------------------------------------------------------------------------------------------------------
1111
public static class EnumExtensions {
1212
private static readonly ConcurrentDictionary<Type, Array> EnumValuesCache = new();
13-
13+
private static readonly ConcurrentDictionary<Type, bool> IsFlagsEnumCache = new();
14+
1415
/// <summary>
1516
/// Retrieves all values of the specified enum type from the cache, falling back to reflection if uncached.
1617
/// </summary>
@@ -49,4 +50,26 @@ public static T[] GetFlagsAsArray<T>(this T flagEnum, bool excludeZeroValue = tr
4950
/// </summary>
5051
public static List<T> GetFlagsAsList<T>(this T flagEnum, bool excludeZeroValue = true) where T : struct, Enum
5152
=> GetFlags(flagEnum, excludeZeroValue).ToList();
53+
54+
/// <summary>
55+
/// Determines whether the specified flags are set in the given enum value.
56+
/// </summary>
57+
/// <typeparam name="T">The type of the Enum.</typeparam>
58+
/// <param name="flagEnum">The enum value to be inspected.</param>
59+
/// <param name="flag">The flag or flags to check for in the enum value.</param>
60+
/// <returns>A boolean indicating whether the specified flags are set in the enum value.</returns>
61+
/// <exception cref="ArgumentException">
62+
/// Thrown if the provided enum type does not have the [Flags] attribute.
63+
/// </exception>
64+
public static bool HasFlag<T>(this T flagEnum, T flag) where T : struct, Enum {
65+
bool isFlagsEnum = IsFlagsEnumCache.GetOrAdd(typeof(T), t => t.IsDefined(typeof(FlagsAttribute), false));
66+
if (!isFlagsEnum) throw new ArgumentException("The provided enum type must have the [Flags] attribute.", nameof(flagEnum));
67+
68+
// Convert enums to unsigned numeric types to perform bitwise comparison
69+
ulong flagEnumValue = Convert.ToUInt64(flagEnum);
70+
ulong flagValue = Convert.ToUInt64(flag);
71+
72+
// Perform the bitwise comparison
73+
return (flagEnumValue & flagValue) == flagValue;
74+
}
5275
}

tests/Tests.CodeOfChaos.Extensions.Analyzers/Tests.CodeOfChaos.Extensions.Analyzers.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111

1212
<ItemGroup>
1313
<PackageReference Include="CodeOfChaos.Testing.TUnit" Version="0.8.1"/>
14-
<PackageReference Include="TUnit" Version="0.18.60"/>
14+
<PackageReference Include="TUnit" Version="0.19.6" />
1515
</ItemGroup>
1616

1717
<ItemGroup>

tests/Tests.CodeOfChaos.Extensions.AspNetCore/Tests.CodeOfChaos.Extensions.AspNetCore.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
<ItemGroup>
1414
<PackageReference Include="JetBrains.Annotations" Version="2024.3.0"/>
1515
<PackageReference Include="Moq" Version="4.20.72"/>
16-
<PackageReference Include="TUnit" Version="0.18.60"/>
16+
<PackageReference Include="TUnit" Version="0.19.6" />
1717
<PackageReference Include="Bogus" Version="35.6.2"/>
1818
</ItemGroup>
1919

tests/Tests.CodeOfChaos.Extensions.DependencyInjection.Generators/Tests.CodeOfChaos.Extensions.DependencyInjection.Generators.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
<PackageReference Include="Microsoft.CodeAnalysis.CSharp.Workspaces" Version="4.13.0"/>
2020
<PackageReference Include="Moq" Version="4.20.72"/>
2121
<PackageReference Include="System.Formats.Asn1" Version="9.0.3"/>
22-
<PackageReference Include="TUnit" Version="0.18.60"/>
22+
<PackageReference Include="TUnit" Version="0.19.6" />
2323
</ItemGroup>
2424

2525
<ItemGroup>

tests/Tests.CodeOfChaos.Extensions.DependencyInjection/Tests.CodeOfChaos.Extensions.DependencyInjection.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
<PackageReference Include="JetBrains.Annotations" Version="2024.3.0"/>
1616
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="9.0.3"/>
1717
<PackageReference Include="Moq" Version="4.20.72"/>
18-
<PackageReference Include="TUnit" Version="0.18.60"/>
18+
<PackageReference Include="TUnit" Version="0.19.6" />
1919
</ItemGroup>
2020

2121
<ItemGroup>

tests/Tests.CodeOfChaos.Extensions.EntityFrameworkCore/Tests.CodeOfChaos.Extensions.EntityFrameworkCore.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
<ItemGroup>
1414
<PackageReference Include="JetBrains.Annotations" Version="2024.3.0"/>
1515
<PackageReference Include="Moq" Version="4.20.72"/>
16-
<PackageReference Include="TUnit" Version="0.18.60"/>
16+
<PackageReference Include="TUnit" Version="0.19.6" />
1717
<PackageReference Include="Bogus" Version="35.6.2"/>
1818
</ItemGroup>
1919

tests/Tests.CodeOfChaos.Extensions.FluentValidation/Tests.CodeOfChaos.Extensions.FluentValidation.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
<ItemGroup>
1414
<PackageReference Include="JetBrains.Annotations" Version="2024.3.0"/>
1515
<PackageReference Include="Moq" Version="4.20.72"/>
16-
<PackageReference Include="TUnit" Version="0.18.60"/>
16+
<PackageReference Include="TUnit" Version="0.19.6" />
1717
<PackageReference Include="Bogus" Version="35.6.2"/>
1818
</ItemGroup>
1919

tests/Tests.CodeOfChaos.Extensions.Serilog/Tests.CodeOfChaos.Extensions.Serilog.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
<ItemGroup>
1414
<PackageReference Include="JetBrains.Annotations" Version="2024.3.0"/>
1515
<PackageReference Include="Moq" Version="4.20.72"/>
16-
<PackageReference Include="TUnit" Version="0.18.60"/>
16+
<PackageReference Include="TUnit" Version="0.19.6" />
1717
<PackageReference Include="Bogus" Version="35.6.2"/>
1818
</ItemGroup>
1919

tests/Tests.CodeOfChaos.Extensions/EnumExtensionTests.cs

Lines changed: 29 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,14 +11,16 @@ namespace Tests.CodeOfChaos.Extensions;
1111
public class EnumExtensionsTest {
1212

1313
[Flags]
14-
private enum TestFlags {
14+
public enum TestFlags {
1515
None = 0,
1616
Flag1 = 1 << 0,// 1
1717
Flag2 = 1 << 1,// 2
1818
Flag3 = 1 << 2,// 4
1919
Flag4 = 1 << 3// 8
20-
}// ReSharper disable UnusedMember.Local
21-
private enum NonFlagsEnum {
20+
}
21+
22+
// ReSharper disable UnusedMember.Local
23+
public enum NonFlagsEnum {
2224
Value1 = 0,
2325
Value2 = 1,
2426
Value3 = 2
@@ -136,4 +138,28 @@ public async Task GetFlagsAsList_ShouldExcludeZero_WhenExcludeZeroValueIsTrue()
136138
var expected = new List<TestFlags> { TestFlags.Flag1 };
137139
await Assert.That(result).IsEquivalentTo(expected);
138140
}
141+
142+
[Test]
143+
[Arguments(TestFlags.Flag1, TestFlags.Flag1, true)]
144+
[Arguments(TestFlags.Flag1, TestFlags.Flag2, false)]
145+
[Arguments(TestFlags.Flag1 | TestFlags.Flag2, TestFlags.Flag1, true)]
146+
[Arguments(TestFlags.Flag1 | TestFlags.Flag2, TestFlags.Flag2, true)]
147+
[Arguments(TestFlags.Flag1 | TestFlags.Flag2, TestFlags.Flag3, false)]
148+
[Arguments(TestFlags.Flag1 | TestFlags.Flag2, TestFlags.Flag4, false)]
149+
public async Task HasFlag_WithSingleFlag_ReturnsTrue(TestFlags value, TestFlags containsFlag, bool expected) {
150+
// Act
151+
bool result = value.HasFlag(containsFlag);
152+
153+
// Assert
154+
await Assert.That(result).IsEqualTo(expected);
155+
}
156+
157+
[Test]
158+
public async Task HasFlag_WithNonFlagsEnum_ThrowsArgumentException() {
159+
// Arrange
160+
const NonFlagsEnum value = NonFlagsEnum.Value1;
161+
162+
// Act & Assert
163+
await Assert.ThrowsAsync<ArgumentException>(() => Task.FromResult(value.HasFlag(NonFlagsEnum.Value2)));
164+
}
139165
}

tests/Tests.CodeOfChaos.Extensions/Tests.CodeOfChaos.Extensions.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
<ItemGroup>
1414
<PackageReference Include="JetBrains.Annotations" Version="2024.3.0"/>
1515
<PackageReference Include="Moq" Version="4.20.72"/>
16-
<PackageReference Include="TUnit" Version="0.18.60"/>
16+
<PackageReference Include="TUnit" Version="0.19.6" />
1717
<PackageReference Include="Bogus" Version="35.6.2"/>
1818
</ItemGroup>
1919

0 commit comments

Comments
 (0)