import json import html import unittest import re from html.parser import HTMLParser from unittest.mock import patch import app from grounding_demo.console import compile_query, query_from_prompt, targets_html class ConsoleTest(unittest.TestCase): def test_request_ids_distinguish_identical_results_and_errors(self): path = str(app.ROOT / app.CASES[0]["image"]) raw = "<|object_ref_start|>car<|object_ref_end|><|box_start|><1><2><30><40><|box_end|>" runs = [] for error in (False, False, True): with patch.object(app.GroundingClient, "infer", return_value=(raw, .1, {}), side_effect=TimeoutError("test") if error else None): states = list(app.run_console(path, "car", "grounding")) ids = [re.search("data-run-id='([^']+)'", state[5]).group(1) for state in states] self.assertEqual(ids[0], ids[-1]) self.assertIn("data-phase='busy'", states[0][5]) self.assertNotIn("data-phase='busy'", states[-1][5]) self.assertTrue(states[-1][-1]["interactive"]) runs.append(ids[0]) self.assertEqual(len(set(runs)), 3) def test_all_case_prompts_roundtrip_exactly(self): for row in app.CASES: with self.subTest(case=row["id"]): query = query_from_prompt(row["prompt"], row["route"]) self.assertEqual(compile_query(query, row["route"]), row["prompt"]) def test_category_separator(self): self.assertIn("carperson.", compile_query("car, person", "grounding")) def test_every_gallery_route_has_loadable_replacement_examples(self): self.assertEqual(len(app.CASES), 22) self.assertEqual({row["route"] for row in app.CASES}, set(app.ROUTE_META)) for route in app.ROUTE_META: with self.subTest(route=route): choices, gallery, *loaded = app.change_route(route) self.assertEqual(len(choices["choices"]), len(app.BY_ROUTE[route])) self.assertEqual(len(gallery["value"]), len(app.BY_ROUTE[route])) self.assertEqual(loaded[8], "[]") self.assertIn("Image ready", loaded[10]) def test_case_switch_resets_prediction(self): output = app.load_case(app.CASES[1]["id"]) self.assertEqual(output[8], "[]") self.assertIn("Image ready", output[10]) def test_upload_cannot_reveal_unrelated_gt(self): row = app.CASES[0] path = str(app.ROOT / row["image"]) uploaded = app.upload_image(path, row["route"], row["prompt"]) self.assertIsNone(uploaded[1]) self.assertEqual(uploaded[2], path) self.assertEqual(uploaded[8], "[]") self.assertFalse(hasattr(app, "switch_view")) self.assertFalse(any(c.get("props", {}).get("elem_id") == "view-toggle" for c in app.demo.config["components"])) def test_invalid_protocol_is_not_shown_as_valid_overlay(self): row = app.CASES[0] valid = "<|object_ref_start|>car<|object_ref_end|><|box_start|><1><2><30><40><|box_end|>" invalid = "<|object_ref_start|>car<|object_ref_end|><|box_start|><1><2><3><|box_end|>" result = app.result_bundle( str(app.ROOT / row["image"]), row["prompt"], row["route"], valid + invalid ) self.assertEqual(result["normalized"], "[]") self.assertIn("Protocol error", result["metrics"]) def test_actual_request_uses_latest_query_without_reference(self): row = app.CASES[0] path = str(app.ROOT / row["image"]) response = "<|object_ref_start|>car<|object_ref_end|><|box_start|><1><2><30><40><|box_end|>" with patch.object(app.GroundingClient, "infer", return_value=(response, 1.2, {})) as infer: output = app.run_inference(path, "car", row["route"]) infer.assert_called_once_with(path, compile_query("car", row["route"])) self.assertIsInstance(output[0], app.Image.Image) self.assertEqual(len(output), 6) self.assertIn("1 visual targets", output[-1]) def test_labels_are_html_escaped(self): self.assertIn( "<script>", targets_html([{"label": "