from unittest.mock import patch

from yslow.probe import probe, icmp_ping


class TestIcmpPingParsing:
    def test_parses_standard_output(self):
        fake_output = (
            "PING 192.168.1.1 (192.168.1.1) 56(84) bytes of data.\n"
            "64 bytes from 192.168.1.1: icmp_seq=1 ttl=64 time=1.23 ms\n"
            "\n"
            "--- 192.168.1.1 ping statistics ---\n"
        )
        with patch("yslow.probe.subprocess.check_output", return_value=fake_output):
            assert icmp_ping("192.168.1.1") == 1.23

    def test_parses_fractional_time(self):
        fake_output = "64 bytes from 8.8.8.8: icmp_seq=1 ttl=118 time=24.6 ms\n"
        with patch("yslow.probe.subprocess.check_output", return_value=fake_output):
            assert icmp_ping("8.8.8.8") == 24.6

    def test_returns_none_on_timeout(self):
        from subprocess import TimeoutExpired

        with patch(
            "yslow.probe.subprocess.check_output",
            side_effect=TimeoutExpired("ping", 3),
        ):
            assert icmp_ping("10.0.0.1") is None


class TestProbe:
    def test_all_succeed(self):
        with (
            patch("yslow.probe.tcp_ping", return_value=5.0),
            patch("yslow.probe.time.sleep"),
        ):
            result = probe("1.1.1.1", "test", 3, port=443, method="tcp")
        assert result.sent == 3
        assert result.lost == 0
        assert result.rtts == [5.0, 5.0, 5.0]

    def test_all_fail(self):
        with (
            patch("yslow.probe.tcp_ping", return_value=None),
            patch("yslow.probe.time.sleep"),
        ):
            result = probe("1.1.1.1", "test", 3, port=443, method="tcp")
        assert result.sent == 3
        assert result.lost == 3
        assert result.rtts == []

    def test_partial_loss(self):
        returns = [5.0, None, 7.0]
        with (
            patch("yslow.probe.tcp_ping", side_effect=returns),
            patch("yslow.probe.time.sleep"),
        ):
            result = probe("1.1.1.1", "test", 3, port=443, method="tcp")
        assert result.sent == 3
        assert result.lost == 1
        assert result.rtts == [5.0, 7.0]

    def test_icmp_method(self):
        with (
            patch("yslow.probe.icmp_ping", return_value=2.0),
            patch("yslow.probe.time.sleep"),
        ):
            result = probe("192.168.1.1", "gw", 2, method="icmp")
        assert result.rtts == [2.0, 2.0]
