Files
reimburse/native-engine/tests/test_engine_build.py
T
2026-09-16 16:06:21 +08:00

77 lines
3.2 KiB
Python

import os
import shutil
import subprocess
import tempfile
import unittest
from pathlib import Path
class EngineBuildTests(unittest.TestCase):
def setUp(self):
self.temporary = tempfile.TemporaryDirectory()
self.root = Path(self.temporary.name)
engine = Path(__file__).resolve().parents[1]
for name in ['engine-fingerprint.sh', 'ensure-engine.sh']:
shutil.copyfile(engine / name, self.root / name)
for name in ['engine.py', 'exports.py', 'requirements.txt', 'requirements.lock.txt',
'personal-expense-template.xlsx', 'helper.entitlements']:
(self.root / name).write_text('fixture\n')
self.binary = self.root / 'dist/receipt-engine-helper.app/Contents/MacOS/receipt-engine-helper'
(self.root / 'build-engine.sh').write_text('''#!/bin/bash
set -euo pipefail
cd "$(dirname "$0")"
echo build >> builds.log
mkdir -p dist/receipt-engine-helper.app/Contents/MacOS
printf 'fixture engine\\n' > dist/receipt-engine-helper.app/Contents/MacOS/receipt-engine-helper
chmod +x dist/receipt-engine-helper.app/Contents/MacOS/receipt-engine-helper
SOURCE_HASH="$(bash engine-fingerprint.sh)"
BINARY_HASH="$(shasum -a 256 dist/receipt-engine-helper.app/Contents/MacOS/receipt-engine-helper | cut -d ' ' -f 1)"
printf '%s\\n%s\\n' "$SOURCE_HASH" "$BINARY_HASH" > dist/receipt-engine-helper.source.sha256
''')
def tearDown(self):
self.temporary.cleanup()
def ensure(self):
return subprocess.run(['bash', str(self.root / 'ensure-engine.sh')],
capture_output=True, text=True, timeout=20)
def build_count(self):
return len((self.root / 'builds.log').read_text().splitlines())
def test_missing_engine_builds_and_unchanged_engine_is_reused(self):
self.assertEqual(self.ensure().returncode, 0)
self.assertEqual(self.build_count(), 1)
self.assertEqual(self.ensure().returncode, 0)
self.assertEqual(self.build_count(), 1)
def test_changed_sources_rebuild_even_when_timestamp_is_unchanged(self):
self.assertEqual(self.ensure().returncode, 0)
source = self.root / 'exports.py'
original = source.stat()
source.write_text('new grouping implementation\n')
os.utime(source, ns=(original.st_atime_ns, original.st_mtime_ns))
self.assertEqual(self.ensure().returncode, 0)
self.assertEqual(self.build_count(), 2)
def test_replaced_binary_rebuilds(self):
self.assertEqual(self.ensure().returncode, 0)
self.binary.write_text('old engine\n')
self.assertEqual(self.ensure().returncode, 0)
self.assertEqual(self.build_count(), 2)
def test_missing_stamp_rebuilds(self):
self.assertEqual(self.ensure().returncode, 0)
(self.root / 'dist/receipt-engine-helper.source.sha256').unlink()
self.assertEqual(self.ensure().returncode, 0)
self.assertEqual(self.build_count(), 2)
def test_failed_rebuild_does_not_accept_old_engine(self):
self.assertEqual(self.ensure().returncode, 0)
(self.root / 'build-engine.sh').write_text('exit 17\n')
self.assertEqual(self.ensure().returncode, 17)
if __name__ == '__main__':
unittest.main()