Files
VianoBugAnalysis/tests/test_thin_investigation.py

87 lines
4.3 KiB
Python

import copy
import json
import pytest
from viano_bug_analysis.analysis.investigation_view import working_view, thin_view
from viano_bug_analysis.analysis.investigation_prompt import build_prompt
from viano_bug_analysis.case.contracts import validate
from viano_bug_analysis.tools import ToolError
from test_project_research import source
from test_investigation_view import context
def restore(view):
for entry in view['evidence'].values():
for capture in entry['content']['items']:
result = capture.get('result', {})
table = result.get('items')
if not isinstance(table, dict) or 'encoding' not in table:
continue
if table['encoding'] == 'source_line_table_v1':
result['items'] = [{**table['common'], **dict(zip(table['columns'], row))} for row in table['rows']]
else:
result['items'] = [{**table['common'], 'row': dict(zip(table['columns'], row))} for row in table['rows']]
return view
def test_tables_are_lossless_including_rows_limits_and_other_hypotheses():
c = context()
for eid, entry in c['evidence'].items():
entry['content']['items'] = [
{'query': {'kind': 'source.read', 'path': 'code.cpp', 'start_line': 1, 'end_line': 80},
'result': {'coverage': 'selected_lines', 'truncated': False,
'items': [{'path': 'code.cpp', 'sha256': 'a'*64, 'size': 1000,
'line': i, 'text': 'line '+str(i), 'text_truncated': False,
'typed_metadata': False if i % 2 else 0} for i in range(1, 81)]}},
{'query': {'kind': 'database.rows', 'table': 'example'},
'result': {'coverage': 'partial_filtered_rows', 'truncated': True, 'next_offset': 2,
'items': [{'table': 'example', 'row': {'id': 1, 'path': 'a'*64, 'value': None}},
{'table': 'example', 'row': {'id': 2, 'path': 'b'*64, 'value': False}}]}}]
original = copy.deepcopy(c)
compact = thin_view(c)
assert len(json.dumps(compact)) < len(json.dumps(working_view(c))) / 2
assert json.dumps(restore(copy.deepcopy(compact)), sort_keys=True) == json.dumps(working_view(c), sort_keys=True)
assert c == original
def test_nonuniform_rows_are_not_coerced_to_null():
c = context()
entry = next(iter(c['evidence'].values()))
entry['content']['items'] = [{'query': {'kind': 'database.rows'}, 'result': {'items': [
{'row': {'id': 1, 'value': None}}, {'row': {'id': 2}}]}}]
assert thin_view(c)['evidence'] == working_view(c)['evidence']
def test_archived_v4_requests_keep_their_original_working_view():
c = context()
c['prompt_version'] = 'investigation_project_v4'
request = build_prompt(c)
assert request['prompt_version'] == 'investigation_project_v4'
schema = request['output_schema']
assert json.loads(request['messages'][1]['content'])['input'] == working_view(c)
c['prompt_version'] = 'investigation_project_v5'
request = build_prompt(c)
assert request['prompt_version'] == 'investigation_project_v5'
assert request['output_schema'] == schema
assert json.loads(request['messages'][1]['content'])['input'] == thin_view(c)
def test_eof_returns_remaining_lines_and_empty_read_with_explicit_scope(source):
for start, expected in ((2, [2, 3]), (4, [])):
args = {'kind': 'source.read', 'path': 'module.cpp', 'start_line': start, 'end_line': 60}
result = source.query(args)
assert [i['line'] for i in result['items']] == expected
assert result['eof'] is True and result['total_lines'] == 3
assert result['truncated'] is False and result['coverage'] == 'selected_lines'
assert result['requested_end_line'] == 60
assert result['returned_end_line'] == (3 if expected else None)
validate({'format':'viano-project-capture','format_version':1,'query':args,
'origin':source.binding(),'result':result}, 'project-capture')
@pytest.mark.parametrize('start,end', [(0, 3), (1, 81), (4, 3), (True, 3), (1, 2.0)])
def test_eof_does_not_bypass_safety_limits(source, start, end):
with pytest.raises(ToolError, match='PROJECT_SOURCE_RANGE'):
source.query({'kind': 'source.read', 'path': 'module.cpp', 'start_line': start, 'end_line': end})