Skip to content

Commit

Permalink
update bitmask with test
Browse files Browse the repository at this point in the history
  • Loading branch information
danieleguido committed Nov 12, 2024
1 parent 2a5d707 commit a74ed1b
Show file tree
Hide file tree
Showing 4 changed files with 93 additions and 20 deletions.
52 changes: 50 additions & 2 deletions impresso/tests/models/test_userBitmap.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
from django.conf import settings
from django.test import TestCase
from django.contrib.auth.models import User, Group
from ...models import Profile, UserBitmap
from ...models import Profile, UserBitmap, DatasetBitmapPosition
from django.utils import timezone
from ...utils.bitmap import int_to_bytes, is_access_allowed
from ...utils.bitmask import BitMask64


class UserBitmapTestCase(TestCase):
Expand All @@ -20,7 +22,12 @@ def setUp(self):
name=settings.IMPRESSO_GROUP_USER_PLAN_EDUCATIONAL
)

def test_user_bitmap_guest_to_researcher(self):
def test_user_bitmap_lifecycle(self):
self._user_bitmap_guest_to_researcher()
self._user_bitmap_add_remove_subscriptions()
self._user_bitmap_check_access_auth_only()

def _user_bitmap_guest_to_researcher(self):
self.assertEqual(
str(self.userBitmap),
f"testuser Bitmap {bin(UserBitmap.USER_PLAN_GUEST)}",
Expand Down Expand Up @@ -53,3 +60,44 @@ def test_user_bitmap_guest_to_researcher(self):
b"\x1e",
"from left to right, user has access to public domain, to content requiring auth and to content requiring researcher",
)

def _user_bitmap_add_remove_subscriptions(self):
test_subscription_domain_A = DatasetBitmapPosition.objects.create(
name="Domain of TEST A archives",
)
test_subscription_domain_B = DatasetBitmapPosition.objects.create(
name="Domain of TEST B archives",
)
self.userBitmap.subscriptions.add(
test_subscription_domain_B,
)
# adding a subscription trigger a post_save, let's get it back
self.userBitmap.refresh_from_db()
# now the bitmap should be 0b1111001

self.assertEqual(
self.userBitmap.get_bitmap_as_int(),
0b1111001,
"from left to right, user researcher has access to subscription TEST B",
)

# remove the subscription to B and add the subscription to A
self.userBitmap.subscriptions.remove(test_subscription_domain_B)
self.userBitmap.subscriptions.add(test_subscription_domain_A)
self.userBitmap.refresh_from_db()

self.assertEqual(
self.userBitmap.get_bitmap_as_int(),
0b111101,
"from left to right, user researcher has access to subscription TEST A",
)

def _user_bitmap_check_access_auth_only(self):
print("userBitmap as int:\n", bin(self.userBitmap.get_bitmap_as_int()))
print("content as int\n", bin(0b10))
print("userBitmap:\n", str(BitMask64(self.userBitmap.bitmap)))
content_permissions_mask_auth_only = BitMask64(0b10) # NO public domain!
print(
"content_permissions_mask_auth_only:\n",
str(content_permissions_mask_auth_only),
)
16 changes: 16 additions & 0 deletions impresso/tests/utils/test_bitmask.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import unittest
from impresso.utils.bitmask import BitMask64


class TestBitMask64(unittest.TestCase):

def test_init_with_string(self):
bitmask = BitMask64("010110101")
self.assertEqual(
str(bitmask),
"0000000000000000000000000000000000000000000000000000000010110101",
)

reverted_bitmask = BitMask64("010110101", reverse=True)
# we expect 0b101011010 = 346
self.assertEqual(int(reverted_bitmask), 0b101011010)
18 changes: 0 additions & 18 deletions impresso/utils/bitmap.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,24 +52,6 @@ def int_to_bytes(n: int) -> bytes:
return n.to_bytes((n.bit_length() + 7) // 8, "big")


def str_to_bytes(s: str) -> bytes:
"""
Converts a string to a bytes object.
Args:
- s (str): The string to be converted.
Returns:
- bytes: The bytes object.
Example Usage:
>>> s = "1"
>>> str_to_bytes(s)
b"1"
"""
return s.encode()


def check_bitmap_keys_overlap(
user_bitmap_key: str, content_bitmap_key: Union[int, str]
) -> bool:
Expand Down
27 changes: 27 additions & 0 deletions impresso/utils/bitmask.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
class BitMask64:
def __init__(self, value: str | int | bytes = 0, reverse: bool = False):
if isinstance(value, str):
if not all(c in "01" for c in value):
raise ValueError("String must contain only '0' and '1'")
if len(value) > 64:
raise ValueError("String must contain maximum 64 characters")
self._value = int(value[::-1], 2) if reverse else int(value, 2)
elif isinstance(value, int):
self._value = value
elif isinstance(value, bytes):
if len(value) > 8:
raise ValueError("Bytes must contain maximum 8 bytes")
self._value = int.from_bytes(value, byteorder="big")
# // reverse the bits
self._value = int(bin(self._value)[2:].zfill(64)[::-1], 2)

else:
raise TypeError("Value must be a string of bits or an integer.")
# Ensure the value is within the 64-bit range and pad if necessary
self._value &= 0xFFFFFFFFFFFFFFFF

def __int__(self):
return self._value

def __str__(self):
return bin(self._value)[2:].zfill(64)

0 comments on commit a74ed1b

Please sign in to comment.