Compare commits
1 commit
Author | SHA1 | Date | |
---|---|---|---|
c9a0745c81 |
5 changed files with 168 additions and 18 deletions
|
@ -8,6 +8,7 @@ description = "MUC implementation allowing participants to play the Hanabi game.
|
|||
[dependencies]
|
||||
async-trait = "^0.1"
|
||||
chrono = "0.4.22"
|
||||
dyn-clone = "1.0.9"
|
||||
env_logger = "^0.9"
|
||||
futures = "^0.3"
|
||||
lazy_static = "^1.4"
|
||||
|
|
126
src/component.rs
126
src/component.rs
|
@ -19,7 +19,10 @@ use crate::error::Error;
|
|||
use std::collections::VecDeque;
|
||||
#[cfg(test)]
|
||||
use std::fmt;
|
||||
use std::marker::Send;
|
||||
// #[cfg(test)]
|
||||
// use std::iter::IntoIterator;
|
||||
#[cfg(test)]
|
||||
use std::marker::{Send, Sync};
|
||||
use std::ops::{Deref, DerefMut};
|
||||
use std::pin::Pin;
|
||||
use std::task::Context;
|
||||
|
@ -27,6 +30,8 @@ use std::task::Context;
|
|||
use std::thread;
|
||||
|
||||
use async_trait::async_trait;
|
||||
#[cfg(test)]
|
||||
use dyn_clone::{clone_trait_object, DynClone};
|
||||
use futures::{task::Poll, Stream};
|
||||
use log::debug;
|
||||
use tokio_xmpp::Component as TokioXMPPComponent;
|
||||
|
@ -92,16 +97,47 @@ impl Component {
|
|||
}
|
||||
}
|
||||
|
||||
/*
|
||||
#[cfg(test)]
|
||||
pub trait ExpectCb<T>: FnOnce(T) + Send + Sync + DynClone + 'static {}
|
||||
#[cfg(test)]
|
||||
clone_trait_object!(ExpectCb<Iq>);
|
||||
#[cfg(test)]
|
||||
clone_trait_object!(ExpectCb<Message>);
|
||||
#[cfg(test)]
|
||||
clone_trait_object!(ExpectCb<Presence>);
|
||||
|
||||
#[cfg(test)]
|
||||
impl ExpectCb<T> for dyn FnOnce(T) {}
|
||||
*/
|
||||
|
||||
#[cfg(test)]
|
||||
pub trait Foo: FnOnce(Iq) + DynClone {}
|
||||
#[cfg(test)]
|
||||
clone_trait_object!(Foo);
|
||||
#[cfg(test)]
|
||||
pub trait Bar: Foo + Send + Sync + 'static {}
|
||||
#[cfg(test)]
|
||||
clone_trait_object!(Bar);
|
||||
|
||||
#[cfg(test)]
|
||||
pub trait ExpectIq: FnOnce(Iq) + Send + Sync + DynClone + 'static {}
|
||||
#[cfg(test)]
|
||||
impl ExpectIq for dyn FnOnce(Iq) where Self: ExpectIq {}
|
||||
#[cfg(test)]
|
||||
clone_trait_object!(ExpectIq);
|
||||
|
||||
#[cfg(test)]
|
||||
#[derive(Clone)]
|
||||
enum Expect {
|
||||
/// Simple Element
|
||||
Element(TestElement),
|
||||
/// Callback taking an Iq, with a description alongside
|
||||
Iq(Box<dyn FnOnce(Iq) + Send + 'static>, String),
|
||||
/// Callback taking a Presence, with a description alongside
|
||||
Presence(Box<dyn FnOnce(Presence) + Send + 'static>, String),
|
||||
Iq(Box<dyn ExpectIq>, String),
|
||||
/// Callback taking a Message, with a description alongside
|
||||
Message(Box<dyn FnOnce(Message) + Send + 'static>, String),
|
||||
Message(Box<dyn FnOnce(Message) + Send + Sync + 'static>, String),
|
||||
/// Callback taking a Presence, with a description alongside
|
||||
Presence(Box<dyn FnOnce(Presence) + Send + Sync + 'static>, String),
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
@ -117,6 +153,63 @@ impl fmt::Debug for Expect {
|
|||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[derive(Debug)]
|
||||
pub struct Scenario {
|
||||
inbuf: VecDeque<TestElement>,
|
||||
expectbuf: VecDeque<Expect>,
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
impl Scenario {
|
||||
pub fn new() -> Self {
|
||||
Scenario {
|
||||
inbuf: VecDeque::new(),
|
||||
expectbuf: VecDeque::new(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn into_inner(self) -> (VecDeque<TestElement>, VecDeque<Expect>) {
|
||||
(self.inbuf, self.expectbuf)
|
||||
}
|
||||
|
||||
pub fn with_input<E: Into<TestElement>>(mut self, el: E) -> Self {
|
||||
self.inbuf.push_back(el.into());
|
||||
self
|
||||
}
|
||||
|
||||
pub fn with_expect<E: Into<TestElement>>(mut self, el: E) -> Self {
|
||||
self.expectbuf.push_back(Expect::Element(el.into()));
|
||||
self
|
||||
}
|
||||
|
||||
pub fn with_expect_iq<F: ExpectIq, S: Into<String>>(mut self, callback: F, desc: S) -> Self {
|
||||
self.expectbuf
|
||||
.push_back(Expect::Iq(Box::new(callback), desc.into()));
|
||||
self
|
||||
}
|
||||
|
||||
pub fn with_expect_message<F: FnOnce(Message) + Send + Sync + 'static, S: Into<String>>(
|
||||
mut self,
|
||||
callback: F,
|
||||
desc: S,
|
||||
) -> Self {
|
||||
self.expectbuf
|
||||
.push_back(Expect::Message(Box::new(callback), desc.into()));
|
||||
self
|
||||
}
|
||||
|
||||
pub fn with_expect_presence<F: FnOnce(Presence) + Send + Sync + 'static, S: Into<String>>(
|
||||
mut self,
|
||||
callback: F,
|
||||
desc: S,
|
||||
) -> Self {
|
||||
self.expectbuf
|
||||
.push_back(Expect::Presence(Box::new(callback), desc.into()));
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[derive(Clone, Eq, PartialEq)]
|
||||
pub struct TestElement(pub Element);
|
||||
|
@ -197,12 +290,7 @@ pub struct TestComponent {
|
|||
impl TestComponent {
|
||||
pub fn new(in_buffer: Vec<Element>) -> Self {
|
||||
TestComponent {
|
||||
in_buffer: VecDeque::from(
|
||||
in_buffer
|
||||
.into_iter()
|
||||
.map(|el| TestElement(el))
|
||||
.collect::<Vec<_>>(),
|
||||
),
|
||||
in_buffer: VecDeque::from(in_buffer.into_iter().map(TestElement).collect::<Vec<_>>()),
|
||||
expect_buffer: VecDeque::new(),
|
||||
}
|
||||
}
|
||||
|
@ -212,16 +300,12 @@ impl TestComponent {
|
|||
self.expect_buffer.push_back(Expect::Element(el.into()))
|
||||
}
|
||||
|
||||
pub fn expect_iq<F: FnOnce(Iq) + Send + 'static, S: Into<String>>(
|
||||
&mut self,
|
||||
callback: F,
|
||||
desc: S,
|
||||
) {
|
||||
pub fn expect_iq<F: ExpectIq, S: Into<String>>(&mut self, callback: F, desc: S) {
|
||||
self.expect_buffer
|
||||
.push_back(Expect::Iq(Box::new(callback), desc.into()))
|
||||
}
|
||||
|
||||
pub fn expect_message<F: FnOnce(Message) + Send + 'static, S: Into<String>>(
|
||||
pub fn expect_message<F: FnOnce(Message) + Send + Sync + 'static, S: Into<String>>(
|
||||
&mut self,
|
||||
callback: F,
|
||||
desc: S,
|
||||
|
@ -230,7 +314,7 @@ impl TestComponent {
|
|||
.push_back(Expect::Message(Box::new(callback), desc.into()))
|
||||
}
|
||||
|
||||
pub fn expect_presence<F: FnOnce(Presence) + Send + 'static, S: Into<String>>(
|
||||
pub fn expect_presence<F: FnOnce(Presence) + Send + Sync + 'static, S: Into<String>>(
|
||||
&mut self,
|
||||
callback: F,
|
||||
desc: S,
|
||||
|
@ -239,6 +323,12 @@ impl TestComponent {
|
|||
.push_back(Expect::Presence(Box::new(callback), desc.into()))
|
||||
}
|
||||
|
||||
pub fn expect_scenario<S: Into<String>>(&mut self, scenario: Scenario, desc: S) {
|
||||
let (input, expected) = scenario.into_inner();
|
||||
self.in_buffer.extend(input);
|
||||
self.expect_buffer.extend(expected);
|
||||
}
|
||||
|
||||
fn send_stanza_inner<E: Into<TestElement> + Send>(&mut self, el: E) -> Result<(), Error> {
|
||||
let out: TestElement = el.into();
|
||||
let expected = self.expect_buffer.pop_front();
|
||||
|
|
|
@ -14,6 +14,8 @@
|
|||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
#![feature(let_chains)]
|
||||
#![feature(once_cell)]
|
||||
// #![feature(trait_alias)]
|
||||
// Maybe change that someday?
|
||||
#![allow(clippy::result_large_err)]
|
||||
|
||||
|
@ -22,6 +24,8 @@ mod error;
|
|||
mod handlers;
|
||||
mod room;
|
||||
|
||||
#[cfg(test)]
|
||||
mod scenarios;
|
||||
#[cfg(test)]
|
||||
mod tests;
|
||||
|
||||
|
|
50
src/scenarios.rs
Normal file
50
src/scenarios.rs
Normal file
|
@ -0,0 +1,50 @@
|
|||
// Copyright (C) 2022-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 crate::component::Scenario;
|
||||
|
||||
use std::str::FromStr;
|
||||
use std::sync::LazyLock;
|
||||
|
||||
use lazy_static::lazy_static;
|
||||
use xmpp_parsers::BareJid;
|
||||
|
||||
/*
|
||||
lazy_static! {
|
||||
static ref COMPONENT_JID: BareJid = BareJid::from_str("commons.social").unwrap();
|
||||
static ref ROOM1: BareJid = COMPONENT_JID.with_node("direct-action");
|
||||
|
||||
/// https://en.wikipedia.org/wiki/Louise_Michel
|
||||
static ref LOUISE_BARE: BareJid = BareJid::from_str("louise@example.net").unwrap();
|
||||
static ref LOUISE_NICK: String = String::from("louise");
|
||||
|
||||
/// https://en.wikipedia.org/wiki/Kanno_Sugako
|
||||
static ref SUGAKO_BARE: BareJid = BareJid::from_str("すがこ@example.net").unwrap();
|
||||
static ref SUGAKO_NICK: String = String::from("すがこ");
|
||||
|
||||
/// https://en.wikipedia.org/wiki/Rosa_Luxemburg
|
||||
static ref ROSA_BARE: BareJid = BareJid::from_str("rosa@example.net").unwrap();
|
||||
static ref ROSA_NICK: String = String::from("rosa");
|
||||
|
||||
/// https://en.wikipedia.org/wiki/Peter_Kropotkin
|
||||
static ref PETER_BARE: BareJid = BareJid::from_str("peter@example.net").unwrap();
|
||||
static ref PETER_NICK: String = String::from("peter");
|
||||
*/
|
||||
|
||||
/// Creates a room of one participant
|
||||
// pub static CREATE_ROOM_1: LazyLock<Scenario> = LazyLock::new(|| Scenario::new());
|
||||
lazy_static! {
|
||||
pub static ref CREATE_ROOM_1: Scenario = Scenario::new();
|
||||
}
|
|
@ -16,9 +16,11 @@
|
|||
use crate::component::TestComponent;
|
||||
use crate::handlers::handle_stanza;
|
||||
use crate::room::Room;
|
||||
use crate::scenarios::CREATE_ROOM_1;
|
||||
|
||||
use std::collections::{BTreeMap, HashMap};
|
||||
use std::str::FromStr;
|
||||
use std::sync::LazyLock;
|
||||
|
||||
use lazy_static::lazy_static;
|
||||
use xmpp_parsers::{
|
||||
|
@ -56,6 +58,9 @@ async fn test_join_presence_empty_room() {
|
|||
let mut component = TestComponent::new(vec![join]);
|
||||
let mut rooms: HashMap<BareJid, Room> = HashMap::new();
|
||||
|
||||
// let create_room = LazyLock::force(&CREATE_ROOM_1);
|
||||
component.expect_scenario(*CREATE_ROOM_1, "Create room of 1 participant");
|
||||
|
||||
// Room is empty so there should be:
|
||||
// - No presence sent except for self-presence
|
||||
// - No message history
|
||||
|
|
Loading…
Reference in a new issue