#[cfg(test)]
mod tests {
use goap::prelude::*;
use std::collections::HashMap;
fn create_test_state() -> State {
let mut state = State::empty();
state.set("has_wood", StateVar::from_f64(1.0));
state.set("has_tools", StateVar::from_f64(1.0));
state
}
fn create_test_action() -> Action {
let mut preconditions = State::empty();
preconditions.set("has_wood", StateVar::from_f64(1.0));
preconditions.set("has_tools", StateVar::from_f64(1.0));
let mut effects = HashMap::new();
effects.insert("has_planks".to_string(), StateOperation::set_f64(1.0));
effects.insert("has_wood".to_string(), StateOperation::set_f64(0.0));
Action::from_parts("make_planks", 2.0, preconditions, effects)
}
#[test]
fn test_action_creation() {
let action = create_test_action();
assert_eq!(action.name, "make_planks");
assert_eq!(action.cost, 2.0);
assert_eq!(action.preconditions.get::<f64>("has_wood"), Some(1.0));
assert_eq!(action.preconditions.get::<f64>("has_tools"), Some(1.0));
if let StateOperation::Set(value) = action.effects.get("has_planks").unwrap() {
assert_eq!(value.as_f64(), Some(1.0));
} else {
panic!("Expected Set operation");
}
}
#[test]
fn test_can_execute_with_valid_state() {
let action = create_test_action();
let valid_state = create_test_state();
assert!(action.can_execute(&valid_state));
}
#[test]
fn test_can_execute_with_invalid_state() {
let action = create_test_action();
let mut invalid_state = State::empty();
invalid_state.set("has_tools", StateVar::from_f64(1.0));
assert!(!action.can_execute(&invalid_state));
}
#[test]
fn test_apply_effects() {
let action = create_test_action();
let initial_state = create_test_state();
let result_state = action.apply_effect(&initial_state);
assert_eq!(result_state.get::<f64>("has_planks"), Some(1.0));
assert_eq!(result_state.get::<f64>("has_wood"), Some(0.0));
assert_eq!(result_state.get::<f64>("has_tools"), Some(1.0));
}
#[test]
fn test_builder_bool_preconditions() {
let action = Action::new("test_action")
.requires("has_key", true)
.requires("door_locked", false)
.build();
assert_eq!(action.preconditions.get::<bool>("has_key"), Some(true));
assert_eq!(action.preconditions.get::<bool>("door_locked"), Some(false));
}
#[test]
fn test_builder_bool_effects() {
let action = Action::new("unlock_door")
.sets("door_unlocked", true)
.sets("has_key", false)
.build();
if let StateOperation::Set(value) = action.effects.get("door_unlocked").unwrap() {
assert_eq!(value, &StateVar::Bool(true));
} else {
panic!("Expected Set operation for door_unlocked");
}
if let StateOperation::Set(value) = action.effects.get("has_key").unwrap() {
assert_eq!(value, &StateVar::Bool(false));
} else {
panic!("Expected Set operation for has_key");
}
}
#[test]
fn test_builder_i64_preconditions() {
let action = Action::new("buy_item")
.requires("gold", 100)
.requires("level", 5)
.build();
assert_eq!(action.preconditions.get::<i64>("gold"), Some(100));
assert_eq!(action.preconditions.get::<i64>("level"), Some(5));
}
#[test]
fn test_builder_i64_set_effects() {
let action = Action::new("set_gold")
.sets("gold", 200)
.sets("level", 10)
.build();
if let StateOperation::Set(value) = action.effects.get("gold").unwrap() {
assert_eq!(value, &StateVar::I64(200));
} else {
panic!("Expected Set operation for gold");
}
if let StateOperation::Set(value) = action.effects.get("level").unwrap() {
assert_eq!(value, &StateVar::I64(10));
} else {
panic!("Expected Set operation for level");
}
}
#[test]
fn test_builder_i64_add_effects() {
let action = Action::new("gain_resources")
.adds("gold", 50)
.adds("experience", 100)
.build();
if let StateOperation::Add(value) = action.effects.get("gold").unwrap() {
assert_eq!(*value, 50);
} else {
panic!("Expected Add operation for gold");
}
if let StateOperation::Add(value) = action.effects.get("experience").unwrap() {
assert_eq!(*value, 100);
} else {
panic!("Expected Add operation for experience");
}
}
#[test]
fn test_builder_i64_subtract_effects() {
let action = Action::new("spend_resources")
.subtracts("gold", 25)
.subtracts("energy", 10)
.build();
if let StateOperation::Subtract(value) = action.effects.get("gold").unwrap() {
assert_eq!(*value, 25);
} else {
panic!("Expected Subtract operation for gold");
}
if let StateOperation::Subtract(value) = action.effects.get("energy").unwrap() {
assert_eq!(*value, 10);
} else {
panic!("Expected Subtract operation for energy");
}
}
#[test]
fn test_builder_f64_preconditions() {
let action = Action::new("precise_action")
.requires("health", 75.5)
.requires("speed", 2.25)
.build();
assert_eq!(action.preconditions.get::<f64>("health"), Some(75.5));
assert_eq!(action.preconditions.get::<f64>("speed"), Some(2.25));
}
#[test]
fn test_builder_f64_set_effects() {
let action = Action::new("restore_health")
.sets("health", 100.0)
.sets("mana", 50.75)
.build();
if let StateOperation::Set(value) = action.effects.get("health").unwrap() {
assert_eq!(value, &StateVar::F64(100000));
} else {
panic!("Expected Set operation for health");
}
if let StateOperation::Set(value) = action.effects.get("mana").unwrap() {
assert_eq!(value, &StateVar::F64(50750));
} else {
panic!("Expected Set operation for mana");
}
}
#[test]
fn test_builder_f64_add_effects() {
let action = Action::new("boost_stats")
.adds("speed", 1.5)
.adds("strength", 2.25)
.build();
if let StateOperation::Add(value) = action.effects.get("speed").unwrap() {
assert_eq!(*value, 1500);
} else {
panic!("Expected Add operation for speed");
}
if let StateOperation::Add(value) = action.effects.get("strength").unwrap() {
assert_eq!(*value, 2250);
} else {
panic!("Expected Add operation for strength");
}
}
#[test]
fn test_builder_f64_subtract_effects() {
let action = Action::new("drain_stats")
.subtracts("energy", 10.5)
.subtracts("stamina", 5.75)
.build();
if let StateOperation::Subtract(value) = action.effects.get("energy").unwrap() {
assert_eq!(*value, 10500);
} else {
panic!("Expected Subtract operation for energy");
}
if let StateOperation::Subtract(value) = action.effects.get("stamina").unwrap() {
assert_eq!(*value, 5750);
} else {
panic!("Expected Subtract operation for stamina");
}
}
#[test]
fn test_builder_string_preconditions() {
let action = Action::new("enter_area")
.requires("location", "town")
.requires("state", "peaceful")
.build();
assert_eq!(action.preconditions.get::<String>("location"), Some("town".to_string()));
assert_eq!(action.preconditions.get::<String>("state"), Some("peaceful".to_string()));
}
#[test]
fn test_builder_string_effects() {
let action = Action::new("travel")
.sets("location", "forest")
.sets("weather", "rainy")
.build();
if let StateOperation::Set(value) = action.effects.get("location").unwrap() {
assert_eq!(value, &StateVar::String("forest".to_string()));
} else {
panic!("Expected Set operation for location");
}
if let StateOperation::Set(value) = action.effects.get("weather").unwrap() {
assert_eq!(value, &StateVar::String("rainy".to_string()));
} else {
panic!("Expected Set operation for weather");
}
}
#[test]
fn test_builder_cost() {
let action = Action::new("expensive_action").cost(15.5).build();
assert_eq!(action.cost, 15.5);
}
#[test]
fn test_builder_default_cost() {
let action = Action::new("default_cost_action").build();
assert_eq!(action.cost, 1.0);
}
#[test]
fn test_builder_mixed_preconditions() {
let action = Action::new("complex_action")
.requires("has_key", true)
.requires("gold", 100)
.requires("health", 75.5)
.requires("location", "castle")
.build();
assert_eq!(action.preconditions.get::<bool>("has_key"), Some(true));
assert_eq!(action.preconditions.get::<i64>("gold"), Some(100));
assert_eq!(action.preconditions.get::<f64>("health"), Some(75.5));
assert_eq!(action.preconditions.get::<String>("location"), Some("castle".to_string()));
}
#[test]
fn test_builder_mixed_effects() {
let action = Action::new("complex_effects")
.sets("door_open", true)
.sets("gold", 200)
.adds("experience", 50)
.subtracts("energy", 25)
.sets("health", 100.0)
.adds("speed", 1.5)
.sets("location", "treasure_room")
.build();
if let StateOperation::Set(value) = action.effects.get("door_open").unwrap() {
assert_eq!(value, &StateVar::Bool(true));
} else {
panic!("Expected Set operation for door_open");
}
if let StateOperation::Set(value) = action.effects.get("gold").unwrap() {
assert_eq!(value, &StateVar::I64(200));
} else {
panic!("Expected Set operation for gold");
}
if let StateOperation::Add(value) = action.effects.get("experience").unwrap() {
assert_eq!(*value, 50);
} else {
panic!("Expected Add operation for experience");
}
if let StateOperation::Subtract(value) = action.effects.get("energy").unwrap() {
assert_eq!(*value, 25);
} else {
panic!("Expected Subtract operation for energy");
}
if let StateOperation::Set(value) = action.effects.get("health").unwrap() {
assert_eq!(value, &StateVar::F64(100000));
} else {
panic!("Expected Set operation for health");
}
if let StateOperation::Add(value) = action.effects.get("speed").unwrap() {
assert_eq!(*value, 1500);
} else {
panic!("Expected Add operation for speed");
}
if let StateOperation::Set(value) = action.effects.get("location").unwrap() {
assert_eq!(value, &StateVar::String("treasure_room".to_string()));
} else {
panic!("Expected Set operation for location");
}
}
}