mod fixture;
use std::{cell::RefCell, rc::Rc};
use fixture::*;
use hocon_rs::{Config, Value};
use logic_constructor::prelude::*;
#[test]
fn running_predefined_actions() {
let player = PlayerEntity {
hp: Rc::new(RefCell::new(100.0)),
};
let enemy = EnemyEntity {
hp: Rc::new(RefCell::new(100.0)),
};
let enemy_hp = enemy.hp.clone();
let player_hp = player.hp.clone();
let attack = LcActionConfig {
data: vec![LcSingleActionConfig {
action: Box::new(DealDamage { amount: 15.0 }),
collision: CollisionKind::OTHER,
}],
};
let friendly_attack = LcActionConfig {
data: vec![LcSingleActionConfig {
action: Box::new(DealDamage { amount: 10.0 }),
collision: CollisionKind::SAME_KIND,
}],
};
let heal = LcActionConfig {
data: vec![LcSingleActionConfig {
action: Box::new(Heal { amount: 5.0 }),
collision: CollisionKind::OTHER,
}],
};
let self_heal = LcActionConfig {
data: vec![LcSingleActionConfig {
action: Box::new(Heal { amount: 5.0 }),
collision: CollisionKind::SELF,
}],
};
run_lca(&attack, &player.clone().into(), &enemy.clone().into());
assert_eq!(*player_hp.borrow(), 100.0);
assert_eq!(*enemy_hp.borrow(), 85.0);
run_lca(&heal, &player.clone().into(), &enemy.clone().into());
run_lca(&heal, &player.clone().into(), &enemy.clone().into());
assert_eq!(*player_hp.borrow(), 100.0);
assert_eq!(*enemy_hp.borrow(), 95.0);
run_lca(&self_heal, &player.clone().into(), &enemy.clone().into());
assert_eq!(*player_hp.borrow(), 105.0);
assert_eq!(*enemy_hp.borrow(), 95.0);
run_lca(
&friendly_attack,
&player.clone().into(),
&player.clone().into(),
);
assert_eq!(*player_hp.borrow(), 95.0);
assert_eq!(*enemy_hp.borrow(), 95.0);
run_lca(&attack, &player.clone().into(), &player.clone().into());
assert_eq!(*player_hp.borrow(), 95.0);
assert_eq!(*enemy_hp.borrow(), 95.0);
}
fn parse_value(hocon_str: &str) -> Value {
Config::parse_str(hocon_str, None).unwrap()
}
fn get_field<'a>(value: &'a Value, key: &str) -> &'a Value {
value.as_object().unwrap().get(key).unwrap()
}
#[test]
fn parses_raw_simple_format_defaults_to_other() {
let value = parse_value(r#"{ DealDamage: 10 }"#);
let raw = parse_lc_config_raw(&value).unwrap();
assert_eq!(raw.collision, CollisionKind::OTHER);
assert!(
raw.effect_value
.as_object()
.unwrap()
.contains_key("DealDamage")
);
}
#[test]
fn parses_raw_full_format_with_collision() {
let value = parse_value(
r#"
{
lca: { DealDamage: 25 }
collision: "Self"
}
"#,
);
let raw = parse_lc_config_raw(&value).unwrap();
assert_eq!(raw.collision, CollisionKind::SELF);
assert!(
raw.effect_value
.as_object()
.unwrap()
.contains_key("DealDamage")
);
}
#[test]
fn parses_raw_partial_full_format_is_error() {
let value = parse_value(r#"{ lca: { DealDamage: 10 } }"#);
let err = parse_lc_config_raw(&value).unwrap_err();
assert!(err.contains("requires 'collision' field"));
let value = parse_value(r#"{ collision: "Self" }"#);
let err = parse_lc_config_raw(&value).unwrap_err();
assert!(err.contains("requires 'lca' field"));
}
#[test]
fn parses_typed_lc_config_via_effect_closure() {
let value = parse_value(r#"{ lca: { DealDamage: 15 }, collision: "Self" }"#);
let config: LcSingleActionConfig<LcGameEntity> =
parse_lc_config(&value, &parse_game_effect).unwrap();
assert_eq!(config.collision, CollisionKind::SELF);
let entity = EnemyEntity {
hp: Rc::new(RefCell::new(100.0)),
};
let hp = entity.hp.clone();
let action = LcActionConfig { data: vec![config] };
let source: LcEntity<LcGameEntity> = entity.into();
run_lca(&action, &source, &source);
assert_eq!(*hp.borrow(), 85.0);
}
#[test]
fn parses_list_mixed_simple_and_full_forms() {
let hocon_str = r#"
list = [
{ DealDamage: 10 }
{ lca: { Heal: 20 }, collision: "Self" }
{ lca: { DealDamage: 30 }, collision: "Self | Other" }
]
"#;
let parsed = parse_value(hocon_str);
let value = get_field(&parsed, "list");
let configs: Vec<LcSingleActionConfig<LcGameEntity>> =
parse_lc_config_list(value, &parse_game_effect).unwrap();
assert_eq!(configs.len(), 3);
assert_eq!(configs[0].collision, CollisionKind::OTHER);
assert_eq!(configs[1].collision, CollisionKind::SELF);
assert_eq!(
configs[2].collision,
CollisionKind::SELF | CollisionKind::OTHER
);
}
#[test]
fn parses_list_propagates_index_in_errors() {
let hocon_str = r#"
list = [
{ DealDamage: 10 }
{ Unknown: 5 }
]
"#;
let parsed = parse_value(hocon_str);
let value = get_field(&parsed, "list");
let err = match parse_lc_config_list::<LcGameEntity, _>(value, &parse_game_effect) {
Ok(_) => panic!("expected parse error"),
Err(e) => e,
};
assert!(err.contains("index 1"));
assert!(err.contains("unknown effect"));
}
#[test]
fn parses_list_rejects_non_array() {
let value = parse_value(r#"{ DealDamage: 10 }"#);
let err = parse_lc_config_list_raw(&value).unwrap_err();
assert!(err.contains("expects an array"));
}
#[test]
fn parses_lc_action_config_from_hocon_array() {
let hocon_str = r#"
list = [
{ DealDamage: 10 }
{ lca: { Heal: 7 }, collision: "Self" }
]
"#;
let parsed = parse_value(hocon_str);
let value = get_field(&parsed, "list");
let action: LcActionConfig<LcGameEntity> =
parse_lc_action_config(value, &parse_game_effect).unwrap();
assert_eq!(action.data.len(), 2);
assert_eq!(action.data[0].collision, CollisionKind::OTHER);
assert_eq!(action.data[1].collision, CollisionKind::SELF);
}
#[test]
fn parsed_lc_action_config_runs_end_to_end() {
let hocon_str = r#"
list = [
{ DealDamage: 15 }
{ lca: { Heal: 4 }, collision: "Self" }
]
"#;
let parsed = parse_value(hocon_str);
let value = get_field(&parsed, "list");
let action: LcActionConfig<LcGameEntity> =
parse_lc_action_config(value, &parse_game_effect).unwrap();
let player = PlayerEntity {
hp: Rc::new(RefCell::new(100.0)),
};
let enemy = EnemyEntity {
hp: Rc::new(RefCell::new(100.0)),
};
let player_hp = player.hp.clone();
let enemy_hp = enemy.hp.clone();
run_lca(&action, &player.clone().into(), &enemy.clone().into());
assert_eq!(*enemy_hp.borrow(), 85.0);
assert_eq!(*player_hp.borrow(), 104.0);
}
#[test]
fn parses_empty_lc_action_config() {
let parsed = parse_value(r#"list = []"#);
let value = get_field(&parsed, "list");
let action: LcActionConfig<LcGameEntity> =
parse_lc_action_config(value, &parse_game_effect).unwrap();
assert_eq!(action.data.len(), 0);
}
#[test]
fn parses_lc_action_config_rejects_non_array() {
let value = parse_value(r#"{ DealDamage: 10 }"#);
let err = match parse_lc_action_config::<LcGameEntity, _>(&value, &parse_game_effect) {
Ok(_) => panic!("expected parse error"),
Err(e) => e,
};
assert!(err.contains("expects an array"));
}
#[test]
fn parses_lc_action_config_propagates_inner_errors() {
let hocon_str = r#"
list = [
{ DealDamage: 10 }
{ Unknown: 1 }
]
"#;
let parsed = parse_value(hocon_str);
let value = get_field(&parsed, "list");
let err = match parse_lc_action_config::<LcGameEntity, _>(value, &parse_game_effect) {
Ok(_) => panic!("expected parse error"),
Err(e) => e,
};
assert!(err.contains("index 1"));
assert!(err.contains("unknown effect"));
}