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": "