Skip to content

Commit

Permalink
feat: support text nodes configured from XML builder
Browse files Browse the repository at this point in the history
  • Loading branch information
Ronald Holshausen committed May 26, 2020
1 parent d72a210 commit a2a7f55
Show file tree
Hide file tree
Showing 3 changed files with 69 additions and 43 deletions.
17 changes: 4 additions & 13 deletions native/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

9 changes: 5 additions & 4 deletions native/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,10 @@ neon-build = "0.4.0"

[dependencies]
neon = { version = "0.4.0", features = ["event-handler-api"] }
pact_mock_server = "0.7.4"
pact_mock_server_ffi = "0.0.6"
pact_matching = "0.6.0"
pact_verifier = "0.8.1"
pact_mock_server = { version = "0.7.5", path = "../../pact-reference/rust/pact_mock_server" }
pact_mock_server_ffi = { version = "0.0.6", path = "../../pact-reference/rust/pact_mock_server_ffi" }
pact_matching = { version = "0.6.1", path = "../../pact-reference/rust/pact_matching" }
pact_verifier = { version = "0.8.0", path = "../../pact-reference/rust/pact_verifier" }
env_logger = "0.7"
log = "0.4.6"
uuid = { version = "0.6", features = ["v4"] }
Expand All @@ -36,3 +36,4 @@ sxd-document = "0.3.2"
async-trait = "0.1.24"
reqwest = "0.10"
native-tls = { version = "0.2.4" }
either = "1.5.3"
86 changes: 60 additions & 26 deletions native/src/xml.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
//! XML handling
use serde_json::Value::Number;
use sxd_document::dom::Document;
use sxd_document::dom::Element;
use sxd_document::dom::ChildOfElement;
use sxd_document::dom::{Document, Element, ChildOfElement, Text};
use serde_json::Value;
use serde_json::map::Map;
use sxd_document::Package;
Expand All @@ -11,6 +9,8 @@ use pact_matching::models::matchingrules::{MatchingRule, Category, RuleLogic};
use pact_matching::models::generators::{Generators, GeneratorCategory, Generator};
use pact_matching::models::json_utils::json_to_string;
use log::*;
use std::collections::HashMap;
use either::Either;

