From a50d19a2a14edc4db02169b0d66e298b4185b2b0 Mon Sep 17 00:00:00 2001 From: Louis Vallat Date: Mon, 1 Nov 2021 14:47:42 +0100 Subject: [PATCH] Added the add_album command and the according tests Signed-off-by: Louis Vallat --- src/album.rs | 83 ++++++++++++++++++++++++++++++++++++++++++++++++++-- src/main.rs | 19 +++++++++++- src/utils.rs | 28 +++++++++++++++++- 3 files changed, 126 insertions(+), 4 deletions(-) diff --git a/src/album.rs b/src/album.rs index 46ed578..c51b1d9 100644 --- a/src/album.rs +++ b/src/album.rs @@ -2,7 +2,7 @@ use serde::Deserialize; use serde_json::{from_str, json}; use tabled::Tabled; use hyper::{Method, Request, body::Body, header::{AUTHORIZATION, CONTENT_TYPE, COOKIE}}; -use crate::{utils::{display_option_string, body_to_str}, LycheeClient}; +use crate::{LycheeClient, utils::{display_option_string, body_to_str}}; #[derive(Deserialize, Debug, Tabled)] pub struct Album { @@ -47,11 +47,29 @@ pub async fn get_album(c: &LycheeClient, lychee_session: &str, id: &str) -> Albu let s = res.status(); let b = body_to_str(res.into_body()).await; assert_ne!(b, "\"false\"", "This albumID doesn't exist."); - assert_ne!(s, 500, "The server returned an error, check that the given albumID is valid and try again."); + assert_ne!(s, 500, "The server returned an internal error, check that the given albumID is valid and try again."); let v: Album = from_str(b.as_str()).unwrap(); return v; } +pub async fn add_album(c: &LycheeClient, lychee_session: &str, title: &str, parent_id: Option) -> String { + if title.len() > 100 { panic!("The title can't have more than 100 characters.") }; + let b = json!({ "title": title, "parent_id": if parent_id.is_some() { parent_id.unwrap() } else { 0 } }); + let req = Request::builder() + .method(Method::POST) + .uri(c.endpoint.to_string() + "/api/Album::add") + .header(COOKIE, lychee_session) + .header(AUTHORIZATION, c.api_key.to_string()) + .header(CONTENT_TYPE, "application/json") + .body(Body::from(b.to_string())) + .expect("Cannot request /api/Album::add."); + let res = c.client.request(req).await.unwrap(); + let s = res.status(); + let b = body_to_str(res.into_body()).await; + assert_ne!(s, 500, "The server returned an internal error."); + return b; +} + #[cfg(test)] mod album_tests { use hyper_tls::HttpsConnector; @@ -60,6 +78,8 @@ mod album_tests { use serde_json::json; use crate::{LycheeClient, get_album}; + use super::add_album; + fn setup() -> LycheeClient { let https = HttpsConnector::new(); return LycheeClient { @@ -69,6 +89,63 @@ mod album_tests { }; } + #[test] + #[should_panic] + fn add_album_title_too_long() { + let client = setup(); + let m = mock("POST", "/api/Album::add") + .match_header("cookie", "cookie value") + .match_header("content/type", "application/json") + .create(); + + tokio_test::block_on(add_album(&client, "cookie value", "12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901", None)); + m.assert(); + } + + #[test] + #[should_panic] + fn add_album_returned_500() { + let client = setup(); + let m = mock("POST", "/api/Album::add") + .match_header("cookie", "cookie value") + .match_header("content-type", "application/json") + .with_status(500) + .create(); + + tokio_test::block_on(add_album(&client, "cookie value", "1", None)); + m.assert(); + } + + #[test] + fn add_album_some_parent_id() { + let client = setup(); + let m = mock("POST", "/api/Album::add") + .match_header("cookie", "v") + .match_header("content-type", "application/json") + .with_body("1234") + .match_body(json!({"title": "title", "parent_id": 123}).to_string().as_str()) + .create(); + + tokio_test::block_on(add_album(&client, "v", "title", Some(123))); + + m.assert(); + } + + #[test] + fn add_album_none_parent_id() { + let client = setup(); + let m = mock("POST", "/api/Album::add") + .match_header("cookie", "v") + .match_header("content-type", "application/json") + .with_body("1234") + .match_body(json!({"title": "t", "parent_id": 0}).to_string().as_str()) + .create(); + + tokio_test::block_on(add_album(&client, "v", "t", None)); + + m.assert(); + } + #[test] #[should_panic] fn get_album_returned_false() { @@ -90,6 +167,7 @@ mod album_tests { let m = mock("POST", "/api/Album::get") .with_body("{}") .with_header("content-type", "application/json") + .match_header("content-type", "application/json") .match_header("cookie", "cookie value") .with_status(500) .create(); @@ -106,6 +184,7 @@ mod album_tests { .with_body(payload.to_string()) .with_header("content-type", "application/json") .match_header("cookie", "cookie value") + .match_header("content-type", "application/json") .match_body(json!({"albumID":"16344947463510"}).to_string().as_str()) .create(); diff --git a/src/main.rs b/src/main.rs index 46d76b5..a7a4a52 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,4 +1,4 @@ -use crate::{album::get_album, albums::get_albums, config::{get_session_file, read_config, setup_config_data_storage}, session::login, utils::{write_to_file, read_from_file, body_to_str}}; +use crate::{album::{add_album, get_album}, albums::get_albums, config::{get_session_file, read_config, setup_config_data_storage}, session::login, utils::{body_to_str, numeric_validator, read_from_file, write_to_file}}; use hyper_tls::HttpsConnector; use hyper::{Client, client::HttpConnector}; use clap::{App, Arg, SubCommand, crate_version}; @@ -59,6 +59,18 @@ async fn main() -> Result<(), Box> { .value_name("ID") .required(true) .help("Specify the album id to query data from.")) + ) + .subcommand( + SubCommand::with_name("add_album") + .about("Create an album.") + .arg(Arg::with_name("title") + .long("title").short("t") + .required(true) + .help("The album title to create.") + .value_name("TITLE")) + .arg(Arg::with_name("parent_id") + .long("parent").short("p").help("The parent id for the album to create.") + .value_name("PARENT_ID").validator(numeric_validator)) ); let matches = app.clone().get_matches(); @@ -88,6 +100,11 @@ async fn main() -> Result<(), Box> { let id = m.value_of("id").unwrap(); let a = get_album(&client, &lychee_session_cookie, id).await; println!("{}", Table::new(vec![a]).to_string()); + } else if let Some(m) = matches.subcommand_matches("add_album") { + let title = m.value_of("title").unwrap(); + let parent_id = if m.is_present("parent_id") { Some(m.value_of("parent_id").unwrap().parse::().unwrap()) } else {None}; + let a = add_album(&client, &lychee_session_cookie, title, parent_id).await; + println!("{}", a); } else { App::print_long_help(&mut app).unwrap(); } diff --git a/src/utils.rs b/src/utils.rs index dcecdda..24cb123 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -25,10 +25,36 @@ pub fn display_option_string(o: &Option) -> String { } } +pub fn numeric_validator(s: String) -> Result<(), String> { + if s.parse::().is_ok() { return Ok(()); } + else { return Err("This is expected to be a numeric value, and it looks like it isn't.".to_string()); } +} + #[cfg(test)] mod utils_tests { use hyper::Body; - use crate::utils::body_to_str; + use crate::utils::{body_to_str, display_option_string, numeric_validator}; + + #[test] + fn numeric_validator_numeric() { + assert!(numeric_validator("123".to_string()).is_ok()); + assert!(numeric_validator("16357551305932".to_string()).is_ok()); + } + + #[test] + fn numeric_validator_not_numeric() { + assert!(numeric_validator("abc".to_string()).is_err()); + } + + #[test] + fn display_option_string_some() { + assert_eq!("data", display_option_string(&Some("data".to_string()))); + } + + #[test] + fn display_option_string_none() { + assert_eq!("N/A", display_option_string(&None)); + } #[test] fn body_to_str_empty() {