import json import subprocess import tempfile import unittest from pathlib import Path ROOT = Path(__file__).resolve().parents[1] INSTALL = ROOT / 'scripts' / 'install_into_repo.sh' class ArnesCoreTests(unittest.TestCase): def run_cmd(self, args, cwd=None, input_text=None, check=True): result = subprocess.run( args, cwd=cwd or ROOT, input=input_text, text=True, capture_output=True, ) if check and result.returncode != 0: raise AssertionError( f"Command failed: {args}\nSTDOUT:\n{result.stdout}\nSTDERR:\n{result.stderr}" ) return result def test_install_refuses_source_repo(self): result = self.run_cmd([str(INSTALL), str(ROOT)], check=False) self.assertNotEqual(result.returncode, 0) self.assertIn('Refusing to install ARNES into its own source repository', result.stdout) def test_install_start_verify_and_publish_in_external_repo(self): with tempfile.TemporaryDirectory() as tmp: tmp_path = Path(tmp) target = tmp_path / 'project-repo' remote = tmp_path / 'remote.git' self.run_cmd([str(INSTALL), str(target)]) self.assertTrue((target / 'scripts' / 'start.sh').is_file()) self.assertFalse((target / 'tests').exists(), 'source self-tests must not be installed into project repo') self.run_cmd(['git', 'config', 'user.name', 'ARNES Bot'], cwd=target) self.run_cmd(['git', 'config', 'user.email', 'arnes@example.com'], cwd=target) self.run_cmd(['git', 'init', '--bare', str(remote)]) self.run_cmd(['git', 'remote', 'add', 'origin', str(remote)], cwd=target) wizard_input = '\n'.join([ 'demo-project', 'Demo project', 'project', '1', '', '', '', '', ]) + '\n' self.run_cmd(['./scripts/start.sh'], cwd=target, input_text=wizard_input) self.assertTrue((target / 'project' / 'tests').is_dir()) cfg = json.loads((target / 'harness' / 'project.config.json').read_text(encoding='utf-8')) self.assertEqual(cfg['app_dir'], 'project') self.assertEqual(cfg['commands']['test'], 'python3 -m unittest discover -s project/tests -v') verify_result = self.run_cmd(['./scripts/verify.sh'], cwd=target) self.assertIn('Harness verificado', verify_result.stdout) self.run_cmd(['python3', 'scripts/new_ticket.py'], cwd=target, input_text='\n'.join([ 'fix', 'Repair docs', 'Need docs repair', 'Make docs clear', 'Docs flow', 'No redesign', 'low', 'med', 'Docs clear', 'Verify green', '', ]) + '\n') with (target / 'project' / 'README.md').open('a', encoding='utf-8') as fh: fh.write('\nchange\n') publish_result = self.run_cmd( ['python3', 'scripts/publish_ticket.py', '--feature-id', 'F-001'], cwd=target, ) self.assertIn('done ->', publish_result.stdout) publish_path = target / 'work' / 'artifacts' / 'F-001' / 'publish.json' payload = json.loads(publish_path.read_text(encoding='utf-8')) self.assertEqual(payload['verdict'], 'PUBLISHED') self.assertTrue(payload['pushed']) self.assertEqual(payload['remote'], 'origin') status_result = self.run_cmd(['git', 'status', '--short'], cwd=target) self.assertEqual(status_result.stdout.strip(), '') remote_refs = self.run_cmd(['git', 'ls-remote', 'origin'], cwd=target) self.assertIn('refs/heads/master', remote_refs.stdout) def test_agent_status_rejects_invalid_agent(self): result = self.run_cmd( ['python3', 'scripts/agent_status.py', 'set', '--agent', 'nope'], check=False, ) self.assertNotEqual(result.returncode, 0) combined = (result.stdout + result.stderr) self.assertIn('Invalid agent: nope', combined) if __name__ == '__main__': unittest.main()