feat(opnsense-config): Add MaybeString type to preserve xml serialization of empty elements
This commit is contained in:
parent
ebdc83b21b
commit
ab59923dae
23
harmony-rs/Cargo.lock
generated
23
harmony-rs/Cargo.lock
generated
@ -440,6 +440,12 @@ dependencies = [
|
|||||||
"cipher",
|
"cipher",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "diff"
|
||||||
|
version = "0.1.13"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "56254986775e3233ffa9c4d7d3faaf6d36a2c09d30b20687e9f88bc8bafc16c8"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "digest"
|
name = "digest"
|
||||||
version = "0.10.7"
|
version = "0.10.7"
|
||||||
@ -1242,6 +1248,7 @@ dependencies = [
|
|||||||
"async-trait",
|
"async-trait",
|
||||||
"env_logger",
|
"env_logger",
|
||||||
"log",
|
"log",
|
||||||
|
"pretty_assertions",
|
||||||
"russh",
|
"russh",
|
||||||
"russh-keys",
|
"russh-keys",
|
||||||
"serde",
|
"serde",
|
||||||
@ -1426,6 +1433,16 @@ dependencies = [
|
|||||||
"zerocopy",
|
"zerocopy",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pretty_assertions"
|
||||||
|
version = "1.4.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3ae130e2f271fbc2ac3a40fb1d07180839cdbbe443c7a27e1e3c13c5cac0116d"
|
||||||
|
dependencies = [
|
||||||
|
"diff",
|
||||||
|
"yansi",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "primeorder"
|
name = "primeorder"
|
||||||
version = "0.13.6"
|
version = "0.13.6"
|
||||||
@ -2594,6 +2611,12 @@ dependencies = [
|
|||||||
"tracing",
|
"tracing",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "yansi"
|
||||||
|
version = "1.0.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "cfe53a6657fd280eaa890a3bc59152892ffa3e30101319d168b781ed6529b049"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "yaserde"
|
name = "yaserde"
|
||||||
version = "0.11.1"
|
version = "0.11.1"
|
||||||
|
|||||||
@ -17,3 +17,6 @@ xml-rs = "0.8"
|
|||||||
thiserror = "1.0"
|
thiserror = "1.0"
|
||||||
async-trait = { workspace = true }
|
async-trait = { workspace = true }
|
||||||
tokio = { workspace = true }
|
tokio = { workspace = true }
|
||||||
|
|
||||||
|
[dev-dependencies]
|
||||||
|
pretty_assertions = "1.4.1"
|
||||||
|
|||||||
@ -194,6 +194,8 @@ mod tests {
|
|||||||
let serialized = yaserde::ser::to_string_with_config(&config.opnsense, &yaserde_cfg).unwrap();
|
let serialized = yaserde::ser::to_string_with_config(&config.opnsense, &yaserde_cfg).unwrap();
|
||||||
|
|
||||||
fs::write("/tmp/serialized.xml", &serialized).unwrap();
|
fs::write("/tmp/serialized.xml", &serialized).unwrap();
|
||||||
|
std::process::Command::new("xmllint").arg("/tmp/serialized.xml").arg("--output").arg("/tmp/serialized.xmllint.xml").status().expect("xmllint failed");
|
||||||
|
|
||||||
assert_eq!(config_file_str, serialized);
|
assert_eq!(config_file_str, serialized);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,21 +1,5 @@
|
|||||||
use xml::reader::{EventReader, XmlEvent as ReadEvent};
|
use xml::reader::XmlEvent as ReadEvent;
|
||||||
use xml::writer::{EventWriter, XmlEvent as WriteEvent};
|
|
||||||
use yaserde::{ser, YaDeserialize as YaDeserializeTrait, YaSerialize as YaSerializeTrait};
|
use yaserde::{ser, YaDeserialize as YaDeserializeTrait, YaSerialize as YaSerializeTrait};
|
||||||
use yaserde_derive::{YaDeserialize, YaSerialize};
|
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Default, YaDeserialize)]
|
|
||||||
pub struct Parent {
|
|
||||||
// pub rawxml_child: RawXml,
|
|
||||||
pub string_child: String,
|
|
||||||
pub child_child: Child,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Default, YaDeserialize)]
|
|
||||||
pub struct Child {
|
|
||||||
pub child_val: String,
|
|
||||||
pub child_val2: String,
|
|
||||||
pub child_option: Option<String>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Default)]
|
#[derive(Debug, PartialEq, Default)]
|
||||||
pub struct RawXml(String);
|
pub struct RawXml(String);
|
||||||
@ -131,119 +115,100 @@ impl YaSerializeTrait for RawXml {
|
|||||||
todo!()
|
todo!()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// impl YaSerializeTrait for RawXml {
|
|
||||||
// fn serialize<W: std::io::Write>(
|
|
||||||
// &self,
|
|
||||||
// writer: &mut yaserde::ser::Serializer<W>,
|
|
||||||
// ) -> Result<(), String> {
|
|
||||||
// let mut reader = EventReader::from_str(&self.0);
|
|
||||||
// loop {
|
|
||||||
// match reader.next() {
|
|
||||||
// Ok(ReadEvent::StartElement {
|
|
||||||
// name,
|
|
||||||
// attributes,
|
|
||||||
// namespace,
|
|
||||||
// }) => {
|
|
||||||
// let write = WriteEvent::from(reader.next().unwrap());
|
|
||||||
// writer
|
|
||||||
// .write(WriteEvent::StartElement {
|
|
||||||
// name: name.clone(),
|
|
||||||
// attributes: attributes.clone(),
|
|
||||||
// namespace: namespace.clone(),
|
|
||||||
// })
|
|
||||||
// .map_err(|e| e.to_string())?;
|
|
||||||
// }
|
|
||||||
// Ok(ReadEvent::EndElement { name }) => {
|
|
||||||
// writer
|
|
||||||
// .write(WriteEvent::EndElement { name: Some(name) })
|
|
||||||
// .map_err(|e| e.to_string())?;
|
|
||||||
// }
|
|
||||||
// Ok(ReadEvent::Characters(content)) => {
|
|
||||||
// writer
|
|
||||||
// .write(WriteEvent::Characters(&content))
|
|
||||||
// .map_err(|e| e.to_string())?;
|
|
||||||
// }
|
|
||||||
// Ok(ReadEvent::Eof) => break,
|
|
||||||
// Err(e) => return Err(e.to_string()),
|
|
||||||
// _ => {}
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// Ok(())
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
#[test]
|
|
||||||
fn rawxml_should_buffer_empty_element() {
|
|
||||||
let rawxml: RawXml = yaserde::de::from_str("<something/>").unwrap();
|
|
||||||
assert_eq!(rawxml.0, String::from("<something></something>"));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
#[cfg(test)]
|
||||||
fn rawxml_should_buffer_elements_with_different_case_as_they_are() {
|
mod test {
|
||||||
let xml = "<xml><Some_thing></Some_thing><something></something></xml>";
|
use super::*;
|
||||||
let rawxml: RawXml = yaserde::de::from_str(xml).unwrap();
|
use yaserde_derive::YaDeserialize;
|
||||||
assert_eq!(rawxml.0, String::from(xml));
|
use yaserde_derive::YaSerialize;
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
#[derive(Debug, PartialEq, Default, YaDeserialize)]
|
||||||
fn rawxml_should_buffer_elements_with_attributes() {
|
pub struct Parent {
|
||||||
let xml = r#"<xml version="ababa"><Some_thing></Some_thing><something></something></xml>"#;
|
// pub rawxml_child: RawXml,
|
||||||
let rawxml: RawXml = yaserde::de::from_str(xml).unwrap();
|
pub string_child: String,
|
||||||
assert_eq!(rawxml.0, String::from(xml));
|
pub child_child: Child,
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn rawxml_should_handle_complex_documents() {
|
|
||||||
let xml = r#"<xml><OpenVPN version="1.0.0"><Overwrites></Overwrites><Instances></Instances><StaticKeys></StaticKeys></OpenVPN><Gateways version="0.0.1"></Gateways><HAProxy version="4.0.0"><general><enabled>1</enabled><gracefulStop>0</gracefulStop><hardStopAfter>60s</hardStopAfter><closeSpreadTime></closeSpreadTime><seamlessReload>0</seamlessReload><storeOcsp>0</storeOcsp><showIntro>1</showIntro><peers><enabled>0</enabled><name1></name1><listen1></listen1><port1>1024</port1><name2></name2><listen2></listen2><port2>1024</port2></peers><tuning><root>0</root><maxConnections></maxConnections><nbthread>1</nbthread><sslServerVerify>ignore</sslServerVerify><maxDHSize>2048</maxDHSize><bufferSize>16384</bufferSize></tuning></general></HAProxy></xml>"#;
|
|
||||||
let rawxml: RawXml = yaserde::de::from_str(xml).unwrap();
|
|
||||||
assert_eq!(rawxml.0, String::from(xml));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn rawxml_should_serialize_simple_documents() {
|
|
||||||
let xml = r#"<?xml version="1.0" encoding="utf-8"?><xml />"#;
|
|
||||||
let rawxml: RawXml = yaserde::de::from_str(xml).unwrap();
|
|
||||||
assert_eq!(yaserde::ser::to_string(&rawxml).unwrap(), xml);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn rawxml_should_serialize_complex_documents() {
|
|
||||||
let xml = r#"<?xml version="1.0" encoding="utf-8"?><xml><OpenVPN version="1.0.0"><Overwrites /><Instances /><StaticKeys /></OpenVPN><Gateways version="0.0.1" /><HAProxy version="4.0.0"><general><enabled>1</enabled><gracefulStop>0</gracefulStop><hardStopAfter>60s</hardStopAfter><closeSpreadTime /><seamlessReload>0</seamlessReload><storeOcsp>0</storeOcsp><showIntro>1</showIntro><peers><enabled>0</enabled><name1 /><listen1 /><port1>1024</port1><name2 /><listen2 /><port2>1024</port2></peers><tuning><root>0</root><maxConnections /><nbthread>1</nbthread><sslServerVerify>ignore</sslServerVerify><maxDHSize>2048</maxDHSize><bufferSize>16384</bufferSize></tuning></general></HAProxy></xml>"#;
|
|
||||||
let rawxml: RawXml = yaserde::de::from_str(xml).unwrap();
|
|
||||||
assert_eq!(yaserde::ser::to_string(&rawxml).unwrap(), xml);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn rawxml_should_allow_siblings_before() {
|
|
||||||
#[derive(YaDeserialize, YaSerialize)]
|
|
||||||
struct Config {
|
|
||||||
paul: Vec<String>,
|
|
||||||
raw: RawXml,
|
|
||||||
}
|
}
|
||||||
let xml = r#"<?xml version="1.0" encoding="utf-8"?><Config><paul>bobob</paul><paul>patate</paul><raw>allo something</raw></Config>"#;
|
|
||||||
let config: Config = yaserde::de::from_str(xml).unwrap();
|
|
||||||
assert_eq!(yaserde::ser::to_string(&config).unwrap(), xml);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
#[derive(Debug, PartialEq, Default, YaDeserialize)]
|
||||||
fn rawxml_should_allow_siblings_after() {
|
pub struct Child {
|
||||||
#[derive(YaDeserialize, YaSerialize)]
|
pub child_val: String,
|
||||||
struct Config {
|
pub child_val2: String,
|
||||||
raw: RawXml,
|
pub child_option: Option<String>,
|
||||||
paul: Vec<String>,
|
|
||||||
}
|
}
|
||||||
let xml = r#"<?xml version="1.0" encoding="utf-8"?><Config><raw>allo something</raw><paul>bobob</paul><paul>patate</paul></Config>"#;
|
|
||||||
let config: Config = yaserde::de::from_str(xml).unwrap();
|
|
||||||
assert_eq!(config.paul.get(0).unwrap(), "bobob");
|
|
||||||
assert_eq!(config.paul.get(1).unwrap(), "patate");
|
|
||||||
assert_eq!(config.paul.len(), 2);
|
|
||||||
assert_eq!(config.raw.0, "<raw>allo something</raw>");
|
|
||||||
assert_eq!(yaserde::ser::to_string(&config).unwrap(), xml);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn rawxml_should_allow_being_end_of_document() {
|
fn rawxml_should_buffer_empty_element() {
|
||||||
let xml = r#"<?xml version="1.0" encoding="utf-8"?><Config><raw>allo something</raw><paul>bobob</paul><paul>patate</paul></Config>"#;
|
let rawxml: RawXml = yaserde::de::from_str("<something/>").unwrap();
|
||||||
let config: RawXml = yaserde::de::from_str(xml).unwrap();
|
assert_eq!(rawxml.0, String::from("<something></something>"));
|
||||||
assert_eq!(yaserde::ser::to_string(&config).unwrap(), xml);
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn rawxml_should_buffer_elements_with_different_case_as_they_are() {
|
||||||
|
let xml = "<xml><Some_thing></Some_thing><something></something></xml>";
|
||||||
|
let rawxml: RawXml = yaserde::de::from_str(xml).unwrap();
|
||||||
|
assert_eq!(rawxml.0, String::from(xml));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn rawxml_should_buffer_elements_with_attributes() {
|
||||||
|
let xml = r#"<xml version="ababa"><Some_thing></Some_thing><something></something></xml>"#;
|
||||||
|
let rawxml: RawXml = yaserde::de::from_str(xml).unwrap();
|
||||||
|
assert_eq!(rawxml.0, String::from(xml));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn rawxml_should_handle_complex_documents() {
|
||||||
|
let xml = r#"<xml><OpenVPN version="1.0.0"><Overwrites></Overwrites><Instances></Instances><StaticKeys></StaticKeys></OpenVPN><Gateways version="0.0.1"></Gateways><HAProxy version="4.0.0"><general><enabled>1</enabled><gracefulStop>0</gracefulStop><hardStopAfter>60s</hardStopAfter><closeSpreadTime></closeSpreadTime><seamlessReload>0</seamlessReload><storeOcsp>0</storeOcsp><showIntro>1</showIntro><peers><enabled>0</enabled><name1></name1><listen1></listen1><port1>1024</port1><name2></name2><listen2></listen2><port2>1024</port2></peers><tuning><root>0</root><maxConnections></maxConnections><nbthread>1</nbthread><sslServerVerify>ignore</sslServerVerify><maxDHSize>2048</maxDHSize><bufferSize>16384</bufferSize></tuning></general></HAProxy></xml>"#;
|
||||||
|
let rawxml: RawXml = yaserde::de::from_str(xml).unwrap();
|
||||||
|
assert_eq!(rawxml.0, String::from(xml));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn rawxml_should_serialize_simple_documents() {
|
||||||
|
let xml = r#"<?xml version="1.0" encoding="utf-8"?><xml />"#;
|
||||||
|
let rawxml: RawXml = yaserde::de::from_str(xml).unwrap();
|
||||||
|
assert_eq!(yaserde::ser::to_string(&rawxml).unwrap(), xml);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn rawxml_should_serialize_complex_documents() {
|
||||||
|
let xml = r#"<?xml version="1.0" encoding="utf-8"?><xml><OpenVPN version="1.0.0"><Overwrites /><Instances /><StaticKeys /></OpenVPN><Gateways version="0.0.1" /><HAProxy version="4.0.0"><general><enabled>1</enabled><gracefulStop>0</gracefulStop><hardStopAfter>60s</hardStopAfter><closeSpreadTime /><seamlessReload>0</seamlessReload><storeOcsp>0</storeOcsp><showIntro>1</showIntro><peers><enabled>0</enabled><name1 /><listen1 /><port1>1024</port1><name2 /><listen2 /><port2>1024</port2></peers><tuning><root>0</root><maxConnections /><nbthread>1</nbthread><sslServerVerify>ignore</sslServerVerify><maxDHSize>2048</maxDHSize><bufferSize>16384</bufferSize></tuning></general></HAProxy></xml>"#;
|
||||||
|
let rawxml: RawXml = yaserde::de::from_str(xml).unwrap();
|
||||||
|
assert_eq!(yaserde::ser::to_string(&rawxml).unwrap(), xml);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn rawxml_should_allow_siblings_before() {
|
||||||
|
#[derive(YaDeserialize, YaSerialize)]
|
||||||
|
struct Config {
|
||||||
|
paul: Vec<String>,
|
||||||
|
raw: RawXml,
|
||||||
|
}
|
||||||
|
let xml = r#"<?xml version="1.0" encoding="utf-8"?><Config><paul>bobob</paul><paul>patate</paul><raw>allo something</raw></Config>"#;
|
||||||
|
let config: Config = yaserde::de::from_str(xml).unwrap();
|
||||||
|
assert_eq!(yaserde::ser::to_string(&config).unwrap(), xml);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn rawxml_should_allow_siblings_after() {
|
||||||
|
#[derive(YaDeserialize, YaSerialize)]
|
||||||
|
struct Config {
|
||||||
|
raw: RawXml,
|
||||||
|
paul: Vec<String>,
|
||||||
|
}
|
||||||
|
let xml = r#"<?xml version="1.0" encoding="utf-8"?><Config><raw>allo something</raw><paul>bobob</paul><paul>patate</paul></Config>"#;
|
||||||
|
let config: Config = yaserde::de::from_str(xml).unwrap();
|
||||||
|
assert_eq!(config.paul.get(0).unwrap(), "bobob");
|
||||||
|
assert_eq!(config.paul.get(1).unwrap(), "patate");
|
||||||
|
assert_eq!(config.paul.len(), 2);
|
||||||
|
assert_eq!(config.raw.0, "<raw>allo something</raw>");
|
||||||
|
assert_eq!(yaserde::ser::to_string(&config).unwrap(), xml);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn rawxml_should_allow_being_end_of_document() {
|
||||||
|
let xml = r#"<?xml version="1.0" encoding="utf-8"?><Config><raw>allo something</raw><paul>bobob</paul><paul>patate</paul></Config>"#;
|
||||||
|
let config: RawXml = yaserde::de::from_str(xml).unwrap();
|
||||||
|
assert_eq!(yaserde::ser::to_string(&config).unwrap(), xml);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
173
harmony-rs/opnsense-config/src/infra/maybe_string.rs
Normal file
173
harmony-rs/opnsense-config/src/infra/maybe_string.rs
Normal file
@ -0,0 +1,173 @@
|
|||||||
|
use xml::reader::XmlEvent as ReadEvent;
|
||||||
|
use xml::writer::XmlEvent as WriteEvent;
|
||||||
|
use yaserde::{ser, YaDeserialize as YaDeserializeTrait, YaSerialize as YaSerializeTrait};
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, Default)]
|
||||||
|
pub struct MaybeString {
|
||||||
|
field_name: String,
|
||||||
|
content: Option<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl YaDeserializeTrait for MaybeString {
|
||||||
|
fn deserialize<R: std::io::Read>(
|
||||||
|
reader: &mut yaserde::de::Deserializer<R>,
|
||||||
|
) -> Result<Self, String> {
|
||||||
|
let field_name = match reader.peek()? {
|
||||||
|
ReadEvent::StartElement {
|
||||||
|
name, attributes, ..
|
||||||
|
} => {
|
||||||
|
if attributes.len() > 0 {
|
||||||
|
return Err(String::from(
|
||||||
|
"Attributes not currently supported by MaybeString",
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
name.local_name.clone()
|
||||||
|
}
|
||||||
|
_ => return Err(String::from("Unsupporte ReadEvent type")),
|
||||||
|
};
|
||||||
|
reader.next_event()?;
|
||||||
|
|
||||||
|
let content = match reader.peek()? {
|
||||||
|
ReadEvent::Characters(content) => Some(content.clone()),
|
||||||
|
ReadEvent::EndElement { name } => {
|
||||||
|
if name.local_name != field_name {
|
||||||
|
return Err(format!(
|
||||||
|
"Invalid EndElement, expected {field_name} but got {}",
|
||||||
|
name.local_name
|
||||||
|
));
|
||||||
|
}
|
||||||
|
None
|
||||||
|
}
|
||||||
|
_ => return Err(String::from("Unsupporte ReadEvent type")),
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(Self {
|
||||||
|
field_name,
|
||||||
|
content,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl YaSerializeTrait for MaybeString {
|
||||||
|
fn serialize<W: std::io::Write>(&self, writer: &mut ser::Serializer<W>) -> Result<(), String> {
|
||||||
|
let start_element_event = WriteEvent::start_element(self.field_name.as_str());
|
||||||
|
writer.write(start_element_event).expect("Writer failed");
|
||||||
|
match &self.content {
|
||||||
|
Some(content) => {
|
||||||
|
writer
|
||||||
|
.write(WriteEvent::characters(content))
|
||||||
|
.expect("Writer failed");
|
||||||
|
}
|
||||||
|
None => {}
|
||||||
|
};
|
||||||
|
|
||||||
|
writer
|
||||||
|
.write(WriteEvent::end_element())
|
||||||
|
.expect("Writer failed");
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn serialize_attributes(
|
||||||
|
&self,
|
||||||
|
_attributes: Vec<xml::attribute::OwnedAttribute>,
|
||||||
|
_namespace: xml::namespace::Namespace,
|
||||||
|
) -> Result<
|
||||||
|
(
|
||||||
|
Vec<xml::attribute::OwnedAttribute>,
|
||||||
|
xml::namespace::Namespace,
|
||||||
|
),
|
||||||
|
String,
|
||||||
|
> {
|
||||||
|
unimplemented!("MaybeString does not currently support attributes")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test {
|
||||||
|
use super::*;
|
||||||
|
use pretty_assertions::assert_eq;
|
||||||
|
use yaserde_derive::YaDeserialize;
|
||||||
|
use yaserde_derive::YaSerialize;
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, Default, YaDeserialize, YaSerialize)]
|
||||||
|
struct TestStruct {
|
||||||
|
maybe: MaybeString,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn maybe_string_should_deserialize_empty_element() {
|
||||||
|
let initial_xml = "<struct><maybe/></struct>";
|
||||||
|
let test_struct: TestStruct =
|
||||||
|
yaserde::de::from_str(initial_xml).expect("Shoudl deserialize teststruct");
|
||||||
|
println!("Got test_struct {:?}", test_struct);
|
||||||
|
assert_eq!(
|
||||||
|
test_struct,
|
||||||
|
TestStruct {
|
||||||
|
maybe: MaybeString {
|
||||||
|
field_name: String::from("maybe"),
|
||||||
|
content: None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn maybe_string_should_deserialize_content() {
|
||||||
|
let initial_xml = "<struct><maybe>some content</maybe></struct>";
|
||||||
|
let test_struct: TestStruct =
|
||||||
|
yaserde::de::from_str(initial_xml).expect("Shoudl deserialize teststruct");
|
||||||
|
println!("Got test_struct {:?}", test_struct);
|
||||||
|
assert_eq!(
|
||||||
|
test_struct,
|
||||||
|
TestStruct {
|
||||||
|
maybe: MaybeString {
|
||||||
|
field_name: String::from("maybe"),
|
||||||
|
content: Some(String::from("some content"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn maybe_string_should_deserialize_empty_long_format() {
|
||||||
|
let initial_xml = "<struct><maybe></maybe></struct>";
|
||||||
|
let test_struct: TestStruct =
|
||||||
|
yaserde::de::from_str(initial_xml).expect("Shoudl deserialize teststruct");
|
||||||
|
println!("Got test_struct {:?}", test_struct);
|
||||||
|
assert_eq!(
|
||||||
|
test_struct,
|
||||||
|
TestStruct {
|
||||||
|
maybe: MaybeString {
|
||||||
|
field_name: String::from("maybe"),
|
||||||
|
content: None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn maybe_string_should_serialize_to_empty_element() {
|
||||||
|
let initial_xml =
|
||||||
|
r#"<?xml version="1.0" encoding="utf-8"?><TestStruct><maybe /></TestStruct>"#;
|
||||||
|
let test_struct: TestStruct =
|
||||||
|
yaserde::de::from_str(initial_xml).expect("Shoudl deserialize teststruct");
|
||||||
|
println!("Got test_struct {:?}", test_struct);
|
||||||
|
assert_eq!(
|
||||||
|
yaserde::ser::to_string(&test_struct).expect("should serialize teststruct"),
|
||||||
|
initial_xml
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn maybe_string_should_serialize_content() {
|
||||||
|
let initial_xml = r#"<?xml version="1.0" encoding="utf-8"?><TestStruct><maybe>some content</maybe></TestStruct>"#;
|
||||||
|
let test_struct: TestStruct =
|
||||||
|
yaserde::de::from_str(initial_xml).expect("Shoudl deserialize teststruct");
|
||||||
|
println!("Got test_struct {:?}", test_struct);
|
||||||
|
assert_eq!(
|
||||||
|
yaserde::ser::to_string(&test_struct).expect("should serialize teststruct"),
|
||||||
|
initial_xml
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,3 +1,4 @@
|
|||||||
|
|
||||||
pub mod generic_xml;
|
pub mod generic_xml;
|
||||||
|
pub mod maybe_string;
|
||||||
|
|
||||||
|
|||||||
@ -1,4 +1,8 @@
|
|||||||
use super::opnsense::{OPNsense, StaticMap};
|
use super::opnsense::{OPNsense, StaticMap};
|
||||||
|
use crate::infra::maybe_string::MaybeString;
|
||||||
|
use crate::modules::opnsense::NumberOption;
|
||||||
|
use crate::modules::opnsense::Range;
|
||||||
|
use yaserde_derive::{YaDeserialize, YaSerialize};
|
||||||
|
|
||||||
pub struct DhcpConfig<'a> {
|
pub struct DhcpConfig<'a> {
|
||||||
opnsense: &'a mut OPNsense,
|
opnsense: &'a mut OPNsense,
|
||||||
@ -14,10 +18,10 @@ impl<'a> DhcpConfig<'a> {
|
|||||||
mac,
|
mac,
|
||||||
ipaddr,
|
ipaddr,
|
||||||
hostname,
|
hostname,
|
||||||
descr: Some("Automatically generated".into()),
|
descr: Default::default(),
|
||||||
winsserver: None,
|
winsserver: Default::default(),
|
||||||
dnsserver: None,
|
dnsserver: Default::default(),
|
||||||
ntpserver: None,
|
ntpserver: Default::default(),
|
||||||
};
|
};
|
||||||
self.opnsense.dhcpd.lan.staticmaps.push(static_map);
|
self.opnsense.dhcpd.lan.staticmaps.push(static_map);
|
||||||
}
|
}
|
||||||
@ -26,3 +30,115 @@ impl<'a> DhcpConfig<'a> {
|
|||||||
&self.opnsense.dhcpd.lan.staticmaps
|
&self.opnsense.dhcpd.lan.staticmaps
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Default, PartialEq, Debug, YaSerialize, YaDeserialize)]
|
||||||
|
#[yaserde(rename = "dhcpd")]
|
||||||
|
pub struct Dhcpd {
|
||||||
|
#[yaserde(rename = "lan")]
|
||||||
|
pub lan: DhcpInterface,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Default, PartialEq, Debug, YaSerialize, YaDeserialize)]
|
||||||
|
pub struct DhcpInterface {
|
||||||
|
pub enable: i32,
|
||||||
|
pub gateway: String,
|
||||||
|
pub domain: String,
|
||||||
|
#[yaserde(rename = "ddnsdomainalgorithm")]
|
||||||
|
pub ddns_domain_algorithm: String,
|
||||||
|
#[yaserde(rename = "numberoptions")]
|
||||||
|
pub number_options: Vec<NumberOption>,
|
||||||
|
#[yaserde(rename = "range")]
|
||||||
|
pub range: Range,
|
||||||
|
pub winsserver: MaybeString,
|
||||||
|
pub dnsserver: MaybeString,
|
||||||
|
pub ntpserver: MaybeString,
|
||||||
|
#[yaserde(rename = "staticmap")]
|
||||||
|
pub staticmaps: Vec<StaticMap>,
|
||||||
|
pub pool: MaybeString,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Default, PartialEq, Debug, YaSerialize, YaDeserialize)]
|
||||||
|
pub struct DhcpRange {
|
||||||
|
#[yaserde(rename = "from")]
|
||||||
|
pub from: String,
|
||||||
|
#[yaserde(rename = "to")]
|
||||||
|
pub to: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test {
|
||||||
|
use super::*;
|
||||||
|
use pretty_assertions::assert_eq;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn dhcpd_should_deserialize_serialize_identical() {
|
||||||
|
let dhcpd: Dhcpd =
|
||||||
|
yaserde::de::from_str(SERIALIZED_DHCPD).expect("Deserialize Dhcpd failed");
|
||||||
|
|
||||||
|
let yaserde_cfg = yaserde::ser::Config {
|
||||||
|
perform_indent: true,
|
||||||
|
write_document_declaration: false,
|
||||||
|
..Default::default()
|
||||||
|
};
|
||||||
|
assert_eq!(
|
||||||
|
yaserde::ser::to_string_with_config(&dhcpd, &yaserde_cfg)
|
||||||
|
.expect("Serialize Dhcpd failed"),
|
||||||
|
SERIALIZED_DHCPD
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const SERIALIZED_DHCPD: &str = "<dhcpd>
|
||||||
|
<lan>
|
||||||
|
<enable>1</enable>
|
||||||
|
<gateway>192.168.20.1</gateway>
|
||||||
|
<domain>somedomain.yourlocal.mcd</domain>
|
||||||
|
<ddnsdomainalgorithm>hmac-md5</ddnsdomainalgorithm>
|
||||||
|
<numberoptions>
|
||||||
|
<item/>
|
||||||
|
</numberoptions>
|
||||||
|
<range>
|
||||||
|
<from>192.168.20.50</from>
|
||||||
|
<to>192.168.20.200</to>
|
||||||
|
</range>
|
||||||
|
<winsserver/>
|
||||||
|
<dnsserver>192.168.20.1</dnsserver>
|
||||||
|
<ntpserver/>
|
||||||
|
<staticmap>
|
||||||
|
<mac>55:55:55:55:55:1c</mac>
|
||||||
|
<ipaddr>192.168.20.160</ipaddr>
|
||||||
|
<hostname>somehost983</hostname>
|
||||||
|
<descr>someservire8</descr>
|
||||||
|
<winsserver/>
|
||||||
|
<dnsserver/>
|
||||||
|
<ntpserver/>
|
||||||
|
</staticmap>
|
||||||
|
<staticmap>
|
||||||
|
<mac>55:55:55:55:55:1c</mac>
|
||||||
|
<ipaddr>192.168.20.155</ipaddr>
|
||||||
|
<hostname>somehost893</hostname>
|
||||||
|
<winsserver/>
|
||||||
|
<dnsserver/>
|
||||||
|
<ntpserver/>
|
||||||
|
</staticmap>
|
||||||
|
<staticmap>
|
||||||
|
<mac>55:55:55:55:55:1c</mac>
|
||||||
|
<ipaddr>192.168.20.165</ipaddr>
|
||||||
|
<hostname>somehost893</hostname>
|
||||||
|
<descr/>
|
||||||
|
<winsserver/>
|
||||||
|
<dnsserver/>
|
||||||
|
<ntpserver/>
|
||||||
|
</staticmap>
|
||||||
|
<staticmap>
|
||||||
|
<mac>55:55:55:55:55:1c</mac>
|
||||||
|
<ipaddr>192.168.20.50</ipaddr>
|
||||||
|
<hostname>hostswitch2</hostname>
|
||||||
|
<descr>switch-2 (bottom)</descr>
|
||||||
|
<winsserver/>
|
||||||
|
<dnsserver/>
|
||||||
|
<ntpserver/>
|
||||||
|
</staticmap>
|
||||||
|
<pool/>
|
||||||
|
</lan>
|
||||||
|
</dhcpd>";
|
||||||
|
}
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user