Skip to content

Instantly share code, notes, and snippets.

@rianjs
Created October 11, 2021 13:23
Show Gist options
  • Save rianjs/ce46d0be1e88f66bf5a57954357c3dae to your computer and use it in GitHub Desktop.
Save rianjs/ce46d0be1e88f66bf5a57954357c3dae to your computer and use it in GitHub Desktop.
Creating semantic bitmasks using enums
public bool HasPermission(long userPermissions, Permission desiredAction)
{
if (userPermissions < 1)
{
return false;
}
var asLong = (long)desiredAction;
var hasPermission = userPermissions & asLong;
return hasPermission != 0;
}
public enum PermissionMask : long
{
Read = 1L,
Edit = Read << 1,
Create = Edit << 1,
Delete = Create << 1,
}
public void DisplayMasks()
{
WriteLine($"{PermissionMask.Read}:\tBinary:{Convert.ToString((long)PermissionMask.Read, 2).PadLeft(8, '0')}\tLong:{(long)PermissionMask.Read:N0}");
WriteLine($"{PermissionMask.Edit}:\tBinary:{Convert.ToString((long)PermissionMask.Edit, 2).PadLeft(8, '0')}\tLong:{(long)PermissionMask.Edit:N0}");
WriteLine($"{PermissionMask.Create}:\tBinary:{Convert.ToString((long)PermissionMask.Create, 2).PadLeft(8, '0')}\tLong:{(long)PermissionMask.Create:N0}");
WriteLine($"{PermissionMask.Delete}:\tBinary:{Convert.ToString((long)PermissionMask.Delete, 2).PadLeft(8, '0')}\tLong:{(long)PermissionMask.Delete:N0}");
// Read: Binary:00000001 Long:1
// Edit: Binary:00000010 Long:2
// Create: Binary:00000100 Long:4
// Delete: Binary:00001000 Long:8
}
public static IEnumerable<ITestCaseData> HasPermissionTestCases()
{
yield return new TestCaseData(0L, Permission.Edit)
.Returns(false)
.SetName("Can't edit with zero permissions");
yield return new TestCaseData(-1L, Permission.Edit)
.Returns(false)
.SetName("Can't edit with permissions < 0");
var enumerablePermissions = Enum.GetValues(typeof(Permission)).Cast<Permission>();
//Tautologies
foreach (var permission in enumerablePermissions)
{
yield return new TestCaseData((long)permission, permission)
.Returns(true)
.SetName($"Permission.{permission} allows Permission.{permission}");
}
//Contradictions
foreach (var outer in enumerablePermissions) //If I have Permission.Foo
{
foreach (var inner in enumerablePermissions.Where(p => p != outer)) //I can't do Permission.Bar
{
yield return new TestCaseData((long)outer, inner)
.Returns(false)
.SetName($"Permission.{outer} doesn't allow for Permission.{inner}");
}
}
//Some combinations
var allowed = enumerablePermissions.Take(2).ToList();
var aggregation = allowed
.Cast<long>()
.Aggregate((a, b) => a | b);
foreach (var permission in enumerablePermissions)
{
var returns = allowed.Contains(permission);
yield return new TestCaseData(aggregation, permission)
.Returns(returns)
.SetName($"Permissions {string.Join(",", allowed)} against Permission.{permission} = {returns}");
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment