Add prestige graph
This commit is contained in:
318
tests/test_ascension.gd
Normal file
318
tests/test_ascension.gd
Normal file
@@ -0,0 +1,318 @@
|
||||
extends Node
|
||||
|
||||
var passed: int = 0
|
||||
var failed: int = 0
|
||||
var _game_root: Node = null
|
||||
|
||||
|
||||
func _ready() -> void:
|
||||
await run()
|
||||
|
||||
|
||||
func run() -> void:
|
||||
print("\n=== TEST: Ascension Buff System ===\n")
|
||||
TestUtils.set_test_name("ascension")
|
||||
|
||||
_test_node_resource()
|
||||
_test_node_validation()
|
||||
_test_node_parent_checking()
|
||||
_test_catalogue_queries()
|
||||
_test_purchase_flow()
|
||||
_test_prestige_does_not_reset_prestige_buffs()
|
||||
_test_multiplier_computation()
|
||||
_test_save_load_roundtrip()
|
||||
|
||||
_print_summary()
|
||||
|
||||
|
||||
#region Node Resource Tests
|
||||
func _test_node_resource() -> void:
|
||||
print("--- Node Resource ---")
|
||||
|
||||
var node: PrestigeBuffNode = PrestigeBuffNode.new()
|
||||
node.id = &"test_node"
|
||||
node.display_name = "Test Node"
|
||||
node.effect_type = PrestigeBuffNode.EffectType.CURRENCY_PRODUCTION_MULTIPLIER
|
||||
node.effect_value = 2.0
|
||||
node.cost_mantissa = 5.0
|
||||
node.cost_exponent = 2 # cost = 5e2 = 500
|
||||
|
||||
var cost: BigNumber = node.get_cost()
|
||||
TestUtils.assert_equals(5.0, cost.mantissa, "cost mantissa matches")
|
||||
TestUtils.assert_equals(2, cost.exponent, "cost exponent matches")
|
||||
TestUtils.assert_false(node.has_parents(), "node with no parents returns false")
|
||||
|
||||
|
||||
func _test_node_validation() -> void:
|
||||
print("--- Node Validation ---")
|
||||
|
||||
var valid: PrestigeBuffNode = PrestigeBuffNode.new()
|
||||
valid.id = &"valid_id"
|
||||
valid.cost_mantissa = 1.0
|
||||
TestUtils.assert_true(valid.is_valid(), "node with id and positive cost is valid")
|
||||
|
||||
var no_id: PrestigeBuffNode = PrestigeBuffNode.new()
|
||||
no_id.cost_mantissa = 1.0
|
||||
TestUtils.assert_false(no_id.is_valid(), "node with empty id is invalid")
|
||||
|
||||
var zero_cost: PrestigeBuffNode = PrestigeBuffNode.new()
|
||||
zero_cost.id = &"has_id"
|
||||
zero_cost.cost_mantissa = 0.0
|
||||
TestUtils.assert_false(zero_cost.is_valid(), "node with zero cost is invalid")
|
||||
|
||||
|
||||
func _test_node_parent_checking() -> void:
|
||||
print("--- Parent Checking ---")
|
||||
|
||||
var unlocked: Dictionary = {}
|
||||
unlocked[&"parent_a"] = true
|
||||
unlocked[&"parent_b"] = false
|
||||
|
||||
var node: PrestigeBuffNode = PrestigeBuffNode.new()
|
||||
node.id = &"child"
|
||||
node.parent_ids = [&"parent_a"]
|
||||
|
||||
TestUtils.assert_true(node.all_parents_unlocked(unlocked), "all parents unlocked when all are true")
|
||||
|
||||
node.parent_ids = [&"parent_a", &"parent_b"]
|
||||
TestUtils.assert_false(node.all_parents_unlocked(unlocked), "not all parents unlocked when one is false")
|
||||
|
||||
node.parent_ids = [&"nonexistent"]
|
||||
TestUtils.assert_false(node.all_parents_unlocked(unlocked), "missing parent treated as not unlocked")
|
||||
#endregion
|
||||
|
||||
|
||||
#region Catalogue Tests
|
||||
func _test_catalogue_queries() -> void:
|
||||
print("--- Catalogue Queries ---")
|
||||
|
||||
var root: PrestigeBuffNode = _make_node(&"root", [], 0, 0.0)
|
||||
var child_a: PrestigeBuffNode = _make_node(&"child_a", [&"root"], 1, 0.0)
|
||||
var child_b: PrestigeBuffNode = _make_node(&"child_b", [&"root"], 1, 1.0)
|
||||
var grandchild: PrestigeBuffNode = _make_node(&"grandchild", [&"child_a", &"child_b"], 2, 0.0)
|
||||
|
||||
var cat: PrestigeBuffCatalogue = PrestigeBuffCatalogue.new()
|
||||
cat.nodes = [root, child_a, child_b, grandchild]
|
||||
|
||||
TestUtils.assert_equals(root, cat.get_node_by_id(&"root"), "get_node_by_id finds root")
|
||||
TestUtils.assert_equals(null, cat.get_node_by_id(&"nonexistent"), "get_node_by_id returns null for unknown id")
|
||||
|
||||
var ids: Array[StringName] = cat.get_all_ids()
|
||||
TestUtils.assert_equals(4, ids.size(), "get_all_ids returns 4 ids")
|
||||
|
||||
var roots: Array[PrestigeBuffNode] = cat.get_root_nodes()
|
||||
TestUtils.assert_equals(1, roots.size(), "one root node")
|
||||
TestUtils.assert_equals(&"root", roots[0].id, "root node id is 'root'")
|
||||
|
||||
var children: Array[PrestigeBuffNode] = cat.get_children_of(&"root")
|
||||
TestUtils.assert_equals(2, children.size(), "root has 2 children")
|
||||
|
||||
var grandkids: Array[PrestigeBuffNode] = cat.get_children_of(&"child_a")
|
||||
TestUtils.assert_equals(1, grandkids.size(), "child_a has 1 child")
|
||||
#endregion
|
||||
|
||||
|
||||
#region Purchase Flow Tests
|
||||
func _test_purchase_flow() -> void:
|
||||
print("--- Purchase Flow ---")
|
||||
|
||||
var scene: PackedScene = load("res://docs/gyms/tiny_sword/tiny_sword.tscn")
|
||||
_game_root = scene.instantiate()
|
||||
add_child(_game_root)
|
||||
await _wait()
|
||||
|
||||
var gs: LevelGameState = _game_root.find_child("LevelGameState")
|
||||
if gs == null:
|
||||
print("[ERROR] LevelGameState not found")
|
||||
return
|
||||
|
||||
# Give ascension currency for purchasing
|
||||
gs.add_currency_by_id(&"ascension", BigNumber.from_float(100.0))
|
||||
await _wait()
|
||||
|
||||
# Verify catalogue has our two nodes
|
||||
var cat: PrestigeBuffCatalogue = gs.prestige_buff_catalogue
|
||||
TestUtils.assert_not_null(cat, "prestige_buff_catalogue is set")
|
||||
if cat == null:
|
||||
return
|
||||
|
||||
TestUtils.assert_true(cat.nodes.size() >= 2, "catalogue has at least 2 nodes")
|
||||
|
||||
# Verify nodes initialized in state
|
||||
TestUtils.assert_false(gs.is_prestige_buff_unlocked(&"gold_boost"), "gold_boost starts locked")
|
||||
TestUtils.assert_false(gs.is_prestige_buff_unlocked(&"farm_boost"), "farm_boost starts locked")
|
||||
|
||||
# Check can_purchase (both are root nodes with no parents, should be purchaseable)
|
||||
TestUtils.assert_true(gs.can_purchase_prestige_buff(&"gold_boost"), "gold_boost is purchasable")
|
||||
TestUtils.assert_true(gs.can_purchase_prestige_buff(&"farm_boost"), "farm_boost is purchasable")
|
||||
|
||||
# Check cost
|
||||
var cost: BigNumber = gs.get_prestige_buff_cost(&"gold_boost")
|
||||
TestUtils.assert_greater_than(cost.mantissa, 0.0, "gold_boost cost > 0")
|
||||
|
||||
# Purchase gold_boost
|
||||
var purchased: bool = gs.purchase_prestige_buff(&"gold_boost")
|
||||
TestUtils.assert_true(purchased, "purchase_prestige_buff returns true")
|
||||
TestUtils.assert_true(gs.is_prestige_buff_unlocked(&"gold_boost"), "gold_boost is now unlocked")
|
||||
TestUtils.assert_false(gs.can_purchase_prestige_buff(&"gold_boost"), "cannot repurchase already unlocked node")
|
||||
|
||||
# farm_boost should still be available (both are roots, independent)
|
||||
TestUtils.assert_true(gs.can_purchase_prestige_buff(&"farm_boost"), "farm_boost is still purchasable")
|
||||
|
||||
# Verify available buffs
|
||||
var available: Array[PrestigeBuffNode] = gs.get_available_prestige_buffs()
|
||||
var found_farm: bool = false
|
||||
var found_gold: bool = false
|
||||
for node in available:
|
||||
if node.id == &"farm_boost":
|
||||
found_farm = true
|
||||
if node.id == &"gold_boost":
|
||||
found_gold = true
|
||||
TestUtils.assert_true(found_farm, "farm_boost appears in available buffs")
|
||||
TestUtils.assert_false(found_gold, "gold_boost does NOT appear in available buffs (already unlocked)")
|
||||
|
||||
# Test cannot purchase with insufficient currency
|
||||
gs._prestige_buff_unlocked.clear()
|
||||
gs._initialize_prestige_buffs()
|
||||
# Drain ascension currency
|
||||
var bal: BigNumber = gs.get_currency_amount_by_id(&"ascension")
|
||||
gs.spend_currency_by_id(&"ascension", bal)
|
||||
TestUtils.assert_false(gs.can_purchase_prestige_buff(&"gold_boost"), "cannot purchase with no currency")
|
||||
|
||||
# Restore currency, re-unlock gold_boost for later tests
|
||||
gs.add_currency_by_id(&"ascension", BigNumber.from_float(100.0))
|
||||
gs.purchase_prestige_buff(&"gold_boost")
|
||||
await _wait()
|
||||
#endregion
|
||||
|
||||
|
||||
func _test_prestige_does_not_reset_prestige_buffs() -> void:
|
||||
print("--- Prestige Does Not Reset Prestige ---")
|
||||
|
||||
if _game_root == null:
|
||||
return
|
||||
|
||||
var gs: LevelGameState = _game_root.find_child("LevelGameState")
|
||||
if gs == null:
|
||||
return
|
||||
|
||||
# gold_boost should be unlocked from previous test
|
||||
TestUtils.assert_true(gs.is_prestige_buff_unlocked(&"gold_boost"), "gold_boost unlocked before prestige")
|
||||
|
||||
# Give enough currency to prestige
|
||||
gs.add_currency_by_id(&"gold", BigNumber.new(1.0, 10)) # 1e10 gold
|
||||
await _wait()
|
||||
|
||||
var pm: PrestigeManager = _game_root.find_child("PrestigeManager") as PrestigeManager
|
||||
if pm == null:
|
||||
print("[WARN] PrestigeManager not found; skipping prestige test")
|
||||
return
|
||||
|
||||
# Perform prestige if possible
|
||||
if pm.can_prestige():
|
||||
pm.perform_prestige()
|
||||
await _wait()
|
||||
|
||||
# After prestige, gold_boost should STILL be unlocked
|
||||
TestUtils.assert_true(gs.is_prestige_buff_unlocked(&"gold_boost"), "gold_boost still unlocked after prestige")
|
||||
else:
|
||||
# Manual simulation: call reset_for_prestige directly and verify ascension survives
|
||||
gs.reset_for_prestige(true, false, [&"ascension"])
|
||||
await _wait()
|
||||
TestUtils.assert_true(gs.is_prestige_buff_unlocked(&"gold_boost"), "gold_boost still unlocked after reset_for_prestige")
|
||||
#endregion
|
||||
|
||||
|
||||
func _test_multiplier_computation() -> void:
|
||||
print("--- Multiplier Computation ---")
|
||||
|
||||
if _game_root == null:
|
||||
return
|
||||
|
||||
var gs: LevelGameState = _game_root.find_child("LevelGameState")
|
||||
if gs == null:
|
||||
return
|
||||
|
||||
# gold_boost is already unlocked (from purchase test). Effect type 1 = GENERATOR_PRODUCTION_MULTIPLIER
|
||||
var mult: float = gs.get_prestige_buff_multiplier(PrestigeBuffNode.EffectType.CURRENCY_PRODUCTION_MULTIPLIER, &"goldmine")
|
||||
TestUtils.assert_greater_than(mult, 1.0, "multiplier for goldmine is > 1.0 with gold_boost unlocked")
|
||||
|
||||
# farm_boost is NOT unlocked, multiplier for farm should be 1.0
|
||||
var farm_mult: float = gs.get_prestige_buff_multiplier(PrestigeBuffNode.EffectType.CURRENCY_PRODUCTION_MULTIPLIER, &"farm")
|
||||
TestUtils.assert_equals(1.0, farm_mult, "multiplier for farm is 1.0 (farm_boost not unlocked)")
|
||||
|
||||
# Unlock farm_boost and check again
|
||||
gs.add_currency_by_id(&"ascension", BigNumber.from_float(100.0))
|
||||
gs.purchase_prestige_buff(&"farm_boost")
|
||||
await _wait()
|
||||
|
||||
var farm_mult2: float = gs.get_prestige_buff_multiplier(PrestigeBuffNode.EffectType.CURRENCY_PRODUCTION_MULTIPLIER, &"farm")
|
||||
TestUtils.assert_greater_than(farm_mult2, 1.0, "multiplier for farm is > 1.0 after unlocking farm_boost")
|
||||
|
||||
# Check that unrelated effect type returns 1.0
|
||||
var unrelated: float = gs.get_prestige_buff_multiplier(PrestigeBuffNode.EffectType.RESEARCH_XP_MULTIPLIER, &"")
|
||||
TestUtils.assert_equals(1.0, unrelated, "unrelated effect type returns 1.0")
|
||||
#endregion
|
||||
|
||||
|
||||
func _test_save_load_roundtrip() -> void:
|
||||
print("--- Save/Load Roundtrip ---")
|
||||
|
||||
if _game_root == null:
|
||||
return
|
||||
|
||||
var gs: LevelGameState = _game_root.find_child("LevelGameState")
|
||||
if gs == null:
|
||||
return
|
||||
|
||||
# Both gold_boost and farm_boost should be unlocked
|
||||
TestUtils.assert_true(gs.is_prestige_buff_unlocked(&"gold_boost"), "gold_boost unlocked before save")
|
||||
TestUtils.assert_true(gs.is_prestige_buff_unlocked(&"farm_boost"), "farm_boost unlocked before save")
|
||||
|
||||
# Save
|
||||
gs.save_game()
|
||||
await _wait()
|
||||
|
||||
# Clear state manually to simulate fresh load
|
||||
gs._prestige_buff_unlocked.clear()
|
||||
TestUtils.assert_false(gs.is_prestige_buff_unlocked(&"gold_boost"), "gold_boost false after clear")
|
||||
TestUtils.assert_false(gs.is_prestige_buff_unlocked(&"farm_boost"), "farm_boost false after clear")
|
||||
|
||||
# Load
|
||||
gs.load_game()
|
||||
await _wait()
|
||||
|
||||
# Both should be restored
|
||||
TestUtils.assert_true(gs.is_prestige_buff_unlocked(&"gold_boost"), "gold_boost restored after load")
|
||||
TestUtils.assert_true(gs.is_prestige_buff_unlocked(&"farm_boost"), "farm_boost restored after load")
|
||||
#endregion
|
||||
|
||||
|
||||
#region Helpers
|
||||
func _make_node(id: StringName, parent_ids: Array[StringName], tier: int, x_pos: float) -> PrestigeBuffNode:
|
||||
var n: PrestigeBuffNode = PrestigeBuffNode.new()
|
||||
n.id = id
|
||||
n.display_name = String(id)
|
||||
n.parent_ids = parent_ids
|
||||
n.tier = tier
|
||||
n.x_position = x_pos
|
||||
n.cost_mantissa = 1.0
|
||||
return n
|
||||
|
||||
|
||||
func _wait() -> void:
|
||||
await get_tree().create_timer(0.3).timeout
|
||||
|
||||
|
||||
func _print_summary() -> void:
|
||||
TestUtils.print_result()
|
||||
passed = TestUtils.get_passed()
|
||||
failed = TestUtils.get_failed()
|
||||
|
||||
|
||||
func get_passed() -> int:
|
||||
return passed
|
||||
|
||||
|
||||
func get_failed() -> int:
|
||||
return failed
|
||||
Reference in New Issue
Block a user