Files
aetherbound-guild/runtime/tests/fg3/content_registry_test.gd
T

187 lines
9.4 KiB
GDScript

extends SceneTree
const Content = preload("res://fg3/content_registry.gd")
var failures: Array[String] = []
var rejected_cases := 0
func _initialize() -> void:
call_deferred("run_test")
func run_test() -> void:
var first := Content.snapshot()
var second := Content.snapshot()
var validation := Content.validate(first)
expect(validation.ok, "canonical registry validates: %s" % str(validation.errors))
expect(first == second, "catalog loading and enrichment are byte-identical")
expect(String(first.catalog_hash).length() == 64, "catalog hash is canonical")
verify_counts_and_identity(first)
verify_route_and_market_authority(first)
verify_contract2_authority(first)
verify_negative_boundaries(first)
if failures.is_empty():
print("ABG_FG3_CONTENT_GRAPH_OK new_equipment=16 complete_equipment=40 new_artifacts=4 complete_artifacts=7 enemies=12 bosses=2 contract1_routes=15 contract2_routes=36 markets=5+12 localized=76 source=7_exact negative_cases=%d" % rejected_cases)
quit(0)
else:
for failure in failures:
push_error(failure)
quit(1)
func verify_counts_and_identity(content: Dictionary) -> void:
expect(content.region.id == "RG-02", "Region identity is exact")
expect(
content.contract.id == "CTR-R2-01"
and content.contract.slice_start_market == 8
and content.contract.slice_end_market == 13,
"Contract-1 ending boundary is exact"
)
expect(content.contract.boss_executable, "Contract 1 Boss execution is enabled in Step 2")
expect(content.contract2.id == "CTR-R2-02" and content.contract2.boss_id == "BO-R2-02" and not content.contract2.boss_executable, "Contract 2 boundary is exact and Boss execution stays frozen")
expect(content.equipment.size() == 16, "EQ-065..080 are exposed")
expect(content.artifacts.size() == 4, "four missing Artifact rows are exposed")
expect(content.bosses.size() == 2, "both Siltwake Boss identities are exposed")
expect(content.routes.size() == 15 and content.markets.size() == 5, "15 routes and five Markets are exposed")
expect(content.inherited.equipment_ids.size() + content.equipment.size() == 40, "complete Region equipment count is 40")
expect(content.inherited.enemy_ids.size() == 12, "complete Region enemy count is 12")
expect(content.inherited.artifact_ids.size() + content.artifacts.size() == 7, "complete Region Artifact count is seven")
expect(content.source == Content.SOURCE_AUTHORITY, "seven source blobs are exact")
var ids := {}
for singleton in [content.region, content.contract, content.contract2]:
verify_row(singleton, ids)
for family in [content.equipment, content.artifacts, content.bosses, content.routes, content.contract2_routes]:
for row in family:
verify_row(row, ids)
expect(ids.size() == 76, "all 76 bounded identities are unique and localized")
func verify_route_and_market_authority(content: Dictionary) -> void:
var routes := Content.rows_by_id(content, "routes")
var markets := Content.markets_by_index(content)
var expected_capacities := {8: 7, 9: 8, 10: 8, 11: 9, 12: 9}
var expected_levels := {8: 3, 9: 3, 10: 4, 11: 4, 12: 4}
var enemy_usage := {}
for enemy_id in content.inherited.enemy_ids:
enemy_usage[String(enemy_id)] = 0
for market_index in [8, 9, 10, 11, 12]:
var market: Dictionary = markets[market_index]
expect(market.round_index == market_index, "Market %d binds the same Round" % market_index)
expect(market.cleared_rounds_before == market_index - 1, "Market %d stores clear lineage" % market_index)
expect(market.line_capacity == expected_capacities[market_index], "Market %d capacity is exact" % market_index)
expect(market.offer_level == expected_levels[market_index], "Market %d offer level follows the formula" % market_index)
expect(market.route_ids.size() == 3 and market.required_equipment_ids.size() == 2, "Market %d has exact board authority" % market_index)
for risk in range(3):
var route: Dictionary = routes[market.route_ids[risk]]
expect(route.market_index == market_index and route.risk == risk, "Market %d risk %d identity is exact" % [market_index, risk])
expect(route.reward_coin == 20 + 2 * market_index + 7 * risk, "Market %d risk %d reward is exact" % [market_index, risk])
expect(route.wave_order.map(func(wave): return wave.enemy_id) == route.enemy_ids, "Market %d risk %d wave order is exact" % [market_index, risk])
for enemy_id in route.enemy_ids:
enemy_usage[String(enemy_id)] += 1
for enemy_id in enemy_usage:
expect(enemy_usage[enemy_id] >= 2, "%s appears in at least two distinct route decisions" % enemy_id)
expect(markets[12].milestone_disclosure == "boss_preparation", "Market 12 discloses Boss preparation")
func verify_contract2_authority(content: Dictionary) -> void:
var routes := Content.rows_by_id(content, "contract2_routes")
expect(routes.size() == 36 and content.contract2_markets.size() == 12, "Contract 2 has 36 routes and twelve Markets")
var enemy_usage := {}
for enemy_id in content.inherited.enemy_ids:
enemy_usage[String(enemy_id)] = 0
for market_index in range(1, 13):
var market: Dictionary = content.contract2_markets[market_index - 1]
expect(market.market_index == market_index and market.round_index == market_index, "Contract-2 Market %d identity is exact" % market_index)
expect(market.line_capacity == 10 and market.offer_level == 1 + int(floor(float(market_index - 1) / 3.0)), "Contract-2 Market %d capacity and offer level are exact" % market_index)
for risk in range(3):
var route_id := "RO-R2-C02-M%02d-Q%d" % [market_index, risk]
var route: Dictionary = routes[route_id]
expect(route.reward_coin == 20 + 2 * market_index + 7 * risk, "%s reward formula is exact" % route_id)
expect(route.wave_order.map(func(wave): return wave.enemy_id) == route.enemy_ids, "%s wave order is exact" % route_id)
for enemy_id in route.enemy_ids:
enemy_usage[String(enemy_id)] += 1
for enemy_id in enemy_usage:
expect(enemy_usage[enemy_id] >= 2, "%s remains exercised in Contract 2" % enemy_id)
expect(content.contract2_markets[-1].first_order_changer_id == "BO-R2-02", "Market 12 discloses Drowned Bell as first-order changer")
func verify_row(row: Dictionary, ids: Dictionary) -> void:
expect(not ids.has(row.id), "%s is globally unique" % row.id)
ids[row.id] = true
expect(not String(row.name_en).is_empty() and not String(row.name_zh).is_empty(), "%s has bilingual names" % row.id)
expect(not String(row.preview).is_empty() and row.response_tags.size() >= 3, "%s has preview and response tags" % row.id)
expect(String(row.execution_key).begins_with("execute.") and String(row.mechanic_signature).length() == 64, "%s has dispatch and signature" % row.id)
func verify_negative_boundaries(canonical: Dictionary) -> void:
var source_drift := canonical.duplicate(true)
source_drift.source.economy_blob = "0".repeat(40)
expect_rejected(source_drift, "source drift", "source:economy_blob")
var missing_item := canonical.duplicate(true)
missing_item.equipment.pop_back()
expect_rejected(missing_item, "missing item", "family_ids:equipment")
var duplicate_route := canonical.duplicate(true)
duplicate_route.routes[1].id = "RO-R2-M08-Q0"
expect_rejected(duplicate_route, "duplicate route", "duplicate_global_id:RO-R2-M08-Q0")
var unknown_enemy := canonical.duplicate(true)
unknown_enemy.routes[0].enemy_ids[0] = "EN-R2-99"
unknown_enemy.routes[0].wave_order[0].enemy_id = "EN-R2-99"
expect_rejected(unknown_enemy, "unknown enemy", "route_enemy:RO-R2-M08-Q0")
var reward_drift := canonical.duplicate(true)
reward_drift.routes[7].reward_coin += 1
expect_rejected(reward_drift, "reward drift", "route_reward:RO-R2-M10-Q1")
var disabled_first_boss := canonical.duplicate(true)
disabled_first_boss.bosses[0].executable = false
expect_rejected(disabled_first_boss, "first Boss disabled", "boss_execution_boundary:BO-R2-01")
var executable_second_boss := canonical.duplicate(true)
executable_second_boss.bosses[1].executable = true
expect_rejected(executable_second_boss, "second Boss execution leak", "boss_execution_boundary:BO-R2-02")
var missing_contract2_route := canonical.duplicate(true)
missing_contract2_route.contract2_routes.pop_back()
expect_rejected(missing_contract2_route, "missing Contract-2 route", "contract2_route_count")
var artifact_conflict := canonical.duplicate(true)
artifact_conflict.artifacts[0].conflict_id = "AR-013"
expect_rejected(artifact_conflict, "Artifact conflict", "artifact_conflict:AR-009")
var capacity_drift := canonical.duplicate(true)
capacity_drift.markets[4].line_capacity = 10
expect_rejected(capacity_drift, "capacity drift", "market_capacity:12")
var level_drift := canonical.duplicate(true)
level_drift.markets[2].offer_level = 3
expect_rejected(level_drift, "offer-level drift", "market_offer_level:10")
var item_reference := canonical.duplicate(true)
item_reference.markets[0].required_equipment_ids[0] = "EQ-999"
expect_rejected(item_reference, "unknown required item", "market_equipment:8:EQ-999")
var filler := canonical.duplicate(true)
filler.bosses[1].rule = "TODO placeholder"
expect_rejected(filler, "filler Boss", "filler:BO-R2-02:todo")
func expect_rejected(content: Dictionary, label: String, expected_error: String) -> void:
var result := Content.validate(content)
var found := false
for error in result.errors:
if String(error).begins_with(expected_error):
found = true
expect(not result.ok and found, "%s rejects with %s; got %s" % [label, expected_error, str(result.errors)])
if not result.ok and found:
rejected_cases += 1
func expect(condition: bool, message: String) -> void:
if not condition:
failures.append("FG-3 content registry: %s" % message)