File: test_ipv6.py

package info (click to toggle)
python-django 3%3A5.2.5-1
  • links: PTS, VCS
  • area: main
  • in suites: experimental
  • size: 61,236 kB
  • sloc: python: 361,585; javascript: 19,250; xml: 211; makefile: 182; sh: 28
file content (109 lines) | stat: -rw-r--r-- 5,060 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
import traceback
from decimal import Decimal
from io import StringIO
from ipaddress import IPv6Address

from django.core.exceptions import ValidationError
from django.test import SimpleTestCase
from django.utils.ipv6 import (
    MAX_IPV6_ADDRESS_LENGTH,
    clean_ipv6_address,
    is_valid_ipv6_address,
)


class TestUtilsIPv6(SimpleTestCase):
    def test_validates_correct_plain_address(self):
        self.assertTrue(is_valid_ipv6_address("fe80::223:6cff:fe8a:2e8a"))
        self.assertTrue(is_valid_ipv6_address("2a02::223:6cff:fe8a:2e8a"))
        self.assertTrue(is_valid_ipv6_address("1::2:3:4:5:6:7"))
        self.assertTrue(is_valid_ipv6_address("::"))
        self.assertTrue(is_valid_ipv6_address("::a"))
        self.assertTrue(is_valid_ipv6_address("2::"))

    def test_validates_correct_with_v4mapping(self):
        self.assertTrue(is_valid_ipv6_address("::ffff:254.42.16.14"))
        self.assertTrue(is_valid_ipv6_address("::ffff:0a0a:0a0a"))

    def test_validates_correct_with_ipv6_instance(self):
        cases = [
            IPv6Address("::ffff:2.125.160.216"),
            IPv6Address("fe80::1"),
            IPv6Address("::"),
        ]
        for case in cases:
            with self.subTest(case=case):
                self.assertIs(is_valid_ipv6_address(case), True)

    def test_validates_incorrect_plain_address(self):
        self.assertFalse(is_valid_ipv6_address("foo"))
        self.assertFalse(is_valid_ipv6_address("127.0.0.1"))
        self.assertFalse(is_valid_ipv6_address("12345::"))
        self.assertFalse(is_valid_ipv6_address("1::2:3::4"))
        self.assertFalse(is_valid_ipv6_address("1::zzz"))
        self.assertFalse(is_valid_ipv6_address("1::2:3:4:5:6:7:8"))
        self.assertFalse(is_valid_ipv6_address("1:2"))
        self.assertFalse(is_valid_ipv6_address("1:::2"))
        self.assertFalse(is_valid_ipv6_address("fe80::223: 6cff:fe8a:2e8a"))
        self.assertFalse(is_valid_ipv6_address("2a02::223:6cff :fe8a:2e8a"))

    def test_validates_incorrect_with_v4mapping(self):
        self.assertFalse(is_valid_ipv6_address("::ffff:999.42.16.14"))
        self.assertFalse(is_valid_ipv6_address("::ffff:zzzz:0a0a"))
        # The ::1.2.3.4 format used to be valid but was deprecated
        # in RFC 4291 section 2.5.5.1.
        self.assertTrue(is_valid_ipv6_address("::254.42.16.14"))
        self.assertTrue(is_valid_ipv6_address("::0a0a:0a0a"))
        self.assertFalse(is_valid_ipv6_address("::999.42.16.14"))
        self.assertFalse(is_valid_ipv6_address("::zzzz:0a0a"))

    def test_validates_incorrect_with_non_string(self):
        cases = [None, [], {}, (), Decimal("2.46"), 192.168, 42]
        for case in cases:
            with self.subTest(case=case):
                self.assertIs(is_valid_ipv6_address(case), False)

    def test_cleans_plain_address(self):
        self.assertEqual(clean_ipv6_address("DEAD::0:BEEF"), "dead::beef")
        self.assertEqual(
            clean_ipv6_address("2001:000:a:0000:0:fe:fe:beef"), "2001:0:a::fe:fe:beef"
        )
        self.assertEqual(
            clean_ipv6_address("2001::a:0000:0:fe:fe:beef"), "2001:0:a::fe:fe:beef"
        )

    def test_cleans_with_v4_mapping(self):
        self.assertEqual(clean_ipv6_address("::ffff:0a0a:0a0a"), "::ffff:10.10.10.10")
        self.assertEqual(clean_ipv6_address("::ffff:1234:1234"), "::ffff:18.52.18.52")
        self.assertEqual(clean_ipv6_address("::ffff:18.52.18.52"), "::ffff:18.52.18.52")
        self.assertEqual(clean_ipv6_address("::ffff:0.52.18.52"), "::ffff:0.52.18.52")
        self.assertEqual(clean_ipv6_address("::ffff:0.0.0.0"), "::ffff:0.0.0.0")

    def test_unpacks_ipv4(self):
        self.assertEqual(
            clean_ipv6_address("::ffff:0a0a:0a0a", unpack_ipv4=True), "10.10.10.10"
        )
        self.assertEqual(
            clean_ipv6_address("::ffff:1234:1234", unpack_ipv4=True), "18.52.18.52"
        )
        self.assertEqual(
            clean_ipv6_address("::ffff:18.52.18.52", unpack_ipv4=True), "18.52.18.52"
        )

    def test_address_too_long(self):
        addresses = [
            "0000:0000:0000:0000:0000:ffff:192.168.100.228",  # IPv4-mapped IPv6 address
            "0000:0000:0000:0000:0000:ffff:192.168.100.228%123456",  # % scope/zone
            "fe80::223:6cff:fe8a:2e8a:1234:5678:00000",  # MAX_IPV6_ADDRESS_LENGTH + 1
        ]
        msg = "This is the error message."
        value_error_msg = "Unable to convert %s to an IPv6 address (value too long)."
        for addr in addresses:
            with self.subTest(addr=addr):
                self.assertGreater(len(addr), MAX_IPV6_ADDRESS_LENGTH)
                self.assertEqual(is_valid_ipv6_address(addr), False)
                with self.assertRaisesMessage(ValidationError, msg) as ctx:
                    clean_ipv6_address(addr, error_message=msg)
                exception_traceback = StringIO()
                traceback.print_exception(ctx.exception, file=exception_traceback)
                self.assertIn(value_error_msg % addr, exception_traceback.getvalue())