import platform
import subprocess
from unittest.mock import Mock, mock_open, patch
import pytest
from hardware_utils import HardwareComparator, HardwareInfo
@pytest.fixture
def hardware():
return HardwareInfo()
class TestHardwareInfo:
def test_init(self, hardware):
assert hardware.os_type == platform.system()
assert hardware.machine == platform.machine()
@patch("hardware_utils.platform.system")
def test_init_with_different_os(self, mock_system):
mock_system.return_value = "Linux"
hardware = HardwareInfo()
assert hardware.os_type == "Linux"
def test_run_command_empty_cmd(self, hardware):
with pytest.raises(ValueError, match="Command list cannot be empty"):
hardware._run_command([])
@patch("hardware_utils.run_safe_command")
def test_run_command_success(self, mock_run_safe, hardware):
mock_result = Mock()
mock_result.stdout = "test output\n"
mock_run_safe.return_value = mock_result
result = hardware._run_command(["echo", "test"])
assert result == "test output"
mock_run_safe.assert_called_once_with(
"echo",
["test"],
cwd=None,
capture_output=True,
text=True,
check=True,
)
@patch("hardware_utils.run_safe_command")
def test_run_command_failure(self, mock_run_safe, hardware):
mock_run_safe.side_effect = subprocess.CalledProcessError(1, "cmd")
with pytest.raises(subprocess.CalledProcessError):
hardware._run_command(["false"])
@patch("hardware_utils.platform.system")
@patch.object(HardwareInfo, "_run_command")
def test_get_cpu_info_darwin(self, mock_run_command, mock_system):
mock_system.return_value = "Darwin"
mock_run_command.side_effect = ["Intel(R) Core(TM) i7-9750H CPU @ 2.60GHz", "6", "12"]
hardware = HardwareInfo()
cpu_model, cpu_cores, cpu_threads = hardware.get_cpu_info()
assert cpu_model == "Intel(R) Core(TM) i7-9750H CPU @ 2.60GHz"
assert cpu_cores == "6"
assert cpu_threads == "12"
@patch("hardware_utils.platform.system")
@patch("hardware_utils.shutil.which")
@patch.object(HardwareInfo, "_run_command")
def test_get_cpu_info_linux_with_lscpu(self, mock_run_command, mock_which, mock_system):
mock_system.return_value = "Linux"
mock_which.side_effect = lambda cmd: cmd in ["lscpu", "nproc"]
lscpu_output = """Architecture: x86_64
CPU op-mode(s): 32-bit, 64-bit
Model name: Intel(R) Core(TM) i7-8700K CPU @ 3.70GHz
Core(s) per socket: 6
Socket(s): 1
Thread(s) per core: 2"""
mock_run_command.side_effect = [
lscpu_output, lscpu_output, "12", ]
hardware = HardwareInfo()
cpu_model, cpu_cores, cpu_threads = hardware.get_cpu_info()
assert cpu_model == "Intel(R) Core(TM) i7-8700K CPU @ 3.70GHz"
assert cpu_cores == "6"
assert cpu_threads == "12"
@patch("hardware_utils.platform.system")
@patch("hardware_utils.shutil.which")
@patch("builtins.open", new_callable=mock_open, read_data="processor\t: 0\nmodel name\t: AMD Ryzen 5 3600\nprocessor\t: 1\n")
def test_get_cpu_info_linux_fallback_cpuinfo(self, _mock_file, mock_which, mock_system):
mock_system.return_value = "Linux"
mock_which.return_value = None
hardware = HardwareInfo()
cpu_model, cpu_cores, cpu_threads = hardware.get_cpu_info()
assert cpu_model == "AMD Ryzen 5 3600"
assert cpu_cores == "Unknown" assert cpu_threads == "2"
@patch("hardware_utils.platform.system")
@patch("hardware_utils.shutil.which")
@patch.object(HardwareInfo, "_run_command")
def test_get_cpu_info_windows(self, mock_run_command, mock_which, mock_system):
mock_system.return_value = "Windows"
mock_which.side_effect = lambda cmd: cmd == "powershell"
mock_run_command.side_effect = ["Intel(R) Core(TM) i7-10700K CPU @ 3.80GHz", "8", "16"]
hardware = HardwareInfo()
cpu_model, cpu_cores, cpu_threads = hardware.get_cpu_info()
assert cpu_model == "Intel(R) Core(TM) i7-10700K CPU @ 3.80GHz"
assert cpu_cores == "8"
assert cpu_threads == "16"
@patch("hardware_utils.platform.system")
def test_get_cpu_info_unknown_os(self, mock_system):
mock_system.return_value = "UnknownOS"
hardware = HardwareInfo()
cpu_model, cpu_cores, cpu_threads = hardware.get_cpu_info()
assert cpu_model == "Unknown"
assert cpu_cores == "Unknown"
assert cpu_threads == "Unknown"
@patch("hardware_utils.platform.system")
@patch.object(HardwareInfo, "_run_command")
def test_get_cpu_info_command_failure(self, mock_run_command, mock_system):
mock_system.return_value = "Darwin"
mock_run_command.side_effect = subprocess.CalledProcessError(1, "cmd")
hardware = HardwareInfo()
cpu_model, cpu_cores, cpu_threads = hardware.get_cpu_info()
assert cpu_model == "Unknown"
assert cpu_cores == "Unknown"
assert cpu_threads == "Unknown"
@patch("hardware_utils.platform.system")
@patch.object(HardwareInfo, "_run_command")
def test_get_memory_info_darwin(self, mock_run_command, mock_system):
mock_system.return_value = "Darwin"
mock_run_command.return_value = "17179869184"
hardware = HardwareInfo()
memory = hardware.get_memory_info()
assert memory == "16.0 GB"
@patch("hardware_utils.platform.system")
@patch("builtins.open", new_callable=mock_open, read_data="MemTotal: 16384000 kB\n")
def test_get_memory_info_linux(self, _mock_file, mock_system):
mock_system.return_value = "Linux"
hardware = HardwareInfo()
memory = hardware.get_memory_info()
assert memory == "15.6 GB"
@patch("hardware_utils.platform.system")
@patch("hardware_utils.shutil.which")
@patch.object(HardwareInfo, "_run_command")
def test_get_memory_info_windows(self, mock_run_command, mock_which, mock_system):
mock_system.return_value = "Windows"
mock_which.side_effect = lambda cmd: cmd == "powershell"
mock_run_command.return_value = "32.0 GB"
hardware = HardwareInfo()
memory = hardware.get_memory_info()
assert memory == "32.0 GB"
@patch("hardware_utils.platform.system")
def test_get_memory_info_unknown_os(self, mock_system):
mock_system.return_value = "UnknownOS"
hardware = HardwareInfo()
memory = hardware.get_memory_info()
assert memory == "Unknown"
@patch("hardware_utils.shutil.which")
@patch.object(HardwareInfo, "_run_command")
def test_get_rust_info_success(self, mock_run_command, mock_which, hardware):
mock_which.return_value = "/usr/bin/rustc"
mock_run_command.side_effect = ["rustc 1.70.0 (90c541806 2023-05-31)", "rustc 1.70.0 (90c541806 2023-05-31)\nhost: x86_64-apple-darwin\n"]
rust_version, rust_target = hardware.get_rust_info()
assert rust_version == "rustc 1.70.0 (90c541806 2023-05-31)"
assert rust_target == "x86_64-apple-darwin"
@patch("hardware_utils.shutil.which")
def test_get_rust_info_no_rustc(self, mock_which, hardware):
mock_which.return_value = None
rust_version, rust_target = hardware.get_rust_info()
assert rust_version == "Unknown"
assert rust_target == "Unknown"
@patch("hardware_utils.shutil.which")
@patch.object(HardwareInfo, "_run_command")
def test_get_rust_info_command_failure(self, mock_run_command, mock_which, hardware):
mock_which.return_value = "/usr/bin/rustc"
mock_run_command.side_effect = subprocess.CalledProcessError(1, "cmd")
rust_version, rust_target = hardware.get_rust_info()
assert rust_version == "Unknown"
assert rust_target == "Unknown"
def test_get_hardware_info(self, hardware):
with (
patch.object(hardware, "get_cpu_info") as mock_cpu,
patch.object(hardware, "get_memory_info") as mock_memory,
patch.object(hardware, "get_rust_info") as mock_rust,
):
mock_cpu.return_value = ("Intel i7", "8", "16")
mock_memory.return_value = "16.0 GB"
mock_rust.return_value = ("rustc 1.70.0", "x86_64-unknown-linux-gnu")
info = hardware.get_hardware_info()
expected_keys = ["OS", "CPU", "CPU_CORES", "CPU_THREADS", "MEMORY", "RUST", "TARGET"]
assert set(info.keys()) == set(expected_keys)
assert info["CPU"] == "Intel i7"
assert info["CPU_CORES"] == "8"
assert info["CPU_THREADS"] == "16"
assert info["MEMORY"] == "16.0 GB"
assert info["RUST"] == "rustc 1.70.0"
assert info["TARGET"] == "x86_64-unknown-linux-gnu"
@pytest.mark.parametrize(
("system_name", "expected_os"), [("Darwin", "macOS"), ("Linux", "Linux"), ("Windows", "Windows"), ("FreeBSD", "Unknown (FreeBSD)")]
)
@patch("hardware_utils.platform.system")
def test_get_hardware_info_os_mapping(self, mock_system, system_name, expected_os):
mock_system.return_value = system_name
hardware = HardwareInfo()
with (
patch.object(hardware, "get_cpu_info") as mock_cpu,
patch.object(hardware, "get_memory_info") as mock_memory,
patch.object(hardware, "get_rust_info") as mock_rust,
):
mock_cpu.return_value = ("CPU", "4", "8")
mock_memory.return_value = "8.0 GB"
mock_rust.return_value = ("rustc 1.70.0", "target")
info = hardware.get_hardware_info()
assert info["OS"] == expected_os
def test_format_hardware_info(self, hardware):
test_info = {
"OS": "macOS",
"CPU": "Intel i7",
"CPU_CORES": "8",
"CPU_THREADS": "16",
"MEMORY": "16.0 GB",
"RUST": "rustc 1.70.0",
"TARGET": "x86_64-apple-darwin",
}
formatted = hardware.format_hardware_info(test_info)
assert "Hardware Information:" in formatted
assert "OS: macOS" in formatted
assert "CPU: Intel i7" in formatted
assert "CPU Cores: 8" in formatted
assert "CPU Threads: 16" in formatted
assert "Memory: 16.0 GB" in formatted
assert "Rust: rustc 1.70.0" in formatted
assert "Target: x86_64-apple-darwin" in formatted
def test_format_hardware_info_none(self, hardware):
with patch.object(hardware, "get_hardware_info") as mock_get_info:
mock_get_info.return_value = {
"OS": "Linux",
"CPU": "AMD Ryzen",
"CPU_CORES": "6",
"CPU_THREADS": "12",
"MEMORY": "32.0 GB",
"RUST": "rustc 1.70.0",
"TARGET": "x86_64-unknown-linux-gnu",
}
formatted = hardware.format_hardware_info(None)
assert "OS: Linux" in formatted
class TestHardwareComparator:
def test_parse_baseline_hardware_complete(self):
baseline_content = """Benchmark Results
Generated on: 2023-06-15 10:30:00
Hardware Information:
OS: macOS
CPU: Intel(R) Core(TM) i7-9750H CPU @ 2.60GHz
CPU Cores: 6
CPU Threads: 12
Memory: 16.0 GB
Rust: rustc 1.70.0 (90c541806 2023-05-31)
Target: x86_64-apple-darwin
Benchmark Results:
test_benchmark ... 1.234 ms
"""
info = HardwareComparator.parse_baseline_hardware(baseline_content)
expected = {
"OS": "macOS",
"CPU": "Intel(R) Core(TM) i7-9750H CPU @ 2.60GHz",
"CPU_CORES": "6",
"CPU_THREADS": "12",
"MEMORY": "16.0 GB",
"RUST": "rustc 1.70.0 (90c541806 2023-05-31)",
"TARGET": "x86_64-apple-darwin",
}
assert info == expected
def test_parse_baseline_hardware_partial(self):
baseline_content = """Hardware Information:
OS: Linux
CPU: AMD Ryzen 5 3600
Memory: 32.0 GB
Other content here...
"""
info = HardwareComparator.parse_baseline_hardware(baseline_content)
assert info["OS"] == "Linux"
assert info["CPU"] == "AMD Ryzen 5 3600"
assert info["MEMORY"] == "32.0 GB"
assert info["CPU_CORES"] == "Unknown" assert info["RUST"] == "Unknown"
def test_parse_baseline_hardware_empty(self):
baseline_content = "No hardware information found"
info = HardwareComparator.parse_baseline_hardware(baseline_content)
for value in info.values():
assert value == "Unknown"
def test_compare_hardware_identical(self):
current_info = {
"OS": "macOS",
"CPU": "Intel i7",
"CPU_CORES": "8",
"CPU_THREADS": "16",
"MEMORY": "16.0 GB",
"RUST": "rustc 1.70.0",
"TARGET": "x86_64-apple-darwin",
}
baseline_info = current_info.copy()
report, has_warnings = HardwareComparator.compare_hardware(current_info, baseline_info)
assert not has_warnings
assert "Hardware configurations are compatible" in report
def test_compare_hardware_different_os(self):
current_info = {
"OS": "Linux",
"CPU": "Intel i7",
"CPU_CORES": "8",
"CPU_THREADS": "16",
"MEMORY": "16.0 GB",
"RUST": "rustc 1.70.0",
"TARGET": "x86_64-unknown-linux-gnu",
}
baseline_info = current_info.copy()
baseline_info["OS"] = "macOS"
report, has_warnings = HardwareComparator.compare_hardware(current_info, baseline_info)
assert has_warnings
assert "OS differs: Linux vs macOS" in report
def test_compare_hardware_different_cpu(self):
current_info = {
"OS": "Linux",
"CPU": "AMD Ryzen 5 3600",
"CPU_CORES": "6",
"CPU_THREADS": "12",
"MEMORY": "16.0 GB",
"RUST": "rustc 1.70.0",
"TARGET": "x86_64-unknown-linux-gnu",
}
baseline_info = current_info.copy()
baseline_info["CPU"] = "Intel i7-8700K"
report, has_warnings = HardwareComparator.compare_hardware(current_info, baseline_info)
assert has_warnings
assert "CPU differs:" in report
assert "results may not be directly comparable" in report
def test_compare_hardware_different_cores(self):
current_info = {
"OS": "Linux",
"CPU": "Intel i7",
"CPU_CORES": "8",
"CPU_THREADS": "16",
"MEMORY": "16.0 GB",
"RUST": "rustc 1.70.0",
"TARGET": "x86_64-unknown-linux-gnu",
}
baseline_info = current_info.copy()
baseline_info["CPU_CORES"] = "6"
report, has_warnings = HardwareComparator.compare_hardware(current_info, baseline_info)
assert has_warnings
assert "CPU core count differs: 8 vs 6 cores" in report
def test_compare_hardware_memory_tolerance(self):
current_info = {
"OS": "Linux",
"CPU": "Intel i7",
"CPU_CORES": "8",
"CPU_THREADS": "16",
"MEMORY": "16.0 GB",
"RUST": "rustc 1.70.0",
"TARGET": "x86_64-unknown-linux-gnu",
}
baseline_info = current_info.copy()
baseline_info["MEMORY"] = "15.95 GB"
report, has_warnings = HardwareComparator.compare_hardware(current_info, baseline_info)
assert not has_warnings
baseline_info["MEMORY"] = "15.6 GB"
report, has_warnings = HardwareComparator.compare_hardware(current_info, baseline_info)
assert has_warnings
assert "Memory differs:" in report
def test_compare_hardware_unknown_baseline(self):
current_info = {
"OS": "Linux",
"CPU": "Intel i7",
"CPU_CORES": "8",
"CPU_THREADS": "16",
"MEMORY": "16.0 GB",
"RUST": "rustc 1.70.0",
"TARGET": "x86_64-unknown-linux-gnu",
}
baseline_info = {
"OS": "Unknown",
"CPU": "Unknown",
"CPU_CORES": "Unknown",
"CPU_THREADS": "Unknown",
"MEMORY": "Unknown",
"RUST": "Unknown",
"TARGET": "Unknown",
}
report, has_warnings = HardwareComparator.compare_hardware(current_info, baseline_info)
assert not has_warnings
assert "Hardware configurations are compatible" in report
@pytest.mark.parametrize(
("memory_str", "expected"),
[
("16.0 GB", 16.0),
("32.5 GB", 32.5),
("8GB", 8.0),
("64 GB", 64.0),
("16,5 GB", 16.5), ("1.0 TB", 1.0), ("Unknown", None),
("Invalid format", None),
("", None),
],
)
def test_extract_memory_value(self, memory_str, expected):
result = HardwareComparator._extract_memory_value(memory_str)
if expected is None:
assert result is None
else:
assert result == pytest.approx(expected, abs=1e-9)
class TestHardwareUtilsIntegration:
def test_real_hardware_info_structure(self):
hardware = HardwareInfo()
info = hardware.get_hardware_info()
expected_keys = {"OS", "CPU", "CPU_CORES", "CPU_THREADS", "MEMORY", "RUST", "TARGET"}
assert set(info.keys()) == expected_keys
for key, value in info.items():
assert isinstance(value, str), f"Key {key} should have string value"
def test_cpu_info_returns_tuples(self):
hardware = HardwareInfo()
cpu_model, cpu_cores, cpu_threads = hardware.get_cpu_info()
rust_version, rust_target = hardware.get_rust_info()
assert isinstance(cpu_model, str)
assert isinstance(cpu_cores, str)
assert isinstance(cpu_threads, str)
assert isinstance(rust_version, str)
assert isinstance(rust_target, str)
def test_memory_info_returns_string(self):
hardware = HardwareInfo()
memory = hardware.get_memory_info()
assert isinstance(memory, str)
def test_formatted_output_structure(self):
hardware = HardwareInfo()
formatted = hardware.format_hardware_info()
assert isinstance(formatted, str)
assert "Hardware Information:" in formatted
expected_fields = ["OS:", "CPU:", "CPU Cores:", "CPU Threads:", "Memory:", "Rust:", "Target:"]
for field in expected_fields:
assert field in formatted