from types import SimpleNamespace import pytest from evalscope.api.messages import ContentImage, ContentText from evalscope.api.metric import SampleScore from evalscope.benchmarks.vtcbench.vtcbench_adapter import ( PROMPT_PREFIXES, PROMPT_SUFFIXES, VTCBenchAdapter, _calculate_metrics, _normalize_response, _remove_html_tags, ) def _make_adapter(subset: str, eval_mode: str) -> VTCBenchAdapter: adapter = object.__new__(VTCBenchAdapter) adapter.current_subset_name = subset adapter.eval_mode = eval_mode adapter._missing_media_warned = set() adapter._benchmark_meta = SimpleNamespace(aggregation='mean') return adapter def test_official_metric_normalization_and_dispatch() -> None: assert _normalize_response('4075987 Wrong ') == 'wrong' metrics = _calculate_metrics('4075987 5943250', ['4075987', '5943250']) assert metrics['contains_any'] == 1.0 assert metrics['contains_all'] == 0.5 memory_metrics = _calculate_metrics('Adoption agencies', ['adoption agencies', 'agencies']) assert memory_metrics['rouge_l'] == 1.0 adapter = _make_adapter('Memory', 'text') score = adapter.match_score( original_prediction='Adoption agencies', filtered_prediction='ignored', reference='ignored', task_state=SimpleNamespace(metadata={ 'subset': 'Memory', 'answers': ['adoption agencies', 'agencies'], }), ) assert score.value['score'] == 1.0 assert score.main_score_name == 'score' aggregates = adapter.aggregate_scores([ SampleScore(score=score, sample_id=0), SampleScore(score=score, sample_id=1), ]) unified = next(item for item in aggregates if item.metric_name == 'normalized_score') assert unified.score == 1.0 assert unified.num == 2 def test_empty_answers_are_rejected() -> None: with pytest.raises(ValueError, match='at least one reference answer'): _calculate_metrics('answer', []) def test_text_mode_matches_official_context_order_and_html_cleanup() -> None: adapter = _make_adapter('Memory', 'text') record = { 'problem': 'What did Evan buy?', 'answers': ['a Prius'], '_context': "
I bought a Prius.
\n", } sample = adapter.record_to_sample(record) content = sample.input[0].content assert all(isinstance(item, ContentText) for item in content) assert content[0].text == _remove_html_tags(record['_context']) assert content[-1].text == PROMPT_SUFFIXES['Memory'].format(question=record['problem']) assert 'data-speaker' not in content[0].text assert 'Evan:' in content[0].text def test_vtc_mode_places_images_inside_official_template() -> None: adapter = _make_adapter('Reasoning', 'vtc') record = { 'problem': 'Who has been to Paris?', 'answers': ['Yuki'], 'images': ['data:image/jpeg;base64,AA==', 'data:image/jpeg;base64,AQ=='], } sample = adapter.record_to_sample(record) content = sample.input[0].content assert isinstance(content[0], ContentText) assert content[0].text == PROMPT_PREFIXES['Reasoning'] assert isinstance(content[1], ContentImage) assert isinstance(content[2], ContentImage) assert isinstance(content[3], ContentText) assert content[3].text == PROMPT_SUFFIXES['Reasoning'].format(question=record['problem']) def test_vtc_mode_requires_context_images() -> None: adapter = _make_adapter('Retrieval', 'vtc') with pytest.raises(ValueError, match='at least one context image'): adapter.record_to_sample({ 'problem': 'What is the number?', 'answers': ['42'], 'images': [], })