From a78b559307d7d9573f953dbc277ce45cb1395828 Mon Sep 17 00:00:00 2001 From: h1alexbel Date: Wed, 10 Jul 2024 18:46:06 +0300 Subject: [PATCH 01/10] feat(#17): register_user handler, tracing-subscriber crate --- server/Cargo.toml | 1 + server/src/lib.rs | 13 ++++++--- server/src/objects/mod.rs | 22 ++++++++++++++++ server/src/objects/user.rs | 42 ++++++++++++++++++++++++++++++ server/src/routes/register_user.rs | 35 +++++++++++++++++++++++++ 5 files changed, 109 insertions(+), 4 deletions(-) create mode 100644 server/src/objects/mod.rs create mode 100644 server/src/objects/user.rs create mode 100644 server/src/routes/register_user.rs diff --git a/server/Cargo.toml b/server/Cargo.toml index edd3b8d2..015821f2 100644 --- a/server/Cargo.toml +++ b/server/Cargo.toml @@ -44,3 +44,4 @@ axum = "0.7.5" log = { version = "0.4.21", features = [] } env_logger = "0.11.3" tempdir = "0.3.7" +tracing-subscriber = "0.3.18" diff --git a/server/src/lib.rs b/server/src/lib.rs index 10bcefd1..fba2fbc9 100644 --- a/server/src/lib.rs +++ b/server/src/lib.rs @@ -22,14 +22,16 @@ use std::io; use anyhow::Result; -use axum::routing::get; +use axum::routing::{get, post}; use axum::Router; use tokio::net::TcpListener; use crate::routes::home; -use crate::xml::storage::touch_storage; +use crate::routes::register_user::{register_user}; +use crate::xml::storage::Storage; pub mod report; +mod objects; mod routes; mod xml; @@ -46,8 +48,11 @@ impl Server { impl Server { pub async fn start(self) -> Result<()> { - touch_storage(Some("fakehub.xml")); - let app: Router = Router::new().route("/", get(home::home)); + tracing_subscriber::fmt::init(); + Storage::new(Some("fakehub.xml")); + let app: Router = Router::new() + .route("/", get(home::home)) + .route("/users", post(register_user)); let addr: String = format!("0.0.0.0:{}", self.port); let started: io::Result = TcpListener::bind(addr.clone()).await; match started { diff --git a/server/src/objects/mod.rs b/server/src/objects/mod.rs new file mode 100644 index 00000000..06c393b7 --- /dev/null +++ b/server/src/objects/mod.rs @@ -0,0 +1,22 @@ +// The MIT License (MIT) +// +// Copyright (c) 2024 Aliaksei Bialiauski +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +pub mod user; diff --git a/server/src/objects/user.rs b/server/src/objects/user.rs new file mode 100644 index 00000000..2155498f --- /dev/null +++ b/server/src/objects/user.rs @@ -0,0 +1,42 @@ +// The MIT License (MIT) +// +// Copyright (c) 2024 Aliaksei Bialiauski +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +use anyhow::Result; +use log::info; +use serde::Deserialize; + +#[derive(Debug, Deserialize)] +pub struct User { + pub(crate) username: String, +} + +impl User { + pub fn new(username: String) -> User { + User { username } + } +} + +impl User { + pub async fn save(self) -> Result<()> { + info!("registering user @{}", self.username); + Ok(()) + } +} diff --git a/server/src/routes/register_user.rs b/server/src/routes/register_user.rs new file mode 100644 index 00000000..7a30051e --- /dev/null +++ b/server/src/routes/register_user.rs @@ -0,0 +1,35 @@ +// The MIT License (MIT) +// +// Copyright (c) 2024 Aliaksei Bialiauski +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +use axum::http::StatusCode; +use axum::Json; + +use crate::objects::user::User; + +pub async fn register_user(Json(payload): Json) -> Result { + let user = User::new(payload.username.clone()); + match user.save().await { + Ok(_) => Ok(StatusCode::CREATED), + Err(e) => Err( + format!("Can't register {}: {}", payload.username, e), + ), + } +} From 40a32a23728e4527df1a2334553a84fa6a463d93 Mon Sep 17 00:00:00 2001 From: h1alexbel Date: Wed, 10 Jul 2024 18:46:28 +0300 Subject: [PATCH 02/10] feat(#17): pub mod --- server/src/routes/mod.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/server/src/routes/mod.rs b/server/src/routes/mod.rs index dc2b5115..36cc97c9 100644 --- a/server/src/routes/mod.rs +++ b/server/src/routes/mod.rs @@ -21,3 +21,4 @@ // SOFTWARE. pub mod home; pub mod rs_err; +pub mod register_user; From b8b9336b5b61df7b895b3683c934b9669a623f5b Mon Sep 17 00:00:00 2001 From: h1alexbel Date: Wed, 10 Jul 2024 18:46:47 +0300 Subject: [PATCH 03/10] feat(#17): storage redesigned to struct --- server/src/xml/storage.rs | 73 +++++++++++++++++++++++++++++++-------- 1 file changed, 58 insertions(+), 15 deletions(-) diff --git a/server/src/xml/storage.rs b/server/src/xml/storage.rs index 165c57ff..dea008e0 100644 --- a/server/src/xml/storage.rs +++ b/server/src/xml/storage.rs @@ -19,37 +19,63 @@ // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. +use anyhow::Result; use std::fs::File; - +use std::io::Write; use log::info; -pub fn touch_storage(path: Option<&str>) -> File { - let location = path.unwrap_or("fakehub.xml"); - info!("Initializing XML storage: {location}"); - match File::create(location) { - Ok(file) => { - info!("'{location}' initialized"); - file - } - Err(err) => { - panic!("fakehub storage failed to initialize in '{location}': {err}") +#[derive(Default)] +pub struct Storage { + pub(crate) path: String, +} + +impl Storage { + pub fn new(path: Option<&str>) -> Storage { + let location = path.unwrap_or("fakehub.xml"); + info!("Initializing XML storage: {location}"); + let mut file = match File::create(location) { + Ok(file) => { + file + } + Err(err) => { + panic!("fakehub storage failed to initialize in '{location}': {err}"); + } + }; + if let Err(err) = file.write_all( + "\ + \ + ".as_bytes() + ) { + panic!("Failed to write initial content to '{}': {}", location, err); } + info!("'{}' initialized", location); + Storage { path: String::from(location) } + } +} + +// @todo #17:35min Implement #xml function in Storage. +// This function should return full XML storage has at the moment. #xml +// function should be thread-safe, as it intended to be used concurrently. +// Don't forget to create a unit tests related to #xml function. +impl Storage { + pub fn xml() -> Result<()> { + Ok(()) } } #[cfg(test)] mod tests { + use std::fs; use anyhow::Result; use tempdir::TempDir; - - use crate::xml::storage::touch_storage; + use crate::xml::storage::Storage; #[test] fn creates_xml_storage() -> Result<()> { let temp = TempDir::new("temp")?; let path = temp.path().join("fakehub.xml"); let storage = path.to_str(); - touch_storage(storage); + Storage::new(storage); assert!( path.exists(), "storage file {:?} was not created, but should be", @@ -58,12 +84,29 @@ mod tests { Ok(()) } + #[test] + fn reads_initial_content() -> Result<()>{ + let temp = TempDir::new("temp")?; + let path = temp.path().join("fakehub.xml"); + Storage::new(path.to_str()); + let xml = fs::read_to_string(path).unwrap(); + let expected = ""; + assert_eq!( + xml, + expected, + "Received initial XML {} does not match with expected {}", + xml, + expected + ); + Ok(()) + } + #[test] fn creates_xml_storage_with_different_name() -> Result<()> { let temp = TempDir::new("temp")?; let path = temp.path().join("test.xml"); let storage = path.to_str(); - touch_storage(storage); + Storage::new(storage); assert!( path.exists(), "storage file {:?} was not created, but should be", From 5e0c434b1e9b7a69558fc01347a7f5981cbc8406 Mon Sep 17 00:00:00 2001 From: h1alexbel Date: Wed, 10 Jul 2024 19:04:42 +0300 Subject: [PATCH 04/10] feat(#17): serde_xml_rs, puzzle for #save --- server/Cargo.toml | 1 + server/src/objects/user.rs | 36 +++++++++++++++++++++++++++++++++--- 2 files changed, 34 insertions(+), 3 deletions(-) diff --git a/server/Cargo.toml b/server/Cargo.toml index 015821f2..a9eb42e1 100644 --- a/server/Cargo.toml +++ b/server/Cargo.toml @@ -38,6 +38,7 @@ path = "src/lib.rs" openapi = { path = "../github-mirror" } anyhow = "1.0.86" serde = { version = "1.0.203", features = ["derive"] } +serde-xml-rs = "0.6.0" serde_json = "1.0.117" tokio = { version = "1.0.0", features = ["rt", "rt-multi-thread", "macros", "fs"] } axum = "0.7.5" diff --git a/server/src/objects/user.rs b/server/src/objects/user.rs index 2155498f..e7732ce6 100644 --- a/server/src/objects/user.rs +++ b/server/src/objects/user.rs @@ -20,10 +20,11 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. use anyhow::Result; -use log::info; -use serde::Deserialize; +use log::{debug, info}; +use serde::{Deserialize, Serialize}; +use serde_xml_rs::to_string; -#[derive(Debug, Deserialize)] +#[derive(Debug, Serialize, Deserialize)] pub struct User { pub(crate) username: String, } @@ -34,9 +35,38 @@ impl User { } } +// @todo #17:40min Apply XMLed user to the node in storage. +// We should apply XMLed user to the XML node in storage. First we +// need to check that user with provided name does not exist, and only then +// apply it to the storage. Keep in mind that application function in the +// storage should be thread-safe (as well as #xml function). Don't forget to +// create unit tests that prove that. impl User { pub async fn save(self) -> Result<()> { info!("registering user @{}", self.username); + let xml = to_string(&self).unwrap(); + debug!("XMLed user: {}", xml); + Ok(()) + } +} + +#[cfg(test)] +mod tests { + use anyhow::Result; + use crate::objects::user::User; + + #[test] + fn returns_username() -> Result<()> { + let expected = "jeff"; + let jeff = User::new(String::from(expected)); + assert_eq!( + jeff.username, + expected, + "Username {} from user: {:?} does not match with expected {}", + jeff.username, + jeff, + expected + ); Ok(()) } } From 2ee37bf18dd5011caa25de8687253b82c2ed2abd Mon Sep 17 00:00:00 2001 From: h1alexbel Date: Wed, 10 Jul 2024 19:12:20 +0300 Subject: [PATCH 05/10] feat(#17): clean for fmt --- server/src/lib.rs | 4 ++-- server/src/objects/user.rs | 8 +++----- server/src/routes/mod.rs | 2 +- server/src/routes/register_user.rs | 4 +--- server/src/xml/storage.rs | 26 ++++++++++++++------------ 5 files changed, 21 insertions(+), 23 deletions(-) diff --git a/server/src/lib.rs b/server/src/lib.rs index fba2fbc9..ecb41aa5 100644 --- a/server/src/lib.rs +++ b/server/src/lib.rs @@ -27,11 +27,11 @@ use axum::Router; use tokio::net::TcpListener; use crate::routes::home; -use crate::routes::register_user::{register_user}; +use crate::routes::register_user::register_user; use crate::xml::storage::Storage; -pub mod report; mod objects; +pub mod report; mod routes; mod xml; diff --git a/server/src/objects/user.rs b/server/src/objects/user.rs index e7732ce6..799cc64c 100644 --- a/server/src/objects/user.rs +++ b/server/src/objects/user.rs @@ -53,6 +53,7 @@ impl User { #[cfg(test)] mod tests { use anyhow::Result; + use crate::objects::user::User; #[test] @@ -60,12 +61,9 @@ mod tests { let expected = "jeff"; let jeff = User::new(String::from(expected)); assert_eq!( - jeff.username, - expected, + jeff.username, expected, "Username {} from user: {:?} does not match with expected {}", - jeff.username, - jeff, - expected + jeff.username, jeff, expected ); Ok(()) } diff --git a/server/src/routes/mod.rs b/server/src/routes/mod.rs index 36cc97c9..1e466dc4 100644 --- a/server/src/routes/mod.rs +++ b/server/src/routes/mod.rs @@ -20,5 +20,5 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. pub mod home; -pub mod rs_err; pub mod register_user; +pub mod rs_err; diff --git a/server/src/routes/register_user.rs b/server/src/routes/register_user.rs index 7a30051e..ae5edbd4 100644 --- a/server/src/routes/register_user.rs +++ b/server/src/routes/register_user.rs @@ -28,8 +28,6 @@ pub async fn register_user(Json(payload): Json) -> Result Ok(StatusCode::CREATED), - Err(e) => Err( - format!("Can't register {}: {}", payload.username, e), - ), + Err(e) => Err(format!("Can't register {}: {}", payload.username, e)), } } diff --git a/server/src/xml/storage.rs b/server/src/xml/storage.rs index dea008e0..785d0d55 100644 --- a/server/src/xml/storage.rs +++ b/server/src/xml/storage.rs @@ -1,3 +1,6 @@ +use std::fs::File; +use std::io::Write; + // The MIT License (MIT) // // Copyright (c) 2024 Aliaksei Bialiauski @@ -20,8 +23,6 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. use anyhow::Result; -use std::fs::File; -use std::io::Write; use log::info; #[derive(Default)] @@ -34,9 +35,7 @@ impl Storage { let location = path.unwrap_or("fakehub.xml"); info!("Initializing XML storage: {location}"); let mut file = match File::create(location) { - Ok(file) => { - file - } + Ok(file) => file, Err(err) => { panic!("fakehub storage failed to initialize in '{location}': {err}"); } @@ -44,12 +43,15 @@ impl Storage { if let Err(err) = file.write_all( "\ \ - ".as_bytes() + " + .as_bytes(), ) { panic!("Failed to write initial content to '{}': {}", location, err); } info!("'{}' initialized", location); - Storage { path: String::from(location) } + Storage { + path: String::from(location), + } } } @@ -66,8 +68,10 @@ impl Storage { #[cfg(test)] mod tests { use std::fs; + use anyhow::Result; use tempdir::TempDir; + use crate::xml::storage::Storage; #[test] @@ -85,18 +89,16 @@ mod tests { } #[test] - fn reads_initial_content() -> Result<()>{ + fn reads_initial_content() -> Result<()> { let temp = TempDir::new("temp")?; let path = temp.path().join("fakehub.xml"); Storage::new(path.to_str()); let xml = fs::read_to_string(path).unwrap(); let expected = ""; assert_eq!( - xml, - expected, + xml, expected, "Received initial XML {} does not match with expected {}", - xml, - expected + xml, expected ); Ok(()) } From 698d8194a4beedc1a0ad54b209a6299d8de13b4c Mon Sep 17 00:00:00 2001 From: h1alexbel Date: Wed, 10 Jul 2024 19:19:43 +0300 Subject: [PATCH 06/10] feat(#17): allow dead code --- server/src/xml/storage.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/server/src/xml/storage.rs b/server/src/xml/storage.rs index 785d0d55..9f8c3e9f 100644 --- a/server/src/xml/storage.rs +++ b/server/src/xml/storage.rs @@ -26,6 +26,7 @@ use anyhow::Result; use log::info; #[derive(Default)] +#[allow(dead_code)] pub struct Storage { pub(crate) path: String, } @@ -60,6 +61,7 @@ impl Storage { // function should be thread-safe, as it intended to be used concurrently. // Don't forget to create a unit tests related to #xml function. impl Storage { + #[allow(dead_code)] pub fn xml() -> Result<()> { Ok(()) } From 2a866974bb1792f5f0fa67b2724e414176e26650 Mon Sep 17 00:00:00 2001 From: h1alexbel Date: Thu, 11 Jul 2024 09:41:39 +0300 Subject: [PATCH 07/10] feat(#17): INIT_XML const --- server/src/xml/storage.rs | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/server/src/xml/storage.rs b/server/src/xml/storage.rs index 9f8c3e9f..afc1588b 100644 --- a/server/src/xml/storage.rs +++ b/server/src/xml/storage.rs @@ -31,6 +31,10 @@ pub struct Storage { pub(crate) path: String, } +const INIT_XML: &str = "\ + \ + "; + impl Storage { pub fn new(path: Option<&str>) -> Storage { let location = path.unwrap_or("fakehub.xml"); @@ -41,12 +45,7 @@ impl Storage { panic!("fakehub storage failed to initialize in '{location}': {err}"); } }; - if let Err(err) = file.write_all( - "\ - \ - " - .as_bytes(), - ) { + if let Err(err) = file.write_all(INIT_XML.as_bytes()) { panic!("Failed to write initial content to '{}': {}", location, err); } info!("'{}' initialized", location); From 2bb8df344dc44248a9434e6f0c0930de4e08d353 Mon Sep 17 00:00:00 2001 From: h1alexbel Date: Thu, 11 Jul 2024 10:15:18 +0300 Subject: [PATCH 08/10] feat(#17): hamcrest --- server/Cargo.toml | 1 + server/src/lib.rs | 6 +++++- server/src/objects/user.rs | 10 +++------- server/src/report/latex.rs | 9 +++------ server/src/xml/storage.rs | 19 ++++--------------- 5 files changed, 16 insertions(+), 29 deletions(-) diff --git a/server/Cargo.toml b/server/Cargo.toml index a9eb42e1..2b128160 100644 --- a/server/Cargo.toml +++ b/server/Cargo.toml @@ -46,3 +46,4 @@ log = { version = "0.4.21", features = [] } env_logger = "0.11.3" tempdir = "0.3.7" tracing-subscriber = "0.3.18" +hamcrest = "0.1.5" diff --git a/server/src/lib.rs b/server/src/lib.rs index ecb41aa5..c0a1b08f 100644 --- a/server/src/lib.rs +++ b/server/src/lib.rs @@ -34,6 +34,9 @@ mod objects; pub mod report; mod routes; mod xml; +#[allow(unused_imports)] +#[macro_use] +extern crate hamcrest; #[derive(Default)] pub struct Server { @@ -68,11 +71,12 @@ impl Server { #[cfg(test)] mod tests { use anyhow::Result; + use hamcrest::{equal_to, is, HamcrestMatcher}; #[test] fn creates_the_server() -> Result<()> { let server = crate::Server::new(1234); - assert_eq!(server.port, 1234); + assert_that!(server.port, is(equal_to(1234))); Ok(()) } } diff --git a/server/src/objects/user.rs b/server/src/objects/user.rs index 799cc64c..1c19363a 100644 --- a/server/src/objects/user.rs +++ b/server/src/objects/user.rs @@ -52,19 +52,15 @@ impl User { #[cfg(test)] mod tests { - use anyhow::Result; - use crate::objects::user::User; + use anyhow::Result; + use hamcrest::{equal_to, is, HamcrestMatcher}; #[test] fn returns_username() -> Result<()> { let expected = "jeff"; let jeff = User::new(String::from(expected)); - assert_eq!( - jeff.username, expected, - "Username {} from user: {:?} does not match with expected {}", - jeff.username, jeff, expected - ); + assert_that!(jeff.username, is(equal_to(String::from(expected)))); Ok(()) } } diff --git a/server/src/report/latex.rs b/server/src/report/latex.rs index 74148575..ea45db29 100644 --- a/server/src/report/latex.rs +++ b/server/src/report/latex.rs @@ -45,9 +45,9 @@ pub fn template(path: &str) -> String { #[cfg(test)] mod tests { - use anyhow::Result; - use crate::report::latex::template; + use anyhow::Result; + use hamcrest::{equal_to, is, HamcrestMatcher}; #[test] // @todo #41:60min Add support of @ExtendsWith from JUnit in order to pass expected as test parameter. @@ -64,10 +64,7 @@ mod tests { \tbd{History: TBD} \end{document} "; - assert_eq!( - content, expected, - "Template content '{content}' does not match with '{expected}'" - ); + assert_that!(content, is(equal_to(String::from(expected)))); Ok(()) } } diff --git a/server/src/xml/storage.rs b/server/src/xml/storage.rs index afc1588b..b01958a7 100644 --- a/server/src/xml/storage.rs +++ b/server/src/xml/storage.rs @@ -71,6 +71,7 @@ mod tests { use std::fs; use anyhow::Result; + use hamcrest::{equal_to, is, HamcrestMatcher}; use tempdir::TempDir; use crate::xml::storage::Storage; @@ -81,11 +82,7 @@ mod tests { let path = temp.path().join("fakehub.xml"); let storage = path.to_str(); Storage::new(storage); - assert!( - path.exists(), - "storage file {:?} was not created, but should be", - storage - ); + assert_that!(path.exists(), is(equal_to(true))); Ok(()) } @@ -96,11 +93,7 @@ mod tests { Storage::new(path.to_str()); let xml = fs::read_to_string(path).unwrap(); let expected = ""; - assert_eq!( - xml, expected, - "Received initial XML {} does not match with expected {}", - xml, expected - ); + assert_that!(xml, is(equal_to(String::from(expected)))); Ok(()) } @@ -110,11 +103,7 @@ mod tests { let path = temp.path().join("test.xml"); let storage = path.to_str(); Storage::new(storage); - assert!( - path.exists(), - "storage file {:?} was not created, but should be", - storage - ); + assert_that!(path.exists(), is(equal_to(true))); Ok(()) } } From 49bea5cd1e492c5ef1f3f145d12a5bf4e6a79e8a Mon Sep 17 00:00:00 2001 From: h1alexbel Date: Thu, 11 Jul 2024 11:32:30 +0300 Subject: [PATCH 09/10] feat(#17): clippy reject unwrap puzzle --- server/src/objects/user.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/server/src/objects/user.rs b/server/src/objects/user.rs index 1c19363a..4519d4a4 100644 --- a/server/src/objects/user.rs +++ b/server/src/objects/user.rs @@ -41,6 +41,9 @@ impl User { // apply it to the storage. Keep in mind that application function in the // storage should be thread-safe (as well as #xml function). Don't forget to // create unit tests that prove that. +// @todo #17:30min Configure clippy to reject code with #unwrap(). +// We should prohibit to use #unwrap() function in our code. Let's configure +// clippy tool in the respective manner and get rid of all #unwrap() calls. impl User { pub async fn save(self) -> Result<()> { info!("registering user @{}", self.username); From 77b876511d9595c27ce6e3a85122076541ef8f94 Mon Sep 17 00:00:00 2001 From: h1alexbel Date: Thu, 11 Jul 2024 11:35:01 +0300 Subject: [PATCH 10/10] feat(#17): multiline string --- server/src/xml/storage.rs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/server/src/xml/storage.rs b/server/src/xml/storage.rs index b01958a7..939b4c7d 100644 --- a/server/src/xml/storage.rs +++ b/server/src/xml/storage.rs @@ -31,9 +31,10 @@ pub struct Storage { pub(crate) path: String, } -const INIT_XML: &str = "\ - \ - "; +const INIT_XML: &str = " + + +"; impl Storage { pub fn new(path: Option<&str>) -> Storage { @@ -92,7 +93,7 @@ mod tests { let path = temp.path().join("fakehub.xml"); Storage::new(path.to_str()); let xml = fs::read_to_string(path).unwrap(); - let expected = ""; + let expected = "\n\n\n"; assert_that!(xml, is(equal_to(String::from(expected)))); Ok(()) }