summaryrefslogtreecommitdiffstats
path: root/netaddr/tests/strategy
diff options
context:
space:
mode:
Diffstat (limited to 'netaddr/tests/strategy')
-rw-r--r--netaddr/tests/strategy/__init__.py0
-rw-r--r--netaddr/tests/strategy/test_eui48_strategy.py58
-rw-r--r--netaddr/tests/strategy/test_ipv4_strategy.py83
-rw-r--r--netaddr/tests/strategy/test_ipv6_strategy.py169
4 files changed, 310 insertions, 0 deletions
diff --git a/netaddr/tests/strategy/__init__.py b/netaddr/tests/strategy/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/netaddr/tests/strategy/__init__.py
diff --git a/netaddr/tests/strategy/test_eui48_strategy.py b/netaddr/tests/strategy/test_eui48_strategy.py
new file mode 100644
index 0000000..adea7a9
--- /dev/null
+++ b/netaddr/tests/strategy/test_eui48_strategy.py
@@ -0,0 +1,58 @@
+import sys
+
+import pytest
+
+from netaddr.strategy import eui48
+
+
+def test_strategy_eui48():
+ b = '00000000-00001111-00011111-00010010-11100111-00110011'
+ i = 64945841971
+ t = (0x0, 0x0f, 0x1f, 0x12, 0xe7, 0x33)
+ s = '00-0F-1F-12-E7-33'
+
+ assert eui48.bits_to_int(b) == i
+ assert eui48.int_to_bits(i) == b
+
+ assert eui48.int_to_str(i) == s
+ assert eui48.str_to_int(s) == i
+
+ assert eui48.int_to_words(i) == t
+ assert eui48.words_to_int(t) == i
+ assert eui48.words_to_int(list(t)) == i
+
+
+@pytest.mark.skipif(sys.version_info > (3,), reason="requires python 2.x")
+def test_strategy_eui48_py2():
+ i = 64945841971
+ p = '\x00\x0f\x1f\x12\xe73'
+ assert eui48.int_to_packed(i) == p
+ assert eui48.packed_to_int(p) == i
+
+
+@pytest.mark.skipif(sys.version_info < (3,), reason="requires python 3.x")
+def test_strategy_eui48_py3():
+ i = 64945841971
+ p = b'\x00\x0f\x1f\x12\xe73'
+ assert eui48.int_to_packed(i) == p
+ assert eui48.packed_to_int(p) == i
+
+
+def test_strategy_eui48_alternate_dialect():
+ b = '00000000:00001111:00011111:00010010:11100111:00110011'
+ i = 64945841971
+ t = (0x0, 0x0f, 0x1f, 0x12, 0xe7, 0x33)
+ s = '0:f:1f:12:e7:33'
+
+ assert eui48.bits_to_int(b, eui48.mac_unix) == i
+ assert eui48.int_to_bits(i, eui48.mac_unix) == b
+
+ assert eui48.int_to_str(i, eui48.mac_unix) == s
+ assert eui48.int_to_str(i, eui48.mac_cisco) == '000f.1f12.e733'
+ assert eui48.int_to_str(i, eui48.mac_unix) == '0:f:1f:12:e7:33'
+ assert eui48.int_to_str(i, eui48.mac_unix_expanded) == '00:0f:1f:12:e7:33'
+ assert eui48.str_to_int(s) == i
+
+ assert eui48.int_to_words(i, eui48.mac_unix) == t
+ assert eui48.words_to_int(t, eui48.mac_unix) == i
+ assert eui48.words_to_int(list(t), eui48.mac_unix) == i
diff --git a/netaddr/tests/strategy/test_ipv4_strategy.py b/netaddr/tests/strategy/test_ipv4_strategy.py
new file mode 100644
index 0000000..607d816
--- /dev/null
+++ b/netaddr/tests/strategy/test_ipv4_strategy.py
@@ -0,0 +1,83 @@
+import sys
+
+import pytest
+
+from netaddr import INET_PTON, AddrFormatError
+from netaddr.strategy import ipv4
+
+
+def test_strategy_ipv4():
+ b = '11000000.00000000.00000010.00000001'
+ i = 3221225985
+ t = (192, 0, 2, 1)
+ s = '192.0.2.1'
+ bin_val = '0b11000000000000000000001000000001'
+
+ assert ipv4.bits_to_int(b) == i
+ assert ipv4.int_to_bits(i) == b
+ assert ipv4.int_to_str(i) == s
+ assert ipv4.int_to_words(i) == t
+ assert ipv4.int_to_bin(i) == bin_val
+ assert ipv4.int_to_bin(i) == bin_val
+ assert ipv4.bin_to_int(bin_val) == i
+ assert ipv4.words_to_int(t) == i
+ assert ipv4.words_to_int(list(t)) == i
+ assert ipv4.valid_bin(bin_val)
+
+
+@pytest.mark.skipif(sys.version_info > (3,), reason="requires python 2.x")
+def test_strategy_ipv4_py2():
+ i = 3221225985
+ p = '\xc0\x00\x02\x01'
+ assert ipv4.int_to_packed(i) == p
+ assert ipv4.packed_to_int(p) == i
+
+
+@pytest.mark.skipif(sys.version_info < (3,), reason="requires python 3.x")
+def test_strategy_ipv4_py3():
+ i = 3221225985
+ p = b'\xc0\x00\x02\x01'
+ assert ipv4.int_to_packed(i) == p
+ assert ipv4.packed_to_int(p) == i
+
+
+def test_strategy_inet_aton_behaviour():
+ # inet_aton() is a very old system call and is very permissive with
+ # regard to what is assume is a valid IPv4 address. Unfortunately, it
+ # is also the most widely used by system software used in software today,
+ # so netaddr supports this behaviour by default.
+
+ assert ipv4.str_to_int('127') == 127
+ assert ipv4.str_to_int('0x7f') == 127
+ assert ipv4.str_to_int('0177') == 127
+ assert ipv4.str_to_int('127.1') == 2130706433
+ assert ipv4.str_to_int('0x7f.1') == 2130706433
+ assert ipv4.str_to_int('0177.1') == 2130706433
+ assert ipv4.str_to_int('127.0.0.1') == 2130706433
+
+
+def test_strategy_inet_pton_behaviour():
+ # inet_pton() is a newer system call that supports both IPv4 and IPv6.
+ # It is a lot more strict about what it deems to be a valid IPv4 address
+ # and doesn't support many of the features found in inet_aton() such as
+ # support for non- decimal octets, partial numbers of octets, etc.
+
+ with pytest.raises(AddrFormatError):
+ ipv4.str_to_int('127', flags=INET_PTON)
+
+ with pytest.raises(AddrFormatError):
+ ipv4.str_to_int('0x7f', flags=INET_PTON)
+
+ with pytest.raises(AddrFormatError):
+ ipv4.str_to_int('0177', flags=INET_PTON)
+
+ with pytest.raises(AddrFormatError):
+ ipv4.str_to_int('127.1', flags=INET_PTON)
+
+ with pytest.raises(AddrFormatError):
+ ipv4.str_to_int('0x7f.1', flags=INET_PTON)
+
+ with pytest.raises(AddrFormatError):
+ ipv4.str_to_int('0177.1', flags=INET_PTON)
+
+ assert ipv4.str_to_int('127.0.0.1', flags=INET_PTON) == 2130706433
diff --git a/netaddr/tests/strategy/test_ipv6_strategy.py b/netaddr/tests/strategy/test_ipv6_strategy.py
new file mode 100644
index 0000000..34c278e
--- /dev/null
+++ b/netaddr/tests/strategy/test_ipv6_strategy.py
@@ -0,0 +1,169 @@
+import platform
+import sys
+
+import pytest
+
+from netaddr import AddrFormatError
+from netaddr.strategy import ipv6
+
+
+def test_strategy_ipv6():
+ b = '0000000000000000:0000000000000000:0000000000000000:0000000000000000:0000000000000000:0000000000000000:1111111111111111:1111111111111110'
+ i = 4294967294
+ t = (0, 0, 0, 0, 0, 0, 0xffff, 0xfffe)
+ s = '::255.255.255.254'
+
+ assert ipv6.bits_to_int(b) == i
+ assert ipv6.int_to_bits(i) == b
+
+ assert ipv6.int_to_str(i) == s
+ assert ipv6.str_to_int(s) == i
+
+ assert ipv6.int_to_words(i) == t
+ assert ipv6.words_to_int(t) == i
+ assert ipv6.words_to_int(list(t)) == i
+
+
+@pytest.mark.skipif(sys.version_info > (3,), reason="requires python 2.x")
+def test_strategy_ipv6_py2():
+ i = 4294967294
+ p = '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff\xff\xfe'
+ assert ipv6.int_to_packed(i) == p
+ assert ipv6.packed_to_int(p) == 4294967294
+
+
+@pytest.mark.skipif(sys.version_info < (3,), reason="requires python 3.x")
+def test_strategy_ipv6_py3():
+ i = 4294967294
+ p = b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff\xff\xfe'
+ assert ipv6.int_to_packed(i) == p
+ assert ipv6.packed_to_int(p) == 4294967294
+
+
+@pytest.mark.parametrize('str_value', (
+ '2001:0db8:0000:0000:0000:0000:1428:57ab',
+ '2001:0db8:0000:0000:0000::1428:57ab',
+ '2001:0db8:0:0:0:0:1428:57ab',
+ '2001:0db8:0:0::1428:57ab',
+ '2001:0db8::1428:57ab',
+ '2001:0DB8:0000:0000:0000:0000:1428:57AB',
+ '2001:DB8::1428:57AB',
+))
+def test_strategy_ipv6_equivalent_variants(str_value):
+ assert ipv6.str_to_int(str_value) == 42540766411282592856903984951992014763
+
+
+@pytest.mark.parametrize('str_value', (
+ # Long forms.
+ 'FEDC:BA98:7654:3210:FEDC:BA98:7654:3210',
+ '1080:0:0:0:8:800:200C:417A', # a unicast address
+ 'FF01:0:0:0:0:0:0:43', # a multicast address
+ '0:0:0:0:0:0:0:1', # the loopback address
+ '0:0:0:0:0:0:0:0', # the unspecified addresses
+
+ # Short forms.
+ '1080::8:800:200C:417A', # a unicast address
+ 'FF01::43', # a multicast address
+ '::1', # the loopback address
+ '::', # the unspecified addresses
+
+ # IPv4 compatible forms.
+ '::192.0.2.1',
+ '::ffff:192.0.2.1',
+ '0:0:0:0:0:0:192.0.2.1',
+ '0:0:0:0:0:FFFF:192.0.2.1',
+ '0:0:0:0:0:0:13.1.68.3',
+ '0:0:0:0:0:FFFF:129.144.52.38',
+ '::13.1.68.3',
+ '::FFFF:129.144.52.38',
+
+ # Other tests.
+ '1::',
+ '::ffff',
+ 'ffff::',
+ 'ffff::ffff',
+ '0:1:2:3:4:5:6:7',
+ '8:9:a:b:c:d:e:f',
+ '0:0:0:0:0:0:0:0',
+ 'ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff',
+))
+def test_strategy_ipv6_valid_str(str_value):
+ assert ipv6.valid_str(str_value)
+
+
+@pytest.mark.parametrize('str_value', (
+ 'g:h:i:j:k:l:m:n', # bad chars.
+ '0:0:0:0:0:0:0:0:0', # too long,
+ # Unexpected types.
+ [],
+ (),
+ {},
+ True,
+ False,
+))
+def test_strategy_ipv6_is_not_valid_str(str_value):
+ assert not ipv6.valid_str(str_value)
+
+
+def test_strategy_ipv6_valid_str_exception_on_empty_string():
+ with pytest.raises(AddrFormatError):
+ ipv6.valid_str('')
+
+
+@pytest.mark.parametrize(('long_form', 'short_form'), (
+ ('FEDC:BA98:7654:3210:FEDC:BA98:7654:3210', 'fedc:ba98:7654:3210:fedc:ba98:7654:3210'),
+ ('1080:0:0:0:8:800:200C:417A', '1080::8:800:200c:417a'), # unicast address
+ ('FF01:0:0:0:0:0:0:43', 'ff01::43'), # multicast address
+ ('0:0:0:0:0:0:0:1', '::1'), # loopback address
+ ('0:0:0:0:0:0:0:0', '::'), # unspecified addresses
+))
+def test_strategy_ipv6_string_compaction(long_form, short_form):
+ int_val = ipv6.str_to_int(long_form)
+ calc_short_form = ipv6.int_to_str(int_val)
+ assert calc_short_form == short_form
+
+
+def test_strategy_ipv6_mapped_and_compatible_ipv4_string_formatting():
+ assert ipv6.int_to_str(0xffffff) == '::0.255.255.255'
+ assert ipv6.int_to_str(0xffffffff) == '::255.255.255.255'
+ assert ipv6.int_to_str(0x1ffffffff) == '::1:ffff:ffff'
+ assert ipv6.int_to_str(0xffffffffffff) == '::ffff:255.255.255.255'
+ assert ipv6.int_to_str(0xfffeffffffff) == '::fffe:ffff:ffff'
+ assert ipv6.int_to_str(0xffffffffffff) == '::ffff:255.255.255.255'
+ assert ipv6.int_to_str(0xfffffffffff1) == '::ffff:255.255.255.241'
+ assert ipv6.int_to_str(0xfffffffffffe) == '::ffff:255.255.255.254'
+ assert ipv6.int_to_str(0xffffffffff00) == '::ffff:255.255.255.0'
+ assert ipv6.int_to_str(0xffffffff0000) == '::ffff:255.255.0.0'
+ assert ipv6.int_to_str(0xffffff000000) == '::ffff:255.0.0.0'
+ assert ipv6.int_to_str(0xffff000000) == '::ff:ff00:0'
+ assert ipv6.int_to_str(0x1ffff00000000) == '::1:ffff:0:0'
+ # So this is strange. Even though on Windows we get decimal notation in a lot of the addresses above,
+ # in case of 0.0.0.0 we get hex instead, unless it's Python 2, then we get decimal... unless it's
+ # actually PyPy Python 2, then we always get hex (again, only on Windows). Worth investigating, putting
+ # the conditional assert here for now to make this visible.
+ if platform.system() == 'Windows' and (
+ platform.python_version() >= '3.0' or platform.python_implementation() == 'PyPy'
+ ):
+ assert ipv6.int_to_str(0xffff00000000) == '::ffff:0:0'
+ else:
+ assert ipv6.int_to_str(0xffff00000000) == '::ffff:0.0.0.0'
+
+
+def test_strategy_ipv6_str_to_int_behaviour_legacy_mode():
+ assert ipv6.str_to_int('::127') == 295
+
+ with pytest.raises(AddrFormatError):
+ ipv6.str_to_int('::0x7f')
+
+ assert ipv6.str_to_int('::0177') == 375
+
+ with pytest.raises(AddrFormatError):
+ ipv6.str_to_int('::127.1')
+
+ with pytest.raises(AddrFormatError):
+ ipv6.str_to_int('::0x7f.1')
+
+ with pytest.raises(AddrFormatError):
+ ipv6.str_to_int('::0177.1')
+
+ assert ipv6.str_to_int('::127.0.0.1') == 2130706433