Files
idle/tests/test_ascension.gd

326 lines
11 KiB
GDScript

extends Node
var passed: int = 0
var failed: int = 0
var _game_root: Node = null
func _ready() -> void:
pass # run() is called by the test runner; avoid double-execution.
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()
# Use a unique save path to avoid contamination from previous test runs.
var save_path: String = "user://test_ascension_%d.json" % randi()
DirAccess.remove_absolute(ProjectSettings.globalize_path(save_path))
var gs: LevelGameState = _game_root.get_node("LevelGameState")
gs.save_file_path = save_path
add_child(_game_root)
await _wait()
gs = _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")
# gold_boost is a root node (no parents), farm_boost requires gold_boost as parent.
TestUtils.assert_true(gs.can_purchase_prestige_buff(&"gold_boost"), "gold_boost is purchasable")
TestUtils.assert_false(gs.can_purchase_prestige_buff(&"farm_boost"), "farm_boost is NOT purchasable (parent gold_boost not yet unlocked)")
# 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