87 lines
4.2 KiB
Python
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()
|