File size: 8,057 Bytes
827e786
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
import sys
from pathlib import Path

sys.path.insert(0, str(Path(__file__).resolve().parents[1]))
import app


def _assert(cond: bool, msg: str) -> None:
    if not cond:
        raise AssertionError(msg)


def test_prompt_uses_visible_rows_only() -> None:
    # If selected state contains stale hidden tags, prompt should still reflect visible-row selections only.
    row_defs = [
        {"name": "r1", "label": "R1", "tags": ["solo", "female"], "tag_meta": {}},
        {"name": "r2", "label": "R2", "tags": ["cub"], "tag_meta": {}},
    ]
    payload = app._build_ui_payload(
        console_text="x",
        row_defs=row_defs,
        selected_tags=["solo", "rosalina_(mario)"],
    )
    prompt_text = payload[2]
    selected_state = payload[3]
    _assert("rosalina \\(mario\\)" not in prompt_text, "stale hidden tag leaked into prompt")
    _assert("solo" in prompt_text, "visible selected tag missing from prompt")
    _assert("rosalina_(mario)" not in selected_state, "stale hidden tag leaked into selected state")


def test_row_deduping() -> None:
    row_defs = [
        {
            "name": "other_retrieved",
            "label": "Other (Retrieved)",
            "tags": ["cub", "expressions", "invalid_tag", "cub", "expressions"],
            "tag_meta": {},
        }
    ]
    prompt_text, row_values_state, _, checkbox_updates = app._build_row_component_updates(
        row_defs=row_defs,
        selected_tags=["cub", "expressions"],
        max_rows=app.display_max_rows_default,
    )
    _assert(prompt_text == "cub, expressions", "prompt should be deduped and ordered from row")
    _assert(row_values_state[0] == ["cub", "expressions"], "row selected values should be deduped")
    first_choices = checkbox_updates[0]["choices"]
    first_values = [v for _, v in first_choices]
    _assert(first_values == ["cub", "expressions", "invalid_tag"], "row choices should be deduped")


def test_rebuild_ignores_stale_selected_state() -> None:
    row_defs = [
        {"name": "selected_other", "label": "Selected (Other)", "tags": ["solo", "female", "anthro"], "tag_meta": {}},
        {"name": "other_retrieved", "label": "Other (Retrieved)", "tags": ["cub", "expressions"], "tag_meta": {}},
    ]
    # Simulate UI state where user has deselected anthro, but stale selected state still contains it.
    selected_state = ["solo", "female", "anthro", "cub"]
    row_values_state = [["solo", "female"], ["cub"]]
    out = app._rebuild_rows_from_selected(
        selected_state,
        row_defs,
        row_values_state,
        app.display_top_groups_default,
        app.display_top_tags_per_group_default,
        app.display_rank_top_k_default,
    )
    prompt = out[1]
    selected_after = out[2]
    _assert("anthro" not in selected_after, "rebuild should not resurrect stale deselected tags")
    _assert("anthro" not in prompt, "prompt should not include stale deselected tags")
    _assert("solo" in prompt and "female" in prompt and "cub" in prompt, "rebuild should retain current row selections")


def test_toggle_then_rebuild_does_not_resurrect_removed_tag() -> None:
    row_defs = [
        {"name": "selected_other", "label": "Selected (Other)", "tags": ["solo", "anthro", "female"], "tag_meta": {}},
        {"name": "other_retrieved", "label": "Other (Retrieved)", "tags": ["cub", "expressions"], "tag_meta": {}},
    ]
    selected_state = ["solo", "anthro", "female", "cub"]
    row_values_state = [["solo", "anthro", "female"], ["cub"]]

    # User unchecks anthro in row 0.
    toggle_out = app._on_toggle_row(
        0,
        ["solo", "female"],
        selected_state,
        False,
        row_defs,
        row_values_state,
        app.display_max_rows_default,
    )
    selected_after_toggle = toggle_out[0]
    row_values_after_toggle = toggle_out[3]
    _assert("anthro" not in selected_after_toggle, "toggle should remove anthro from selected state")

    # Rebuild from current row values must preserve the user-toggle result.
    rebuild_out = app._rebuild_rows_from_selected(
        selected_after_toggle,
        row_defs,
        row_values_after_toggle,
        app.display_top_groups_default,
        app.display_top_tags_per_group_default,
        app.display_rank_top_k_default,
    )
    prompt_after_rebuild = rebuild_out[1]
    selected_after_rebuild = rebuild_out[2]
    _assert("anthro" not in selected_after_rebuild, "rebuild should not resurrect deselected anthro")
    _assert("anthro" not in prompt_after_rebuild, "prompt should not contain deselected anthro after rebuild")
    _assert("solo" in prompt_after_rebuild and "female" in prompt_after_rebuild, "kept selections should remain")
    _assert("cub" in prompt_after_rebuild, "other retrieved selection should remain")


