Spaces:
Sleeping
Sleeping
| """TDD for spaceutil.plot.build_umap_figure.""" | |
| from __future__ import annotations | |
| def test_returns_plotly_figure(synthetic_cards): | |
| import plotly.graph_objects as go | |
| from spaceutil.plot import build_umap_figure | |
| fig = build_umap_figure(synthetic_cards) | |
| assert isinstance(fig, go.Figure) | |
| def test_base_trace_only_without_highlights(synthetic_cards): | |
| from spaceutil.plot import build_umap_figure | |
| fig = build_umap_figure(synthetic_cards, highlight_indices=None) | |
| assert len(fig.data) == 1 | |
| def test_overlay_trace_added_for_highlights(synthetic_cards): | |
| from spaceutil.plot import build_umap_figure | |
| fig = build_umap_figure(synthetic_cards, highlight_indices=[0, 2, 5]) | |
| assert len(fig.data) == 2 | |
| def test_empty_highlights_treated_as_none(synthetic_cards): | |
| from spaceutil.plot import build_umap_figure | |
| fig = build_umap_figure(synthetic_cards, highlight_indices=[]) | |
| assert len(fig.data) == 1 | |
| def test_base_trace_customdata_carries_corpus_index(synthetic_cards): | |
| """Click events need to round-trip the corpus index from customdata, | |
| so we can resolve any clicked point back to a corpus row regardless | |
| of which trace it landed on.""" | |
| from spaceutil.plot import build_umap_figure | |
| fig = build_umap_figure(synthetic_cards) | |
| base = fig.data[0] | |
| assert base.customdata is not None | |
| assert len(base.customdata) == len(synthetic_cards) | |
| first_row = base.customdata[0] | |
| # customdata rows may be array-like; first element must be the index. | |
| assert int(first_row[0]) == 0 | |
| assert int(base.customdata[5][0]) == 5 | |
| def test_overlay_trace_customdata_length_matches_highlights(synthetic_cards): | |
| from spaceutil.plot import build_umap_figure | |
| indices = [1, 3, 7, 11] | |
| fig = build_umap_figure(synthetic_cards, highlight_indices=indices) | |
| overlay = fig.data[1] | |
| assert overlay.customdata is not None | |
| assert len(overlay.customdata) == len(indices) | |
| def test_hover_text_includes_card_name(synthetic_cards): | |
| from spaceutil.plot import build_umap_figure | |
| fig = build_umap_figure(synthetic_cards) | |
| base = fig.data[0] | |
| assert base.text is not None | |
| assert len(base.text) == len(synthetic_cards) | |
| assert synthetic_cards[0]["name"] in base.text[0] | |
| def test_cost_curve_figure_with_hits(): | |
| import plotly.graph_objects as go | |
| from spaceutil.plot import build_cost_curve_figure | |
| from spaceutil.synergy import SynergyHit | |
| hits = [ | |
| SynergyHit(1, "A", "A", 0.9, 0.0, 0.9, False, "Character", ["Red"], 3, "OP01"), | |
| SynergyHit(2, "B", "B", 0.8, 0.0, 0.8, False, "Character", ["Red"], 3, "OP01"), | |
| SynergyHit(3, "C", "C", 0.7, 0.0, 0.7, False, "Event", ["Red"], 7, "OP01"), | |
| ] | |
| fig = build_cost_curve_figure(hits) | |
| assert isinstance(fig, go.Figure) | |
| assert len(fig.data) == 1 | |
| bar = fig.data[0] | |
| # Two distinct cost buckets: 3 (count 2) and 7 (count 1) | |
| assert list(bar.x) == ["3", "7"] | |
| assert list(bar.y) == [2, 1] | |
| def test_cost_curve_figure_empty_shows_placeholder(): | |
| import plotly.graph_objects as go | |
| from spaceutil.plot import build_cost_curve_figure | |
| fig = build_cost_curve_figure([]) | |
| assert isinstance(fig, go.Figure) | |
| # Empty case has no bar trace | |
| assert len(fig.data) == 0 | |
| # But carries an annotation | |
| assert fig.layout.annotations is not None | |
| assert any("pick a leader" in a.text.lower() for a in fig.layout.annotations) | |