mirror of
https://github.com/OpenKMIP/PyKMIP.git
synced 2025-07-03 04:04:22 +02:00
Updating support for the Interval primitive
This change updates the Interval primitive, adding a fresh implementation and documentation. A new unit test suite for the primitive is included.
This commit is contained in:
parent
26e44a07e1
commit
a79e9d7f99
@ -21,6 +21,14 @@ class InvalidKmipEncoding(Exception):
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class InvalidPaddingBytes(Exception):
|
||||||
|
"""
|
||||||
|
An exception raised for errors when processing the padding bytes of
|
||||||
|
primitive encodings.
|
||||||
|
"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
class InvalidPrimitiveLength(Exception):
|
class InvalidPrimitiveLength(Exception):
|
||||||
"""
|
"""
|
||||||
An exception raised for errors when processing primitives with invalid
|
An exception raised for errors when processing primitives with invalid
|
||||||
|
@ -839,8 +839,109 @@ class DateTime(LongInteger):
|
|||||||
return time.ctime(self.value)
|
return time.ctime(self.value)
|
||||||
|
|
||||||
|
|
||||||
class Interval(Integer):
|
class Interval(Base):
|
||||||
|
"""
|
||||||
|
An encodeable object representing an interval of time.
|
||||||
|
|
||||||
def __init__(self, value=None, tag=Tags.DEFAULT):
|
An Interval is one of the KMIP primitive object types. It is encoded as
|
||||||
super(Interval, self).__init__(value, tag)
|
an unsigned, big-endian, 32-bit integer, where the value has a resolution
|
||||||
self.type = Types.INTERVAL
|
of one second. For more information, see Section 9.1 of the KMIP 1.1
|
||||||
|
specification.
|
||||||
|
"""
|
||||||
|
LENGTH = 4
|
||||||
|
|
||||||
|
# Bounds for unsigned 32-bit integers
|
||||||
|
MIN = 0
|
||||||
|
MAX = 4294967296
|
||||||
|
|
||||||
|
def __init__(self, value=0, tag=Tags.DEFAULT):
|
||||||
|
super(Interval, self).__init__(tag, type=Types.INTERVAL)
|
||||||
|
|
||||||
|
self.value = value
|
||||||
|
self.length = Interval.LENGTH
|
||||||
|
|
||||||
|
self.validate()
|
||||||
|
|
||||||
|
def read(self, istream):
|
||||||
|
"""
|
||||||
|
Read the encoding of the Interval from the input stream.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
istream (stream): A buffer containing the encoded bytes of the
|
||||||
|
value of an Interval. Usually a BytearrayStream object.
|
||||||
|
Required.
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
InvalidPrimitiveLength: if the Interval encoding read in has an
|
||||||
|
invalid encoded length.
|
||||||
|
InvalidPaddingBytes: if the Interval encoding read in does not use
|
||||||
|
zeroes for its padding bytes.
|
||||||
|
"""
|
||||||
|
super(Interval, self).read(istream)
|
||||||
|
|
||||||
|
# Check for a valid length before even trying to parse the value.
|
||||||
|
if self.length != Interval.LENGTH:
|
||||||
|
raise exceptions.InvalidPrimitiveLength(
|
||||||
|
"interval length must be {0}".format(Interval.LENGTH))
|
||||||
|
|
||||||
|
# Decode the Interval value and the padding bytes.
|
||||||
|
self.value = unpack('!I', istream.read(Interval.LENGTH))[0]
|
||||||
|
pad = unpack('!I', istream.read(Interval.LENGTH))[0]
|
||||||
|
|
||||||
|
# Verify that the padding bytes are zero bytes.
|
||||||
|
if pad is not 0:
|
||||||
|
raise exceptions.InvalidPaddingBytes("padding bytes must be zero")
|
||||||
|
|
||||||
|
self.validate()
|
||||||
|
|
||||||
|
def write(self, ostream):
|
||||||
|
"""
|
||||||
|
Write the encoding of the Interval to the output stream.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
ostream (stream): A buffer to contain the encoded bytes of an
|
||||||
|
Interval. Usually a BytearrayStream object. Required.
|
||||||
|
"""
|
||||||
|
super(Interval, self).write(ostream)
|
||||||
|
ostream.write(pack('!I', self.value))
|
||||||
|
ostream.write(pack('!I', 0))
|
||||||
|
|
||||||
|
def validate(self):
|
||||||
|
"""
|
||||||
|
Verify that the value of the Interval is valid.
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
TypeError: if the value is not of type int or long
|
||||||
|
ValueError: if the value cannot be represented by an unsigned
|
||||||
|
32-bit integer
|
||||||
|
"""
|
||||||
|
if self.value is not None:
|
||||||
|
if type(self.value) not in six.integer_types:
|
||||||
|
raise TypeError('expected (one of): {0}, observed: {1}'.format(
|
||||||
|
six.integer_types, type(self.value)))
|
||||||
|
else:
|
||||||
|
if self.value > Interval.MAX:
|
||||||
|
raise ValueError(
|
||||||
|
'interval value greater than accepted max')
|
||||||
|
elif self.value < Interval.MIN:
|
||||||
|
raise ValueError('interval value less than accepted min')
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
value = "value={0}".format(self.value)
|
||||||
|
tag = "tag={0}".format(self.tag)
|
||||||
|
return "Interval({0}, {1})".format(value, tag)
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return "{0}".format(self.value)
|
||||||
|
|
||||||
|
def __eq__(self, other):
|
||||||
|
if isinstance(other, Interval):
|
||||||
|
return self.value == other.value
|
||||||
|
else:
|
||||||
|
return NotImplemented
|
||||||
|
|
||||||
|
def __ne__(self, other):
|
||||||
|
if isinstance(other, Interval):
|
||||||
|
return not self.__eq__(other)
|
||||||
|
else:
|
||||||
|
return NotImplemented
|
||||||
|
@ -15,35 +15,211 @@
|
|||||||
|
|
||||||
import testtools
|
import testtools
|
||||||
|
|
||||||
|
from kmip.core import exceptions
|
||||||
|
from kmip.core import primitives
|
||||||
from kmip.core import utils
|
from kmip.core import utils
|
||||||
|
|
||||||
|
|
||||||
class TestInterval(testtools.TestCase):
|
class TestInterval(testtools.TestCase):
|
||||||
|
"""
|
||||||
|
Test suite for the Interval primitive.
|
||||||
|
"""
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
super(TestInterval, self).setUp()
|
super(TestInterval, self).setUp()
|
||||||
self.stream = utils.BytearrayStream()
|
|
||||||
|
# Encoding and value based on Section 9.1.2 of the KMIP 1.1
|
||||||
|
# specification.
|
||||||
|
self.value = 864000
|
||||||
|
self.encoding = (
|
||||||
|
b'\x42\x00\x00\x0A\x00\x00\x00\x04\x00\x0D\x2F\x00\x00\x00\x00'
|
||||||
|
b'\x00')
|
||||||
|
self.encoding_bad_length = (
|
||||||
|
b'\x42\x00\x00\x0A\x00\x00\x00\x05\x00\x0D\x2F\x00\x00\x00\x00'
|
||||||
|
b'\x00')
|
||||||
|
self.encoding_bad_padding = (
|
||||||
|
b'\x42\x00\x00\x0A\x00\x00\x00\x04\x00\x0D\x2F\x00\x00\x00\x00'
|
||||||
|
b'\xFF')
|
||||||
|
|
||||||
def tearDown(self):
|
def tearDown(self):
|
||||||
super(TestInterval, self).tearDown()
|
super(TestInterval, self).tearDown()
|
||||||
|
|
||||||
def test_init(self):
|
def test_init(self):
|
||||||
self.skip('')
|
"""
|
||||||
|
Test that an Interval can be instantiated.
|
||||||
|
"""
|
||||||
|
interval = primitives.Interval(1)
|
||||||
|
self.assertEqual(1, interval.value)
|
||||||
|
|
||||||
def test_init_unset(self):
|
def test_init_unset(self):
|
||||||
self.skip('')
|
"""
|
||||||
|
Test that an Interval can be instantiated with no input.
|
||||||
def test_validate_on_valid(self):
|
"""
|
||||||
self.skip('')
|
interval = primitives.Interval()
|
||||||
|
self.assertEqual(0, interval.value)
|
||||||
def test_validate_on_valid_unset(self):
|
|
||||||
self.skip('')
|
|
||||||
|
|
||||||
def test_validate_on_invalid_type(self):
|
def test_validate_on_invalid_type(self):
|
||||||
self.skip('')
|
"""
|
||||||
|
Test that a TypeError is thrown on input of invalid type (e.g., str).
|
||||||
|
"""
|
||||||
|
self.assertRaises(TypeError, primitives.Interval, 'invalid')
|
||||||
|
|
||||||
|
def test_validate_on_invalid_value_too_big(self):
|
||||||
|
"""
|
||||||
|
Test that a ValueError is thrown on input that is too large.
|
||||||
|
"""
|
||||||
|
self.assertRaises(
|
||||||
|
ValueError, primitives.Interval, primitives.Interval.MAX + 1)
|
||||||
|
|
||||||
|
def test_validate_on_invalid_value_too_small(self):
|
||||||
|
"""
|
||||||
|
Test that a ValueError is thrown on input that is too small.
|
||||||
|
"""
|
||||||
|
self.assertRaises(
|
||||||
|
ValueError, primitives.Interval, primitives.Interval.MIN - 1)
|
||||||
|
|
||||||
def test_read(self):
|
def test_read(self):
|
||||||
self.skip('')
|
"""
|
||||||
|
Test that an Interval can be read from a byte stream.
|
||||||
|
"""
|
||||||
|
stream = utils.BytearrayStream(self.encoding)
|
||||||
|
interval = primitives.Interval()
|
||||||
|
interval.read(stream)
|
||||||
|
self.assertEqual(self.value, interval.value)
|
||||||
|
|
||||||
|
def test_read_on_invalid_length(self):
|
||||||
|
"""
|
||||||
|
Test that an InvalidPrimitiveLength exception is thrown when attempting
|
||||||
|
to decode an Interval with an invalid length.
|
||||||
|
"""
|
||||||
|
stream = utils.BytearrayStream(self.encoding_bad_length)
|
||||||
|
interval = primitives.Interval()
|
||||||
|
self.assertRaises(
|
||||||
|
exceptions.InvalidPrimitiveLength, interval.read, stream)
|
||||||
|
|
||||||
|
def test_read_on_invalid_padding(self):
|
||||||
|
"""
|
||||||
|
Test that an InvalidPaddingBytes exception is thrown when attempting
|
||||||
|
to decode an Interval with invalid padding bytes.
|
||||||
|
"""
|
||||||
|
stream = utils.BytearrayStream(self.encoding_bad_padding)
|
||||||
|
interval = primitives.Interval()
|
||||||
|
self.assertRaises(
|
||||||
|
exceptions.InvalidPaddingBytes, interval.read, stream)
|
||||||
|
|
||||||
def test_write(self):
|
def test_write(self):
|
||||||
self.skip('')
|
"""
|
||||||
|
Test that an Interval can be written to a byte stream.
|
||||||
|
"""
|
||||||
|
stream = utils.BytearrayStream()
|
||||||
|
interval = primitives.Interval(self.value)
|
||||||
|
interval.write(stream)
|
||||||
|
|
||||||
|
result = stream.read()
|
||||||
|
self.assertEqual(len(self.encoding), len(result))
|
||||||
|
self.assertEqual(self.encoding, result)
|
||||||
|
|
||||||
|
def test_repr(self):
|
||||||
|
"""
|
||||||
|
Test that the representation of a Interval is formatted properly.
|
||||||
|
"""
|
||||||
|
long_int = primitives.Interval()
|
||||||
|
value = "value={0}".format(long_int.value)
|
||||||
|
tag = "tag={0}".format(long_int.tag)
|
||||||
|
self.assertEqual(
|
||||||
|
"Interval({0}, {1})".format(value, tag), repr(long_int))
|
||||||
|
|
||||||
|
def test_str(self):
|
||||||
|
"""
|
||||||
|
Test that the string representation of a Interval is formatted
|
||||||
|
properly.
|
||||||
|
"""
|
||||||
|
self.assertEqual("0", str(primitives.Interval()))
|
||||||
|
|
||||||
|
def test_equal_on_equal(self):
|
||||||
|
"""
|
||||||
|
Test that the equality operator returns True when comparing two
|
||||||
|
Intervals.
|
||||||
|
"""
|
||||||
|
a = primitives.Interval(1)
|
||||||
|
b = primitives.Interval(1)
|
||||||
|
|
||||||
|
self.assertTrue(a == b)
|
||||||
|
self.assertTrue(b == a)
|
||||||
|
|
||||||
|
def test_equal_on_equal_and_empty(self):
|
||||||
|
"""
|
||||||
|
Test that the equality operator returns True when comparing two
|
||||||
|
Intervals.
|
||||||
|
"""
|
||||||
|
a = primitives.Interval()
|
||||||
|
b = primitives.Interval()
|
||||||
|
|
||||||
|
self.assertTrue(a == b)
|
||||||
|
self.assertTrue(b == a)
|
||||||
|
|
||||||
|
def test_equal_on_not_equal(self):
|
||||||
|
"""
|
||||||
|
Test that the equality operator returns False when comparing two
|
||||||
|
Intervals with different values.
|
||||||
|
"""
|
||||||
|
a = primitives.Interval(1)
|
||||||
|
b = primitives.Interval(2)
|
||||||
|
|
||||||
|
self.assertFalse(a == b)
|
||||||
|
self.assertFalse(b == a)
|
||||||
|
|
||||||
|
def test_equal_on_type_mismatch(self):
|
||||||
|
"""
|
||||||
|
Test that the equality operator returns False when comparing a
|
||||||
|
Interval to a non-Interval object.
|
||||||
|
"""
|
||||||
|
a = primitives.Interval()
|
||||||
|
b = 'invalid'
|
||||||
|
|
||||||
|
self.assertFalse(a == b)
|
||||||
|
self.assertFalse(b == a)
|
||||||
|
|
||||||
|
def test_not_equal_on_equal(self):
|
||||||
|
"""
|
||||||
|
Test that the inequality operator returns False when comparing
|
||||||
|
two Intervals with the same values.
|
||||||
|
"""
|
||||||
|
a = primitives.Interval(1)
|
||||||
|
b = primitives.Interval(1)
|
||||||
|
|
||||||
|
self.assertFalse(a != b)
|
||||||
|
self.assertFalse(b != a)
|
||||||
|
|
||||||
|
def test_not_equal_on_equal_and_empty(self):
|
||||||
|
"""
|
||||||
|
Test that the inequality operator returns False when comparing
|
||||||
|
two Intervals.
|
||||||
|
"""
|
||||||
|
a = primitives.Interval()
|
||||||
|
b = primitives.Interval()
|
||||||
|
|
||||||
|
self.assertFalse(a != b)
|
||||||
|
self.assertFalse(b != a)
|
||||||
|
|
||||||
|
def test_not_equal_on_not_equal(self):
|
||||||
|
"""
|
||||||
|
Test that the inequality operator returns True when comparing two
|
||||||
|
Intervals with different values.
|
||||||
|
"""
|
||||||
|
a = primitives.Interval(1)
|
||||||
|
b = primitives.Interval(2)
|
||||||
|
|
||||||
|
self.assertTrue(a != b)
|
||||||
|
self.assertTrue(b != a)
|
||||||
|
|
||||||
|
def test_not_equal_on_type_mismatch(self):
|
||||||
|
"""
|
||||||
|
Test that the inequality operator returns True when comparing a
|
||||||
|
Interval to a non-Interval object.
|
||||||
|
"""
|
||||||
|
a = primitives.Interval()
|
||||||
|
b = 'invalid'
|
||||||
|
|
||||||
|
self.assertTrue(a != b)
|
||||||
|
self.assertTrue(b != a)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user