def test_toggle_does_not_cross_activate_unrelated_row_tag() -> None:
    row_defs = [
        {"name": "organization", "label": "Organization", "tags": ["pinup", "close-up"], "tag_meta": {}},
        {"name": "color_markings", "label": "Color Markings", "tags": ["shoulder_markings", "black_markings"], "tag_meta": {}},
    ]
    selected_state = []
    row_values_state = [[], []]

    # User enables close-up in organization row.
    out = app._on_toggle_row(
        0,
        ["close-up"],
        selected_state,
        False,
        row_defs,
        row_values_state,
        app.display_max_rows_default,
    )
    selected_after = out[0]
    row_values_after = out[3]
    _assert("close-up" in selected_after, "close-up should be selected")
    _assert("shoulder_markings" not in selected_after, "unrelated row tag should not be auto-selected")
    _assert(row_values_after[0] == ["close-up"], "organization row values should include close-up only")
    _assert(row_values_after[1] == [], "color markings row should remain unselected")


def test_shared_tag_mirrors_without_unrelated_cross_toggle() -> None:
    row_defs = [
        {"name": "objects_props", "label": "Objects Props", "tags": ["holding_face", "holding_clothing"], "tag_meta": {}},
        {"name": "expression_detail", "label": "Expression Detail", "tags": ["open_mouth", "closed_smile"], "tag_meta": {}},
        {"name": "pose_action_detail", "label": "Pose Action Detail", "tags": ["holding_face", "walking"], "tag_meta": {}},
    ]
    selected_state = []
    row_values_state = [[], [], []]

    # Enable open_mouth; should not affect holding_face rows.
    out1 = app._on_toggle_row(
        1,
        ["open_mouth"],
        selected_state,
        False,
        row_defs,
        row_values_state,
        app.display_max_rows_default,
    )
    sel1 = out1[0]
    vals1 = out1[3]
    _assert("open_mouth" in sel1, "open_mouth should be selected")
    _assert("holding_face" not in sel1, "holding_face must remain unselected")
    _assert(vals1[0] == [], "objects props row should remain unselected")
    _assert(vals1[1] == ["open_mouth"], "expression row should select open_mouth")
    _assert(vals1[2] == [], "pose row should remain unselected")

    # Enable holding_face in objects row; should mirror only to pose row, not expression row.
    out2 = app._on_toggle_row(
        0,
        ["holding_face"],
        sel1,
        True,
        row_defs,
        vals1,
        app.display_max_rows_default,
    )
    sel2 = out2[0]
    vals2 = out2[3]
    _assert("holding_face" in sel2 and "open_mouth" in sel2, "both explicitly selected tags should be present")
    _assert(vals2[0] == ["holding_face"], "objects row should select holding_face")
    _assert(vals2[1] == ["open_mouth"], "expression row should keep open_mouth only")
    _assert(vals2[2] == ["holding_face"], "pose row should mirror holding_face")


def main() -> None:
    test_prompt_uses_visible_rows_only()
    test_row_deduping()
    test_rebuild_ignores_stale_selected_state()
    test_toggle_then_rebuild_does_not_resurrect_removed_tag()
    test_toggle_does_not_cross_activate_unrelated_row_tag()
    test_shared_tag_mirrors_without_unrelated_cross_toggle()
    print("ui state smoke: ok")


if __name__ == "__main__":
    main()