"""Real-Git checks for pinned initialization and safe legacy migration; no network.""" import importlib.util import os from pathlib import Path import subprocess import tempfile import unittest from unittest.mock import patch spec = importlib.util.spec_from_file_location('airdef_tool', Path(__file__).with_name('airdef.py')) tool = importlib.util.module_from_spec(spec) spec.loader.exec_module(tool) def git(where, *args): return subprocess.check_output(['git', '-C', str(where), *args], stderr=subprocess.STDOUT, text=True).strip() class CheckoutTests(unittest.TestCase): def setUp(self): self.tmp = tempfile.TemporaryDirectory() self.addCleanup(self.tmp.cleanup) self.base = Path(self.tmp.name) self.engine = self.base / 'engine' self.engine.mkdir() git(self.engine, 'init', '-q') git(self.engine, 'config', 'user.name', 'Fixture') git(self.engine, 'config', 'user.email', 'fixture@example.invalid') (self.engine / 'marker').write_text('old') git(self.engine, 'add', 'marker') git(self.engine, 'commit', '-qm', 'old') self.old = git(self.engine, 'rev-parse', 'HEAD') (self.engine / 'marker').write_text('new') git(self.engine, 'commit', '-qam', 'new') self.new = git(self.engine, 'rev-parse', 'HEAD') self.parent = self.base / 'airdef' self.parent.mkdir() git(self.parent, 'init', '-q') (self.parent / '.gitmodules').write_text('[submodule "horizon"]\n path = horizon\n url = ' + str(self.engine) + '\n') git(self.parent, 'add', '.gitmodules') self.pin(self.old) self.addCleanup(patch.stopall) patch.object(tool, 'ROOT', self.parent).start() patch.object(tool, 'FORK', self.parent / 'horizon').start() patch.dict(os.environ, {'GIT_ALLOW_PROTOCOL': 'file'}).start() def pin(self, sha): git(self.parent, 'update-index', '--add', '--cacheinfo', '160000,' + sha + ',horizon') def test_initialization_uses_pin_instead_of_newer_tip(self): tool.fork() self.assertEqual(git(tool.FORK, 'rev-parse', 'HEAD'), self.old) self.assertEqual((tool.FORK / 'marker').read_text(), 'old') tool.fork() # idempotent def test_dirty_checkout_is_preserved_when_pin_changes(self): tool.fork() (tool.FORK / 'marker').write_text('user changes') self.pin(self.new) with self.assertRaises(SystemExit): tool.fork() self.assertEqual((tool.FORK / 'marker').read_text(), 'user changes') self.assertEqual(git(tool.FORK, 'rev-parse', 'HEAD'), self.old) def test_old_standalone_clone_is_absorbed_without_losing_branches(self): git(self.parent, 'clone', str(self.engine), 'horizon') git(tool.FORK, 'checkout', '-qb', 'my-work', self.old) self.pin(self.new) tool.fork() self.assertTrue((tool.FORK / '.git').is_file()) self.assertEqual(git(tool.FORK, 'rev-parse', 'HEAD'), self.new) self.assertEqual(git(tool.FORK, 'rev-parse', 'my-work'), self.old) if __name__ == '__main__': unittest.main()