WIP scansion/test codegen
Signed-off-by: Maxime “pep” Buquet <pep@bouah.net>
This commit is contained in:
parent
4366ae116a
commit
e432c8b17e
10 changed files with 380 additions and 17 deletions
16
Cargo.toml
16
Cargo.toml
|
@ -22,3 +22,19 @@ jid = { version = "*" }
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
syntect = "5.0"
|
syntect = "5.0"
|
||||||
diff = "0.1"
|
diff = "0.1"
|
||||||
|
scansion = { version = "*" }
|
||||||
|
|
||||||
|
[build-dependencies]
|
||||||
|
jid = { version = "*", features = ["minidom"] }
|
||||||
|
minidom = { version = "*" }
|
||||||
|
quote = "1.0"
|
||||||
|
rand = "0.8"
|
||||||
|
scansion = { version = "*" }
|
||||||
|
|
||||||
|
[patch.crates-io]
|
||||||
|
sasl = { git = "https://code.bouah.net/pep/xmpp-rs.git" }
|
||||||
|
jid = { git = "https://code.bouah.net/pep/xmpp-rs.git", branch = "jid-quote" }
|
||||||
|
minidom = { git = "https://code.bouah.net/pep/xmpp-rs.git" }
|
||||||
|
xmpp-parsers = { git = "https://code.bouah.net/pep/xmpp-rs.git" }
|
||||||
|
tokio-xmpp = { git = "https://code.bouah.net/pep/xmpp-rs.git" }
|
||||||
|
scansion = { git = "https://code.bouah.net/pep/scansion-rs", branch = "quote" }
|
||||||
|
|
201
build.rs
Normal file
201
build.rs
Normal file
|
@ -0,0 +1,201 @@
|
||||||
|
// Copyright (C) 2023-2099 The crate authors.
|
||||||
|
//
|
||||||
|
// This program is free software: you can redistribute it and/or modify it
|
||||||
|
// under the terms of the GNU Affero General Public License as published by the
|
||||||
|
// Free Software Foundation, either version 3 of the License, or (at your
|
||||||
|
// option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License
|
||||||
|
// for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU Affero General Public License
|
||||||
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
use std::ffi::OsString;
|
||||||
|
use std::fmt::Display;
|
||||||
|
use std::fs::File;
|
||||||
|
use std::io::{self, BufWriter, Read, Write};
|
||||||
|
use std::path::{Path, PathBuf};
|
||||||
|
|
||||||
|
use minidom::Error as MinidomError;
|
||||||
|
use quote::{format_ident, quote, TokenStreamExt};
|
||||||
|
use scansion::{read_actions_component, read_spec, Spec};
|
||||||
|
|
||||||
|
fn generate_spec_tokens(spec: Spec) -> Result<impl TokenStreamExt + Display, MinidomError> {
|
||||||
|
println!("FOO0");
|
||||||
|
|
||||||
|
let docstr = {
|
||||||
|
let mut tmp = String::new();
|
||||||
|
if let Some(ref meta) = spec.metadata {
|
||||||
|
tmp.push_str(meta.title.as_str());
|
||||||
|
tmp.push('\n');
|
||||||
|
|
||||||
|
if let Some(ref desc) = meta.description {
|
||||||
|
tmp.push_str(desc.as_str());
|
||||||
|
tmp.push('\n');
|
||||||
|
}
|
||||||
|
|
||||||
|
for tag in &meta.tags {
|
||||||
|
tmp.push_str("tag: ");
|
||||||
|
tmp.push_str(tag.as_str());
|
||||||
|
tmp.push('\n');
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
tmp.push_str("No metadata");
|
||||||
|
}
|
||||||
|
|
||||||
|
tmp
|
||||||
|
};
|
||||||
|
|
||||||
|
let context = spec.context.clone();
|
||||||
|
let actions = read_actions_component(spec, &context).unwrap();
|
||||||
|
|
||||||
|
let stanzas_in = actions
|
||||||
|
.inbound
|
||||||
|
.into_iter()
|
||||||
|
.map(|elem| {
|
||||||
|
// TODO: Prevent having to parse elements again.
|
||||||
|
// We do need some kind of structure already though to be able to verify the presence
|
||||||
|
// of attrs and all before the generation.
|
||||||
|
let elem_str = String::from(&elem);
|
||||||
|
quote! { ScanElement::new(#elem_str.parse::<Element>().unwrap()).apply_context(&context) }
|
||||||
|
})
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
|
let stanzas_out = actions
|
||||||
|
.outbound
|
||||||
|
.into_iter()
|
||||||
|
.map(|elem| {
|
||||||
|
let elem_str = String::from(&elem);
|
||||||
|
quote! {
|
||||||
|
component.expect(
|
||||||
|
#elem_str.parse::<ScanElement>().unwrap().apply_context(&context)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
|
println!("FOO1");
|
||||||
|
|
||||||
|
let (context_keys, context_values) = context
|
||||||
|
.into_iter()
|
||||||
|
.fold((vec![], vec![]), |(mut keys, mut vals), (k, v)| {
|
||||||
|
println!("BAR0");
|
||||||
|
keys.push(quote! { #k });
|
||||||
|
println!("BAR1");
|
||||||
|
vals.push(quote! { #v });
|
||||||
|
println!("BAR2: {:?}; {:?}", keys, vals);
|
||||||
|
(keys, vals)
|
||||||
|
});
|
||||||
|
|
||||||
|
println!("FOO2");
|
||||||
|
|
||||||
|
Ok(quote! {
|
||||||
|
#![doc = #docstr]
|
||||||
|
use crate::component::TestComponent;
|
||||||
|
use crate::handlers::handle_stanza;
|
||||||
|
use crate::room::Room;
|
||||||
|
|
||||||
|
use ::std::collections::HashMap;
|
||||||
|
use ::xmpp_parsers::{Jid, BareJid, FullJid, Element};
|
||||||
|
use ::scansion::{ScanElement, Entity, Client};
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn spec() {
|
||||||
|
let context: ::scansion::Context = {
|
||||||
|
let tmp = ::std::collections::HashMap::new();
|
||||||
|
let (keys, values) = (vec![#(#context_keys),*], vec![#(#context_values),*]);
|
||||||
|
for (k, v) in keys.iter().zip(values.iter()) {
|
||||||
|
tmp.insert(String::from(*k), v.clone());
|
||||||
|
}
|
||||||
|
tmp
|
||||||
|
};
|
||||||
|
|
||||||
|
let stanzas_in = vec![#(#stanzas_in),*];
|
||||||
|
let mut component = TestComponent::new_scan(stanzas_in);
|
||||||
|
let mut rooms: HashMap<BareJid, Room> = HashMap::new();
|
||||||
|
|
||||||
|
#(#stanzas_out)*
|
||||||
|
|
||||||
|
println!("FOO: {component:?}");
|
||||||
|
handle_stanza(&mut component, &mut rooms).await.unwrap();
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn generate_mod_tokens(modfiles: Vec<OsString>) -> impl TokenStreamExt + Display {
|
||||||
|
let modfiles: Vec<_> = modfiles
|
||||||
|
.into_iter()
|
||||||
|
.map(|s| format_ident!("{}", s.into_string().unwrap().strip_suffix(".rs").unwrap()))
|
||||||
|
.collect();
|
||||||
|
quote! {
|
||||||
|
/// Scansion tests module.
|
||||||
|
/// These tests are generated by the build script, DO NOT EDIT.
|
||||||
|
|
||||||
|
#(#[cfg(test)] mod #modfiles;)*
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn read_input_dir(indir: PathBuf, outdir: PathBuf) -> io::Result<Vec<OsString>> {
|
||||||
|
// Will be used to generate mod.rs
|
||||||
|
let mut modfiles: Vec<OsString> = Vec::new();
|
||||||
|
|
||||||
|
for entry in indir.read_dir()? {
|
||||||
|
let mut p = entry?.path();
|
||||||
|
match p.extension() {
|
||||||
|
Some(ext) if ext == "scs" => (),
|
||||||
|
_ => continue,
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut infile = File::open(p.clone())?;
|
||||||
|
let mut contents = String::new();
|
||||||
|
infile.read_to_string(&mut contents)?;
|
||||||
|
|
||||||
|
let spec = read_spec(&contents);
|
||||||
|
match spec {
|
||||||
|
Ok(_) => println!("Path: {p:?}: \x1b[32m OK\x1b[0m"),
|
||||||
|
Err(err) => {
|
||||||
|
println!("Path: {p:?}: \x1b[31mERR\x1b[0m\n{err:?}");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Path is now only going to be used as .rs
|
||||||
|
p.set_extension("rs");
|
||||||
|
|
||||||
|
let filename = OsString::from(p.file_name().unwrap());
|
||||||
|
let outpath = outdir.join(filename.clone());
|
||||||
|
println!("Outpath: {outpath:?}");
|
||||||
|
|
||||||
|
let tokens = generate_spec_tokens(spec.unwrap()).unwrap();
|
||||||
|
let mut output = BufWriter::new(File::create(&outpath)?);
|
||||||
|
write!(output, "{}", tokens)?;
|
||||||
|
|
||||||
|
// Add to the set of files for which generation succeeded to then generate mod.rs
|
||||||
|
modfiles.push(filename);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(modfiles)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() -> io::Result<()> {
|
||||||
|
let indir = Path::new("./specs");
|
||||||
|
let outdir = Path::new("./src/tests/scansion");
|
||||||
|
|
||||||
|
if !indir.is_dir() || !outdir.is_dir() {
|
||||||
|
return Err(io::Error::new(
|
||||||
|
io::ErrorKind::Other,
|
||||||
|
"Input and output paths must be directories.",
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
let modfiles = read_input_dir(indir.to_path_buf(), outdir.to_path_buf())?;
|
||||||
|
|
||||||
|
let mut modout = BufWriter::new(File::create(outdir.join("mod.rs"))?);
|
||||||
|
let tokens = generate_mod_tokens(modfiles);
|
||||||
|
write!(modout, "{}", tokens)?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
|
@ -28,6 +28,7 @@ use async_trait::async_trait;
|
||||||
use diff;
|
use diff;
|
||||||
use futures::{task::Poll, Stream};
|
use futures::{task::Poll, Stream};
|
||||||
use log::debug;
|
use log::debug;
|
||||||
|
use scansion::ScanElement;
|
||||||
use syntect::{
|
use syntect::{
|
||||||
easy::HighlightLines,
|
easy::HighlightLines,
|
||||||
highlighting::{Style, ThemeSet},
|
highlighting::{Style, ThemeSet},
|
||||||
|
@ -59,17 +60,23 @@ impl fmt::Debug for Expect {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Eq, PartialEq)]
|
#[derive(Clone)]
|
||||||
pub struct TestElement(pub Element);
|
pub struct TestElement(pub ScanElement);
|
||||||
|
|
||||||
impl Deref for TestElement {
|
impl Deref for TestElement {
|
||||||
type Target = Element;
|
type Target = ScanElement;
|
||||||
|
|
||||||
fn deref(&self) -> &Self::Target {
|
fn deref(&self) -> &Self::Target {
|
||||||
&self.0
|
&self.0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl PartialEq<Element> for TestElement {
|
||||||
|
fn eq(&self, other: &Element) -> bool {
|
||||||
|
self.0 == *other
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl fmt::Debug for TestElement {
|
impl fmt::Debug for TestElement {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
write!(f, "{}", String::from(&self.0))
|
write!(f, "{}", String::from(&self.0))
|
||||||
|
@ -90,31 +97,43 @@ impl From<&TestElement> for String {
|
||||||
|
|
||||||
impl From<Element> for TestElement {
|
impl From<Element> for TestElement {
|
||||||
fn from(elem: Element) -> Self {
|
fn from(elem: Element) -> Self {
|
||||||
Self(elem)
|
Self(ScanElement::new(elem))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<TestElement> for Element {
|
impl From<TestElement> for Element {
|
||||||
fn from(elem: TestElement) -> Self {
|
fn from(elem: TestElement) -> Self {
|
||||||
elem.0
|
elem.0.elem
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<Iq> for TestElement {
|
impl From<Iq> for TestElement {
|
||||||
fn from(elem: Iq) -> Self {
|
fn from(elem: Iq) -> Self {
|
||||||
Self(Element::from(elem))
|
Self(Element::from(elem).into())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<Presence> for TestElement {
|
impl From<Presence> for TestElement {
|
||||||
fn from(elem: Presence) -> Self {
|
fn from(elem: Presence) -> Self {
|
||||||
Self(Element::from(elem))
|
Self(Element::from(elem).into())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<Message> for TestElement {
|
impl From<Message> for TestElement {
|
||||||
fn from(elem: Message) -> Self {
|
fn from(elem: Message) -> Self {
|
||||||
Self(Element::from(elem))
|
Self(Element::from(elem).into())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<ScanElement> for TestElement {
|
||||||
|
fn from(scan: ScanElement) -> Self {
|
||||||
|
Self(scan)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<TestElement> for ScanElement {
|
||||||
|
fn from(elem: TestElement) -> ScanElement {
|
||||||
|
ScanElement::new(elem.into())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -132,7 +151,21 @@ impl Component {
|
||||||
in_buffer: VecDeque::from(
|
in_buffer: VecDeque::from(
|
||||||
in_buffer
|
in_buffer
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|el| TestElement(el))
|
.map(|elem| TestElement::from(elem))
|
||||||
|
.collect::<Vec<_>>(),
|
||||||
|
),
|
||||||
|
expect_buffer: HashMap::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn new_scan(in_buffer: Vec<ScanElement>) -> Self {
|
||||||
|
let _ = env_logger::builder().is_test(true).try_init();
|
||||||
|
|
||||||
|
Component {
|
||||||
|
in_buffer: VecDeque::from(
|
||||||
|
in_buffer
|
||||||
|
.into_iter()
|
||||||
|
.map(|elem| TestElement::from(elem))
|
||||||
.collect::<Vec<_>>(),
|
.collect::<Vec<_>>(),
|
||||||
),
|
),
|
||||||
expect_buffer: HashMap::new(),
|
expect_buffer: HashMap::new(),
|
||||||
|
@ -358,7 +391,7 @@ impl Stream for Component {
|
||||||
|
|
||||||
fn poll_next(mut self: Pin<&mut Self>, _cx: &mut Context) -> Poll<Option<Self::Item>> {
|
fn poll_next(mut self: Pin<&mut Self>, _cx: &mut Context) -> Poll<Option<Self::Item>> {
|
||||||
while self.in_buffer.len() > 0 {
|
while self.in_buffer.len() > 0 {
|
||||||
return Poll::Ready(self.in_buffer.pop_front().map(|el| el.0));
|
return Poll::Ready(self.in_buffer.pop_front().map(|el| el.0.elem));
|
||||||
}
|
}
|
||||||
|
|
||||||
Poll::Ready(None)
|
Poll::Ready(None)
|
||||||
|
@ -370,11 +403,25 @@ impl Drop for Component {
|
||||||
// Don't assert if we're already panicking. Rustc displays a huge backtrace when "panicked
|
// Don't assert if we're already panicking. Rustc displays a huge backtrace when "panicked
|
||||||
// while panicking" even when nobody asks for it (RUST_BACKTRACE unset). Let the error
|
// while panicking" even when nobody asks for it (RUST_BACKTRACE unset). Let the error
|
||||||
// appear if there isn't any other error.
|
// appear if there isn't any other error.
|
||||||
if !thread::panicking() {
|
if !thread::panicking() && !self.expect_buffer.is_empty() {
|
||||||
assert!(
|
let mut buffer = String::new();
|
||||||
self.expect_buffer.is_empty(),
|
for (_stream, buf) in &self.expect_buffer {
|
||||||
"Remaining expected elements in the buffer"
|
for expect in buf {
|
||||||
);
|
match expect {
|
||||||
|
Expect::Element(el) => {
|
||||||
|
let elem = String::from(el);
|
||||||
|
buffer
|
||||||
|
.push_str(format!("expected: `{}`", Component::hl(&elem)).as_str());
|
||||||
|
}
|
||||||
|
expect_cb => {
|
||||||
|
buffer.push_str(format!("expected: {:?}", expect_cb).as_str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
debug!("\n{}", buffer);
|
||||||
|
panic!("Remaining expected elements in the buffer");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
15
src/room.rs
15
src/room.rs
|
@ -462,14 +462,14 @@ impl Room {
|
||||||
let presence_join = Presence::new(PresenceType::None)
|
let presence_join = Presence::new(PresenceType::None)
|
||||||
.with_from(Jid::Full(new_session.participant().clone()));
|
.with_from(Jid::Full(new_session.participant().clone()));
|
||||||
|
|
||||||
let presence_join_to_others = presence_join.clone().with_payloads(vec![MucUser {
|
let _presence_join_to_others = presence_join.clone().with_payloads(vec![MucUser {
|
||||||
status: vec![],
|
status: vec![],
|
||||||
items: vec![MucItem::new(Affiliation::Owner, Role::Moderator)],
|
items: vec![MucItem::new(Affiliation::Owner, Role::Moderator)],
|
||||||
}
|
}
|
||||||
.into()]);
|
.into()]);
|
||||||
|
|
||||||
let occupant = self.get_occupant(&new_session)?;
|
let occupant = self.get_occupant(&new_session)?;
|
||||||
let mucuser = MucUser {
|
let _mucuser = MucUser {
|
||||||
status: vec![],
|
status: vec![],
|
||||||
items: {
|
items: {
|
||||||
occupant
|
occupant
|
||||||
|
@ -482,6 +482,16 @@ impl Room {
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
self.broadcast_presence(
|
||||||
|
component,
|
||||||
|
self.get_occupant(&new_session)?,
|
||||||
|
new_session.presence.clone(),
|
||||||
|
BroadcastPresence::Update,
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
/*
|
||||||
for (nick, occupant) in self.occupants.iter() {
|
for (nick, occupant) in self.occupants.iter() {
|
||||||
for session in occupant.iter() {
|
for session in occupant.iter() {
|
||||||
// Self occupant
|
// Self occupant
|
||||||
|
@ -522,6 +532,7 @@ impl Room {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,5 +16,6 @@
|
||||||
mod iq;
|
mod iq;
|
||||||
mod presence;
|
mod presence;
|
||||||
mod presence_msn;
|
mod presence_msn;
|
||||||
|
mod scansion;
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
pub mod templates;
|
pub mod templates;
|
||||||
|
|
0
src/tests/scansion/.keep
Normal file
0
src/tests/scansion/.keep
Normal file
6
src/tests/scansion/mod.rs
Normal file
6
src/tests/scansion/mod.rs
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
#[doc = r" Scansion tests module."]
|
||||||
|
#[doc = r" These tests are generated by the build script, DO NOT EDIT."]
|
||||||
|
#[cfg(test)]
|
||||||
|
mod muc_create_destroy;
|
||||||
|
#[cfg(test)]
|
||||||
|
mod muc_creation;
|
51
src/tests/scansion/muc_create_destroy.rs
Normal file
51
src/tests/scansion/muc_create_destroy.rs
Normal file
|
@ -0,0 +1,51 @@
|
||||||
|
#![doc = "MUC creation, basic messages and destruction\n"]
|
||||||
|
use crate::component::TestComponent;
|
||||||
|
use crate::handlers::handle_stanza;
|
||||||
|
use crate::room::Room;
|
||||||
|
use scansion::ScanElement;
|
||||||
|
use std::collections::HashMap;
|
||||||
|
use xmpp_parsers::{BareJid, Element};
|
||||||
|
#[tokio::test]
|
||||||
|
async fn spec() {
|
||||||
|
println!("FOO0: {:?}", "Admin\nJuliet\nRomeo\n");
|
||||||
|
println!(
|
||||||
|
"FOO0: {:?}",
|
||||||
|
"admin@localhost/DfNgg9VE\njuliet@localhost/lVwkim_k\nromeo@localhost/mK0dD6Ha\n"
|
||||||
|
);
|
||||||
|
let stanzas_in = vec ! [ScanElement :: new ("<presence xmlns='jabber:client' to=\"garden@conference.localhost/romeo\">\n\t\t<x xmlns='http://jabber.org/protocol/muc'/>\n\t</presence>" . parse :: < Element > () . unwrap ()) . with_context (Some (& context)) , ScanElement :: new ("<iq xmlns='jabber:client' id=\"lx3\" to=\"garden@conference.localhost\" type=\"set\">\n\t\t<query xmlns='http://jabber.org/protocol/muc#owner'>\n\t\t\t<x xmlns='jabber:x:data' type=\"submit\"/>\n\t\t</query>\n\t</iq>" . parse :: < Element > () . unwrap ()) . with_context (Some (& context)) , ScanElement :: new ("<message xmlns='jabber:client' id=\"rm1\" to=\"garden@conference.localhost\" type=\"groupchat\">\n\t\t<body>Where are thou my Juliet?</body>\n\t</message>" . parse :: < Element > () . unwrap ()) . with_context (Some (& context)) , ScanElement :: new ("<presence xmlns='jabber:client' to=\"garden@conference.localhost/juliet\">\n\t\t<x xmlns='http://jabber.org/protocol/muc'/>\n\t</presence>" . parse :: < Element > () . unwrap ()) . with_context (Some (& context)) , ScanElement :: new ("<message xmlns='jabber:client' id=\"jm1\" to=\"garden@conference.localhost\" type=\"groupchat\">\n\t\t<body>/me jumps out from behind a tree</body>\n\t</message>" . parse :: < Element > () . unwrap ()) . with_context (Some (& context)) , ScanElement :: new ("<message xmlns='jabber:client' id=\"jm2\" to=\"garden@conference.localhost\" type=\"groupchat\">\n\t\t<body>Here I am!</body>\n\t</message>" . parse :: < Element > () . unwrap ()) . with_context (Some (& context)) , ScanElement :: new ("<message xmlns='jabber:client' id=\"rm2\" to=\"garden@conference.localhost\" type=\"groupchat\">\n\t\t<body>What is this place?</body>\n\t</message>" . parse :: < Element > () . unwrap ()) . with_context (Some (& context)) , ScanElement :: new ("<message xmlns='jabber:client' id=\"jm3\" to=\"garden@conference.localhost\" type=\"groupchat\">\n\t\t<body>I think we're in a script!</body>\n\t</message>" . parse :: < Element > () . unwrap ()) . with_context (Some (& context)) , ScanElement :: new ("<message xmlns='jabber:client' id=\"rm3\" to=\"garden@conference.localhost\" type=\"groupchat\">\n\t\t<body>Oh no! Does that mean our love is not real?!</body>\n\t</message>" . parse :: < Element > () . unwrap ()) . with_context (Some (& context)) , ScanElement :: new ("<message xmlns='jabber:client' id=\"jm4\" to=\"garden@conference.localhost\" type=\"groupchat\">\n\t\t<body>I refuse to accept this! Let's burn this place to the ground!</body>\n\t</message>" . parse :: < Element > () . unwrap ()) . with_context (Some (& context)) , ScanElement :: new ("<message xmlns='jabber:client' id=\"rm4\" to=\"garden@conference.localhost\" type=\"groupchat\">\n\t\t<body>Yes!</body>\n\t</message>" . parse :: < Element > () . unwrap ()) . with_context (Some (& context)) , ScanElement :: new ("<iq xmlns='jabber:client' id=\"lx4\" to=\"garden@conference.localhost\" type=\"set\">\n\t\t<query xmlns='http://jabber.org/protocol/muc#owner'>\n\t\t\t<destroy>\n\t\t\t\t<reason>We refuse to live in this fantasy!</reason>\n\t\t\t</destroy>\n\t\t</query>\n\t</iq>" . parse :: < Element > () . unwrap ()) . with_context (Some (& context)) , ScanElement :: new ("<presence xmlns='jabber:client' to=\"elsewhere@conference.localhost/romeo\">\n\t\t<x xmlns='http://jabber.org/protocol/muc'/>\n\t</presence>" . parse :: < Element > () . unwrap ()) . with_context (Some (& context)) , ScanElement :: new ("<iq xmlns='jabber:client' id=\"lx5\" to=\"elsewhere@conference.localhost\" type=\"set\">\n\t\t<query xmlns='http://jabber.org/protocol/muc#owner'>\n\t\t\t<x xmlns='jabber:x:data' type=\"submit\"/>\n\t\t</query>\n\t</iq>" . parse :: < Element > () . unwrap ()) . with_context (Some (& context)) , ScanElement :: new ("<iq xmlns='jabber:client' id=\"destroy\" to=\"conference.localhost\" type=\"set\">\n\t\t<command xmlns='http://jabber.org/protocol/commands' node=\"http://prosody.im/protocol/muc#destroy\">\n\t\t\t<x xmlns='jabber:x:data'>\n\t\t\t\t<field var=\"rooms\">\n\t\t\t\t\t<value>elsewhere@conference.localhost</value>\n\t\t\t\t</field>\n\t\t\t</x>\n\t\t</command>\n\t</iq>" . parse :: < Element > () . unwrap ()) . with_context (Some (& context))] ;
|
||||||
|
let mut component = TestComponent::new_scan(stanzas_in);
|
||||||
|
let mut rooms: HashMap<BareJid, Room> = HashMap::new();
|
||||||
|
component . expect ("<presence xmlns='jabber:client' from=\"garden@conference.localhost/romeo\">\n\t\t<x xmlns='vcard-temp:x:update'>\n\t\t\t<photo/>\n\t\t</x>\n\t\t<x xmlns='http://jabber.org/protocol/muc#user'>\n\t\t\t<status code=\"201\"/>\n\t\t\t<item affiliation=\"owner\" jid=\"${Romeo's full JID}\" role=\"moderator\"/>\n\t\t\t<status code=\"110\"/>\n\t\t</x>\n\t</presence>" . parse :: < ScanElement > () . unwrap () . with_context (Some (& context))) ;
|
||||||
|
component . expect ("<message xmlns='jabber:client' from=\"garden@conference.localhost\" type=\"groupchat\">\n\t\t<subject/>\n\t</message>" . parse :: < ScanElement > () . unwrap () . with_context (Some (& context))) ;
|
||||||
|
component . expect ("<iq xmlns='jabber:client' from=\"garden@conference.localhost\" id=\"lx3\" type=\"result\"/>" . parse :: < ScanElement > () . unwrap () . with_context (Some (& context))) ;
|
||||||
|
component . expect ("<message xmlns='jabber:client' from=\"garden@conference.localhost/romeo\" id=\"rm1\" type=\"groupchat\">\n\t\t<body>Where are thou my Juliet?</body>\n\t</message>" . parse :: < ScanElement > () . unwrap () . with_context (Some (& context))) ;
|
||||||
|
component . expect ("<presence xmlns='jabber:client' from=\"garden@conference.localhost/romeo\">\n\t\t<x xmlns='vcard-temp:x:update'>\n\t\t\t<photo/>\n\t\t</x>\n\t\t<x xmlns='http://jabber.org/protocol/muc#user'>\n\t\t\t<item affiliation=\"owner\" role=\"moderator\"/>\n\t\t</x>\n\t</presence>" . parse :: < ScanElement > () . unwrap () . with_context (Some (& context))) ;
|
||||||
|
component . expect ("<presence xmlns='jabber:client' from=\"garden@conference.localhost/juliet\">\n\t\t<x xmlns='vcard-temp:x:update'>\n\t\t\t<photo/>\n\t\t</x>\n\t\t<x xmlns='http://jabber.org/protocol/muc#user'>\n\t\t\t<item affiliation=\"none\" jid=\"${Juliet's full JID}\" role=\"participant\"/>\n\t\t\t<status code=\"110\"/>\n\t\t</x>\n\t</presence>" . parse :: < ScanElement > () . unwrap () . with_context (Some (& context))) ;
|
||||||
|
component . expect ("<message xmlns='jabber:client' from=\"garden@conference.localhost/romeo\" id=\"rm1\" type=\"groupchat\">\n\t\t<body>Where are thou my Juliet?</body>\n\t\t<delay xmlns='urn:xmpp:delay' from=\"garden@conference.localhost\" stamp=\"{scansion:any}\"/>\n\t</message>" . parse :: < ScanElement > () . unwrap () . with_context (Some (& context))) ;
|
||||||
|
component . expect ("<message xmlns='jabber:client' from=\"garden@conference.localhost\" type=\"groupchat\">\n\t\t<subject/>\n\t</message>" . parse :: < ScanElement > () . unwrap () . with_context (Some (& context))) ;
|
||||||
|
component . expect ("<presence xmlns='jabber:client' from=\"garden@conference.localhost/juliet\">\n\t\t<x xmlns='vcard-temp:x:update'>\n\t\t\t<photo/>\n\t\t</x>\n\t\t<x xmlns='http://jabber.org/protocol/muc#user'>\n\t\t\t<item affiliation=\"none\" jid=\"${Juliet's full JID}\" role=\"participant\"/>\n\t\t</x>\n\t</presence>" . parse :: < ScanElement > () . unwrap () . with_context (Some (& context))) ;
|
||||||
|
component . expect ("<message xmlns='jabber:client' from=\"garden@conference.localhost/juliet\" id=\"jm1\" type=\"groupchat\">\n\t\t<body>/me jumps out from behind a tree</body>\n\t</message>" . parse :: < ScanElement > () . unwrap () . with_context (Some (& context))) ;
|
||||||
|
component . expect ("<message xmlns='jabber:client' from=\"garden@conference.localhost/juliet\" id=\"jm1\" type=\"groupchat\">\n\t\t<body>/me jumps out from behind a tree</body>\n\t</message>" . parse :: < ScanElement > () . unwrap () . with_context (Some (& context))) ;
|
||||||
|
component . expect ("<message xmlns='jabber:client' from=\"garden@conference.localhost/juliet\" id=\"jm2\" type=\"groupchat\">\n\t\t<body>Here I am!</body>\n\t</message>" . parse :: < ScanElement > () . unwrap () . with_context (Some (& context))) ;
|
||||||
|
component . expect ("<message xmlns='jabber:client' from=\"garden@conference.localhost/juliet\" id=\"jm2\" type=\"groupchat\">\n\t\t<body>Here I am!</body>\n\t</message>" . parse :: < ScanElement > () . unwrap () . with_context (Some (& context))) ;
|
||||||
|
component . expect ("<message xmlns='jabber:client' from=\"garden@conference.localhost/romeo\" id=\"rm2\" type=\"groupchat\">\n\t\t<body>What is this place?</body>\n\t</message>" . parse :: < ScanElement > () . unwrap () . with_context (Some (& context))) ;
|
||||||
|
component . expect ("<message xmlns='jabber:client' from=\"garden@conference.localhost/romeo\" id=\"rm2\" type=\"groupchat\">\n\t\t<body>What is this place?</body>\n\t</message>" . parse :: < ScanElement > () . unwrap () . with_context (Some (& context))) ;
|
||||||
|
component . expect ("<message xmlns='jabber:client' from=\"garden@conference.localhost/juliet\" id=\"jm3\" type=\"groupchat\">\n\t\t<body>I think we're in a script!</body>\n\t</message>" . parse :: < ScanElement > () . unwrap () . with_context (Some (& context))) ;
|
||||||
|
component . expect ("<message xmlns='jabber:client' from=\"garden@conference.localhost/juliet\" id=\"jm3\" type=\"groupchat\">\n\t\t<body>I think we're in a script!</body>\n\t</message>" . parse :: < ScanElement > () . unwrap () . with_context (Some (& context))) ;
|
||||||
|
component . expect ("<message xmlns='jabber:client' from=\"garden@conference.localhost/romeo\" id=\"rm3\" type=\"groupchat\">\n\t\t<body>Oh no! Does that mean our love is not real?!</body>\n\t</message>" . parse :: < ScanElement > () . unwrap () . with_context (Some (& context))) ;
|
||||||
|
component . expect ("<message xmlns='jabber:client' from=\"garden@conference.localhost/romeo\" id=\"rm3\" type=\"groupchat\">\n\t\t<body>Oh no! Does that mean our love is not real?!</body>\n\t</message>" . parse :: < ScanElement > () . unwrap () . with_context (Some (& context))) ;
|
||||||
|
component . expect ("<message xmlns='jabber:client' from=\"garden@conference.localhost/juliet\" id=\"jm4\" type=\"groupchat\">\n\t\t<body>I refuse to accept this! Let's burn this place to the ground!</body>\n\t</message>" . parse :: < ScanElement > () . unwrap () . with_context (Some (& context))) ;
|
||||||
|
component . expect ("<message xmlns='jabber:client' from=\"garden@conference.localhost/juliet\" id=\"jm4\" type=\"groupchat\">\n\t\t<body>I refuse to accept this! Let's burn this place to the ground!</body>\n\t</message>" . parse :: < ScanElement > () . unwrap () . with_context (Some (& context))) ;
|
||||||
|
component . expect ("<message xmlns='jabber:client' from=\"garden@conference.localhost/romeo\" id=\"rm4\" type=\"groupchat\">\n\t\t<body>Yes!</body>\n\t</message>" . parse :: < ScanElement > () . unwrap () . with_context (Some (& context))) ;
|
||||||
|
component . expect ("<message xmlns='jabber:client' from=\"garden@conference.localhost/romeo\" id=\"rm4\" type=\"groupchat\">\n\t\t<body>Yes!</body>\n\t</message>" . parse :: < ScanElement > () . unwrap () . with_context (Some (& context))) ;
|
||||||
|
component . expect ("<presence xmlns='jabber:client' from=\"garden@conference.localhost/juliet\" type=\"unavailable\">\n\t\t<x xmlns='http://jabber.org/protocol/muc#user'>\n\t\t\t<destroy>\n\t\t\t\t<reason>We refuse to live in this fantasy!</reason>\n\t\t\t</destroy>\n\t\t\t<item affiliation=\"none\" jid=\"${Juliet's full JID}\" role=\"none\"/>\n\t\t\t<status code=\"110\"/>\n\t\t</x>\n\t</presence>" . parse :: < ScanElement > () . unwrap () . with_context (Some (& context))) ;
|
||||||
|
component . expect ("<presence xmlns='jabber:client' from=\"garden@conference.localhost/romeo\" type=\"unavailable\">\n\t\t<x xmlns='http://jabber.org/protocol/muc#user'>\n\t\t\t<destroy>\n\t\t\t\t<reason>We refuse to live in this fantasy!</reason>\n\t\t\t</destroy>\n\t\t\t<item affiliation=\"owner\" jid=\"${Romeo's full JID}\" role=\"none\"/>\n\t\t\t<status code=\"110\"/>\n\t\t</x>\n\t</presence>" . parse :: < ScanElement > () . unwrap () . with_context (Some (& context))) ;
|
||||||
|
component . expect ("<iq xmlns='jabber:client' from=\"garden@conference.localhost\" id=\"lx4\" type=\"result\"/>" . parse :: < ScanElement > () . unwrap () . with_context (Some (& context))) ;
|
||||||
|
component . expect ("<presence xmlns='jabber:client' from=\"elsewhere@conference.localhost/romeo\">\n\t\t<x xmlns='vcard-temp:x:update'>\n\t\t\t<photo/>\n\t\t</x>\n\t\t<x xmlns='http://jabber.org/protocol/muc#user'>\n\t\t\t<status code=\"201\"/>\n\t\t\t<item affiliation=\"owner\" jid=\"${Romeo's full JID}\" role=\"moderator\"/>\n\t\t\t<status code=\"110\"/>\n\t\t</x>\n\t</presence>" . parse :: < ScanElement > () . unwrap () . with_context (Some (& context))) ;
|
||||||
|
component . expect ("<message xmlns='jabber:client' from=\"elsewhere@conference.localhost\" type=\"groupchat\">\n\t\t<subject/>\n\t</message>" . parse :: < ScanElement > () . unwrap () . with_context (Some (& context))) ;
|
||||||
|
component . expect ("<iq xmlns='jabber:client' from=\"elsewhere@conference.localhost\" id=\"lx5\" type=\"result\"/>" . parse :: < ScanElement > () . unwrap () . with_context (Some (& context))) ;
|
||||||
|
component . expect ("<presence xmlns='jabber:client' from=\"elsewhere@conference.localhost/romeo\" type=\"unavailable\">\n\t\t<x xmlns='http://jabber.org/protocol/muc#user'>\n\t\t\t<destroy/>\n\t\t\t<item affiliation=\"owner\" jid=\"${Romeo's full JID}\" role=\"none\"/>\n\t\t\t<status code=\"110\"/>\n\t\t</x>\n\t</presence>" . parse :: < ScanElement > () . unwrap () . with_context (Some (& context))) ;
|
||||||
|
component . expect ("<iq xmlns='jabber:client' from=\"conference.localhost\" id=\"destroy\" type=\"result\">\n\t\t<command xmlns='http://jabber.org/protocol/commands' node=\"http://prosody.im/protocol/muc#destroy\" sessionid=\"{scansion:any}\" status=\"completed\">\n\t\t\t<note type=\"info\">The following rooms were destroyed:\nelsewhere@conference.localhost</note>\n\t\t</command>\n\t</iq>" . parse :: < ScanElement > () . unwrap () . with_context (Some (& context))) ;
|
||||||
|
println!("FOO: {component:?}");
|
||||||
|
handle_stanza(&mut component, &mut rooms).await.unwrap();
|
||||||
|
}
|
18
src/tests/scansion/muc_creation.rs
Normal file
18
src/tests/scansion/muc_creation.rs
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
#![doc = "MUC Creation\nSingle user MUC creation\ntag: muc\n"]
|
||||||
|
use crate::component::TestComponent;
|
||||||
|
use crate::handlers::handle_stanza;
|
||||||
|
use crate::room::Room;
|
||||||
|
use scansion::ScanElement;
|
||||||
|
use std::collections::HashMap;
|
||||||
|
use xmpp_parsers::{BareJid, Element};
|
||||||
|
#[tokio::test]
|
||||||
|
async fn spec() {
|
||||||
|
println!("FOO0: {:?}", "louise\n");
|
||||||
|
println!("FOO0: {:?}", "louise@localhost/194\n");
|
||||||
|
let stanzas_in = vec ! [ScanElement :: new ("<presence xmlns='jabber:client' from=\"${louise's full JID}\" to=\"room@muc.localhost/louise\">\n\t\t<x xmlns='http://jabber.org/protocol/muc'/>\n\t</presence>" . parse :: < Element > () . unwrap ()) . with_context (Some (& context))] ;
|
||||||
|
let mut component = TestComponent::new_scan(stanzas_in);
|
||||||
|
let mut rooms: HashMap<BareJid, Room> = HashMap::new();
|
||||||
|
component . expect ("<presence xmlns='jabber:client' from=\"muc.localhost\" id=\"{scansion:any}\" to=\"${louise's full JID}\">\n\t\t<x xmlns='http://jabber.org/protocol/muc#user'>\n\t\t\t<status code=\"201\"/>\n\t\t\t<item affiliation=\"owner\" jid=\"${louise's full JID}\" role=\"moderator\"/>\n\t\t\t<statuc code=\"110\"/>\n\t\t</x>\n\t</presence>" . parse :: < ScanElement > () . unwrap () . with_context (Some (& context))) ;
|
||||||
|
println!("FOO: {component:?}");
|
||||||
|
handle_stanza(&mut component, &mut rooms).await.unwrap();
|
||||||
|
}
|
12
src/tests/scansion/muc_mediated_invite.rs
Normal file
12
src/tests/scansion/muc_mediated_invite.rs
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
use crate::component::TestComponent;
|
||||||
|
use crate::handlers::handle_stanza;
|
||||||
|
use crate::room::Room;
|
||||||
|
use std::collections::HashMap;
|
||||||
|
use xmpp_parsers::BareJid;
|
||||||
|
#[doc = "MUC: Mediated invites\n"]
|
||||||
|
#[tokio::test]
|
||||||
|
async fn spec() {
|
||||||
|
let mut component = TestComponent::new(vec![]);
|
||||||
|
let mut rooms: HashMap<BareJid, Room> = HashMap::new();
|
||||||
|
handle_stanza(&mut component, &mut rooms).await.unwrap();
|
||||||
|
}
|
Loading…
Reference in a new issue