File size: 4,462 Bytes
e0ea7df
 
 
0d8512e
 
 
e0ea7df
0d8512e
 
 
 
 
cc826a1
0d8512e
 
e0ea7df
 
 
 
 
 
0d8512e
 
e0ea7df
 
 
 
 
 
0d8512e
e0ea7df
 
 
 
 
0d8512e
 
e0ea7df
 
0d8512e
e0ea7df
 
 
 
 
 
 
 
 
0d8512e
e0ea7df
 
0d8512e
 
e0ea7df
 
 
 
 
 
 
0d8512e
e0ea7df
 
 
0d8512e
 
e0ea7df
 
0d8512e
e0ea7df
 
 
 
 
 
 
 
 
0d8512e
 
e0ea7df
 
0d8512e
e0ea7df
 
 
 
 
 
 
 
 
 
 
 
0d8512e
e0ea7df
 
 
 
 
 
 
 
 
 
 
 
0d8512e
e0ea7df
 
 
 
 
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
110
111
112
113
114
115
116
"""binary_locator.py 探测逻辑测试。

用 monkeypatch 模拟环境变量、PATH、可执行性检查,覆盖 env/path/common/wsl/全失败分支。
"""

import os
import platform
from pathlib import Path
from unittest.mock import patch

import pytest

from plugins.browser.browser import binary_locator


def _make_executable(tmp_path: Path, name: str = "lightpanda") -> Path:
    """在 tmp_path 下造一个可执行文件。"""
    p = tmp_path / name
    p.write_text("#!/bin/sh\n")
    p.chmod(0o755)
    return p


def test_env_path_detected(tmp_path, monkeypatch):
    """LIGHTPANDA_BINARY 指向可执行文件时 source=env。"""
    binp = _make_executable(tmp_path)
    monkeypatch.setenv("LIGHTPANDA_BINARY", str(binp))
    monkeypatch.setattr(binary_locator.shutil, "which", lambda _: None)
    monkeypatch.setattr(binary_locator, "_read_version", lambda b: "0.2.0")

    r = binary_locator.locate_lightpanda()
    assert r.available is True
    assert r.path == str(binp)
    assert r.source == "env"
    assert r.version == "0.2.0"


def test_env_path_not_executable_falls_through(tmp_path, monkeypatch):
    """LIGHTPANDA_BINARY 指向不可执行文件时不命中。

    注:Windows 不用 Unix 权限位判定可执行性,故直接 mock _check_path_executable
    返回 False 来模拟"存在但不可执行"。
    """
    p = tmp_path / "lightpanda"
    p.write_text("not executable")
    monkeypatch.setenv("LIGHTPANDA_BINARY", str(p))
    monkeypatch.setattr(binary_locator.shutil, "which", lambda _: None)
    monkeypatch.setattr(binary_locator, "_probe_wsl_interop", lambda: None)
    monkeypatch.setattr(binary_locator, "_check_path_executable", lambda path: False)

    r = binary_locator.locate_lightpanda()
    assert r.available is False


def test_path_detected(tmp_path, monkeypatch):
    """shutil.which 找到可执行文件时 source=path。"""
    binp = _make_executable(tmp_path)
    monkeypatch.delenv("LIGHTPANDA_BINARY", raising=False)
    monkeypatch.setattr(binary_locator.shutil, "which", lambda _: str(binp))
    monkeypatch.setattr(binary_locator, "_read_version", lambda b: "0.2.0")
    monkeypatch.setattr(binary_locator, "_probe_wsl_interop", lambda: None)

    r = binary_locator.locate_lightpanda()
    assert r.available is True
    assert r.source == "path"


def test_all_fail_returns_unavailable(monkeypatch):
    """全部探测失败时 available=False 且 source=none。"""
    monkeypatch.delenv("LIGHTPANDA_BINARY", raising=False)
    monkeypatch.setattr(binary_locator.shutil, "which", lambda _: None)
    monkeypatch.setattr(binary_locator, "_probe_wsl_interop", lambda: None)
    monkeypatch.setattr(binary_locator, "_check_path_executable", lambda p: False)

    r = binary_locator.locate_lightpanda()
    assert r.available is False
    assert r.source == "none"
    assert r.error
    assert r.install_hints  # 必须带安装提示


def test_install_hints_contain_docker_and_wsl(monkeypatch):
    """install_hints 总是包含 docker 和 wsl 备选。"""
    monkeypatch.delenv("LIGHTPANDA_BINARY", raising=False)
    monkeypatch.setattr(binary_locator.shutil, "which", lambda _: None)
    monkeypatch.setattr(binary_locator, "_probe_wsl_interop", lambda: None)
    monkeypatch.setattr(binary_locator, "_check_path_executable", lambda p: False)

    r = binary_locator.locate_lightpanda()
    assert "docker" in r.install_hints
    assert "wsl" in r.install_hints


def test_to_dict_serializable(monkeypatch):
    """to_dict 返回可 JSON 序列化的 dict。"""
    import json
    monkeypatch.delenv("LIGHTPANDA_BINARY", raising=False)
    monkeypatch.setattr(binary_locator.shutil, "which", lambda _: None)
    monkeypatch.setattr(binary_locator, "_probe_wsl_interop", lambda: None)
    monkeypatch.setattr(binary_locator, "_check_path_executable", lambda p: False)

    r = binary_locator.locate_lightpanda()
    d = r.to_dict()
    json.dumps(d)  # 不抛即 OK
    assert d["available"] is False


def test_is_binary_available_consistent(monkeypatch):
    """is_binary_available 与 locate_lightpanda().available 一致。"""
    monkeypatch.delenv("LIGHTPANDA_BINARY", raising=False)
    monkeypatch.setattr(binary_locator.shutil, "which", lambda _: None)
    monkeypatch.setattr(binary_locator, "_probe_wsl_interop", lambda: None)
    monkeypatch.setattr(binary_locator, "_check_path_executable", lambda p: False)

    assert binary_locator.is_binary_available() is False