103 lines
3.2 KiB
Bash
Executable File
103 lines
3.2 KiB
Bash
Executable File
#!/bin/bash
|
|
set -e
|
|
|
|
echo "=== MetaCA Studio Test Suite ==="
|
|
|
|
python3 -c "
|
|
from metaca import CARule, CAGrid, TournamentSelector
|
|
|
|
# Test 1: CARule creation and fingerprinting
|
|
print('Test 1: CARule fingerprint...')
|
|
rule = CARule(
|
|
rule_id='test-rule',
|
|
neighborhood='moore',
|
|
states=2,
|
|
transition_table={'0:3': 1, '1:2': 1, '1:3': 1},
|
|
origin_agent='test-agent'
|
|
)
|
|
fp = rule.fingerprint()
|
|
assert len(fp) == 16, f'Expected 16-char fingerprint, got {len(fp)}'
|
|
assert fp == rule.fingerprint(), 'Fingerprint must be deterministic'
|
|
print(f' PASS (fingerprint={fp})')
|
|
|
|
# Test 2: CAGrid initialization
|
|
print('Test 2: Grid initialization...')
|
|
grid = CAGrid(10, 10, states=2)
|
|
assert grid.population() == 0, 'Empty grid should have 0 population'
|
|
assert grid.density() == 0.0, 'Empty grid should have 0 density'
|
|
print(' PASS')
|
|
|
|
# Test 3: Cell operations with wrapping
|
|
print('Test 3: Cell set/get with toroidal wrapping...')
|
|
grid.set_cell(0, 0, 1)
|
|
assert grid.get_cell(0, 0) == 1
|
|
assert grid.get_cell(10, 10) == 1, 'Toroidal wrap failed'
|
|
assert grid.population() == 1
|
|
print(' PASS')
|
|
|
|
# Test 4: Moore neighborhood
|
|
print('Test 4: Moore neighborhood...')
|
|
neighbors = grid.get_moore_neighbors(1, 1)
|
|
assert len(neighbors) == 8, f'Moore should return 8 neighbors, got {len(neighbors)}'
|
|
print(' PASS')
|
|
|
|
# Test 5: Von Neumann neighborhood
|
|
print('Test 5: Von Neumann neighborhood...')
|
|
neighbors = grid.get_vonneumann_neighbors(1, 1)
|
|
assert len(neighbors) == 4, f'VN should return 4 neighbors, got {len(neighbors)}'
|
|
print(' PASS')
|
|
|
|
# Test 6: Game of Life step (B3/S23)
|
|
print('Test 6: Game of Life simulation step...')
|
|
life_rule = CARule(
|
|
rule_id='game-of-life',
|
|
neighborhood='moore',
|
|
states=2,
|
|
transition_table={'0:3': 1, '1:2': 1, '1:3': 1}
|
|
)
|
|
grid2 = CAGrid(5, 5)
|
|
# Blinker pattern
|
|
grid2.set_cell(1, 2, 1)
|
|
grid2.set_cell(2, 2, 1)
|
|
grid2.set_cell(3, 2, 1)
|
|
assert grid2.population() == 3
|
|
next_gen = grid2.step(life_rule)
|
|
assert next_gen.population() == 3, f'Blinker should preserve population, got {next_gen.population()}'
|
|
assert next_gen.get_cell(2, 1) == 1, 'Blinker should rotate'
|
|
assert next_gen.get_cell(2, 3) == 1, 'Blinker should rotate'
|
|
print(' PASS')
|
|
|
|
# Test 7: Tournament selector
|
|
print('Test 7: Tournament selection...')
|
|
selector = TournamentSelector(tournament_size=2)
|
|
for i in range(5):
|
|
r = CARule(rule_id=f'r{i}', neighborhood='moore', states=2,
|
|
transition_table={'0:3': 1}, fitness=float(i))
|
|
selector.add_rule(r)
|
|
top = selector.top_k(3)
|
|
assert len(top) == 3
|
|
assert top[0].fitness == 4.0, 'Top rule should have highest fitness'
|
|
print(' PASS')
|
|
|
|
# Test 8: Merge remote rules with dedup
|
|
print('Test 8: Federated merge with dedup...')
|
|
remote = [CARule(rule_id='r0-dup', neighborhood='moore', states=2,
|
|
transition_table={'0:3': 1}, fitness=10.0)]
|
|
before = len(selector.population)
|
|
selector.merge_remote(remote)
|
|
after = len(selector.population)
|
|
assert after == before, f'Duplicate rule should not increase population ({before} -> {after})'
|
|
print(' PASS')
|
|
|
|
# Test 9: Serialization roundtrip
|
|
print('Test 9: Serialization roundtrip...')
|
|
d = rule.to_dict()
|
|
restored = CARule.from_dict(d)
|
|
assert restored.fingerprint() == rule.fingerprint()
|
|
print(' PASS')
|
|
|
|
print()
|
|
print('All 9 tests passed!')
|
|
"
|
|
|
|
echo "=== All tests passed ===" |