def test_address_space_cannot_describe_net_if_no_previous_supernet(self): """A network can only be described if a supernet exists.""" address_space = AddressSpace(strict_=True) for data in ( ("203.0.113.0/24", "an IPv4 test net"), ("2000::/3", "Current loose global IPv6 network"), ("192.0.2.0/24", "another IPv4 test net"), ("fe80::/64", "IPv6 link-local network"), ("10.123.0.0/16", "A private IPv4 address"), ("2001:db8:ab00::/40", "An IPv6 network in doc range"), ): with self.subTest(data=data): no_previous_supernet = False try: address_space.describe( ip_parameter=data[0], description=data[1], ) except StrictSupernetError: no_previous_supernet = True self.assertTrue( no_previous_supernet, "If strict address space, can describe networks only " "if supernet already exists", )
def test_address_space_cannot_describe_address_if_no_previous_net(self): """An address can only be described if a supernet exists.""" address_space = AddressSpace(strict_=True) for data in ( ("203.0.113.128", "a IPv4 test net address"), ("2000::", "A 6 characts short IPv6 address"), ("192.0.2.192", "another IPv4 test net address"), ("fe80::abcd", "an IPv6 link-local address"), ("10.123.45.67", "A private IPv4 address"), ("2001:db8:abcd::1234", "An IPv6 address in doc range"), ): with self.subTest(data=data): no_previous_supernet = False try: address_space.describe( ip_parameter=data[0], description=data[1], ) except StrictSupernetError: no_previous_supernet = True self.assertTrue( no_previous_supernet, "If strict address space, can describe address only " "if supernet already exists", )
def test_delegated_network_cannot_describe_subnet_as_new(self): """Inserting delegation with present supernet must raise exception.""" for strict in (False, True): with self.subTest(strict=strict): address_space = AddressSpace(strict_=strict) for data in ( ("2001:db8::/32", "2001:db8::/48"), ("203.0.113.0/24", "203.0.113.0/27"), ("fdab:cdef:1234::/48", "fdab:cdef:1234:5678::/64"), ("192.0.2.0/24", "192.0.2.128/26"), ("::/0", "::ab00/126"), ("0.0.0.0/0", "10.0.0.0/8"), ): with self.subTest(data=data): self.assertTrue( address_space.describe_new_delegated_network( network_parameter=data[0], description="actual delegation", ), "Describe a network without a previous inserted " "supernet", ) supernet_detected = False try: address_space.describe_new_delegated_network( network_parameter=data[1], description="trying subnet as delegated", ) except StrictSupernetError: supernet_detected = True self.assertTrue( supernet_detected, "If inserting delegated network, no supernet " "should be present, for strict and non strict " "address spaces")
def test_address_space_strict_cannot_be_assigned_to(self): """AddressSpace's strict member cannot be assigned.""" address_space = AddressSpace() cannot_be_assigned = False try: address_space.strict = False except AttributeError: cannot_be_assigned = True self.assertTrue( cannot_be_assigned, "AddressSpace instance' strict cannot be assigned", )
def test_delegated_network_no_empty_arguments(self): """New delegated network method with no empty argument list.""" for strict in (False, True): with self.subTest(strict=strict): address_space = AddressSpace(strict_=strict) no_empty_arguments = False try: address_space.describe_new_delegated_network() except TypeError: no_empty_arguments = True self.assertTrue( no_empty_arguments, "Empty arguments should not be accepted in " "describe_new_delegated_network", )
def test_delegated_network_keyword_only_no_positional_args(self): """New delegated network must use keyword-only args.""" for strict in (False, True): with self.subTest(strict=strict): address_space = AddressSpace(strict_=strict) no_positional_arguments = False try: address_space.describe_new_delegated_network( "2001:db8::/32", "IPv6 documentation network space") except TypeError: no_positional_arguments = True self.assertTrue( no_positional_arguments, "No positional argument should be accepted in " "describe_new_delegated_network", )
def test_address_space_strict(self): """Retrieve AddressSpace's strict member.""" address_space = AddressSpace() self.assertIsInstance( address_space.strict, bool, "AddressSpace instance expected to have " "a strict boolean member")
def test_address_space_default_strict_should_be_true(self): """Default value for AddressSpace's strict member should be True.""" address_space = AddressSpace() self.assertIs( address_space.strict, True, "AddressSpace's default strict value expected to be True.", )
def test_address_space_init_cannot_accept_positional_arguments(self): """init method as keyword only, without positional parameters.""" no_positional_arguments = False try: AddressSpace(False) except TypeError: no_positional_arguments = True self.assertTrue( no_positional_arguments, "No positional argument should be accepted in __init__", )
def test_delegated_network_cannot_insert_same_as_new(self): """Inserting delegation with same net must raise exception.""" for net in ( "2001:db8::/32", "2001:db8::/48", "203.0.113.0/24", "203.0.113.0/27", "fdab:cdef:1234::/48", "fdab:cdef:1234:5678::/64", "192.0.2.0/24", "192.0.2.128/26", "::/0", "::ab00/126", "0.0.0.0/0", "10.0.0.0/8", ): with self.subTest(net=net): for strict in (False, True): with self.subTest(strict=strict): address_space = AddressSpace(strict_=strict) self.assertTrue( address_space.describe_new_delegated_network( network_parameter=net, description="actual delegation", ), "Describe a network without a previous inserted " "supernet", ) same_net = False try: address_space.describe_new_delegated_network( network_parameter=net, description="trying to insert same as new", ) except SameDelegationAsNewError: same_net = True self.assertTrue( same_net, "Cannot insert same delegation as new more than " "once", )
class AddressSpace_default_export_TestCase(unittest.TestCase): """Tests related to AddressSpace's data export.""" def setUp(self): self.address_space = AddressSpace() self.exported_data = self.address_space.export_data() def test_address_space_export_for_default_instance(self): """Default instance should evaluate to True.""" self.assertTrue(self.exported_data, "exported data should truth evaluate to True") def test_address_space_export_for_default_instance_should_be_dict(self): """Default instance should return dict with default values.""" self.assertIsInstance(self.exported_data, dict, "exported data should be a dict") def test_address_space_export_for_default_instance_should_have_keys(self): """Default instance should return dict with keys.""" for key in ("description", "nested_ip_objects"): with self.subTest(key=key): self.assertIn(key, self.exported_data, "exported data should have specific key") def test_address_space_export_for_default_instance_exact_keys(self): """Default instance should return dict with keys.""" keys = set({"description", "nested_ip_objects"}) self.assertEqual(keys, set(self.exported_data), "exported data should have exactly required keys") def test_address_space_export_for_default_instance_values(self): """Default instance export data dict should have two dicts.""" for key in ("description", "nested_ip_objects"): with self.subTest(key=key): self.assertIsInstance(self.exported_data[key], dict, "exported data dict should have dicts") def test_address_space_export_description_should_be_the_same(self): """Exported description should be the same as instance's.""" self.assertEqual( self.exported_data["description"], self.address_space._AddressSpace__description, "Exported description should be the same as instance's.", ) def test_address_space_export_nested_ip_objects_keys(self): """Nested IP object keys validation.""" self.assertEqual( set(self.exported_data["nested_ip_objects"]), set(self.address_space._AddressSpace__networks).union( set(self.address_space._AddressSpace__addresses)), "Exported nested IP object should have the same keys as " "union of networks and address keys.")
def test_delegated_network_into_address_space(self): """Inserts a network without supernet present in address space.""" for strict in (False, True): with self.subTest(strict_=strict): address_space = AddressSpace(strict_=strict) for data in ( ("2001:db8::/32", "IPv6 documentation network space"), ("203.0.113.0/24", "one of IPv4 test net"), ("fdab:cdef:1234::/48", "an IPv6 unique-local net"), ("192.0.2.0/24", "another IPv4 test net"), ("::/0", "whole IPv6 address space"), ("0.0.0.0/0", "whole IPv4 address space"), ): with self.subTest(data=data): self.assertTrue( address_space.describe_new_delegated_network( network_parameter=data[0], description=data[1], ), "Describe a network without a previous inserted " "supernet", )
class AddressSpace_description_TestCase(unittest.TestCase): """Tests for description related methods.""" def setUp(self): """Set up test fixtures with new AddressSpace.""" self.address_space = AddressSpace(strict_=False) def test_address_space_as_AddressSpace(self): """Validate if address_space is instance of AddressSpace.""" self.assertIsInstance(self.address_space, AddressSpace) def test_describe_no_empty_arguments(self): """describe method with no empty argument list.""" no_empty_arguments = False try: self.address_space.describe() except TypeError: no_empty_arguments = True self.assertTrue( no_empty_arguments, "Empty arguments should not be accepted in describe", ) def test_describe_keyword_only_no_positional_arguments(self): """describe method as keyword only, without positional parameters.""" no_positional_arguments = False try: self.address_space.describe("203.0.113.128", "test net address") except TypeError: no_positional_arguments = True self.assertTrue( no_positional_arguments, "No positional argument should be accepted in describe", ) def test_describe_address(self): """Add valid IP address with non-empty str description.""" for parameters in ( ("123.123.123.123", "123 is nice"), ("203.0.113.129", "Second subnet gateway"), ("192.0.2.123", "123 is nice, test net"), ("2001:db8::abcd:ef12", "ipv6 doc address"), ("2000::", "first global address for now"), ("fe80::", "even link-local?"), ): with self.subTest(parameters=parameters): self.assertIs( self.address_space.describe(ip_parameter=parameters[0], description=parameters[1]), True, ) def test_describe_network(self): """Add valid IP network with non-empty str description.""" for parameters in ( ("10.0.0.0/16", "a private IPv4 network"), ("203.0.113.128/25", "part of a test net"), ("0.0.0.0/0", "whole IPv4 address space as network"), ("2001:db8:1234:5678::/64", "a documentation IPv6 network"), ("fe80::/64", "IPv6 link-local network"), ("fd01:2345:6789::/48", "a ~random~ IPv6 unique-local network"), ("::/0", "whole IPv6 address space as network"), ): with self.subTest(parameters=parameters): self.assertIs( self.address_space.describe(description=parameters[1], ip_parameter=parameters[0]), True, ) def test_describe_ip_parameter_not_valid_typeerror(self): """Invalid IP parameter should raise TypeError.""" for invalid_ in (None, 123, set([3, 2, 1])): with self.subTest(invalid_=invalid_): invalid_ip_parameter = False try: self.address_space.describe( description="invalid ip parameter", ip_parameter=invalid_, ) except TypeError: invalid_ip_parameter = True self.assertTrue( invalid_ip_parameter, "Invalid IP parameter should raise TypeError", ) def test_describe_description_not_str_typeerror(self): """Non-str description should raise TypeError.""" for non_str in (None, 123, set([1, 2, 3])): with self.subTest(non_str=non_str): non_str_description = False try: self.address_space.describe(ip_parameter="123.123.123.123", description=non_str) except TypeError: non_str_description = True self.assertTrue( non_str_description, "Non str description should raise TypeError", ) def test_describe_empty_str_valueerror(self): """Empty str description should raise ValueError.""" empty_str_description = False try: self.address_space.describe(ip_parameter="123.123.123.123", description="") except ValueError: empty_str_description = True self.assertTrue( empty_str_description, "Empty str description should raise ValueError", ) def test_description_no_empty_arguments(self): """description method with no empty argument list.""" no_empty_arguments = False try: self.address_space.description() except TypeError: no_empty_arguments = True self.assertTrue( no_empty_arguments, "Empty arguments should not be accepted in description", ) def test_description_ip_parameter_not_valid_typeerror(self): """Invalid IP parameter should raise TypeError.""" for invalid_ in (None, 123, set([2, 3, 1])): with self.subTest(invalid_=invalid_): invalid_ip_parameter = False try: self.address_space.description(ip_parameter=invalid_) except TypeError: invalid_ip_parameter = True self.assertTrue( invalid_ip_parameter, "Invalid IP parameter should raise TypeError", ) def test_describe_then_description(self): """describe then description of IP object should return same str.""" for describe_pair in ( ("203.0.113.128/25", "should be the same"), ("2001:db8::2018:7:12", "hey! an IPv6 Address"), ("0.0.0.0", "address 0 for ipv4"), ): with self.subTest(describe_pair=describe_pair): self.address_space.describe(description=describe_pair[1], ip_parameter=describe_pair[0]) self.assertEqual( self.address_space.description(describe_pair[0]), describe_pair[1], ) def test_describe_network_then_empty_address_description(self): """describe an IP network and retrieve empty str description of an address if it is in network range and not explicitly described.""" for data in ( ("192.0.2.0/24", "a ipv4 test net", "192.0.2.128"), ("192.0.2.0/24", "same net, new address", "192.0.2.192"), ("10.0.0.0/8", "a large private net", "10.123.45.67"), ("fe80::/64", "link-local net", "fe80::ab:cdef"), ("2001:db8:abcd::/48", "ipv6 doc net", "2001:db8:abcd::123"), ("abcd::/16", "currently outside global ipv6", "abcd:123::abc"), ): with self.subTest(data=data): self.address_space.describe(ip_parameter=data[0], description=data[1]) self.assertEqual(self.address_space.description(data[2]), str("")) def test_describe_network_then_empty_subnet_description(self): """describe an IP network and retrieve empty str description of an subnet if it is in network range and not explicitly described.""" for data in ( ("192.0.2.0/24", "a ipv4 test net", "192.0.2.0/25"), ("192.0.2.0/24", "same net, new subnet", "192.0.2.128/25"), ("10.0.0.0/8", "a large private net", "10.123.0.0/16"), ("fe80::/64", "link-local net", "fe80::/126"), ("2001:db8:abcd::/48", "ipv6 doc net", "2001:db8:abcd:123::/64"), ("abcd::/16", "currently outside global ipv6", "abcd:123::/32"), ): with self.subTest(data=data): self.address_space.describe(ip_parameter=data[0], description=data[1]) self.assertEqual(self.address_space.description(data[2]), str("")) def test_valid_address_not_in_any_net_should_return_none(self): """description should return None if a valid address is not described and not in any network.""" for existing_net in ( ipaddress.IPv4Network("192.0.2.0/24"), ipaddress.ip_network("203.0.113.0/25"), "10.0.0.0/16", "fe80::/64", ipaddress.ip_network("2001:db8::/48"), ipaddress.IPv6Network("0:abcd::/32"), ): self.address_space.describe(description="dull description", ip_parameter=existing_net) for outside_address in ( "192.0.3.128", ipaddress.ip_address("203.0.113.128"), ipaddress.IPv4Address("10.128.0.0"), "0.0.0.0", ipaddress.ip_address("fe80:123::abcd"), ipaddress.IPv6Address("2001:db8:abcd::"), "::", ): with self.subTest(outside_address=outside_address): self.assertIs(self.address_space.description(outside_address), None) def test_valid_networks_not_as_any_subnet_should_return_none(self): """description should return None if a valid network is not described and not subnet of any network.""" for existing_net in ( ipaddress.IPv4Network("192.0.2.0/24"), ipaddress.ip_network("203.0.113.0/25"), "10.0.0.0/16", "fe80::/64", ipaddress.ip_network("2001:db8::/48"), ipaddress.IPv6Network("0:abcd::/32"), ): self.address_space.describe(description="dull description", ip_parameter=existing_net) for outside_network in ( "192.0.3.128/25", ipaddress.ip_network("203.0.113.128/26"), ipaddress.IPv4Network("10.128.0.0/9"), "0.0.0.0/0", ipaddress.ip_network("fe80:123::/32"), ipaddress.IPv6Network("2001:db8:abcd::/48"), "::/0", ): with self.subTest(outside_network=outside_network): self.assertIs(self.address_space.description(outside_network), None)
def setUp(self): """Set up test fixtures with new AddressSpace.""" self.address_space = AddressSpace(strict_=False)
def setUp(self): self.address_space = AddressSpace(strict_=False)
def setUp(self): """Export AddressSpace's data.""" self.delegated_tuples = ( ("2001:db8::/32", "IPv6 documentation network space"), ("203.0.113.0/24", "one of IPv4 test net"), ("fdab:cdef:1234::/48", "an IPv6 unique-local net"), ("192.0.2.0/24", "another IPv4 test net"), ) self.subnet_tuples = ( ("2001:db8::/48", "zeroed doc subnet"), ("2001:db8:1234::/48", "digit doc subnet"), ("2001:db8:abcd::/48", "letter doc subnet"), ("203.0.113.0/26", "a 1/4 test subnet"), ("203.0.113.128/27", "1/8 subnet"), ("fdab:cdef:1234:5678::/64", "digit unique local subnet"), ("fdab:cdef:1234:abcd::/64", "letter unique local subnet"), ("192.0.2.64/26", "another 1/4 test subnet"), ("192.0.2.128/25", "1/2 of a test subnet"), ) self.direct_address_tuples = ( ("2001:db8:9876:5432:10::", "direct IPv6 doc address"), ("203.0.113.200", "direct address of a IPv4 test net"), ("fdab:cdef:1234:c001::abcd", "direct IPv6 unique-local address"), ("192.0.2.12", "direct address of another IPv4 test net"), ) self.subnet_address_tuples = ( ("2001:db8::123", "digit address of zeroed doc subnet"), ("2001:db8::abc", "letter address of zeroed doc subnet"), ("2001:db8:1234::abc:123", "mixed address of digit doc subnet"), ("2001:db8:1234::f00:ba", "letter address of digit doc subnet"), ("2001:db8:abcd:abcd::abcd", "abcd address of letter doc subnet"), ("2001:db8:abcd:1234:1234::", "1234 address of letter doc subnet"), ("203.0.113.0", "first address of a 1/4 test subnet"), ("203.0.113.63", "last address of a 1/4 test subnet"), ("203.0.113.130", " almost at begining of 1/8 subnet"), ("203.0.113.150", " almost at the end of 1/8 subnet"), ("fdab:cdef:1234:5678::1234:5678", "12345678 address"), ("fdab:cdef:1234:5678::abcd:abcd", "abcdabcd address"), ("fdab:cdef:1234:abcd::7654:321", "reverse number address"), ("fdab:cdef:1234:abcd::fe:dcba", "reverse letter address"), ("192.0.2.64", "first of another 1/4 test subnet"), ("192.0.2.127", "last of another 1/4 test subnet"), ("192.0.2.200", "200 of 1/2 of a test subnet"), ("192.0.2.234", "234 of 1/2 of a test subnet"), ) self.address_spaces = dict() for strict in (False, True): self.address_spaces[strict] = AddressSpace(strict_=strict) for delegated_data in self.delegated_tuples: self.address_spaces[strict].describe_new_delegated_network( network_parameter=delegated_data[0], description=delegated_data[1], ) for subnet_data in self.subnet_tuples: self.address_spaces[strict].describe( ip_parameter=subnet_data[0], description=subnet_data[1], ) for address_data in (*self.direct_address_tuples, *self.subnet_address_tuples): self.address_spaces[strict].describe( ip_parameter=address_data[0], description=address_data[1], )
def setUp(self): self.address_space = AddressSpace() self.exported_data = self.address_space.export_data()
class AddressSpace_delete_TestCase(unittest.TestCase): """Tests related to delete method in AddressSpace.""" def setUp(self): self.address_space = AddressSpace(strict_=False) def test_delete_no_empty_arguments(self): """delete method with no empty argument list.""" no_empty_arguments = False try: self.address_space.delete() except TypeError: no_empty_arguments = True self.assertTrue( no_empty_arguments, "Empty arguments should not be accepted in delete", ) def test_delete_keyword_only_no_positional_arguments(self): """delete method as keyword only, without positional parameters.""" no_positional_arguments = False try: self.address_space.delete("203.0.113.128", True) except TypeError: no_positional_arguments = True self.assertTrue( no_positional_arguments, "No positional argument should be accepted in delete", ) def test_delete_trying_to_delete_object_not_in_space_error_raise(self): """Trying to delete an IP object not in space should raise Error.""" no_ip_object = False try: self.address_space.delete( ip_parameter="203.0.113.128", cascade=True, ) except IPObjectNotInSpaceError: no_ip_object = True self.assertTrue( no_ip_object, "Cannot delete IP object without explicit description", ) def test_delete_deleting_object_in_space_returns_true(self): """Deleting a described IP object should return True.""" for parameter_description in ( ("203.0.113.128", "an IPv4 test net address"), ("2001:db8:abcd::/48", "an IPv6 doc subnet"), ("123.123.123.123", "123 is nice"), ("203.0.113.129", "Second subnet gateway"), ("192.0.2.123", "123 is nice, test net"), ("2001:db8::abcd:ef12", "ipv6 doc address"), ("2000::", "first global address for now"), ("fe80::", "even link-local?"), ("10.0.0.0/16", "a private IPv4 network"), ("203.0.113.128/25", "part of a test net"), ("0.0.0.0/0", "whole IPv4 address space as network"), ("2001:db8:1234:5678::/64", "a documentation IPv6 network"), ("fe80::/64", "IPv6 link-local network"), ("fd01:2345:6789::/48", "a ~random~ IPv6 unique-local network"), ("::/0", "whole IPv6 address space as network"), ): with self.subTest(parameter_description=parameter_description): self.assertTrue( self.address_space.describe( ip_parameter=parameter_description[0], description=parameter_description[1], )) self.assertTrue( self.address_space.delete( ip_parameter=parameter_description[0], cascade=True, ), "Deleting a described IP object should return True.", ) def test_delete_after_deleting_object_description_should_be_none(self): """Description of a deleted IP object should return None if no other IP object.""" for parameter_description in ( ("203.0.113.128", "an IPv4 test net address"), ("2001:db8:abcd::/48", "an IPv6 doc subnet"), ("123.123.123.123", "123 is nice"), ("203.0.113.129", "Second subnet gateway"), ("192.0.2.123", "123 is nice, test net"), ("2001:db8::abcd:ef12", "ipv6 doc address"), ("2000::", "first global address for now"), ("fe80::", "even link-local?"), ("10.0.0.0/16", "a private IPv4 network"), ("203.0.113.128/25", "part of a test net"), ("0.0.0.0/0", "whole IPv4 address space as network"), ("2001:db8:1234:5678::/64", "a documentation IPv6 network"), ("fe80::/64", "IPv6 link-local network"), ("fd01:2345:6789::/48", "a ~random~ IPv6 unique-local network"), ("::/0", "whole IPv6 address space as network"), ): with self.subTest(parameter_description=parameter_description): self.assertTrue( self.address_space.describe( ip_parameter=parameter_description[0], description=parameter_description[1], )) self.assertTrue( self.address_space.delete( ip_parameter=parameter_description[0], cascade=True, ), "Deleting a described IP object should return True.", ) self.assertIs( self.address_space.description(parameter_description[0]), None, "No IP object, so description should be None", )