""" Verification test suite for Production Backend Engine """ import sys import time import os # Add backend directory to sys.path sys.path.insert(0, os.path.dirname(__file__)) import engine def test_initial_state(): state = engine.get_initial_state() assert state['cash'] == 30.0 assert 'wheat' in state['products'] assert state['products']['wheat']['unlocked'] is True assert state['products']['wheat']['lines'] == 1 assert state['products']['flour']['unlocked'] is False print("PASS: test_initial_state") def test_raw_production_and_logistics(): state = engine.get_initial_state() # Fast forward 10 seconds state['lastTick'] = time.time() - 10.0 updated = engine.process_offline_and_ticks(state) # Wheat has cycle time 1.0s, output 1, 1 line, plus logistics selling assert updated['products']['wheat']['totalProduced'] > 0 assert updated['cash'] > 30.0 print(f"PASS: test_raw_production_and_logistics (Produced: {updated['products']['wheat']['totalProduced']}, Cash: {updated['cash']})") def test_chained_dependency_and_bottleneck(): state = engine.get_initial_state() # Turn off wheat lines to simulate 0 upstream production state['products']['wheat']['lines'] = 0 state['products']['wheat']['stock'] = 0.0 # Unlock flour and give it 1 line state['products']['flour']['unlocked'] = True state['products']['flour']['lines'] = 1 # 1. Process with no wheat: flour should bottleneck state['lastTick'] = time.time() - 5.0 state = engine.process_offline_and_ticks(state) assert state['products']['flour']['stock'] == 0.0 assert state['products']['flour']['isBottlenecked'] is True # 2. Give 10 wheat: flour should consume wheat and produce flour state['products']['wheat']['stock'] = 10.0 state['lastTick'] = time.time() - 4.0 state = engine.process_offline_and_ticks(state) assert state['products']['flour']['totalProduced'] > 0 assert state['products']['wheat']['stock'] < 10.0 # Consumed! print("PASS: test_chained_dependency_and_bottleneck") def test_ipo_and_shares(): state = engine.get_initial_state() state['lifetimeRevenue'] = 400000.0 # $400k earned = engine.calculate_shares_earned(state['lifetimeRevenue']) assert earned == 20 # 10 * sqrt(400k / 100k) = 10 * 2 = 20 # Apply IPO action state = engine.apply_actions(state, [{'type': 'TRIGGER_IPO'}]) assert state['ventureShares'] == 20 assert state['ipoCount'] == 1 assert state['products']['wheat']['lines'] == 1 assert state['cash'] == 30.0 print("PASS: test_ipo_and_shares") def test_chained_microchips_and_boards(): state = engine.get_initial_state() # Unlock silicon, polymers, microchips, circuit_boards for pid in ['silicon', 'polymers', 'microchips', 'circuit_boards']: state['products'][pid]['unlocked'] = True state['products'][pid]['lines'] = 1 state['products'][pid]['stock'] = 0.0 # Give raw materials so silicon and polymers don't bottleneck state['products']['silicon']['stock'] = 10.0 state['products']['polymers']['stock'] = 20.0 # Microchips has 1 logistics fleet selling, but circuit_boards needs 2 microchips state['products']['microchips']['logistics'] = 1 # Simulate 30 seconds state['lastTick'] = time.time() - 30.0 state = engine.process_offline_and_ticks(state) # Verify microchips produced and circuit_boards actually received microchips and produced boards! assert state['products']['microchips']['totalProduced'] > 0 assert state['products']['circuit_boards']['totalProduced'] > 0 print(f"PASS: test_chained_microchips_and_boards (Chips: {state['products']['microchips']['totalProduced']}, Boards: {state['products']['circuit_boards']['totalProduced']})") def test_policy_toggles(): state = engine.get_initial_state() # Unlock wheat and flour state['products']['wheat']['stock'] = 20.0 state['products']['flour']['unlocked'] = True state['products']['flour']['lines'] = 1 # 1. Turn off downstream supply on wheat state = engine.apply_actions(state, [{'type': 'TOGGLE_DOWNSTREAM_SUPPLY', 'productId': 'wheat'}]) assert state['products']['wheat']['supplyDownstreamEnabled'] is False # Simulate 5 seconds: flour should be bottlenecked because wheat supply to downstream is blocked state['lastTick'] = time.time() - 5.0 state = engine.process_offline_and_ticks(state) assert state['products']['flour']['stock'] == 0.0 assert state['products']['flour']['isBottlenecked'] is True # 2. Turn downstream supply back on: flour consumes wheat and produces state = engine.apply_actions(state, [{'type': 'TOGGLE_DOWNSTREAM_SUPPLY', 'productId': 'wheat'}]) assert state['products']['wheat']['supplyDownstreamEnabled'] is True # 3. Turn off logistics fleet on wheat state = engine.apply_actions(state, [{'type': 'TOGGLE_LOGISTICS', 'productId': 'wheat'}]) assert state['products']['wheat']['logisticsEnabled'] is False # Simulate 5 seconds: wheat stock will NOT be sold by logistics fleet cash_before = state['cash'] state['lastTick'] = time.time() - 5.0 state = engine.process_offline_and_ticks(state) assert state['cash'] == cash_before # Wheat logistics paused, no wholesale sales assert state['products']['flour']['totalProduced'] > 0 # Flour received wheat! print("PASS: test_policy_toggles") def test_production_target_throttle(): state = engine.get_initial_state() state['products']['wheat']['logisticsEnabled'] = False # Don't sell to isolate production rate # Set throttle to 0.5 (50%) state = engine.apply_actions(state, [{'type': 'SET_PRODUCTION_TARGET', 'productId': 'wheat', 'target': 0.5}]) assert state['products']['wheat']['productionTarget'] == 0.5 state['lastTick'] = time.time() - 10.0 state = engine.process_offline_and_ticks(state) produced_at_50 = state['products']['wheat']['totalProduced'] # Reset and test at 1.0 (100%) state2 = engine.get_initial_state() state2['products']['wheat']['logisticsEnabled'] = False state2['lastTick'] = time.time() - 10.0 state2 = engine.process_offline_and_ticks(state2) produced_at_100 = state2['products']['wheat']['totalProduced'] # 50% should produce roughly half (5 units vs 10 units over 10s at 1.0s base cycle) assert produced_at_50 < produced_at_100 assert abs(produced_at_50 - (produced_at_100 * 0.5)) <= 1.0 # Set throttle to 0.0 (Paused / Off) state = engine.apply_actions(state, [{'type': 'SET_PRODUCTION_TARGET', 'productId': 'wheat', 'target': 0.0}]) stock_before = state['products']['wheat']['stock'] state['lastTick'] = time.time() - 10.0 state = engine.process_offline_and_ticks(state) assert state['products']['wheat']['stock'] == stock_before # Zero production when throttled to 0% print(f"PASS: test_production_target_throttle (50%: {produced_at_50}, 100%: {produced_at_100})") if __name__ == '__main__': test_initial_state() test_raw_production_and_logistics() test_chained_dependency_and_bottleneck() test_chained_microchips_and_boards() test_policy_toggles() test_production_target_throttle() test_ipo_and_shares() print("\nALL BACKEND ENGINE TESTS PASSED SUCCESSFULLY!")