summaryrefslogtreecommitdiffstats
path: root/netaddr/tests/ip/test_ip_v4.py
diff options
context:
space:
mode:
Diffstat (limited to 'netaddr/tests/ip/test_ip_v4.py')
-rw-r--r--netaddr/tests/ip/test_ip_v4.py547
1 files changed, 547 insertions, 0 deletions
diff --git a/netaddr/tests/ip/test_ip_v4.py b/netaddr/tests/ip/test_ip_v4.py
new file mode 100644
index 0000000..ea6cc31
--- /dev/null
+++ b/netaddr/tests/ip/test_ip_v4.py
@@ -0,0 +1,547 @@
+import pickle
+import types
+import random
+import sys
+
+import pytest
+
+from netaddr import IPAddress, IPNetwork, INET_ATON, INET_PTON, spanning_cidr, AddrFormatError, ZEROFILL, Z, P, NOHOST
+
+
+def test_ipaddress_v4():
+ ip = IPAddress('192.0.2.1')
+ assert ip.version == 4
+ assert repr(ip) == "IPAddress('192.0.2.1')"
+ assert str(ip) == '192.0.2.1'
+ assert ip.format() == '192.0.2.1'
+ assert int(ip) == 3221225985
+ assert hex(ip) == '0xc0000201'
+ if sys.version_info[0] > 2:
+ assert bytes(ip) == b'\xc0\x00\x02\x01'
+ assert ip.bin == '0b11000000000000000000001000000001'
+ assert ip.bits() == '11000000.00000000.00000010.00000001'
+ assert ip.words == (192, 0, 2, 1)
+
+
+@pytest.mark.parametrize(
+ ('value', 'ipaddr', 'network', 'cidr', 'broadcast', 'netmask', 'hostmask', 'size'), [
+ (
+ '192.0.2.1',
+ IPAddress('192.0.2.1'),
+ IPAddress('192.0.2.1'),
+ IPNetwork('192.0.2.1/32'),
+ None,
+ IPAddress('255.255.255.255'),
+ IPAddress('0.0.0.0'),
+ 1,
+ ),
+ (
+ '192.0.2.0/24',
+ IPAddress('192.0.2.0'),
+ IPAddress('192.0.2.0'),
+ IPNetwork('192.0.2.0/24'),
+ IPAddress('192.0.2.255'),
+ IPAddress('255.255.255.0'),
+ IPAddress('0.0.0.255'),
+ 256
+ ),
+ (
+ '192.0.3.112/22',
+ IPAddress('192.0.3.112'),
+ IPAddress('192.0.0.0'),
+ IPNetwork('192.0.0.0/22'),
+ IPAddress('192.0.3.255'),
+ IPAddress('255.255.252.0'),
+ IPAddress('0.0.3.255'),
+ 1024
+ ),
+ ])
+def test_ipnetwork_v4(value, ipaddr, network, cidr, broadcast, netmask, hostmask, size):
+ net = IPNetwork(value)
+ assert net.ip == ipaddr
+ assert net.network == network
+ assert net.cidr == cidr
+ assert net.broadcast == broadcast
+ assert net.netmask == netmask
+ assert net.hostmask == hostmask
+ assert net.size == size
+
+
+def test_ipnetwork_list_operations_v4():
+ ip = IPNetwork('192.0.2.16/29')
+ assert len(ip) == 8
+
+ ip_list = list(ip)
+ assert len(ip_list) == 8
+
+ assert ip_list == [
+ IPAddress('192.0.2.16'),
+ IPAddress('192.0.2.17'),
+ IPAddress('192.0.2.18'),
+ IPAddress('192.0.2.19'),
+ IPAddress('192.0.2.20'),
+ IPAddress('192.0.2.21'),
+ IPAddress('192.0.2.22'),
+ IPAddress('192.0.2.23'),
+ ]
+
+
+def test_ipnetwork_index_operations_v4():
+ ip = IPNetwork('192.0.2.16/29')
+ assert ip[0] == IPAddress('192.0.2.16')
+ assert ip[1] == IPAddress('192.0.2.17')
+ assert ip[-1] == IPAddress('192.0.2.23')
+
+
+def test_ipnetwork_slice_operations_v4():
+ ip = IPNetwork('192.0.2.16/29')
+
+ assert isinstance(ip[0:4], types.GeneratorType)
+
+ assert list(ip[0:4]) == [
+ IPAddress('192.0.2.16'),
+ IPAddress('192.0.2.17'),
+ IPAddress('192.0.2.18'),
+ IPAddress('192.0.2.19'),
+ ]
+
+ assert list(ip[0::2]) == [
+ IPAddress('192.0.2.16'),
+ IPAddress('192.0.2.18'),
+ IPAddress('192.0.2.20'),
+ IPAddress('192.0.2.22'),
+ ]
+
+ assert list(ip[-1::-1]) == [
+ IPAddress('192.0.2.23'),
+ IPAddress('192.0.2.22'),
+ IPAddress('192.0.2.21'),
+ IPAddress('192.0.2.20'),
+ IPAddress('192.0.2.19'),
+ IPAddress('192.0.2.18'),
+ IPAddress('192.0.2.17'),
+ IPAddress('192.0.2.16'),
+]
+
+
+def test_ipnetwork_sort_order():
+ ip_list = list(IPNetwork('192.0.2.128/28'))
+ random.shuffle(ip_list)
+ assert sorted(ip_list) == [
+ IPAddress('192.0.2.128'),
+ IPAddress('192.0.2.129'),
+ IPAddress('192.0.2.130'),
+ IPAddress('192.0.2.131'),
+ IPAddress('192.0.2.132'),
+ IPAddress('192.0.2.133'),
+ IPAddress('192.0.2.134'),
+ IPAddress('192.0.2.135'),
+ IPAddress('192.0.2.136'),
+ IPAddress('192.0.2.137'),
+ IPAddress('192.0.2.138'),
+ IPAddress('192.0.2.139'),
+ IPAddress('192.0.2.140'),
+ IPAddress('192.0.2.141'),
+ IPAddress('192.0.2.142'),
+ IPAddress('192.0.2.143'),
+ ]
+
+def test_ipaddress_and_ipnetwork_canonical_sort_order_by_version():
+ ip_list = [
+ IPAddress('192.0.2.130'),
+ IPNetwork('192.0.2.128/28'),
+ IPAddress('::'),
+ IPNetwork('192.0.3.0/24'),
+ IPNetwork('192.0.2.0/24'),
+ IPNetwork('fe80::/64'),
+ IPNetwork('172.24/12'),
+ IPAddress('10.0.0.1'),
+ ]
+
+ random.shuffle(ip_list)
+ ip_list.sort()
+
+ assert ip_list == [
+ IPAddress('10.0.0.1'),
+ IPNetwork('172.24.0.0/12'),
+ IPNetwork('192.0.2.0/24'),
+ IPNetwork('192.0.2.128/28'),
+ IPAddress('192.0.2.130'),
+ IPNetwork('192.0.3.0/24'),
+ IPAddress('::'),
+ IPNetwork('fe80::/64'),
+ ]
+
+
+def test_ipnetwork_v4_constructor():
+ assert IPNetwork('192.168/16') == IPNetwork('192.168.0.0/16')
+ assert IPNetwork('192.168.0.15') == IPNetwork('192.168.0.15/32')
+ assert IPNetwork('192.168') == IPNetwork('192.168.0.0/32')
+ assert IPNetwork('192.168', implicit_prefix=True) == IPNetwork('192.168.0.0/24')
+ assert IPNetwork('192.168', True) == IPNetwork('192.168.0.0/24')
+ assert IPNetwork('10.0.0.1', True) == IPNetwork('10.0.0.1/8')
+
+
+def test_ipaddress_integer_operations_v4():
+ assert IPAddress('192.0.2.0') + 1 == IPAddress('192.0.2.1')
+ assert 1 + IPAddress('192.0.2.0') == IPAddress('192.0.2.1')
+ assert IPAddress('192.0.2.1') - 1 == IPAddress('192.0.2.0')
+ assert IPAddress('192.0.0.0') + IPAddress('0.0.0.42') == IPAddress('192.0.0.42')
+ assert IPAddress('192.0.0.42') - IPAddress('0.0.0.42') == IPAddress('192.0.0.0')
+
+ with pytest.raises(IndexError):
+ 1 - IPAddress('192.0.2.1')
+
+ ip = IPAddress('10.0.0.1')
+ ip += 1
+ assert ip == IPAddress('10.0.0.2')
+
+ ip -= 1
+ assert ip == IPAddress('10.0.0.1')
+
+ ip += IPAddress('0.0.0.42')
+ assert ip == IPAddress('10.0.0.43')
+
+ ip -= IPAddress('0.0.0.43')
+ assert ip == IPAddress('10.0.0.0')
+
+ # Negative increments around address range boundaries.
+ ip = IPAddress('0.0.0.0')
+ with pytest.raises(IndexError):
+ ip += -1
+
+ ip = IPAddress('255.255.255.255')
+ with pytest.raises(IndexError):
+ ip -= -1
+
+
+def test_ipaddress_binary_operations_v4():
+ assert IPAddress('192.0.2.15') & IPAddress('255.255.255.0') == IPAddress('192.0.2.0')
+ assert IPAddress('255.255.0.0') | IPAddress('0.0.255.255') == IPAddress('255.255.255.255')
+ assert IPAddress('255.255.0.0') ^ IPAddress('255.0.0.0') == IPAddress('0.255.0.0')
+ assert IPAddress('1.2.3.4').packed == '\x01\x02\x03\x04'.encode('ascii')
+
+
+def test_ipnetwork_slices_v4():
+ assert list(IPNetwork('192.0.2.0/29')[0:-1]) == [
+ IPAddress('192.0.2.0'),
+ IPAddress('192.0.2.1'),
+ IPAddress('192.0.2.2'),
+ IPAddress('192.0.2.3'),
+ IPAddress('192.0.2.4'),
+ IPAddress('192.0.2.5'),
+ IPAddress('192.0.2.6'),
+ ]
+
+ assert list(IPNetwork('192.0.2.0/29')[::-1]) == [
+ IPAddress('192.0.2.7'),
+ IPAddress('192.0.2.6'),
+ IPAddress('192.0.2.5'),
+ IPAddress('192.0.2.4'),
+ IPAddress('192.0.2.3'),
+ IPAddress('192.0.2.2'),
+ IPAddress('192.0.2.1'),
+ IPAddress('192.0.2.0'),
+ ]
+
+def test_iterhosts_v4():
+ assert list(IPNetwork('192.0.2.0/29').iter_hosts()) == [
+ IPAddress('192.0.2.1'),
+ IPAddress('192.0.2.2'),
+ IPAddress('192.0.2.3'),
+ IPAddress('192.0.2.4'),
+ IPAddress('192.0.2.5'),
+ IPAddress('192.0.2.6'),
+ ]
+
+
+ assert list(IPNetwork("192.168.0.0/31")) == [
+ IPAddress('192.168.0.0'),
+ IPAddress('192.168.0.1'),
+ ]
+
+ assert list(IPNetwork("192.168.0.0/31").iter_hosts()) == [IPAddress('192.168.0.0'),IPAddress('192.168.0.1')]
+ assert list(IPNetwork("192.168.0.0/32").iter_hosts()) == [IPAddress('192.168.0.0')]
+
+
+def test_ipaddress_boolean_evaluation_v4():
+ assert not bool(IPAddress('0.0.0.0'))
+ assert bool(IPAddress('0.0.0.1'))
+ assert bool(IPAddress('255.255.255.255'))
+
+
+def test_ipnetwork_boolean_evaluation_v4():
+ assert bool(IPNetwork('0.0.0.0/0'))
+
+
+def test_ipnetwork_equality_v4():
+ assert IPNetwork('192.0.2.0/255.255.254.0') == IPNetwork('192.0.2.0/23')
+ assert IPNetwork('192.0.2.65/255.255.254.0') == IPNetwork('192.0.2.0/23')
+ assert IPNetwork('192.0.2.65/255.255.254.0') == IPNetwork('192.0.2.65/23')
+ assert IPNetwork('192.0.2.65/255.255.255.0') != IPNetwork('192.0.2.0/23')
+ assert IPNetwork('192.0.2.65/255.255.254.0') != IPNetwork('192.0.2.65/24')
+
+
+def test_ipnetwork_slicing_v4():
+ ip = IPNetwork('192.0.2.0/23')
+
+ assert ip.first == 3221225984
+ assert ip.last == 3221226495
+
+ assert ip[0] == IPAddress('192.0.2.0')
+ assert ip[-1] == IPAddress('192.0.3.255')
+
+ assert list(ip[::128]) == [
+ IPAddress('192.0.2.0'),
+ IPAddress('192.0.2.128'),
+ IPAddress('192.0.3.0'),
+ IPAddress('192.0.3.128'),
+ ]
+
+
+def test_ip_network_membership_v4():
+ for what, network, result in [
+ (IPAddress('192.0.2.1'), IPNetwork('192.0.2.0/24'), True),
+ (IPAddress('192.0.2.255'), IPNetwork('192.0.2.0/24'), True),
+ (IPNetwork('192.0.2.0/24'), IPNetwork('192.0.2.0/23'), True),
+ (IPNetwork('192.0.2.0/24'), IPNetwork('192.0.2.0/24'), True),
+ (IPNetwork('192.0.2.0/23'), IPNetwork('192.0.2.0/24'), False),
+ ]:
+ assert (what in network) is result
+ assert (str(what) in network) is result
+
+
+def test_ip_network_equality_v4():
+ assert IPNetwork('192.0.2.0/24') == IPNetwork('192.0.2.0/24')
+ assert IPNetwork('192.0.2.0/24') is not IPNetwork('192.0.2.0/24')
+
+ assert not IPNetwork('192.0.2.0/24') != IPNetwork('192.0.2.0/24')
+ assert not IPNetwork('192.0.2.0/24') is IPNetwork('192.0.2.0/24')
+
+
+def test_ipaddress_integer_constructor_v4():
+ assert IPAddress(1) == IPAddress('0.0.0.1')
+ assert IPAddress(1, 4) == IPAddress('0.0.0.1')
+ assert IPAddress(1, 6) == IPAddress('::1')
+ assert IPAddress(10) == IPAddress('0.0.0.10')
+
+
+def test_ipaddress_integer_constructor_v6():
+ assert IPAddress(0x1ffffffff) == IPAddress('::1:ffff:ffff')
+ assert IPAddress(0xffffffff, 6) == IPAddress('::255.255.255.255')
+ assert IPAddress(0x1ffffffff) == IPAddress('::1:ffff:ffff')
+ assert IPAddress(2 ** 128 - 1) == IPAddress('ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff')
+
+
+def test_ipaddress_inet_aton_constructor_v4():
+ assert IPAddress('0x7f.0x1') == IPAddress('127.0.0.1')
+ assert IPAddress('0x7f.0x0.0x0.0x1') == IPAddress('127.0.0.1')
+ assert IPAddress('0177.01') == IPAddress('127.0.0.1')
+ assert IPAddress('0x7f.0.01') == IPAddress('127.0.0.1')
+
+ # Partial addresses - pretty weird, but valid ...
+ assert IPAddress('127') == IPAddress('0.0.0.127')
+ assert IPAddress('127') == IPAddress('0.0.0.127')
+ assert IPAddress('127.1') == IPAddress('127.0.0.1')
+ assert IPAddress('127.0.1') == IPAddress('127.0.0.1')
+
+ # Verify explicit INET_ATON is the same as the current default
+ assert IPAddress('127', flags=INET_ATON) == IPAddress('127')
+
+
+def test_ipaddress_inet_pton_constructor_v4():
+ with pytest.raises(AddrFormatError):
+ IPAddress('0177.01', flags=INET_PTON)
+
+ with pytest.raises(AddrFormatError):
+ IPAddress('0x7f.0.01', flags=INET_PTON)
+
+ with pytest.raises(AddrFormatError):
+ IPAddress('10', flags=INET_PTON)
+
+ with pytest.raises(AddrFormatError):
+ IPAddress('10.1', flags=INET_PTON)
+
+ with pytest.raises(AddrFormatError):
+ IPAddress('10.0.1', flags=INET_PTON)
+
+ assert IPAddress('10.0.0.1', flags=INET_PTON) == IPAddress('10.0.0.1')
+
+
+def test_ipaddress_constructor_zero_filled_octets_v4():
+ assert IPAddress('010.000.000.001') == IPAddress('8.0.0.1')
+ assert IPAddress('010.000.000.001', flags=ZEROFILL) == IPAddress('10.0.0.1')
+ assert IPAddress('010.000.001', flags=ZEROFILL) == IPAddress('10.0.0.1')
+ # Verify explicit INET_ATON is the same as the current default
+ assert IPAddress('010.000.000.001', flags=INET_ATON | ZEROFILL) == IPAddress('10.0.0.1')
+
+ with pytest.raises(AddrFormatError):
+ assert IPAddress('010.000.001', flags=INET_PTON|ZEROFILL)
+
+ assert IPAddress('010.000.000.001', flags=INET_PTON|ZEROFILL) == IPAddress('10.0.0.1')
+
+ # Short flags.
+ assert IPAddress('010.000.000.001', flags=P|Z) == IPAddress('10.0.0.1')
+
+
+def test_ipnetwork_constructor_v4():
+ assert IPNetwork('192.0.2.0/24') == IPNetwork('192.0.2.0/24')
+ assert IPNetwork('192.0.2.0/255.255.255.0') == IPNetwork('192.0.2.0/24')
+ assert IPNetwork('192.0.2.0/0.0.0.255') == IPNetwork('192.0.2.0/24')
+ assert IPNetwork(IPNetwork('192.0.2.0/24')) == IPNetwork('192.0.2.0/24')
+ assert IPNetwork(IPNetwork('192.0.2.0/24')) == IPNetwork('192.0.2.0/24')
+
+
+def test_ip_network_cosntructor_implicit_prefix_flag_v4():
+ assert IPNetwork('192.0.2.0', implicit_prefix=True) == IPNetwork('192.0.2.0/24')
+ assert IPNetwork('231.192.0.15', implicit_prefix=True) == IPNetwork('231.192.0.15/4')
+ assert IPNetwork('10', implicit_prefix=True) == IPNetwork('10.0.0.0/8')
+
+
+def test_ipnetwork_constructor_other_flags_v4():
+ assert IPNetwork('172.24.200') == IPNetwork('172.24.200.0/32')
+ assert IPNetwork('172.24.200', implicit_prefix=True) == IPNetwork('172.24.200.0/16')
+ assert IPNetwork('172.24.200', implicit_prefix=True, flags=NOHOST) == IPNetwork('172.24.0.0/16')
+
+
+def test_ipnetwork_bad_string_constructor():
+ with pytest.raises(AddrFormatError):
+ IPNetwork('foo')
+
+
+def test_ipaddress_netmask_v4():
+ assert IPAddress('0.0.0.0').netmask_bits() == 0
+ assert IPAddress('128.0.0.0').netmask_bits() == 1
+ assert IPAddress('255.0.0.0').netmask_bits() == 8
+ assert IPAddress('255.255.0.0').netmask_bits() == 16
+ assert IPAddress('255.255.255.0').netmask_bits() == 24
+ assert IPAddress('255.255.255.254').netmask_bits() == 31
+ assert IPAddress('255.255.255.255').netmask_bits() == 32
+
+ assert IPAddress('1.1.1.1').netmask_bits() == 32
+
+
+def test_ipaddress_hex_format():
+ assert hex(IPAddress(0)) == '0x0'
+ assert hex(IPAddress(0xffffffff)) == '0xffffffff'
+
+
+@pytest.mark.skipif('sys.version_info > (2,)', reason="requires python 2.x behaviour")
+def test_ipaddress_oct_format_py2():
+ assert oct(IPAddress(0xffffffff)) == '037777777777'
+ assert oct(IPAddress(0)) == '0'
+
+
+@pytest.mark.skipif('sys.version_info < (3,)', reason="python 3.x behaviour")
+def test_ipaddress_oct_format_py3():
+ assert oct(IPAddress(0xffffffff)) == '0o37777777777'
+ assert oct(IPAddress(0)) == '0o0'
+
+
+def test_multicast_info():
+ ip = IPAddress('224.0.1.173')
+ assert ip.info.IPv4[0].designation == 'Multicast'
+ assert ip.info.IPv4[0].prefix == '224/8'
+ assert ip.info.IPv4[0].status == 'Reserved'
+ assert ip.info.Multicast[0].address == '224.0.1.173'
+
+
+def test_ipaddress_pickling_v4():
+ ip = IPAddress(3221225985)
+ assert ip == IPAddress('192.0.2.1')
+
+ buf = pickle.dumps(ip)
+ ip2 = pickle.loads(buf)
+
+ assert ip2 == ip
+ assert id(ip2) != id(ip)
+ assert ip2.value == 3221225985
+ assert ip2.version == 4
+
+
+def test_ipnetwork_pickling_v4():
+ cidr = IPNetwork('192.0.2.0/24')
+ assert cidr == IPNetwork('192.0.2.0/24')
+
+ buf = pickle.dumps(cidr)
+ cidr2 = pickle.loads(buf)
+
+ assert cidr2 == cidr
+ assert id(cidr2) != id(cidr)
+ assert cidr2.value == 3221225984
+ assert cidr2.prefixlen == 24
+ assert cidr2.version == 4
+
+
+def test_ipnetwork_incrementing_by_int():
+ ip = IPNetwork('192.0.2.0/28')
+ results = []
+ for i in range(16):
+ results.append(str(ip))
+ ip += 1
+
+ assert results == [
+ '192.0.2.0/28',
+ '192.0.2.16/28',
+ '192.0.2.32/28',
+ '192.0.2.48/28',
+ '192.0.2.64/28',
+ '192.0.2.80/28',
+ '192.0.2.96/28',
+ '192.0.2.112/28',
+ '192.0.2.128/28',
+ '192.0.2.144/28',
+ '192.0.2.160/28',
+ '192.0.2.176/28',
+ '192.0.2.192/28',
+ '192.0.2.208/28',
+ '192.0.2.224/28',
+ '192.0.2.240/28'
+ ]
+
+
+def test_rfc3021_subnets():
+ # Tests for /31 subnet
+ assert IPNetwork('192.0.2.0/31').network == IPAddress('192.0.2.0')
+ assert IPNetwork('192.0.2.0/31').broadcast is None
+ assert list(IPNetwork('192.0.2.0/31').iter_hosts()) == [IPAddress('192.0.2.0'), IPAddress('192.0.2.1')]
+
+ # Tests for /32 subnet
+ assert IPNetwork('192.0.2.0/32').network == IPAddress('192.0.2.0')
+ assert IPNetwork('192.0.2.0/32').broadcast is None
+ assert list(IPNetwork('192.0.2.0/32').iter_hosts()) == [IPAddress('192.0.2.0')]
+
+
+def test_ipnetwork_change_prefixlen():
+ ip = IPNetwork('192.168.0.0/16')
+ assert ip.prefixlen == 16
+ ip.prefixlen = 8
+ assert ip.prefixlen == 8
+
+ ip = IPNetwork('dead:beef::/16')
+ assert ip.prefixlen == 16
+ ip.prefixlen = 64
+ assert ip.prefixlen == 64
+
+
+def test_ipnetwork_change_netmask():
+ ip = IPNetwork('192.168.0.0/16')
+ ip.netmask = '255.0.0.0'
+ assert ip.prefixlen == 8
+
+ ip = IPNetwork('dead:beef::/16')
+ ip.netmask = 'ffff:ffff:ffff:ffff::'
+ assert ip.prefixlen == 64
+
+
+def test_spanning_cidr_handles_strings():
+ # This that a regression introduced in 0fda41a is fixed. The regression caused an error when str
+ # addresses were passed to the function.
+ addresses = [
+ IPAddress('10.0.0.1'),
+ IPAddress('10.0.0.2'),
+ '10.0.0.3',
+ '10.0.0.4',
+ ]
+ assert spanning_cidr(addresses) == IPNetwork('10.0.0.0/29')
+ assert spanning_cidr(reversed(addresses)) == IPNetwork('10.0.0.0/29')