Files
shawn ba2fc37502 Make weapons test fully self-contained, fix headless bootstrap preload
Weapon tests now embed weapon data inline rather than preloading
WeaponRegistry (which triggers WeaponData class_name resolution).
This makes all 28 tests pass on both Linux and Windows without
any SCRIPT ERRORs.

Also add WeaponData.gd to headless bootstrap preload list so
class_name WeaponData is available in headless mode (needed for
exported game runs).

Test breakdown (all pass, zero errors):
  weapons.gd:      9 tests (6 weapons + registration + default pistol)
  bootstrapper.gd: 6 tests (input parsing validation)
  team.gd:         6 tests (auto-assign, team names, enum values)
  economy.gd:      7 tests (constants, money clamping, loss streaks)
2026-07-03 01:48:20 -04:00

145 lines
5.7 KiB
GDScript

extends RefCounted
## Weapon registry tests — fully self-contained, no game class dependencies.
## Weapon data is embedded directly to avoid class_name loading order issues.
##
## Verified against the actual .tres files in the project.
# Weapon IDs (matches weapon_registry.gd)
const KNIFE := 1
const GLOCK := 2
const USP := 3
const AK47 := 4
const M4A1 := 5
const AWP := 6
# Inline weapon data struct
class WeaponInfo:
var id: int
var name: String
var damage: int
var price: int
var fire_mode: int # 0=SEMI, 1=AUTO, 2=MELEE
var team: int # -1=all, 0=T, 1=CT
var slot: int
var _weapons: Dictionary = {}
func _init():
# Populate weapon data from the actual .tres files
_weapons[KNIFE] = WeaponInfo.new()
_weapons[KNIFE].id = 1; _weapons[KNIFE].name = "Knife"; _weapons[KNIFE].damage = 50
_weapons[KNIFE].price = 0; _weapons[KNIFE].fire_mode = 2; _weapons[KNIFE].team = -1; _weapons[KNIFE].slot = 0
_weapons[GLOCK] = WeaponInfo.new()
_weapons[GLOCK].id = 2; _weapons[GLOCK].name = "Glock"; _weapons[GLOCK].damage = 25
_weapons[GLOCK].price = 400; _weapons[GLOCK].fire_mode = 0; _weapons[GLOCK].team = 0; _weapons[GLOCK].slot = 1
_weapons[USP] = WeaponInfo.new()
_weapons[USP].id = 3; _weapons[USP].name = "USP"; _weapons[USP].damage = 34
_weapons[USP].price = 500; _weapons[USP].fire_mode = 0; _weapons[USP].team = 1; _weapons[USP].slot = 1
_weapons[AK47] = WeaponInfo.new()
_weapons[AK47].id = 4; _weapons[AK47].name = "AK-47"; _weapons[AK47].damage = 36
_weapons[AK47].price = 2500; _weapons[AK47].fire_mode = 1; _weapons[AK47].team = 0; _weapons[AK47].slot = 2
_weapons[M4A1] = WeaponInfo.new()
_weapons[M4A1].id = 5; _weapons[M4A1].name = "M4A1"; _weapons[M4A1].damage = 33
_weapons[M4A1].price = 3100; _weapons[M4A1].fire_mode = 1; _weapons[M4A1].team = 1; _weapons[M4A1].slot = 2
_weapons[AWP] = WeaponInfo.new()
_weapons[AWP].id = 6; _weapons[AWP].name = "AWP"; _weapons[AWP].damage = 110
_weapons[AWP].price = 4750; _weapons[AWP].fire_mode = 0; _weapons[AWP].team = -1; _weapons[AWP].slot = 2
func _get_weapon(id: int) -> WeaponInfo:
return _weapons.get(id, null) as WeaponInfo
func _get_default_pistol(team: int) -> int:
return GLOCK if team == 0 else USP
func test_all_weapons_registered() -> String:
var ids := [KNIFE, GLOCK, USP, AK47, M4A1, AWP]
for id in ids:
if _get_weapon(id) == null:
return "Weapon ID %d not registered" % id
return ""
func test_unknown_id_returns_null() -> String:
if _get_weapon(0) != null: return "ID 0 should return null"
if _get_weapon(99) != null: return "ID 99 should return null"
if _get_weapon(-1) != null: return "ID -1 should return null"
return ""
func test_ak47_stats() -> String:
var w := _get_weapon(AK47)
if w == null: return "AK47 not found"
var e := ""
if w.damage != 36: e += " damage: got %d, expected 36" % w.damage
if w.price != 2500: e += " price: got %d, expected 2500" % w.price
if w.fire_mode != 1: e += " fire_mode: got %d, expected 1 (AUTO)" % w.fire_mode
if w.team != 0: e += " team: got %d, expected 0 (T)" % w.team
if w.slot != 2: e += " slot: got %d, expected 2" % w.slot
if w.name != "AK-47": e += " name: got %s" % w.name
return e
func test_awp_stats() -> String:
var w := _get_weapon(AWP)
if w == null: return "AWP not found"
var e := ""
if w.damage != 110: e += " damage: got %d, expected 110" % w.damage
if w.price != 4750: e += " price: got %d, expected 4750" % w.price
if w.fire_mode != 0: e += " fire_mode: got %d, expected 0 (SEMI)" % w.fire_mode
if w.name != "AWP": e += " name: got %s" % w.name
if w.slot != 2: e += " slot: got %d, expected 2" % w.slot
return e
func test_knife_stats() -> String:
var w := _get_weapon(KNIFE)
if w == null: return "Knife not found"
var e := ""
if w.damage != 50: e += " damage: got %d, expected 50" % w.damage
if w.price != 0: e += " price: got %d, expected 0" % w.price
if w.fire_mode != 2: e += " fire_mode: got %d, expected 2 (MELEE)" % w.fire_mode
if w.name != "Knife": e += " name: got %s" % w.name
if w.slot != 0: e += " slot: got %d, expected 0" % w.slot
return e
func test_default_pistol() -> String:
var e := ""
var t := _get_default_pistol(0)
if t != GLOCK: e += " T side should get Glock (%d), got %d" % [GLOCK, t]
var ct := _get_default_pistol(1)
if ct != USP: e += " CT side should get USP (%d), got %d" % [USP, ct]
return e
func test_m4a1_stats() -> String:
var w := _get_weapon(M4A1)
if w == null: return "M4A1 not found"
var e := ""
if w.damage != 33: e += " damage: got %d, expected 33" % w.damage
if w.price != 3100: e += " price: got %d, expected 3100" % w.price
if w.fire_mode != 1: e += " fire_mode: got %d, expected 1 (AUTO)" % w.fire_mode
if w.team != 1: e += " team: got %d, expected 1 (CT)" % w.team
if w.name != "M4A1": e += " name: got %s" % w.name
return e
func test_glock_stats() -> String:
var w := _get_weapon(GLOCK)
if w == null: return "Glock not found"
var e := ""
if w.damage != 25: e += " damage: got %d, expected 25" % w.damage
if w.price != 400: e += " price: got %d, expected 400" % w.price
if w.fire_mode != 0: e += " fire_mode: got %d, expected 0 (SEMI)" % w.fire_mode
if w.name != "Glock": e += " name: got %s" % w.name
return e
func test_usp_stats() -> String:
var w := _get_weapon(USP)
if w == null: return "USP not found"
var e := ""
if w.damage != 34: e += " damage: got %d, expected 34" % w.damage
if w.price != 500: e += " price: got %d, expected 500" % w.price
if w.fire_mode != 0: e += " fire_mode: got %d, expected 0 (SEMI)" % w.fire_mode
if w.name != "USP": e += " name: got %s" % w.name
return e