Add bit mask enumeration utilities

This changes adds several utilities for working with bit mask
enumerations, including functions to compute bit masks from lists
of enumeration values and vice versa. Unit tests have been added
to cover these new utilities.
This commit is contained in:
Peter Hamilton 2019-03-07 16:29:36 -05:00 committed by Peter Hamilton
parent 8e7dae6629
commit 438ec42574
2 changed files with 133 additions and 3 deletions

View File

@ -18,6 +18,7 @@
import copy
import enum
import functools
import six
@ -1814,14 +1815,86 @@ def convert_attribute_tag_to_name(value):
raise ValueError("Unrecognized attribute tag: {}".format(value))
def get_bit_mask_from_enumerations(enumerations):
"""
A utility function that computes a bit mask from a collection of
enumeration values.
def is_enum_value(enum_class, potential_value):
Args:
enumerations (list): A list of enumeration values to be combined in a
composite bit mask.
Returns:
int: The composite bit mask.
"""
return functools.reduce(
lambda x, y: x | y, [z.value for z in enumerations]
)
def get_enumerations_from_bit_mask(enumeration, mask):
"""
A utility function that creates a list of enumeration values from a bit
mask for a specific mask enumeration class.
Args:
enumeration (class): The enumeration class from which to draw
enumeration values.
mask (int): The bit mask from which to identify enumeration values.
Returns:
list: A list of enumeration values corresponding to the bit mask.
"""
return [x for x in enumeration if (x.value & mask) == x.value]
def is_bit_mask(enumeration, potential_mask):
"""
A utility function that checks if the provided value is a composite bit
mask of enumeration values in the specified enumeration class.
Args:
enumeration (class): One of the mask enumeration classes found in this
file. These include:
* Cryptographic Usage Mask
* Protection Storage Mask
* Storage Status Mask
potential_mask (int): A potential bit mask composed of enumeration
values belonging to the enumeration class.
Returns:
True: if the potential mask is a valid bit mask of the mask enumeration
False: otherwise
"""
if not isinstance(potential_mask, six.integer_types):
return False
mask_enumerations = (
CryptographicUsageMask,
ProtectionStorageMask,
StorageStatusMask
)
if enumeration not in mask_enumerations:
return False
mask = 0
for value in [e.value for e in enumeration]:
if (value & potential_mask) == value:
mask |= value
if mask != potential_mask:
return False
return True
def is_enum_value(enumeration, potential_value):
"""
A utility function that checks if the enumeration class contains the
provided value.
Args:
enum_class (class): One of the enumeration classes found in this file.
enumeration (class): One of the enumeration classes found in this file.
potential_value (int, string): A potential value of the enumeration
class.
@ -1830,7 +1903,7 @@ def is_enum_value(enum_class, potential_value):
False: otherwise
"""
try:
enum_class(potential_value)
enumeration(potential_value)
except ValueError:
return False

View File

@ -87,6 +87,63 @@ class TestEnumUtilityFunctions(testtools.TestCase):
def tearDown(self):
super(TestEnumUtilityFunctions, self).tearDown()
def test_get_bit_mask_from_enumerations(self):
self.assertEqual(
7,
enums.get_bit_mask_from_enumerations(
[
enums.StorageStatusMask.ARCHIVAL_STORAGE,
enums.StorageStatusMask.DESTROYED_STORAGE,
enums.StorageStatusMask.ONLINE_STORAGE
]
)
)
def test_get_enumerations_from_bit_mask(self):
expected = [
enums.StorageStatusMask.ARCHIVAL_STORAGE,
enums.StorageStatusMask.DESTROYED_STORAGE,
enums.StorageStatusMask.ONLINE_STORAGE
]
observed = enums.get_enumerations_from_bit_mask(
enums.StorageStatusMask,
7
)
self.assertEqual(len(expected), len(observed))
for x in expected:
self.assertIn(x, observed)
def test_is_bit_mask(self):
self.assertTrue(
enums.is_bit_mask(
enums.StorageStatusMask,
enums.StorageStatusMask.ARCHIVAL_STORAGE.value |
enums.StorageStatusMask.ONLINE_STORAGE.value
)
)
self.assertFalse(
enums.is_bit_mask(
enums.StorageStatusMask,
enums.StorageStatusMask.DESTROYED_STORAGE
)
)
self.assertFalse(
enums.is_bit_mask(
enums.WrappingMethod,
enums.WrappingMethod.ENCRYPT.value
)
)
self.assertFalse(
enums.is_bit_mask(
enums.ProtectionStorageMask,
0x80000000
)
)
def test_is_enum_value(self):
result = enums.is_enum_value(
enums.CryptographicAlgorithm,