推进 server-rs DDD 分层与新接口接线
This commit is contained in:
92
server-rs/crates/module-runtime-story/src/battle_tests.rs
Normal file
92
server-rs/crates/module-runtime-story/src/battle_tests.rs
Normal file
@@ -0,0 +1,92 @@
|
||||
use serde_json::json;
|
||||
|
||||
use shared_contracts::runtime_story::{
|
||||
RuntimeStoryActionRequest, RuntimeStoryChoiceAction, RuntimeStoryPatch,
|
||||
};
|
||||
|
||||
use crate::{
|
||||
battle::resolve_battle_action, build_status_patch, read_bool_field, read_i32_field,
|
||||
read_optional_string_field,
|
||||
};
|
||||
|
||||
fn build_battle_fixture() -> serde_json::Value {
|
||||
json!({
|
||||
"inBattle": true,
|
||||
"npcInteractionActive": false,
|
||||
"playerHp": 4,
|
||||
"playerMaxHp": 40,
|
||||
"playerMana": 10,
|
||||
"playerMaxMana": 10,
|
||||
"playerSkillCooldowns": {},
|
||||
"runtimeStats": {
|
||||
"hostileNpcsDefeated": 0,
|
||||
"itemsUsed": 0,
|
||||
"questsAccepted": 0,
|
||||
"scenesTraveled": 0,
|
||||
"playTimeMs": 0,
|
||||
"lastPlayTickAt": null
|
||||
},
|
||||
"currentNpcBattleMode": "fight",
|
||||
"currentNpcBattleOutcome": null,
|
||||
"currentEncounter": {
|
||||
"kind": "npc",
|
||||
"id": "npc_bandit_01",
|
||||
"npcName": "断桥匪首",
|
||||
"hostile": true,
|
||||
"hp": 8,
|
||||
"experienceReward": 24
|
||||
},
|
||||
"sceneHostileNpcs": [{
|
||||
"id": "npc_bandit_01",
|
||||
"name": "断桥匪首",
|
||||
"hp": 8,
|
||||
"maxHp": 80,
|
||||
"experienceReward": 24
|
||||
}]
|
||||
})
|
||||
}
|
||||
|
||||
fn build_request(function_id: &str, option_text: &str) -> RuntimeStoryActionRequest {
|
||||
RuntimeStoryActionRequest {
|
||||
session_id: "runtime-main".to_string(),
|
||||
client_version: Some(0),
|
||||
action: RuntimeStoryChoiceAction {
|
||||
action_type: "story_choice".to_string(),
|
||||
function_id: function_id.to_string(),
|
||||
target_id: None,
|
||||
payload: Some(json!({
|
||||
"optionText": option_text
|
||||
})),
|
||||
},
|
||||
snapshot: None,
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn battle_resolution_prefers_player_defeat_when_both_sides_fall_in_same_turn() {
|
||||
let request = build_request("battle_all_in_crush", "全力压制");
|
||||
let mut game_state = build_battle_fixture();
|
||||
|
||||
let resolution = resolve_battle_action(&mut game_state, &request, "battle_all_in_crush")
|
||||
.expect("battle action should resolve");
|
||||
|
||||
assert_eq!(read_i32_field(&game_state, "playerHp"), Some(0));
|
||||
assert_eq!(
|
||||
read_optional_string_field(&game_state, "currentNpcBattleOutcome"),
|
||||
Some("fight_defeat".to_string())
|
||||
);
|
||||
assert_eq!(read_bool_field(&game_state, "inBattle"), Some(false));
|
||||
assert!(resolution.result_text.contains("败北"));
|
||||
assert!(matches!(
|
||||
resolution.patches.first(),
|
||||
Some(RuntimeStoryPatch::BattleResolved { outcome, .. }) if outcome == "defeat"
|
||||
));
|
||||
assert_eq!(
|
||||
resolution.patches.get(1),
|
||||
Some(&build_status_patch(&game_state))
|
||||
);
|
||||
assert_eq!(
|
||||
resolution.battle.and_then(|battle| battle.outcome),
|
||||
Some("defeat".to_string())
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user