diff --git a/TESTING.md b/TESTING.md index 10e6f5d..96a5e6b 100644 --- a/TESTING.md +++ b/TESTING.md @@ -1,6 +1,16 @@ # Pre-Commit Test Checklist -Run through these checks before every commit to ensure consistent feature coverage. +**Automated smoke test (same as CI):** run from the repo root: + +```bash +./run-tests.sh +``` + +This builds the server and mudtool, starts the server with a temporary DB, runs the smoke test below (new player, persistence, admin, registration gate, combat), then cleans up. Use it locally to match what Gitea Actions run on push/pull_request. The script uses `MUD_TEST_DB` (default `./mudserver.db.test`) so it does not overwrite your normal `mudserver.db`. + +--- + +Run through the checks below before every commit to ensure consistent feature coverage. ## Build - [ ] `cargo build` succeeds with no errors @@ -227,9 +237,12 @@ Run through these checks before every commit to ensure consistent feature covera ## Quick Smoke Test Script +The canonical implementation is **`./run-tests.sh`** (see top of this file). The following is the same sequence for reference; when writing or extending tests, keep `run-tests.sh` and this section in sync. + ```bash -# Start server in background -RUST_LOG=info ./target/debug/mudserver & +# Start server in background (use -d for test DB so you don't overwrite mudserver.db) +TEST_DB=./mudserver.db.test +RUST_LOG=info ./target/debug/mudserver -d "$TEST_DB" & SERVER_PID=$! sleep 2 @@ -256,12 +269,12 @@ stats quit EOF -# Test 3: Admin via mudtool -./target/debug/mudtool players list -./target/debug/mudtool players set-admin smoketest true -./target/debug/mudtool players show smoketest -./target/debug/mudtool settings set registration_open false -./target/debug/mudtool settings list +# Test 3: Admin via mudtool (use same test DB) +./target/debug/mudtool -d "$TEST_DB" players list +./target/debug/mudtool -d "$TEST_DB" players set-admin smoketest true +./target/debug/mudtool -d "$TEST_DB" players show smoketest +./target/debug/mudtool -d "$TEST_DB" settings set registration_open false +./target/debug/mudtool -d "$TEST_DB" settings list # Test 4: Admin commands in-game ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -p 2222 smoketest@localhost <<'EOF' @@ -273,14 +286,14 @@ quit EOF # Test 5: Registration gate -./target/debug/mudtool settings set registration_open false +./target/debug/mudtool -d "$TEST_DB" settings set registration_open false ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -p 2222 newplayer@localhost <<'EOF' quit EOF # Test 6: Tick-based combat (connect and wait for ticks) -./target/debug/mudtool settings set registration_open true -./target/debug/mudtool players delete smoketest +./target/debug/mudtool -d "$TEST_DB" settings set registration_open true +./target/debug/mudtool -d "$TEST_DB" players delete smoketest ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -p 2222 smoketest@localhost <<'EOF' 1 1 @@ -297,7 +310,7 @@ EOF # Verify XP changed (combat happened via ticks) # Cleanup -./target/debug/mudtool settings set registration_open true -./target/debug/mudtool players delete smoketest +./target/debug/mudtool -d "$TEST_DB" settings set registration_open true +./target/debug/mudtool -d "$TEST_DB" players delete smoketest kill $SERVER_PID ``` diff --git a/src/game.rs b/src/game.rs index 5994cc2..fc0acce 100644 --- a/src/game.rs +++ b/src/game.rs @@ -157,7 +157,8 @@ pub fn resolve_npc_race_class( if candidates.is_empty() { world.races.first().map(|r| r.id.clone()).unwrap_or_default() } else { - let idx = rng.next_range(0, candidates.len() as i32) as usize; + let len = candidates.len() as i32; + let idx = rng.next_range(0, len.saturating_sub(1)) as usize; candidates[idx].id.clone() } } @@ -187,7 +188,8 @@ pub fn resolve_npc_race_class( if candidates.is_empty() { world.classes.first().map(|c| c.id.clone()).unwrap_or_default() } else { - let idx = rng.next_range(0, candidates.len() as i32) as usize; + let len = candidates.len() as i32; + let idx = rng.next_range(0, len.saturating_sub(1)) as usize; candidates[idx].id.clone() } }