Files
gitea-agent/harness/tests/common/test_pytest_evidence_recipe.py
T

87 lines
4.2 KiB
Python

"""Conditional pytest recipe: documentation contract and real synthetic execution.
Run with an independently admitted pytest interpreter for execution coverage.
No dependency installation occurs in this test or the production workflow.
"""
import importlib.util
import json
import os
from pathlib import Path
import subprocess
import sys
import tempfile
import unittest
ROOT = Path(__file__).resolve().parents[3]
SKILL = ROOT / 'harness/agents/impl/skills/gitea-issue-rework/SKILL.md'
HEADING = '### Conditional pytest evidence recipe'
class PytestEvidenceRecipeTests(unittest.TestCase):
def recipe(self):
text = SKILL.read_text()
self.assertIn(HEADING, text, 'conditional pytest recipe is missing')
section = text.split(HEADING, 1)[1].split('\n### ', 1)[0]
return section, json.loads(section.split('```json\n', 1)[1].split('\n```', 1)[0])
def test_documentation_contract_limits_recipe_to_existing_pytest_projects(self):
section, argv = self.recipe()
for rule in ['pytest를 이미 사용하는', 'PYTEST_ADDOPTS', 'plugin',
'evidence_gap', '이전 실행', '0으로', 'schema', 'unittest',
'warning', 'timeout', 'output_limit']:
self.assertIn(rule, section)
self.assertIsInstance(argv, list)
self.assertEqual(argv[:4], ['{python}', '-B', '-m', 'pytest'])
@unittest.skipUnless(importlib.util.find_spec('pytest'), 'admitted pytest interpreter required')
def test_real_recipe_preserves_pass_skip_warning_summary_under_quiet_project_config(self):
_, argv = self.recipe()
with tempfile.TemporaryDirectory() as temporary:
root = Path(temporary)
(root / 'pytest.ini').write_text('[pytest]\naddopts = -qq\n')
(root / 'test_sample.py').write_text(
'import pytest, warnings\n'
'def test_pass():\n warnings.warn("synthetic warning", UserWarning)\n'
'@pytest.mark.skip(reason="synthetic skip")\ndef test_skip():\n pass\n')
control = self.invoke([sys.executable, '-B', '-m', 'pytest', 'test_sample.py'], root)
self.assertEqual(control['status'], 'completed')
self.assertEqual(control['exit_code'], 0)
self.assertNotIn('1 passed', control['output'])
actual = self.invoke(self.expand(argv), root)
self.assertEqual(actual['status'], 'completed')
self.assertEqual(actual['exit_code'], 0)
self.assertRegex(actual['output'], r'1 passed, 1 skipped, 1 warning')
self.assertNotIn('\x1b[', actual['output'])
@unittest.skipUnless(importlib.util.find_spec('pytest'), 'admitted pytest interpreter required')
def test_real_recipe_preserves_failure_summary_and_exit_code(self):
_, argv = self.recipe()
with tempfile.TemporaryDirectory() as temporary:
root = Path(temporary)
(root / 'pytest.ini').write_text('[pytest]\naddopts = -qq\n')
(root / 'test_sample.py').write_text('def test_fail():\n assert False, "synthetic failure"\n')
actual = self.invoke(self.expand(argv), root)
self.assertEqual(actual['status'], 'completed')
self.assertEqual(actual['exit_code'], 1)
self.assertIn('1 failed', actual['output'])
def expand(self, argv):
return [part.replace('{python}', sys.executable).replace('{tests}', 'test_sample.py') for part in argv]
def invoke(self, argv, root):
import importlib.util
path = ROOT / 'harness/agents/impl/skills/gitea-issue-rework/scripts/evidence_manifest.py'
spec = importlib.util.spec_from_file_location('pytest_recipe_evidence', path)
module = importlib.util.module_from_spec(spec)
spec.loader.exec_module(module)
env = {key: os.environ[key] for key in ['PATH', 'HOME', 'TMPDIR', 'LANG'] if key in os.environ}
# Isolate synthetic tests from unrelated globally installed pytest plugins.
env['PYTEST_DISABLE_PLUGIN_AUTOLOAD'] = '1'
result = module.run_bounded(argv, root, env, 65536, 30)
return {'status': result['status'], 'exit_code': result['exit_code'],
'output': result['output'].decode('utf-8', 'replace')}
if __name__ == '__main__':
unittest.main()