# (c) cavaliba.com - tests / app_data.ipam.get_ip_subnet_hierarchy

from django.test import TestCase

import app_home.cache as cache
from app_data.ipam import get_ip_subnet_hierarchy
from tests import helper


class IpamIpHierarchyTest(TestCase):
    def setUp(self):
        cache.clear()
        # TEST-NET-3 (RFC 5737) - guaranteed not to overlap the builtin
        # 10.0.0.0/8, 192.168.0.0/16, 172.16.0.0/12 seeds (220-ipam.yml)
        helper.add_instance(
            classname="ipam_subnet",
            keyname="203.0.113.0/24",
            fields={"description": "grandparent"},
        )
        helper.add_instance(
            classname="ipam_subnet",
            keyname="203.0.113.0/26",
            fields={"description": "parent"},
        )
        helper.add_instance(
            classname="ipam_subnet",
            keyname="203.0.113.0/28",
            fields={"description": "containing"},
        )
        helper.add_instance(
            classname="ipam_vlan",
            keyname="vlan_test",
            fields={"displayname": "Test VLAN", "subnet": "203.0.113.0/28"},
        )

    def test_hierarchy_climbs_all_the_way_to_universal_supernet(self):
        """No cap - always climbs past our 3 test subnets all the way to the
        builtin 0.0.0.0/0 (seeded by 220-ipam.yml)."""
        hierarchy = get_ip_subnet_hierarchy("203.0.113.5")

        self.assertEqual(
            [h["keyname"] for h in hierarchy],
            ["0.0.0.0/0", "203.0.113.0/24", "203.0.113.0/26", "203.0.113.0/28"],
        )

    def test_is_containing_only_on_last_entry(self):
        hierarchy = get_ip_subnet_hierarchy("203.0.113.5")
        self.assertEqual([h["is_containing"] for h in hierarchy], [False, False, False, True])

    def test_indent_grows_with_position(self):
        hierarchy = get_ip_subnet_hierarchy("203.0.113.5")
        self.assertEqual([h["indent"] for h in hierarchy], ["", "  ", "    ", "      "])

    def test_description_populated_per_subnet(self):
        hierarchy = get_ip_subnet_hierarchy("203.0.113.5")

        by_keyname = {h["keyname"]: h for h in hierarchy}
        self.assertEqual(by_keyname["203.0.113.0/24"]["description"], "grandparent")
        self.assertEqual(by_keyname["203.0.113.0/26"]["description"], "parent")
        self.assertEqual(by_keyname["203.0.113.0/28"]["description"], "containing")
        self.assertEqual(by_keyname["0.0.0.0/0"]["description"], "all")

    def test_vlan_attached_only_to_containing_subnet(self):
        hierarchy = get_ip_subnet_hierarchy("203.0.113.5")

        by_keyname = {h["keyname"]: h for h in hierarchy}
        self.assertEqual(by_keyname["203.0.113.0/28"]["vlans"][0]["displayname"], "Test VLAN")
        self.assertEqual(by_keyname["0.0.0.0/0"]["vlans"], [])
        self.assertEqual(by_keyname["203.0.113.0/24"]["vlans"], [])
        self.assertEqual(by_keyname["203.0.113.0/26"]["vlans"], [])

    def test_invalid_ip_returns_empty(self):
        self.assertEqual(get_ip_subnet_hierarchy("not-an-ip"), [])

    def test_ip_with_no_containing_subnet_returns_empty(self):
        # IPv6 - ip_network("x/32") raises, function must fail closed
        self.assertEqual(get_ip_subnet_hierarchy("2001:db8::1"), [])