pub fn generate_xml_body(attributes: &Map<String, Value>, matching_rules: &mut Category, generators: &mut Generators) -> Result<Vec<u8>, String> {
let package = Package::new();
Expand All @@ -20,8 +20,10 @@ pub fn generate_xml_body(attributes: &Map<String, Value>, matching_rules: &mut C
match attributes.get("root") {
Some(val) => match val {
Value::Object(obj) => {
let node = create_element_from_json(doc, None, obj, matching_rules, generators, &"$".to_string(), false);
doc.root().append_child(node);
match create_element_from_json(doc, None, obj, matching_rules, generators, &"$".to_string(), false, &mut hashmap!{}) {
Either::Left(element) => doc.root().append_child(element),
Either::Right(text) => warn!("Can't append text node to the root")
}
},
_ => {
warn!("Root XML element is not an object: {}", val);
Expand All @@ -32,15 +34,27 @@ pub fn generate_xml_body(attributes: &Map<String, Value>, matching_rules: &mut C
}
}

debug!("Done processing XML body");
let mut output = vec![];
match format_document(&doc, &mut output) {
Ok(_) => Ok(output),
Err(err) => Err(format!("Unable to generate a valid XML document: {}", err) )
}
}

fn create_element_from_json<'a>(doc: Document<'a>, parent: Option<Element<'a>>, object: &Map<String, Value>, matching_rules: &mut Category, generators: &mut Generators, path: &String, type_matcher: bool) -> Element<'a> {
let element = if object.contains_key("pact:matcher:type") {
fn create_element_from_json<'a>(
doc: Document<'a>,
parent: Option<Element<'a>>,
object: &Map<String, Value>,
matching_rules: &mut Category,
generators: &mut Generators,
path: &String,
type_matcher: bool,
namespaces: &mut HashMap<String, String>
) -> Either<Element<'a>, Text<'a>> {
let mut element = None;
let mut text = None;
if object.contains_key("pact:matcher:type") {
if let Some(rule) = MatchingRule::from_integration_json(object) {
matching_rules.add_rule(path, rule, &RuleLogic::And);
}
Expand All @@ -54,10 +68,10 @@ fn create_element_from_json<'a>(doc: Document<'a>, parent: Option<Element<'a>>,
let updated_path = path.to_owned() + ".*";
if let Some(val) = object.get("value") {
if let Value::Object(attr) = val {
let element = doc.create_element(json_to_string(attr.get("name").unwrap()).as_str());
let new_element = doc.create_element(json_to_string(dbg!(attr).get("name").unwrap()).as_str());
if let Some(attributes) = val.get("attributes") {
match attributes {
Value::Object(attributes) => add_attributes(&element, attributes, matching_rules, generators, &updated_path),
Value::Object(attributes) => add_attributes(&new_element, attributes, matching_rules, generators, &updated_path),
_ => ()
}
};
Expand All @@ -67,7 +81,7 @@ fn create_element_from_json<'a>(doc: Document<'a>, parent: Option<Element<'a>>,
Value::Array(children) => for child in children {
match child {
Value::Object(attributes) => {
create_element_from_json(doc, Some(element), attributes, matching_rules, generators, &updated_path, true);
create_element_from_json(doc, Some(new_element), attributes, matching_rules, generators, &updated_path, true, namespaces);
},
_ => panic!("Intermediate JSON format is invalid, child is not an object: {:?}", child)
}
Expand All @@ -76,19 +90,21 @@ fn create_element_from_json<'a>(doc: Document<'a>, parent: Option<Element<'a>>,
}
};

element
element = Some(new_element)
} else {
panic!("Intermediate JSON format is invalid, corresponding value for the given matcher was not an object: {:?}", object)
}
} else {
panic!("Intermediate JSON format is invalid, no corresponding value for the given matcher: {:?}", object)
}
} else {
let name = json_to_string(object.get("name").unwrap());
let element = doc.create_element(name.as_str());
} else if let Some(content) = object.get("content") {
text = Some(doc.create_text(json_to_string(content).as_str()))
} else if let Some(name) = object.get("name") {
let name = json_to_string(name);
let new_element = doc.create_element(name.as_str());
if let Some(attributes) = object.get("attributes") {
match attributes {
Value::Object(attributes) => add_attributes(&element, attributes, matching_rules, generators, path),
Value::Object(attributes) => add_attributes(&new_element, attributes, matching_rules, generators, path),
_ => ()
}
};
Expand All @@ -98,35 +114,53 @@ fn create_element_from_json<'a>(doc: Document<'a>, parent: Option<Element<'a>>,
Value::Array(children) => for child in children {
match child {
Value::Object(attributes) => {
create_element_from_json(doc, Some(element), attributes, matching_rules, generators, &(path.to_owned() + "." + name.as_str()), false);
create_element_from_json(doc, Some(new_element), attributes, matching_rules, generators, &(path.to_owned() + "." + name.as_str()), false, namespaces);
},
_ => panic!("Intermediate JSON format is invalid, child is not an object: {:?}", child)
}
},
_ => panic!("Intermediate JSON format is invalid, children is not an Array: {:?}", children)
}
};
element
element = Some(new_element);
} else {
panic!("Ignoring invalid object {:?}", object);
};

if let Some(parent) = parent {
let examples = match object.get("examples") {
Some(val) => match val {
Number(val) => val.as_u64().unwrap(),
_ => 1
}
None => 1
};
let examples = match object.get("examples") {
Some(val) => match val {
Number(val) => val.as_u64().unwrap(),
_ => 1
}
None => 1
};

if let Some(element) = element {
for _ in 0..examples {
parent.append_child(duplicate_element(doc, &element));
}
} else if let Some(text) = text {
parent.append_child(&text);
}
}

element
if let Some(element) = element {
Either::Left(element)
} else if let Some(text) = text {
Either::Right(text)
} else {
panic!("Intermediate JSON was mapped to neither an element or a text node")
}
}

fn add_attributes(element: &Element, attributes: &Map<String, Value>, matching_rules: &mut Category, generators: &mut Generators, path: &String) {
fn add_attributes(
element: &Element,
attributes: &Map<String, Value>,
matching_rules: &mut Category,
generators: &mut Generators,
path: &String
) {
for (k, v) in attributes {
let path = format!("{}['@{}']", path, k);

Expand Down

0 comments on commit a2a7f55

Please sign in to comment.