cargo fmt
Signed-off-by: Maxime “pep” Buquet <pep@bouah.net>
This commit is contained in:
parent
c847ceb3bf
commit
6ede9da169
3 changed files with 237 additions and 190 deletions
350
src/element.rs
350
src/element.rs
|
@ -35,17 +35,17 @@
|
||||||
//! # mode to ensure that it only matches a completely empty message stanza:
|
//! # mode to ensure that it only matches a completely empty message stanza:
|
||||||
//!
|
//!
|
||||||
//! Louise receives:
|
//! Louise receives:
|
||||||
//! <message scansion:strict="true"/>
|
//! <message scansion:strict="true"/>
|
||||||
//! ```
|
//! ```
|
||||||
|
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::ops::Deref;
|
|
||||||
use std::fmt::Debug;
|
use std::fmt::Debug;
|
||||||
use std::marker::PhantomData;
|
use std::marker::PhantomData;
|
||||||
|
use std::ops::Deref;
|
||||||
|
|
||||||
use crate::{Client, ClientName};
|
|
||||||
use crate::types::VariableAttr;
|
|
||||||
use crate::parsers::parse_variable;
|
use crate::parsers::parse_variable;
|
||||||
|
use crate::types::VariableAttr;
|
||||||
|
use crate::{Client, ClientName};
|
||||||
|
|
||||||
use jid::BareJid;
|
use jid::BareJid;
|
||||||
use minidom::{Element, Node};
|
use minidom::{Element, Node};
|
||||||
|
@ -84,12 +84,8 @@ impl ScanNode {
|
||||||
impl PartialEq<Node> for ScanNode {
|
impl PartialEq<Node> for ScanNode {
|
||||||
fn eq(&self, other: &Node) -> bool {
|
fn eq(&self, other: &Node) -> bool {
|
||||||
match (&self.node, other) {
|
match (&self.node, other) {
|
||||||
(Node::Text(text1), Node::Text(text2)) => {
|
(Node::Text(text1), Node::Text(text2)) => text1 == text2,
|
||||||
text1 == text2
|
(Node::Element(elem1), Node::Element(elem2)) => ScanElement::new(&elem1) == elem2,
|
||||||
},
|
|
||||||
(Node::Element(elem1), Node::Element(elem2)) => {
|
|
||||||
ScanElement::new(&elem1) == elem2
|
|
||||||
},
|
|
||||||
_ => false,
|
_ => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -116,46 +112,46 @@ fn filter_whitespace_nodes(nodes: Vec<Node>) -> Vec<Node> {
|
||||||
(Some(type_), acc)
|
(Some(type_), acc)
|
||||||
};
|
};
|
||||||
|
|
||||||
let rm_empty_text = |node: &Node| {
|
let rm_empty_text = |node: &Node| match node {
|
||||||
match node {
|
Node::Text(text) => text.trim().len() != 0,
|
||||||
Node::Text(text) => {
|
_ => true,
|
||||||
text.trim().len() != 0
|
|
||||||
},
|
|
||||||
_ => true,
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let nodes = nodes
|
let nodes = nodes
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.fold((None::<NodeType>, vec![]), filter_nodes).1;
|
.fold((None::<NodeType>, vec![]), filter_nodes)
|
||||||
|
.1;
|
||||||
|
|
||||||
// Don't remove possibly significant whitespace text leaves
|
// Don't remove possibly significant whitespace text leaves
|
||||||
if nodes.iter().count() == 1 {
|
if nodes.iter().count() == 1 {
|
||||||
nodes
|
nodes
|
||||||
} else {
|
} else {
|
||||||
nodes
|
nodes.into_iter().filter(rm_empty_text).collect()
|
||||||
.into_iter()
|
}
|
||||||
.filter(rm_empty_text)
|
|
||||||
.collect()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
struct ScanNodes<T: Debug> {
|
struct ScanNodes<T: Debug> {
|
||||||
nodes: Vec<Node>,
|
nodes: Vec<Node>,
|
||||||
_strict: PhantomData<T>,
|
_strict: PhantomData<T>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ScanNodes<NonStrictComparison> {
|
impl ScanNodes<NonStrictComparison> {
|
||||||
fn new(nodes: Vec<Node>) -> ScanNodes<NonStrictComparison> {
|
fn new(nodes: Vec<Node>) -> ScanNodes<NonStrictComparison> {
|
||||||
Self { nodes, _strict: PhantomData }
|
Self {
|
||||||
}
|
nodes,
|
||||||
|
_strict: PhantomData,
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ScanNodes<StrictComparison> {
|
impl ScanNodes<StrictComparison> {
|
||||||
fn new_strict(nodes: Vec<Node>) -> ScanNodes<StrictComparison> {
|
fn new_strict(nodes: Vec<Node>) -> ScanNodes<StrictComparison> {
|
||||||
Self { nodes, _strict: PhantomData }
|
Self {
|
||||||
}
|
nodes,
|
||||||
|
_strict: PhantomData,
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Tags with mixed significant text and children tags aren't valid in XMPP, so we know we can
|
/// Tags with mixed significant text and children tags aren't valid in XMPP, so we know we can
|
||||||
|
@ -164,9 +160,9 @@ impl ScanNodes<StrictComparison> {
|
||||||
impl PartialEq<Vec<Node>> for ScanNodes<StrictComparison> {
|
impl PartialEq<Vec<Node>> for ScanNodes<StrictComparison> {
|
||||||
fn eq(&self, other: &Vec<Node>) -> bool {
|
fn eq(&self, other: &Vec<Node>) -> bool {
|
||||||
let filtered_self = filter_whitespace_nodes(self.nodes.clone())
|
let filtered_self = filter_whitespace_nodes(self.nodes.clone())
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(ScanNode::new)
|
.map(ScanNode::new)
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
let filtered_other = filter_whitespace_nodes(other.clone());
|
let filtered_other = filter_whitespace_nodes(other.clone());
|
||||||
|
|
||||||
filtered_self == filtered_other
|
filtered_self == filtered_other
|
||||||
|
@ -181,15 +177,15 @@ impl PartialEq<Vec<Node>> for ScanNodes<NonStrictComparison> {
|
||||||
let filtered_other = filter_whitespace_nodes(other.clone());
|
let filtered_other = filter_whitespace_nodes(other.clone());
|
||||||
|
|
||||||
filter_whitespace_nodes(self.nodes.clone())
|
filter_whitespace_nodes(self.nodes.clone())
|
||||||
.into_iter()
|
.into_iter()
|
||||||
// Maps nodes to their comparison result
|
// Maps nodes to their comparison result
|
||||||
.fold(true, |res, node| {
|
.fold(true, |res, node| {
|
||||||
let scan = ScanNode::new(node);
|
let scan = ScanNode::new(node);
|
||||||
res &&
|
res && filtered_other
|
||||||
filtered_other.iter().find(|onode| {
|
.iter()
|
||||||
&&scan == onode
|
.find(|onode| &&scan == onode)
|
||||||
}).is_some()
|
.is_some()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -200,12 +196,12 @@ impl PartialEq<Vec<Node>> for ScanNodes<NonStrictComparison> {
|
||||||
/// Also uses the custom ScanNode implementation.
|
/// Also uses the custom ScanNode implementation.
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct ScanElement<'a, 'b> {
|
pub struct ScanElement<'a, 'b> {
|
||||||
elem: &'a Element,
|
elem: &'a Element,
|
||||||
context: Option<&'b HashMap<ClientName, Client>>,
|
context: Option<&'b HashMap<ClientName, Client>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'b> Deref for ScanElement<'a, 'b> {
|
impl<'a, 'b> Deref for ScanElement<'a, 'b> {
|
||||||
type Target = Element;
|
type Target = Element;
|
||||||
|
|
||||||
fn deref(&self) -> &Self::Target {
|
fn deref(&self) -> &Self::Target {
|
||||||
&self.elem
|
&self.elem
|
||||||
|
@ -213,24 +209,28 @@ impl<'a, 'b> Deref for ScanElement<'a, 'b> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> ScanElement<'a, 'static> {
|
impl<'a> ScanElement<'a, 'static> {
|
||||||
pub fn new(elem: &'a Element) -> ScanElement {
|
pub fn new(elem: &'a Element) -> ScanElement {
|
||||||
Self { elem, context: None }
|
Self {
|
||||||
}
|
elem,
|
||||||
|
context: None,
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl <'a, 'b> ScanElement<'a, 'b> {
|
impl<'a, 'b> ScanElement<'a, 'b> {
|
||||||
pub fn with_context(self, context: &'b HashMap<ClientName, Client>) -> ScanElement<'a, 'b> {
|
pub fn with_context(self, context: &'b HashMap<ClientName, Client>) -> ScanElement<'a, 'b> {
|
||||||
Self { elem: self.elem, context: Some(context) }
|
Self {
|
||||||
}
|
elem: self.elem,
|
||||||
|
context: Some(context),
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'b> PartialEq<&Element> for ScanElement<'a, 'b> {
|
impl<'a, 'b> PartialEq<&Element> for ScanElement<'a, 'b> {
|
||||||
fn eq(&self, other: &&Element) -> bool {
|
fn eq(&self, other: &&Element) -> bool {
|
||||||
let self_ns = self.elem.ns();
|
let self_ns = self.elem.ns();
|
||||||
if self.elem.name() == other.name() &&
|
if self.elem.name() == other.name() && self_ns == other.ns() {
|
||||||
self_ns == other.ns() {
|
let strict_attr = self.elem.attr("scansion:strict");
|
||||||
|
|
||||||
let strict_attr = self.elem.attr("scansion:strict");
|
|
||||||
|
|
||||||
// Force true if scansion:strict is set or if a tag isn't in the default ns.
|
// Force true if scansion:strict is set or if a tag isn't in the default ns.
|
||||||
let strict = if let Some(val) = strict_attr {
|
let strict = if let Some(val) = strict_attr {
|
||||||
|
@ -239,14 +239,14 @@ impl<'a, 'b> PartialEq<&Element> for ScanElement<'a, 'b> {
|
||||||
self_ns != DEFAULT_NS
|
self_ns != DEFAULT_NS
|
||||||
};
|
};
|
||||||
|
|
||||||
for (attr, val) in self.elem.attrs() {
|
for (attr, val) in self.elem.attrs() {
|
||||||
if val == "{scansion:any}" {
|
if val == "{scansion:any}" {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse variables. If parsing fails, continue attr comparison.
|
// Parse variables. If parsing fails, continue attr comparison.
|
||||||
// If context isn't set, skip this and continue attr comparison.
|
// If context isn't set, skip this and continue attr comparison.
|
||||||
if let Ok((_, var)) = parse_variable(val.into()) &&
|
if let Ok((_, var)) = parse_variable(val.into()) &&
|
||||||
let Some(context) = self.context {
|
let Some(context) = self.context {
|
||||||
let res = match var {
|
let res = match var {
|
||||||
VariableAttr::FullJid(name) => match context.get(&name) {
|
VariableAttr::FullJid(name) => match context.get(&name) {
|
||||||
|
@ -266,33 +266,33 @@ impl<'a, 'b> PartialEq<&Element> for ScanElement<'a, 'b> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
match (attr, other.attr(attr)) {
|
match (attr, other.attr(attr)) {
|
||||||
(attr, _) if attr == "scansion:strict" => continue,
|
(attr, _) if attr == "scansion:strict" => continue,
|
||||||
(_, None) => return false,
|
(_, None) => return false,
|
||||||
(_, Some(oval)) if val != oval => return false,
|
(_, Some(oval)) if val != oval => return false,
|
||||||
_ => (),
|
_ => (),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let onodes = other.nodes().cloned().collect::<Vec<_>>();
|
let onodes = other.nodes().cloned().collect::<Vec<_>>();
|
||||||
|
|
||||||
// Compare attributes count
|
// Compare attributes count
|
||||||
if strict {
|
if strict {
|
||||||
let count = self.elem.attrs().into_iter().count();
|
let count = self.elem.attrs().into_iter().count();
|
||||||
let ocount = other.attrs().into_iter().count();
|
let ocount = other.attrs().into_iter().count();
|
||||||
|
|
||||||
match strict_attr {
|
match strict_attr {
|
||||||
None if count != ocount => return false,
|
None if count != ocount => return false,
|
||||||
Some(_) if count != ocount + 1 => return false,
|
Some(_) if count != ocount + 1 => return false,
|
||||||
_ => (),
|
_ => (),
|
||||||
}
|
}
|
||||||
|
|
||||||
let nodes = ScanNodes::new_strict(self.elem.nodes().cloned().collect());
|
let nodes = ScanNodes::new_strict(self.elem.nodes().cloned().collect());
|
||||||
nodes == onodes
|
nodes == onodes
|
||||||
} else {
|
} else {
|
||||||
let nodes = ScanNodes::new(self.elem.nodes().cloned().collect());
|
let nodes = ScanNodes::new(self.elem.nodes().cloned().collect());
|
||||||
nodes == onodes
|
nodes == onodes
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
@ -304,6 +304,8 @@ mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
|
|
||||||
|
use jid::Jid;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn compare_nodes_simple() {
|
fn compare_nodes_simple() {
|
||||||
let text1 = Node::Text(String::from("\t\t"));
|
let text1 = Node::Text(String::from("\t\t"));
|
||||||
|
@ -360,7 +362,9 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn compare_element_non_strict_whitespace_success() {
|
fn compare_element_non_strict_whitespace_success() {
|
||||||
let elem1: Element = "<presence xmlns='foo'>\n\t<foo/></presence>".parse().unwrap();
|
let elem1: Element = "<presence xmlns='foo'>\n\t<foo/></presence>"
|
||||||
|
.parse()
|
||||||
|
.unwrap();
|
||||||
let elem2: Element = "<presence xmlns='foo'><foo/></presence>".parse().unwrap();
|
let elem2: Element = "<presence xmlns='foo'><foo/></presence>".parse().unwrap();
|
||||||
let scan1 = ScanElement::new(&elem1);
|
let scan1 = ScanElement::new(&elem1);
|
||||||
|
|
||||||
|
@ -369,8 +373,12 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn compare_element_non_strict_whitespace_failure() {
|
fn compare_element_non_strict_whitespace_failure() {
|
||||||
let elem1: Element = "<presence scansion:strict='false' xmlns='foo'>\n\tfoo</presence>".parse().unwrap();
|
let elem1: Element = "<presence scansion:strict='false' xmlns='foo'>\n\tfoo</presence>"
|
||||||
let elem2: Element = "<presence xmlns='foo'>\n\tfoo\t</presence>".parse().unwrap();
|
.parse()
|
||||||
|
.unwrap();
|
||||||
|
let elem2: Element = "<presence xmlns='foo'>\n\tfoo\t</presence>"
|
||||||
|
.parse()
|
||||||
|
.unwrap();
|
||||||
let scan1 = ScanElement::new(&elem1);
|
let scan1 = ScanElement::new(&elem1);
|
||||||
|
|
||||||
assert_ne!(scan1, &elem2);
|
assert_ne!(scan1, &elem2);
|
||||||
|
@ -384,11 +392,15 @@ mod tests {
|
||||||
assert_eq!(scan1, &elem1);
|
assert_eq!(scan1, &elem1);
|
||||||
|
|
||||||
let elem2: Element = "<presence scansion:strict='true' xmlns='jabber:client'>
|
let elem2: Element = "<presence scansion:strict='true' xmlns='jabber:client'>
|
||||||
<x xmlns='http://jabber.org/protocol/muc'/>
|
<x xmlns='http://jabber.org/protocol/muc'/>
|
||||||
</presence>".parse().unwrap();
|
</presence>"
|
||||||
|
.parse()
|
||||||
|
.unwrap();
|
||||||
let elem3: Element = "<presence xmlns='jabber:client'>
|
let elem3: Element = "<presence xmlns='jabber:client'>
|
||||||
<x xmlns='http://jabber.org/protocol/muc'/>
|
<x xmlns='http://jabber.org/protocol/muc'/>
|
||||||
</presence>".parse().unwrap();
|
</presence>"
|
||||||
|
.parse()
|
||||||
|
.unwrap();
|
||||||
let scan2 = ScanElement::new(&elem2);
|
let scan2 = ScanElement::new(&elem2);
|
||||||
|
|
||||||
assert_eq!(scan2, &elem3);
|
assert_eq!(scan2, &elem3);
|
||||||
|
@ -406,18 +418,22 @@ mod tests {
|
||||||
#[test]
|
#[test]
|
||||||
fn compare_element_strict_nodes_success() {
|
fn compare_element_strict_nodes_success() {
|
||||||
let elem1: Element = "<presence scansion:strict='true' xmlns='jabber:client'>
|
let elem1: Element = "<presence scansion:strict='true' xmlns='jabber:client'>
|
||||||
<x xmlns='http://jabber.org/protocol/muc' />
|
<x xmlns='http://jabber.org/protocol/muc' />
|
||||||
<x xmlns='vcard-temp:x:update'>
|
<x xmlns='vcard-temp:x:update'>
|
||||||
<photo/>
|
<photo/>
|
||||||
</x>
|
</x>
|
||||||
</presence>".parse().unwrap();
|
</presence>"
|
||||||
// The same, minus 'scansion:strict'
|
.parse()
|
||||||
|
.unwrap();
|
||||||
|
// The same, minus 'scansion:strict'
|
||||||
let elem2: Element = "<presence xmlns='jabber:client'>
|
let elem2: Element = "<presence xmlns='jabber:client'>
|
||||||
<x xmlns='http://jabber.org/protocol/muc' />
|
<x xmlns='http://jabber.org/protocol/muc' />
|
||||||
<x xmlns='vcard-temp:x:update'>
|
<x xmlns='vcard-temp:x:update'>
|
||||||
<photo/>
|
<photo/>
|
||||||
</x>
|
</x>
|
||||||
</presence>".parse().unwrap();
|
</presence>"
|
||||||
|
.parse()
|
||||||
|
.unwrap();
|
||||||
let scan1 = ScanElement::new(&elem1);
|
let scan1 = ScanElement::new(&elem1);
|
||||||
|
|
||||||
assert_eq!(scan1, &elem2);
|
assert_eq!(scan1, &elem2);
|
||||||
|
@ -426,15 +442,19 @@ mod tests {
|
||||||
#[test]
|
#[test]
|
||||||
fn compare_element_strict_nodes_failure() {
|
fn compare_element_strict_nodes_failure() {
|
||||||
let elem1: Element = "<presence scansion:strict='true' xmlns='jabber:client'>
|
let elem1: Element = "<presence scansion:strict='true' xmlns='jabber:client'>
|
||||||
<x xmlns='http://jabber.org/protocol/muc' />
|
<x xmlns='http://jabber.org/protocol/muc' />
|
||||||
<x xmlns='vcard-temp:x:update'>
|
<x xmlns='vcard-temp:x:update'>
|
||||||
<photo/>
|
<photo/>
|
||||||
</x>
|
</x>
|
||||||
</presence>".parse().unwrap();
|
</presence>"
|
||||||
|
.parse()
|
||||||
|
.unwrap();
|
||||||
let elem2: Element = "<presence scansion:strict='true' xmlns='jabber:client'>
|
let elem2: Element = "<presence scansion:strict='true' xmlns='jabber:client'>
|
||||||
<x xmlns='http://jabber.org/protocol/muc' />
|
<x xmlns='http://jabber.org/protocol/muc' />
|
||||||
<x xmlns='vcard-temp:x:update'/>
|
<x xmlns='vcard-temp:x:update'/>
|
||||||
</presence>".parse().unwrap();
|
</presence>"
|
||||||
|
.parse()
|
||||||
|
.unwrap();
|
||||||
let scan1 = ScanElement::new(&elem1);
|
let scan1 = ScanElement::new(&elem1);
|
||||||
|
|
||||||
assert_ne!(scan1, &elem2);
|
assert_ne!(scan1, &elem2);
|
||||||
|
@ -442,17 +462,23 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn compare_element_non_strict_attributes_success() {
|
fn compare_element_non_strict_attributes_success() {
|
||||||
let elem1: Element = "<presence scansion:strict='false' xmlns='foo'/>".parse().unwrap();
|
let elem1: Element = "<presence scansion:strict='false' xmlns='foo'/>"
|
||||||
|
.parse()
|
||||||
|
.unwrap();
|
||||||
let scan1 = ScanElement::new(&elem1);
|
let scan1 = ScanElement::new(&elem1);
|
||||||
|
|
||||||
assert_eq!(scan1, &elem1);
|
assert_eq!(scan1, &elem1);
|
||||||
|
|
||||||
let elem2: Element = "<presence xmlns='jabber:client'>
|
let elem2: Element = "<presence xmlns='jabber:client'>
|
||||||
<x xmlns='http://jabber.org/protocol/muc' scansion:strict='false' />
|
<x xmlns='http://jabber.org/protocol/muc' scansion:strict='false' />
|
||||||
</presence>".parse().unwrap();
|
</presence>"
|
||||||
|
.parse()
|
||||||
|
.unwrap();
|
||||||
let elem3: Element = "<presence xmlns='jabber:client' foo='bar'>
|
let elem3: Element = "<presence xmlns='jabber:client' foo='bar'>
|
||||||
<x xmlns='http://jabber.org/protocol/muc' baz='qxx' />
|
<x xmlns='http://jabber.org/protocol/muc' baz='qxx' />
|
||||||
</presence>".parse().unwrap();
|
</presence>"
|
||||||
|
.parse()
|
||||||
|
.unwrap();
|
||||||
let scan2 = ScanElement::new(&elem2);
|
let scan2 = ScanElement::new(&elem2);
|
||||||
|
|
||||||
assert_eq!(scan2, &elem3);
|
assert_eq!(scan2, &elem3);
|
||||||
|
@ -460,18 +486,24 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn compare_element_non_strict_attributes_failure() {
|
fn compare_element_non_strict_attributes_failure() {
|
||||||
let elem1: Element = "<presence scansion:strict='false' foo='bar' xmlns='foo'/>".parse().unwrap();
|
let elem1: Element = "<presence scansion:strict='false' foo='bar' xmlns='foo'/>"
|
||||||
|
.parse()
|
||||||
|
.unwrap();
|
||||||
let elem2: Element = "<presence xmlns='foo' />".parse().unwrap();
|
let elem2: Element = "<presence xmlns='foo' />".parse().unwrap();
|
||||||
let scan1 = ScanElement::new(&elem1);
|
let scan1 = ScanElement::new(&elem1);
|
||||||
|
|
||||||
assert_ne!(scan1, &elem2);
|
assert_ne!(scan1, &elem2);
|
||||||
|
|
||||||
let elem2: Element = "<presence xmlns='jabber:client' foo='bar'>
|
let elem2: Element = "<presence xmlns='jabber:client' foo='bar'>
|
||||||
<x xmlns='http://jabber.org/protocol/muc'/>
|
<x xmlns='http://jabber.org/protocol/muc'/>
|
||||||
</presence>".parse().unwrap();
|
</presence>"
|
||||||
|
.parse()
|
||||||
|
.unwrap();
|
||||||
let elem3: Element = "<presence xmlns='jabber:client'>
|
let elem3: Element = "<presence xmlns='jabber:client'>
|
||||||
<x xmlns='http://jabber.org/protocol/muc'/>
|
<x xmlns='http://jabber.org/protocol/muc'/>
|
||||||
</presence>".parse().unwrap();
|
</presence>"
|
||||||
|
.parse()
|
||||||
|
.unwrap();
|
||||||
let scan2 = ScanElement::new(&elem2);
|
let scan2 = ScanElement::new(&elem2);
|
||||||
|
|
||||||
assert_ne!(scan2, &elem3);
|
assert_ne!(scan2, &elem3);
|
||||||
|
@ -479,15 +511,19 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn compare_element_non_strict_elem_success() {
|
fn compare_element_non_strict_elem_success() {
|
||||||
let elem1: Element = "<presence scansion:strict='false' xmlns='foo'/>".parse().unwrap();
|
let elem1: Element = "<presence scansion:strict='false' xmlns='foo'/>"
|
||||||
|
.parse()
|
||||||
|
.unwrap();
|
||||||
let elem2: Element = "<presence xmlns='foo'><foo/></presence>".parse().unwrap();
|
let elem2: Element = "<presence xmlns='foo'><foo/></presence>".parse().unwrap();
|
||||||
let scan1 = ScanElement::new(&elem1);
|
let scan1 = ScanElement::new(&elem1);
|
||||||
|
|
||||||
assert_eq!(scan1, &elem2);
|
assert_eq!(scan1, &elem2);
|
||||||
|
|
||||||
// 'jabber:client' is non strict by default
|
// 'jabber:client' is non strict by default
|
||||||
let elem3: Element = "<presence xmlns='jabber:client'/>".parse().unwrap();
|
let elem3: Element = "<presence xmlns='jabber:client'/>".parse().unwrap();
|
||||||
let elem4: Element = "<presence xmlns='jabber:client'><foo/></presence>".parse().unwrap();
|
let elem4: Element = "<presence xmlns='jabber:client'><foo/></presence>"
|
||||||
|
.parse()
|
||||||
|
.unwrap();
|
||||||
let scan3 = ScanElement::new(&elem3);
|
let scan3 = ScanElement::new(&elem3);
|
||||||
|
|
||||||
assert_eq!(scan3, &elem4);
|
assert_eq!(scan3, &elem4);
|
||||||
|
@ -496,54 +532,66 @@ mod tests {
|
||||||
#[test]
|
#[test]
|
||||||
fn compare_element_non_strict_elem_failure() {
|
fn compare_element_non_strict_elem_failure() {
|
||||||
let elem2: Element = "<message scansion:strict='false' xmlns='jabber:client'>
|
let elem2: Element = "<message scansion:strict='false' xmlns='jabber:client'>
|
||||||
<body>foo</body>
|
<body>foo</body>
|
||||||
</message>".parse().unwrap();
|
</message>"
|
||||||
|
.parse()
|
||||||
|
.unwrap();
|
||||||
let elem3: Element = "<message xmlns='jabber:client'>
|
let elem3: Element = "<message xmlns='jabber:client'>
|
||||||
<body>bar</body>
|
<body>bar</body>
|
||||||
</message>".parse().unwrap();
|
</message>"
|
||||||
|
.parse()
|
||||||
|
.unwrap();
|
||||||
let scan2 = ScanElement::new(&elem2);
|
let scan2 = ScanElement::new(&elem2);
|
||||||
|
|
||||||
assert_ne!(scan2, &elem3);
|
assert_ne!(scan2, &elem3);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn compare_element_propagate_strictness() {
|
fn compare_element_propagate_strictness() {
|
||||||
let elem1: Element = "<message scansion:strict='true' xmlns='jabber:client'>
|
let elem1: Element = "<message scansion:strict='true' xmlns='jabber:client'>
|
||||||
<foo><bar /></foo>
|
<foo><bar /></foo>
|
||||||
</message>".parse().unwrap();
|
</message>"
|
||||||
|
.parse()
|
||||||
|
.unwrap();
|
||||||
let elem2: Element = "<message scansion:strict='true' xmlns='jabber:client'>
|
let elem2: Element = "<message scansion:strict='true' xmlns='jabber:client'>
|
||||||
<foo><bar baz='qxx' /></foo>
|
<foo><bar baz='qxx' /></foo>
|
||||||
</message>".parse().unwrap();
|
</message>"
|
||||||
|
.parse()
|
||||||
|
.unwrap();
|
||||||
let scan1 = ScanElement::new(&elem1);
|
let scan1 = ScanElement::new(&elem1);
|
||||||
|
|
||||||
assert_ne!(scan1, &elem2);
|
assert_ne!(scan1, &elem2);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn ignore_attr_val_success() {
|
fn ignore_attr_val_success() {
|
||||||
let elem1: Element = "<message scansion:strict='true' xmlns='jabber:client' id='{scansion:any}' />"
|
let elem1: Element = "<message xmlns='foo' id='{scansion:any}' />"
|
||||||
.parse().unwrap();
|
.parse()
|
||||||
let elem2: Element = "<message xmlns='jabber:client' id='some-id' />".parse().unwrap();
|
.unwrap();
|
||||||
let scan1 = ScanElement::new(&elem1);
|
let elem2: Element = "<message xmlns='foo' id='some-id' />".parse().unwrap();
|
||||||
|
let scan1 = ScanElement::new(&elem1);
|
||||||
|
|
||||||
assert_eq!(scan1, &elem2);
|
assert_eq!(scan1, &elem2);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn variables_from_context() {
|
fn variables_from_context() {
|
||||||
let louise = Client::new(Jid::from_str("louise@example.com").unwrap(), "passwd");
|
let louise = Client::new(Jid::from_str("louise@example.com").unwrap(), "passwd");
|
||||||
|
|
||||||
let clients = {
|
let clients = {
|
||||||
let mut tmp = HashMap::new();
|
let mut tmp = HashMap::new();
|
||||||
tmp.insert(String::from("louise"), louise);
|
tmp.insert(String::from("louise"), louise);
|
||||||
tmp
|
tmp
|
||||||
};
|
};
|
||||||
|
|
||||||
let elem1: Element = "<message xmlns='foo' to=\"${louise's full JID}\" />"
|
let elem1: Element = "<message xmlns='foo' to=\"${louise's full JID}\" />"
|
||||||
.parse().unwrap();
|
.parse()
|
||||||
let elem2: Element = "<message xmlns='foo' to='louise@example.com' />".parse().unwrap();
|
.unwrap();
|
||||||
let scan1 = ScanElement::new(&elem1).with_context(&clients);
|
let elem2: Element = "<message xmlns='foo' to='louise@example.com' />"
|
||||||
|
.parse()
|
||||||
|
.unwrap();
|
||||||
|
let scan1 = ScanElement::new(&elem1).with_context(&clients);
|
||||||
|
|
||||||
assert_eq!(scan1, &elem2);
|
assert_eq!(scan1, &elem2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
|
|
||||||
use crate::types::{Action, Client, ClientName, Metadata, VariableAttr, Spec};
|
use crate::types::{Action, Client, ClientName, Metadata, Spec, VariableAttr};
|
||||||
|
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
|
@ -280,22 +280,21 @@ pub fn parse_spec(i: &str) -> Result<Spec, Token> {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn parse_variable(s: Span) -> IResult<Span, VariableAttr> {
|
pub fn parse_variable(s: Span) -> IResult<Span, VariableAttr> {
|
||||||
let (s, (_, name, attr, _)) = tuple((
|
let (s, (_, name, attr, _)) = tuple((
|
||||||
tag("${"), take_until_tags(vec![
|
tag("${"),
|
||||||
"'s full JID",
|
take_until_tags(vec!["'s full JID", "'s JID"].into_iter(), "}"),
|
||||||
"'s JID",
|
alt((tag("'s full JID"), tag("'s JID"))),
|
||||||
].into_iter(),
|
tag("}"),
|
||||||
"}",
|
))(s)?;
|
||||||
),
|
|
||||||
alt((tag("'s full JID"), tag("'s JID"))),
|
|
||||||
tag("}"),
|
|
||||||
))(s)?;
|
|
||||||
|
|
||||||
Ok((s, match *attr.fragment() {
|
Ok((
|
||||||
"'s full JID" => VariableAttr::FullJid(name.to_string()),
|
s,
|
||||||
"'s JID" => VariableAttr::BareJid(name.to_string()),
|
match *attr.fragment() {
|
||||||
_ => unreachable!(),
|
"'s full JID" => VariableAttr::FullJid(name.to_string()),
|
||||||
}))
|
"'s JID" => VariableAttr::BareJid(name.to_string()),
|
||||||
|
_ => unreachable!(),
|
||||||
|
},
|
||||||
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
@ -622,28 +621,28 @@ louise receives:
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn parse_variable_attr() {
|
fn parse_variable_attr() {
|
||||||
let buf1: Span = "${louise's full JID}".into();
|
let buf1: Span = "${louise's full JID}".into();
|
||||||
let buf2: Span = "${louise's JID}".into();
|
let buf2: Span = "${louise's JID}".into();
|
||||||
let buf3: Span = "${louise's JID".into();
|
let buf3: Span = "${louise's JID".into();
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
parse_variable(buf1).unwrap().1,
|
parse_variable(buf1).unwrap().1,
|
||||||
VariableAttr::FullJid(String::from("louise")),
|
VariableAttr::FullJid(String::from("louise")),
|
||||||
);
|
);
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
parse_variable(buf2).unwrap().1,
|
parse_variable(buf2).unwrap().1,
|
||||||
VariableAttr::BareJid(String::from("louise")),
|
VariableAttr::BareJid(String::from("louise")),
|
||||||
);
|
);
|
||||||
|
|
||||||
match parse_variable(buf3) {
|
match parse_variable(buf3) {
|
||||||
Err(nom::Err::Error(nom::error::Error { input, .. })) => {
|
Err(nom::Err::Error(nom::error::Error { input, .. })) => {
|
||||||
assert_eq!(input.location_offset(), 2);
|
assert_eq!(input.location_offset(), 2);
|
||||||
assert_eq!(input.location_line(), 1);
|
assert_eq!(input.location_line(), 1);
|
||||||
}
|
}
|
||||||
err => panic!("Expected Err, found: {err:?}"),
|
err => panic!("Expected Err, found: {err:?}"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,8 +10,8 @@ use jid::Jid;
|
||||||
|
|
||||||
#[derive(Debug, PartialEq)]
|
#[derive(Debug, PartialEq)]
|
||||||
pub enum VariableAttr {
|
pub enum VariableAttr {
|
||||||
FullJid(ClientName),
|
FullJid(ClientName),
|
||||||
BareJid(ClientName),
|
BareJid(ClientName),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
|
|
Loading…
Reference in a new issue