mod client; mod clock; mod document; mod field; mod queue; mod session; use client::{Client, ClientChannel}; use clock::Clock; use document::Document; use field::Field; use queue::{Message, MsgType, Queue}; use session::Session; use uuid::Uuid; #[derive(Clone, Debug)] pub enum ActionType { Get, Add, Update, } #[derive(Clone, Debug)] pub enum ErrorType { DocumentNotFound, } pub struct MTTReply { document: String, error_type: Option, } impl MTTReply { fn new(msg: Message) -> Self { Self { document: match msg.get_data("doc") { Some(doc) => doc.to_string(), None => "".to_string(), }, error_type: match msg.get_data("error_type") { Some(err) => Some(err.to_error_type().unwrap()), None => None, }, } } pub fn get_document(&self) -> String { self.document.clone() } pub fn get_error(&self) -> Option { self.error_type.clone() } } #[cfg(test)] mod mtt_replies { use super::*; #[test] fn create_reply_with_no_error() { let mut msg = Message::new(MsgType::Document); let content = format!("content-{}", Uuid::new_v4()); msg.add_data("doc", content.to_string()); let reply = MTTReply::new(msg); assert!(reply.get_error().is_none()); assert_eq!(reply.get_document(), content); } #[test] fn create_reply_with_error() { let mut msg = Message::new(MsgType::Error); msg.add_data("error_type", ErrorType::DocumentNotFound); let reply = MTTReply::new(msg); match reply.get_error() { Some(err) => match err { ErrorType::DocumentNotFound => {} }, None => unreachable!("should return an error type"), } assert_eq!(reply.get_document(), ""); } #[test] fn no_error() { let msg = Message::new(MsgType::Document); let reply = MTTReply::new(msg); assert!(reply.get_error().is_none()); } #[test] fn some_error() { let mut msg = Message::new(MsgType::Error); msg.add_data("error_type", ErrorType::DocumentNotFound); let reply = MTTReply::new(msg); match reply.get_error() { Some(err) => match err { ErrorType::DocumentNotFound => {} }, None => unreachable!("should return an error type"), } } } #[derive(Clone)] pub struct MoreThanText { client_channel: ClientChannel, } impl MoreThanText { pub fn new() -> Self { let queue = Queue::new(); Clock::start(queue.clone()); Document::start(queue.clone()); Session::start(queue.clone()); Self { client_channel: Client::start(queue.clone()), } } pub fn validate_session(&mut self, session: Option) -> Uuid where F: Into, { let mut msg = Message::new(MsgType::SessionValidate); match session { Some(id) => msg.add_data("sess_id", id.into()), None => {} } let rx = self.client_channel.send(msg); let reply = rx.recv().unwrap(); reply.get_data("sess_id").unwrap().to_uuid().unwrap() } pub fn get_document(&self, sess_id: Uuid, action: ActionType, doc_name: S) -> MTTReply where S: Into, { let mut msg = Message::new(MsgType::DocumentRequest); msg.add_data("sess_id", sess_id); msg.add_data("action", action); msg.add_data("name", doc_name.into()); let rx = self.client_channel.send(msg); let reply = rx.recv().unwrap(); MTTReply::new(reply) } } #[cfg(test)] mod mtt { use super::*; #[test] fn session_id_is_unique() { let mut mtt = MoreThanText::new(); let input: Option = None; let mut ids: Vec = Vec::new(); for _ in 0..10 { let id = mtt.validate_session(input.clone()); assert!(!ids.contains(&id)); ids.push(id); } } #[test] fn reuse_existing_session() { let mut mtt = MoreThanText::new(); let initial: Option = None; let id = mtt.validate_session(initial); let output = mtt.validate_session(Some(id.clone())); assert_eq!(output, id); } #[test] fn get_root_document_with_str() { let mut mtt = MoreThanText::new(); let id = mtt.validate_session(Some(Uuid::new_v4())); let output = mtt.get_document(id, ActionType::Get, "root"); assert!(output.get_error().is_none()); } #[test] fn get_root_document_with_string() { let mut mtt = MoreThanText::new(); let id = mtt.validate_session(Some(Uuid::new_v4())); let output = mtt.get_document(id, ActionType::Get, "root".to_string()); assert!(output.get_error().is_none()); } }