"""Tests for web_ui.components module."""
from __future__ import annotations
import pandas as pd
import pytest
from web_ui.components import (
_safe_df_from_rows,
df_to_records,
export_current_rows,
get_vendor_device_map,
progress_html,
render_section_card,
result_dataframe,
result_plot,
result_section,
text_generate_result_section,
video_generate_result_section,
optimizer_result_section,
wire_export,
EXPORT_DIR,
)
class TestGetVendorDeviceMap:
"""Tests for get_vendor_device_map function."""
def test_vendor_device_map_returns_dict(self) -> None:
"""Test that function returns a dictionary."""
result = get_vendor_device_map()
assert isinstance(result, dict)
def test_vendor_device_map_has_lists(self) -> None:
"""Test that values are lists."""
result = get_vendor_device_map()
for vendor, devices in result.items():
assert isinstance(devices, list)
def test_vendor_device_map_not_empty(self) -> None:
"""Test that map is not empty when device profiles are registered."""
result = get_vendor_device_map()
assert isinstance(result, dict)
def test_vendor_device_map_sorted_devices(self) -> None:
"""Test that device lists are sorted."""
result = get_vendor_device_map()
for vendor, devices in result.items():
assert devices == sorted(devices)
def test_vendor_device_map_sorted_vendors(self) -> None:
"""Test that vendors are sorted."""
result = get_vendor_device_map()
vendors = list(result.keys())
assert vendors == sorted(vendors)
def test_vendor_device_map_no_test_vendor(self) -> None:
"""Test TEST_VENDOR is filtered out."""
result = get_vendor_device_map()
assert "TEST_VENDOR" not in result
assert "test_vendor" not in result
class TestProgressHtml:
"""Tests for progress_html function."""
def test_progress_html_basic(self) -> None:
"""Test basic progress HTML generation."""
result = progress_html(5, 10, "Test task", "running")
assert "5/10" in result
assert "50.0%" in result
assert "Test task" in result
assert "running" in result
def test_progress_html_zero_completed(self) -> None:
"""Test with zero completed tasks."""
result = progress_html(0, 10, "Starting", "waiting")
assert "0/10" in result
assert "0.0%" in result
def test_progress_html_all_completed(self) -> None:
"""Test with all tasks completed."""
result = progress_html(10, 10, "Done", "success")
assert "10/10" in result
assert "100.0%" in result
def test_progress_html_empty_status(self) -> None:
"""Test with empty status string."""
result = progress_html(5, 10, "Task", "")
assert "Preparing" in result
def test_progress_html_empty_latest(self) -> None:
"""Test with empty latest string."""
result = progress_html(5, 10, "", "running")
assert "Waiting for the first task" in result
def test_progress_html_clamps_completed(self) -> None:
"""Test completed value is clamped to total."""
result = progress_html(15, 10, "Over", "done")
assert "10/10" in result
assert "100.0%" in result
def test_progress_html_minimum_one_total(self) -> None:
"""Test total is at least 1."""
result = progress_html(0, 0, "Zero", "waiting")
assert "0/1" in result
def test_progress_html_contains_classes(self) -> None:
"""Test HTML contains required CSS classes."""
result = progress_html(5, 10, "Task", "status")
assert "progress-shell" in result
assert "progress-track" in result
assert "progress-fill" in result
assert "progress-caption" in result
class TestResultPlot:
"""Tests for result_plot function."""
def test_result_plot_requires_gradio(self) -> None:
"""Test that result_plot raises RuntimeError without gradio."""
import web_ui.components as comp
original_gr = comp.gr
comp.gr = None
with pytest.raises(RuntimeError, match="gradio is not installed"):
result_plot("test")
comp.gr = original_gr
class TestResultDataframe:
"""Tests for result_dataframe function."""
def test_result_dataframe_requires_gradio(self) -> None:
"""Test that result_dataframe raises RuntimeError without gradio."""
import web_ui.components as comp
original_gr = comp.gr
comp.gr = None
with pytest.raises(RuntimeError, match="gradio is not installed"):
result_dataframe("Test")
comp.gr = original_gr
class TestRenderSectionCard:
"""Tests for render_section_card function."""
def test_render_section_card_requires_gradio(self) -> None:
"""Test that render_section_card raises RuntimeError without gradio."""
import web_ui.components as comp
original_gr = comp.gr
comp.gr = None
with pytest.raises(RuntimeError, match="gradio is not installed"):
render_section_card("Title", "Subtitle")
comp.gr = original_gr
class TestSafeDfFromRows:
"""Tests for _safe_df_from_rows function."""
def test_safe_df_from_none(self) -> None:
"""Test with None returns empty DataFrame."""
result = _safe_df_from_rows(None)
assert result.empty
def test_safe_df_from_empty_list(self) -> None:
"""Test with empty list returns empty DataFrame."""
result = _safe_df_from_rows([])
assert result.empty
def test_safe_df_from_valid_rows(self) -> None:
"""Test with valid rows creates DataFrame."""
rows = [{"a": 1, "b": 2}, {"a": 3, "b": 4}]
result = _safe_df_from_rows(rows)
assert len(result) == 2
assert list(result.columns) == ["a", "b"]
assert result.iloc[0]["a"] == 1
def test_safe_df_from_mixed_columns(self) -> None:
"""Test with rows having different keys."""
rows = [{"a": 1, "b": 2}, {"a": 3, "c": 4}]
result = _safe_df_from_rows(rows)
assert len(result) == 2
assert "a" in result.columns
assert "b" in result.columns
assert "c" in result.columns
class TestExportCurrentRows:
"""Tests for export_current_rows function."""
def test_export_none_returns_none(self) -> None:
"""Test exporting None returns None."""
result = export_current_rows(None, "test")
assert result is None
def test_export_empty_rows_returns_none(self) -> None:
"""Test exporting empty rows returns None."""
result = export_current_rows([], "test")
assert result is None
class TestDfToRecords:
"""Tests for df_to_records function."""
def test_df_to_records_none(self) -> None:
"""Test with None DataFrame."""
result = df_to_records(None)
assert result == []
def test_df_to_records_empty(self) -> None:
"""Test with empty DataFrame."""
result = df_to_records(pd.DataFrame())
assert result == []
def test_df_to_records_basic(self) -> None:
"""Test converting DataFrame to records."""
df = pd.DataFrame({"a": [1, 2], "b": [3, 4]})
result = df_to_records(df)
assert len(result) == 2
assert result[0]["a"] == 1
assert result[1]["b"] == 4
def test_df_to_records_with_nan(self) -> None:
"""Test that NaN values are handled."""
df = pd.DataFrame({"a": [1, None, 3], "b": [4, 5, None]})
result = df_to_records(df)
assert pd.isna(result[1]["a"]) or result[1]["a"] is None
assert pd.isna(result[2]["b"]) or result[2]["b"] is None
def test_df_to_records_preserves_types(self) -> None:
"""Test that data types are preserved."""
df = pd.DataFrame({"int": [1, 2], "float": [1.5, 2.5], "str": ["a", "b"]})
result = df_to_records(df)
assert result[0]["int"] == 1
assert isinstance(result[0]["float"], float)
assert result[0]["str"] == "a"
class TestWireExport:
"""Tests for wire_export function."""
def test_wire_export_requires_gradio(self) -> None:
"""Test wire_export requires gradio."""
import web_ui.components as comp
original_gr = comp.gr
comp.gr = None
class MockComponent:
def click(self, *args, **kwargs):
pass
mock_btn = MockComponent()
wire_export(mock_btn, [], None, "test")
comp.gr = original_gr
class TestTextGenerateResultSection:
"""Tests for text_generate_result_section function."""
def test_text_generate_result_section_requires_gradio(self) -> None:
"""Test that function raises RuntimeError without gradio."""
import web_ui.components as comp
original_gr = comp.gr
comp.gr = None
with pytest.raises(RuntimeError, match="gradio is not installed"):
text_generate_result_section()
comp.gr = original_gr
class TestVideoGenerateResultSection:
"""Tests for video_generate_result_section function."""
def test_video_generate_result_section_requires_gradio(self) -> None:
"""Test that function raises RuntimeError without gradio."""
import web_ui.components as comp
original_gr = comp.gr
comp.gr = None
with pytest.raises(RuntimeError, match="gradio is not installed"):
video_generate_result_section()
comp.gr = original_gr
class TestOptimizerResultSection:
"""Tests for optimizer_result_section function."""
def test_optimizer_result_section_requires_gradio(self) -> None:
"""Test that function raises RuntimeError without gradio."""
import web_ui.components as comp
original_gr = comp.gr
comp.gr = None
with pytest.raises(RuntimeError, match="gradio is not installed"):
optimizer_result_section()
comp.gr = original_gr
class TestResultSection:
"""Tests for result_section function."""
def test_result_section_requires_gradio(self) -> None:
"""Test that function raises RuntimeError without gradio."""
import web_ui.components as comp
original_gr = comp.gr
comp.gr = None
with pytest.raises(RuntimeError, match="gradio is not installed"):
result_section("test_sim_type")
comp.gr = original_gr
class TestExportDir:
"""Tests for EXPORT_DIR constant."""
def test_export_dir_exists(self) -> None:
"""Test that EXPORT_DIR exists."""
assert EXPORT_DIR.exists()
assert EXPORT_DIR.is_dir()
def test_export_dir_path(self) -> None:
"""Test that EXPORT_DIR has correct path."""
assert ".msmodeling_ui" in str(EXPORT_DIR)
assert "exports" in str(EXPORT_DIR)
class TestSafeDfFromRowsEdgeCases:
"""Tests for _safe_df_from_rows edge cases."""
def test_safe_df_with_mixed_types(self) -> None:
"""Test with mixed data types."""
rows = [
{"a": 1, "b": "text", "c": 3.14},
{"a": 2, "b": None, "c": 2.71},
]
result = _safe_df_from_rows(rows)
assert len(result) == 2
assert result.iloc[1]["b"] is None or pd.isna(result.iloc[1]["b"])
def test_safe_df_with_nested_dict(self) -> None:
"""Test with nested dict values."""
rows = [{"a": 1, "nested": {"key": "value"}}]
result = _safe_df_from_rows(rows)
assert len(result) == 1
def test_safe_df_preserves_index(self) -> None:
"""Test that index is preserved."""
rows = [{"a": 1, "b": 2}, {"a": 3, "b": 4}]
result = _safe_df_from_rows(rows)
assert list(result.index) == [0, 1]
class TestDfToRecordsEdgeCases:
"""Tests for df_to_records edge cases."""
def test_df_to_records_with_mixed_nan(self) -> None:
"""Test with mixed NaN and None values."""
df = pd.DataFrame(
{
"a": [1, None, 3],
"b": [4.5, float("nan"), None],
"c": ["x", None, "z"],
}
)
result = df_to_records(df)
assert len(result) == 3
def test_df_to_records_with_datetime(self) -> None:
"""Test with datetime columns."""
import datetime
df = pd.DataFrame(
{
"date": [datetime.datetime(2024, 1, 1)],
"value": [100],
}
)
result = df_to_records(df)
assert len(result) == 1
assert result[0]["value"] == 100
def test_df_to_records_preserves_column_order(self) -> None:
"""Test that column order is preserved."""
df = pd.DataFrame({"z": [1], "a": [2], "m": [3]})
result = df_to_records(df)
assert list(result[0].keys()) == ["z", "a", "m"]
class TestProgressHtmlEdgeCases:
"""Tests for progress_html edge cases."""
def test_progress_html_with_negative_completed(self) -> None:
"""Test with negative completed value."""
result = progress_html(-5, 10, "Task", "running")
assert "0/10" in result
def test_progress_html_with_very_large_numbers(self) -> None:
"""Test with very large numbers."""
result = progress_html(1000000, 2000000, "Task", "running")
assert "50.0%" in result
def test_progress_html_status_fallback(self) -> None:
"""Test status fallback logic."""
result = progress_html(5, 10, "Task", "")
assert "Preparing" in result
class TestGetVendorDeviceMapEdgeCases:
"""Tests for get_vendor_device_map edge cases."""
def test_vendor_device_map_structure(self) -> None:
"""Test that map has correct structure."""
result = get_vendor_device_map()
assert isinstance(result, dict)
for vendor, devices in result.items():
assert isinstance(vendor, str)
assert isinstance(devices, list)
assert all(isinstance(d, str) for d in devices)
def test_vendor_device_map_lowercase_vendors(self) -> None:
"""Test that vendors are strings."""
result = get_vendor_device_map()
if result:
for vendor in result.keys():
assert isinstance(vendor, str)