Something went wrong. Try again.
HEXWORK - A Lantern in the Deep: 3D ASCII terminal roguelike RPG in Rust.
Entirely designed and built by Muse Spark 1.3 to evaluate if I like the model.
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267"""Isolated acceptance controls; mutations only affect TemporaryDirectory data."""import copyimport importlib.utilfrom pathlib import Pathimport shutilimport tempfileimport unittest
import yaml
SCRIPT = Path(__file__).resolve().parents[1] / 'verify_msrv.py'SPEC = importlib.util.spec_from_file_location('verify_msrv', SCRIPT)v = importlib.util.module_from_spec(SPEC)SPEC.loader.exec_module(v)ROOT = SCRIPT.parents[1]
class Contracts(unittest.TestCase): def setUp(self): self.temp = tempfile.TemporaryDirectory() self.addCleanup(self.temp.cleanup) self.root = Path(self.temp.name)
def put(self, name, content): path = self.root / name path.parent.mkdir(parents=True, exist_ok=True) path.write_text(content) return path
def metadata(self): self.put('Cargo.toml', '''[workspace]members = ["crates/*"]exclude = ["vendor/bincode-2.0.1", "vendor/bincode_derive-2.0.1"][workspace.package]rust-version = "1.75"[workspace.dependencies]bincode = { version = "=2.0.1", features = ["derive"] }[patch.crates-io]bincode = { path = "vendor/bincode-2.0.1" }bincode_derive = { path = "vendor/bincode_derive-2.0.1" }''') packages = [] for name in ('hexwork-core', 'hexwork-cli', 'bincode', 'bincode_derive'): local = name.startswith('hexwork-') path = self.put(f'crates/{name}/Cargo.toml' if local else f'vendor/{name}-2.0.1/Cargo.toml', f'[package]\nname = "{name}"\nrust-version.workspace = true\n') targets = [{'name': name, 'kind': ['lib']}] if name == 'hexwork-cli': targets += [{'name': 'hexwork', 'kind': ['bin']}, {'name': 'gate', 'kind': ['test']}, {'name': 'speed', 'kind': ['bench']}, {'name': 'sample', 'kind': ['example']}, {'name': 'build-script-build', 'kind': ['custom-build']}] packages.append({'name': name, 'id': name, 'version': '0.1.0' if local else '2.0.1', 'manifest_path': str(path), 'source': None, 'rust_version': '1.75', 'targets': targets}) self.put('Cargo.lock', 'version = 3\n' + ''.join( f'[[package]]\nname = "{name}"\nversion = "2.0.1"\n' for name in ('bincode', 'bincode_derive'))) return {'workspace_root': str(self.root), 'workspace_members': ['hexwork-core', 'hexwork-cli'], 'packages': packages, 'resolve': {'nodes': [ {'id': 'hexwork-core', 'dependencies': ['bincode']}, {'id': 'hexwork-cli', 'dependencies': ['hexwork-core']}, {'id': 'bincode', 'dependencies': ['bincode_derive']}, {'id': 'bincode_derive', 'dependencies': []}]}}
def workflow(self): jobs = {} for name, channel in [('build', 'stable'), ('msrv', '1.75.0')]: steps = [{'uses': 'actions/checkout@v4'}, {'uses': 'dtolnay/rust-toolchain@' + channel, 'with': {'components': 'rustfmt, clippy'} if name == 'build' else {}}, {'uses': 'actions/setup-python@v5', 'with': {'python-version': '3.11'}}, {'run': v.COMMON_RUNS[0]}, {'run': 'mkdir -p target\n' + v.CAPTURE}] steps += [{'run': c} for c in v.COMMON_RUNS[1:]] if name == 'build': steps.append({'uses': 'taiki-e/install-action@v2', 'with': {'tool': 'cargo-deny'}}) steps += [{'run': c} for c in v.QUALITY[name]] jobs[name] = {'runs-on': '${{ matrix.os }}', 'timeout-minutes': 180, 'strategy': {'matrix': {'os': ['ubuntu-latest', 'macos-latest']}}, 'env': {'RUSTUP_TOOLCHAIN': channel, 'CARGO_TARGET_DIR': f'target/ci-${{{{ matrix.os }}}}-{channel}'}, 'steps': steps} return {'name': 'synthetic', 'on': ['push', 'pull_request'], 'jobs': jobs}
def check_workflow(self, data): path = self.put('ci.yml', yaml.safe_dump(data, sort_keys=False)) return v.verify_ci_msrv_contract(path)
def test_metadata_pristine(self): self.assertEqual(len(v.verify_msrv_metadata(self.root, self.metadata())), 4)
def test_metadata_negative_controls(self): for mutation in ('inheritance', 'integer_inheritance', 'metadata_floor', 'root_floor', 'inactive', 'registry', 'membership', 'exclusion', 'patch', 'lock_checksum', 'truncated'): with self.subTest(mutation=mutation): data = self.metadata() if mutation == 'inheritance': self.put('crates/hexwork-cli/Cargo.toml', '[package]\nname="hexwork-cli"\n') elif mutation == 'integer_inheritance': self.put('crates/hexwork-cli/Cargo.toml', '[package]\nname="hexwork-cli"\nrust-version.workspace = 1\n') elif mutation == 'metadata_floor': data['packages'][0]['rust_version'] = None elif mutation == 'root_floor': p = self.root / 'Cargo.toml' p.write_text(p.read_text().replace('"1.75"', '"1.85"')) elif mutation == 'inactive': data['resolve']['nodes'][0]['dependencies'] = [] elif mutation == 'registry': data['packages'][2]['source'] = 'registry+https://example.com' elif mutation == 'membership': data['workspace_members'].append('bincode') elif mutation == 'exclusion': p = self.root / 'Cargo.toml' p.write_text(p.read_text().replace('exclude = ["vendor/bincode-2.0.1", "vendor/bincode_derive-2.0.1"]', 'exclude = []')) elif mutation == 'patch': data['packages'][2]['manifest_path'] = '/cache/bincode/Cargo.toml' elif mutation == 'lock_checksum': p = self.root / 'Cargo.lock' p.write_text(p.read_text() + 'checksum = "bad"\n') else: data['workspace_members'].remove('hexwork-core') with self.assertRaises(v.ContractError): v.verify_msrv_metadata(self.root, data)
def test_lock_conversion_and_stability(self): original = '# generated\nversion = 4\n[[package]]\nname="a"\nversion="1.0.0"\nchecksum="abc"\ndependencies=["b"]\n' before = self.put('before', original) after = self.put('after', original.replace('version = 4', 'version = 3')) v.verify_lock_v3_conversion(before, after) v.verify_lock_stability(after, after) for change in ('checksum="xyz"', 'dependencies=["c"]', '# extra comment\n', 'version = 3 '): with self.subTest(change=change): text = original.replace('version = 4', 'version = 3') if change.startswith('checksum'): text = text.replace('checksum="abc"', change) elif change.startswith('dependencies'): text = text.replace('dependencies=["b"]', change) elif change.startswith('version'): text = text.replace('version = 3', change) else: text += change after.write_text(text) with self.assertRaises(v.ContractError): v.verify_lock_v3_conversion(before, after) with self.assertRaises(v.ContractError): v.verify_lock_stability(before, after)
def test_fixture_pristine_and_each_tampered_copy(self): destination = self.root / 'crates/hexwork-save/testfixtures' destination.mkdir(parents=True) for name in v.FIXTURES: shutil.copyfile(ROOT / 'crates/hexwork-save/testfixtures' / name, destination / name) v.verify_fixture_integrity(self.root) for name in v.FIXTURES: path = destination / name original = path.read_bytes() path.write_bytes(original + b'tampered') with self.subTest(fixture=name), self.assertRaises(v.ContractError): v.verify_fixture_integrity(self.root) path.write_bytes(original)
def test_partitions_complete_and_ci_exhaustive(self): data = self.metadata() plan = v.make_partitions(data) self.assertEqual(len(plan['commands']), 6) self.assertEqual(len(v.verify_target_partition_coverage(data, plan)), 6) v.verify_target_partition_coverage(data, {'version': 1, 'commands': [v.CI_ALL]}) data['packages'][1]['targets'].append({'name': 'future', 'kind': ['example']}) with self.assertRaises(v.ContractError): v.verify_target_partition_coverage(data, plan) v.verify_target_partition_coverage(data, v.make_partitions(data))
def test_partitions_negative_controls(self): data = self.metadata() for mutation in ('missing', 'all-targets', 'duplicate', 'unknown', 'unlocked'): plan = v.make_partitions(data) if mutation == 'missing': plan['commands'].pop() elif mutation == 'all-targets': plan['commands'][0].remove('--all-targets') elif mutation == 'duplicate': plan['commands'].append(plan['commands'][-1]) elif mutation == 'unknown': plan['commands'][-1][-1] = 'not-a-target' else: plan['commands'][0].remove('--locked') with self.subTest(mutation=mutation), self.assertRaises(v.ContractError): v.verify_target_partition_coverage(data, plan) data['packages'][1]['targets'].append({'name': 'future', 'kind': ['unknown-future-kind']}) with self.assertRaises(v.ContractError): v.make_partitions(data)
def test_ci_pristine(self): self.check_workflow(self.workflow())
def test_ci_malformed_yaml(self): path = self.put('invalid.yml', 'jobs: [unterminated') with self.assertRaises(v.ContractError): v.verify_ci_msrv_contract(path)
def test_ci_every_required_step_is_required(self): base = self.workflow() for name in ('build', 'msrv'): for index, step in enumerate(base['jobs'][name]['steps']): changed = copy.deepcopy(base) del changed['jobs'][name]['steps'][index] with self.subTest(job=name, step=step), self.assertRaises(v.ContractError): self.check_workflow(changed)
def test_ci_checkout_and_action_negative_controls(self): for mutation in ('remove', 'duplicate', 'late', 'unknown', 'null-action'): changed = self.workflow() for name in ('build', 'msrv'): steps = changed['jobs'][name]['steps'] checkout = next(i for i, step in enumerate(steps) if step.get('uses') == 'actions/checkout@v4') if mutation == 'remove': del steps[checkout] elif mutation == 'duplicate': steps.insert(checkout + 1, {'uses': 'actions/checkout@v4'}) elif mutation == 'late': step = steps.pop(checkout) steps.append(step) elif mutation == 'null-action': steps.insert(checkout + 1, {'uses': None}) else: steps.insert(checkout + 1, {'uses': 'example/unrecognized-action@v1'}) with self.subTest(mutation=mutation), self.assertRaises(v.ContractError): self.check_workflow(changed)
def test_ci_negative_controls(self): for mutation in ('locked', 'targets', 'toolchain', 'env', 'budget', 'matrix', 'mask', 'wrapper', 'continue', 'step_env', 'conditional', 'ignore', 'lint', 'python'): changed = self.workflow() job = changed['jobs']['msrv'] test = next(s for s in job['steps'] if s.get('run') == v.QUALITY['msrv'][1]) if mutation == 'locked': test['run'] = test['run'].replace(' --locked', '') elif mutation == 'targets': test['run'] = test['run'].replace(' --all-targets', '') elif mutation == 'toolchain': job['steps'][1]['uses'] = 'dtolnay/rust-toolchain@stable' elif mutation == 'env': job['env']['RUSTUP_TOOLCHAIN'] = 'stable' elif mutation == 'budget': job['timeout-minutes'] = 60 elif mutation == 'matrix': job['strategy']['matrix']['os'].pop() elif mutation == 'mask': test['run'] += ' || true' elif mutation == 'wrapper': test['run'] = 'bash -c ' + repr(test['run']) elif mutation == 'continue': test['continue-on-error'] = True elif mutation == 'step_env': test['env'] = {'RUSTUP_TOOLCHAIN': 'stable'} elif mutation == 'conditional': test['if'] = 'false' elif mutation == 'ignore': test['run'] += ' --ignore-rust-version' elif mutation == 'lint': changed['env'] = {'RUSTFLAGS': '-A warnings'} else: job['steps'][2]['with']['python-version'] = '3.10' with self.subTest(mutation=mutation), self.assertRaises(v.ContractError): self.check_workflow(changed)
if __name__ == '__main__': unittest.main()