summaryrefslogtreecommitdiff
path: root/src/lowlevel/property.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/lowlevel/property.rs')
-rw-r--r--src/lowlevel/property.rs278
1 files changed, 228 insertions, 50 deletions
diff --git a/src/lowlevel/property.rs b/src/lowlevel/property.rs
index 26dcedd..bba693f 100644
--- a/src/lowlevel/property.rs
+++ b/src/lowlevel/property.rs
@@ -1,3 +1,4 @@
+use crate::{ensure_element, ensure_tag_name, get_attribute};
use anyhow::anyhow;
use rgb::RGBA8;
@@ -18,19 +19,14 @@ pub enum Property {
Object { name: String, value: usize },
}
+#[allow(dead_code)]
impl Property {
pub fn from_xml(node: roxmltree::Node) -> anyhow::Result<Property> {
- if node.node_type() != roxmltree::NodeType::Element {
- return Err(anyhow!("xml -> node is not an element"));
- }
+ ensure_element!(node);
+ ensure_tag_name!(node, "property");
- let name = node
- .attribute("name")
- .ok_or(anyhow!("property name missing"))?
- .to_owned();
- let property_type = node
- .attribute("type")
- .ok_or(anyhow!("property type missing"))?;
+ let name = get_attribute!(node, "name")?.to_owned();
+ let property_type = get_attribute!(node, "type")?;
// handle the case that 'string' value is stored in element content instead of value atribute
if property_type == "string" {
@@ -46,9 +42,7 @@ impl Property {
}
}
- let raw_value = node
- .attribute("value")
- .ok_or(anyhow!("property value missing"))?;
+ let raw_value = get_attribute!(node, "value")?;
match property_type {
"string" => Ok(Property::String {
@@ -106,6 +100,7 @@ impl Property {
}
}
+ #[allow(dead_code)]
pub fn value_to_string(self) -> String {
match self {
Property::String { value, .. } => value,
@@ -126,32 +121,124 @@ impl Property {
}
// Wraps any number of custom properties
-#[derive(Debug)]
+#[allow(dead_code)]
+#[derive(Debug, PartialEq)]
pub struct Properties {
pub properties: Vec<Property>,
}
+impl Default for Properties {
+ fn default() -> Self {
+ Properties { properties: vec![] }
+ }
+}
+
impl Properties {
- fn from_xml(node: roxmltree::Node) -> anyhow::Result<Properties> {
- Err(anyhow!("not implemented"))
+ pub fn from_xml(node: roxmltree::Node) -> anyhow::Result<Properties> {
+ let mut properties: Vec<Property> = Vec::new();
+ for property_node in node.children() {
+ if property_node.has_tag_name("property") {
+ properties.push(Property::from_xml(property_node)?)
+ }
+ }
+ Ok(Properties { properties })
}
}
#[cfg(test)]
-mod tests {
+mod parse_property {
use crate::lowlevel::property::Property;
use rgb::RGBA8;
#[test]
- fn parse_color_property() {
- // Find element by id
- let doc = roxmltree::Document::parse(
+ fn string_inside_attribute() {
+ crate::parse_property_test!(
+ Property,
+ r##"<property name="enemyText" type="string" value="hello world"/>"##,
+ Property::String {
+ name: "enemyText".to_owned(),
+ value: "hello world".to_owned()
+ }
+ );
+ }
+
+ #[test]
+ fn string_inside_element() {
+ crate::parse_property_test!(
+ Property,
+ r##"<property name="enemyText" type="string">hello world</property>"##,
+ Property::String {
+ name: "enemyText".to_owned(),
+ value: "hello world".to_owned()
+ }
+ );
+ }
+
+ #[test]
+ fn int() {
+ crate::parse_property_test!(
+ Property,
+ r##"<property name="enemyText" type="int" value="-8"/>"##,
+ Property::Int {
+ name: "enemyText".to_owned(),
+ value: -8
+ }
+ );
+ crate::parse_property_test!(
+ Property,
+ r##"<property name="enemyText" type="int" value="3453"/>"##,
+ Property::Int {
+ name: "enemyText".to_owned(),
+ value: 3453
+ }
+ );
+ }
+
+ #[test]
+ fn float() {
+ crate::parse_property_test!(
+ Property,
+ r##"<property name="ExperienceBoost" type="float" value="-8.8"/>"##,
+ Property::Float {
+ name: "ExperienceBoost".to_owned(),
+ value: -8.8
+ }
+ );
+ crate::parse_property_test!(
+ Property,
+ r##"<property name="ExperienceBoost" type="float" value="0.005"/>"##,
+ Property::Float {
+ name: "ExperienceBoost".to_owned(),
+ value: 0.005
+ }
+ );
+ }
+
+ #[test]
+ fn bool() {
+ crate::parse_property_test!(
+ Property,
+ r##"<property name="isNight" type="bool" value="true"/>"##,
+ Property::Bool {
+ name: "isNight".to_owned(),
+ value: true
+ }
+ );
+ crate::parse_property_test!(
+ Property,
+ r##"<property name="isNight" type="bool" value="false"/>"##,
+ Property::Bool {
+ name: "isNight".to_owned(),
+ value: false
+ }
+ );
+ }
+
+ #[test]
+ fn color() {
+ crate::parse_property_test!(
+ Property,
r##"<property name="enemyTint" type="color" value="#ffa33636"/>"##,
- )
- .unwrap();
- let elem = doc.root_element();
- assert_eq!(
- Property::from_xml(elem).unwrap(),
Property::Color {
name: "enemyTint".to_owned(),
value: RGBA8 {
@@ -161,41 +248,132 @@ mod tests {
a: 54
}
}
+ )
+ }
+
+ #[test]
+ fn file() {
+ crate::parse_property_test!(
+ Property,
+ r##"<property name="music" type="file" value="../music/cave.ogg"/>"##,
+ Property::File {
+ name: "music".to_owned(),
+ value: "../music/cave.ogg".to_owned()
+ }
);
}
#[test]
- fn parse_string_property_inside_attribute() {
- // Find element by id
- let doc = roxmltree::Document::parse(
- r##"<property name="enemyText" type="string" value="hello world"/>"##,
- )
- .unwrap();
- let elem = doc.root_element();
- assert_eq!(
- Property::from_xml(elem).unwrap(),
- Property::String {
- name: "enemyText".to_owned(),
- value: "hello world".to_owned()
+ fn object() {
+ crate::parse_property_test!(
+ Property,
+ r##"<property name="music" type="object" value="2583"/>"##,
+ Property::Object {
+ name: "music".to_owned(),
+ value: 2583
}
);
}
+}
+
+#[cfg(test)]
+mod parse_properties {
+ use crate::lowlevel::property::Properties;
+ use crate::lowlevel::property::Property;
+ use rgb::RGBA8;
#[test]
- fn parse_string_property_inside_element() {
- // Find element by id
- let doc = roxmltree::Document::parse(
- r##"<property name="enemyText" type="string">hello world</property>"##,
- )
- .unwrap();
- let elem = doc.root_element();
- println!("{:?}", elem.first_child());
- assert_eq!(
- Property::from_xml(elem).unwrap(),
- Property::String {
- name: "enemyText".to_owned(),
- value: "hello world".to_owned()
+ fn one_property() {
+ crate::parse_property_test!(
+ Properties,
+ r##"<properties>
+ <property name="enemyTint" type="color" value="#ffa33636"/>
+ </properties>"##,
+ Properties {
+ properties: vec![Property::Color {
+ name: "enemyTint".to_owned(),
+ value: RGBA8 {
+ r: 255,
+ g: 163,
+ b: 54,
+ a: 54
+ }
+ }]
+ }
+ );
+ }
+
+ #[test]
+ fn two_properties() {
+ crate::parse_property_test!(
+ Properties,
+ r##"<properties>
+ <property name="enemyTint" type="color" value="#ffa33636"/>
+ <property name="enemyDropChanceModifier" type="float" value="0.005"/>
+ </properties>"##,
+ Properties {
+ properties: vec![
+ Property::Color {
+ name: "enemyTint".to_owned(),
+ value: RGBA8 {
+ r: 255,
+ g: 163,
+ b: 54,
+ a: 54
+ }
+ },
+ Property::Float {
+ name: "enemyDropChanceModifier".to_owned(),
+ value: 0.005
+ }
+ ]
+ }
+ );
+ }
+
+ #[test]
+ fn two_properties_with_comments() {
+ crate::parse_property_test!(
+ Properties,
+ r##"<properties>
+ <!-- what color the enemy should have -->
+ <property name="enemyTint" type="color" value="#ffa33636"/>
+ <!-- a nother comment -->
+ <property name="enemyDropChanceModifier" type="float" value="0.005"/>
+ </properties>"##,
+ Properties {
+ properties: vec![
+ Property::Color {
+ name: "enemyTint".to_owned(),
+ value: RGBA8 {
+ r: 255,
+ g: 163,
+ b: 54,
+ a: 54
+ }
+ },
+ Property::Float {
+ name: "enemyDropChanceModifier".to_owned(),
+ value: 0.005
+ }
+ ]
}
);
}
+
+ #[test]
+ fn zero_properties() {
+ crate::parse_property_test!(
+ Properties,
+ r##"<properties></properties>"##,
+ Properties { properties: vec![] }
+ );
+ }
+
+ #[test]
+ fn default_value() {
+ let empty_properties: Properties = Default::default();
+
+ assert_eq!(empty_properties.properties.len(), 0)
+ }
}