P23-03: 生活の観察
This commit is contained in:
@@ -71,6 +71,35 @@ def require(value, message):
|
||||
raise ValueError(message)
|
||||
|
||||
|
||||
def check_setup_budget_source(source):
|
||||
"""Cheap preflight for the fixture's shared spend plan, before OS replay."""
|
||||
prepare = source.split('func prepare() -> void:', 1)[1].split('\nfunc ', 1)[0]
|
||||
categories = {
|
||||
'construction': ('budget_builds := builds.duplicate(true)',
|
||||
'budget_builds.append([improvement[',
|
||||
'for row: Array in budget_builds:',
|
||||
'needed[key] += int(definition.construction_cost.get(key, 0))'),
|
||||
'signing': ('for assignment: Array in assignments:',
|
||||
'runtime.mvp_content_catalog.get_recruitment_entry(assignment[0])',
|
||||
'signing_total += signing_cost', 'needed[&"gold"] += signing_total'),
|
||||
'purchase': ('SupplyCatalog.get_item(SupplyCatalog.RAW_FOOD)',
|
||||
'PurchaseQuoteV2.make(SupplyCatalog.RAW_FOOD, purchase_quantity,',
|
||||
'PurchaseQuoteV2.eligible(runtime)', 'purchase_quote[&"effective_total"]',
|
||||
'needed[&"gold"] += purchase_total'),
|
||||
}
|
||||
budget_end = prepare.index('\n\tvar state:')
|
||||
for category, expressions in categories.items():
|
||||
require(all(expression in prepare[:budget_end] for expression in expressions),
|
||||
'setup budget missing spend category: ' + category)
|
||||
require(prepare.count('for assignment: Array in assignments:') == 2,
|
||||
'budget and hire must share assignments')
|
||||
require('&"quantity": purchase_quantity}' in prepare,
|
||||
'budget and purchase must share quantity')
|
||||
require('deltas[key] = needed[key] - state.get_resource(key)' in prepare,
|
||||
'setup budget deltas must cover needed')
|
||||
return set(categories)
|
||||
|
||||
|
||||
def sha(path):
|
||||
return hashlib.sha256(Path(path).read_bytes()).hexdigest()
|
||||
|
||||
@@ -1597,6 +1626,7 @@ def main(argv=None):
|
||||
parser.add_argument('--layout-a', type=Path)
|
||||
parser.add_argument('--layout-b', type=Path)
|
||||
args = parser.parse_args(argv)
|
||||
check_setup_budget_source((args.project_root / 'tests/fixtures/p23-03/observation.gd').read_text())
|
||||
if args.offline_mirror:
|
||||
require(not any((args.verify_only, args.diagnostics, args.layout_a, args.layout_b)),
|
||||
'offline preparation must not be combined with acceptance checks')
|
||||
|
||||
@@ -18,6 +18,30 @@ sys.dont_write_bytecode = True
|
||||
import check_p23_life_observation_evidence as check
|
||||
|
||||
|
||||
class SetupBudgetTests(unittest.TestCase):
|
||||
def setUp(self):
|
||||
self.source = (check.ROOT / 'tests/fixtures/p23-03/observation.gd').read_text()
|
||||
|
||||
def test_all_planned_spends_enter_common_needed_and_deltas(self):
|
||||
self.assertEqual(check.check_setup_budget_source(self.source),
|
||||
{'construction', 'signing', 'purchase'})
|
||||
|
||||
def test_missing_spend_category_fails_before_os_replay(self):
|
||||
expressions = {
|
||||
'construction': 'needed[key] += int(definition.construction_cost.get(key, 0))',
|
||||
'signing': 'needed[&"gold"] += signing_total',
|
||||
'purchase': 'needed[&"gold"] += purchase_total',
|
||||
}
|
||||
for category, expression in expressions.items():
|
||||
with self.subTest(category=category), self.assertRaisesRegex(ValueError, category):
|
||||
check.check_setup_budget_source(self.source.replace(expression, 'pass'))
|
||||
|
||||
def test_missing_delta_coverage_fails(self):
|
||||
with self.assertRaisesRegex(ValueError, 'deltas'):
|
||||
check.check_setup_budget_source(self.source.replace(
|
||||
'deltas[key] = needed[key] - state.get_resource(key)', 'pass'))
|
||||
|
||||
|
||||
class QueuedElevatorTests(unittest.TestCase):
|
||||
def setUp(self):
|
||||
fixture = json.loads((check.ROOT / 'tests/fixtures/p23-03/queued_elevator.json').read_text())
|
||||
|
||||
Reference in New Issue
Block a user