"""Tests for :mod:`mgf.vm.core.configurator.memory` (pure planner)."""

from __future__ import annotations

import xml.etree.ElementTree as ET

import pytest

from mgf.vm.core.configurator import memory
from mgf.vm.core.exceptions import SpecValidationError


def _dom(cur_kib: int = 2097152, max_kib: int = 4194304, hugepages: bool = False) -> ET.Element:
    hb = "<memoryBacking><hugepages/></memoryBacking>" if hugepages else ""
    return ET.fromstring(
        f"<domain><name>web</name><uuid>u</uuid>"
        f"<memory unit='KiB'>{max_kib}</memory>"
        f"<currentMemory unit='KiB'>{cur_kib}</currentMemory>"
        f"{hb}"
        f"</domain>"
    )


class TestPlan:
    def test_grow_current_hotpluggable(self) -> None:
        change = memory.plan(_dom(), current_mb=3072)
        assert "current_mb 2048 -> 3072" in change.summary
        assert change.requires_shutdown is False

    def test_grow_max_requires_shutdown(self) -> None:
        change = memory.plan(_dom(), max_mb=8192)
        assert "max_mb 4096 -> 8192" in change.summary
        assert change.requires_shutdown is True

    def test_enable_hugepages_requires_shutdown(self) -> None:
        change = memory.plan(_dom(), hugepages=True)
        assert "hugepages off -> on" in change.summary
        assert change.requires_shutdown is True
        assert "<hugepages" in change.new_xml

    def test_disable_hugepages_requires_shutdown(self) -> None:
        change = memory.plan(_dom(hugepages=True), hugepages=False)
        assert "hugepages on -> off" in change.summary
        assert change.requires_shutdown is True
        assert "<hugepages" not in change.new_xml
        assert "<memoryBacking" not in change.new_xml

    def test_current_exceeds_max_rejected(self) -> None:
        with pytest.raises(SpecValidationError):
            memory.plan(_dom(), current_mb=8192)

    def test_below_minimum_rejected(self) -> None:
        with pytest.raises(SpecValidationError):
            memory.plan(_dom(), current_mb=32)

    def test_max_below_minimum_rejected(self) -> None:
        with pytest.raises(SpecValidationError):
            memory.plan(_dom(), max_mb=32)

    def test_no_change(self) -> None:
        change = memory.plan(_dom(), current_mb=2048)
        assert change.summary == "no change"
