From 9c8243561f41514c8c9ae6ae3b188fb5cfaa6778 Mon Sep 17 00:00:00 2001 From: Paul Campbell Date: Sat, 30 Nov 2024 18:04:48 +0000 Subject: [PATCH] feat(nextcloud): add command 'nextcloud stack list' --- Cargo.toml | 3 +- src/lib.rs | 13 ++++ src/nextcloud/mod.rs | 1 + src/nextcloud/model.rs | 2 + src/nextcloud/stack.rs | 14 ++-- src/nextcloud/tests.rs | 123 +++++++++++++++++------------- src/nextcloud/tests/stack/list.rs | 69 +++++++++++++++++ src/nextcloud/tests/stack/mod.rs | 4 + 8 files changed, 169 insertions(+), 60 deletions(-) create mode 100644 src/nextcloud/tests/stack/list.rs create mode 100644 src/nextcloud/tests/stack/mod.rs diff --git a/Cargo.toml b/Cargo.toml index f6a7044..03ec669 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -29,5 +29,6 @@ toml = "0.8" [dev-dependencies] assert2 = "0.3" mutants = "0.0" -#pretty_assertions = "1.4" +pretty_assertions = "1.4" +rstest = "0.23" test-log = { version = "0.2", features = ["trace"] } diff --git a/src/lib.rs b/src/lib.rs index 60952bf..dc6fc06 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -42,6 +42,8 @@ enum Command { enum NextcloudCommand { #[clap(subcommand)] Board(NextcloudBoardCommand), + #[clap(subcommand)] + Stack(NextcloudStackCommand), } #[derive(Parser, Debug)] @@ -52,6 +54,14 @@ enum NextcloudBoardCommand { }, } +#[derive(Parser, Debug)] +enum NextcloudStackCommand { + List { + #[clap(long, action = clap::ArgAction::SetTrue)] + dump: bool, + }, +} + #[derive(Clone)] pub struct Ctx { pub fs: FileSystem, @@ -109,6 +119,9 @@ pub async fn run(ctx: Ctx) -> color_eyre::Result<()> { Command::Nextcloud(NextcloudCommand::Board(NextcloudBoardCommand::List { dump, })) => nextcloud::board::list(ctx, dump).await, + Command::Nextcloud(NextcloudCommand::Stack(NextcloudStackCommand::List { + dump, + })) => nextcloud::stack::list(ctx, dump).await, } } } diff --git a/src/nextcloud/mod.rs b/src/nextcloud/mod.rs index a03c0c8..441e8eb 100644 --- a/src/nextcloud/mod.rs +++ b/src/nextcloud/mod.rs @@ -9,6 +9,7 @@ use model::{Board, Card, NextcloudBoardId, Stack}; pub mod board; pub mod model; +pub mod stack; #[cfg(test)] mod tests; diff --git a/src/nextcloud/model.rs b/src/nextcloud/model.rs index ba0e8f9..4849160 100644 --- a/src/nextcloud/model.rs +++ b/src/nextcloud/model.rs @@ -98,6 +98,7 @@ newtype!( newtype!( NextcloudStackTitle, String, + Display, PartialOrd, Ord, "Title of the Stack" @@ -105,6 +106,7 @@ newtype!( newtype!( NextcloudCardTitle, String, + Display, PartialOrd, Ord, "Title of the Card" diff --git a/src/nextcloud/stack.rs b/src/nextcloud/stack.rs index 26a0e0f..8e04c92 100644 --- a/src/nextcloud/stack.rs +++ b/src/nextcloud/stack.rs @@ -1,19 +1,19 @@ // use crate::{p, FullCtx}; -use super::DeckClient; - pub async fn list(ctx: FullCtx, dump: bool) -> color_eyre::Result<()> { - let dc = DeckClient::new(&ctx.cfg.nextcloud, ctx.net); - let apiresult = dc.get_stacks(ctx.cfg.nextcloud.board_id()).await; + let api_result = ctx + .deck_client() + .get_stacks(ctx.cfg.nextcloud.board_id) + .await; if dump { - p!("{}", apiresult.text); + p!(ctx.prt, "{}", api_result.text); } else { - let mut stacks = apiresult.result?; + let mut stacks = api_result.result?; stacks.sort_by_key(|stack| stack.order); stacks .iter() - .for_each(|stack| p!("{}:{}", stack.id, stack.title)); + .for_each(|stack| p!(ctx.prt, "{}:{}", stack.id, stack.title)); } Ok(()) } diff --git a/src/nextcloud/tests.rs b/src/nextcloud/tests.rs index 4819128..a5f60b4 100644 --- a/src/nextcloud/tests.rs +++ b/src/nextcloud/tests.rs @@ -1,5 +1,6 @@ // use kxio::net::StatusCode; +use pretty_assertions::assert_eq as assert_peq; use crate::{ config::NextcloudConfig, @@ -13,6 +14,8 @@ use crate::{ AppConfig, FullCtx, }; +mod stack; + mod config { use super::*; @@ -32,7 +35,7 @@ mod config { //when //then - assert_eq!(cfg.hostname, hostname); + assert_peq!(cfg.hostname, hostname); } #[test] @@ -51,7 +54,7 @@ mod config { //when //then - assert_eq!(cfg.username, username); + assert_peq!(cfg.username, username); } #[test] @@ -70,7 +73,7 @@ mod config { //when //then - assert_eq!(cfg.password, password); + assert_peq!(cfg.password, password); } #[test] @@ -89,7 +92,7 @@ mod config { //when //then - assert_eq!(cfg.board_id, board_id); + assert_peq!(cfg.board_id, board_id); } } @@ -140,7 +143,7 @@ mod commands { //then let output = prt.output(); - assert_eq!( + assert_peq!( output.trim(), include_str!("../tests/responses/nextcloud-board-list.json").trim() // [""].join("\n") ); @@ -160,7 +163,7 @@ mod commands { //then let output = prt.output(); - assert_eq!( + assert_peq!( output.trim(), [ "4:4 Published: Cossmass Infinities", @@ -173,56 +176,68 @@ mod commands { } } - #[tokio::test] - async fn get_stacks() { - //given - let mock_net = kxio::net::mock(); + mod stack { + use super::*; - mock_net - .on() - .get("https://host-name/index.php/apps/deck/api/v1.0/boards/2/stacks") - .basic_auth("username", Some("password")) - .respond(StatusCode::OK) - .body(include_str!("../tests/responses/nextcloud-stack-list.json")) - .expect("mock request"); + #[tokio::test] + async fn list() { + //given + let mock_net = kxio::net::mock(); - let fs = given::a_filesystem(); - let ctx = given::a_full_context(mock_net, fs); - let deck_client = DeckClient::new(&ctx); + mock_net + .on() + .get("https://host-name/index.php/apps/deck/api/v1.0/boards/2/stacks") + .basic_auth("username", Some("password")) + .respond(StatusCode::OK) + .body(include_str!("../tests/responses/nextcloud-stack-list.json")) + .expect("mock request"); - //when - let result = deck_client - .get_stacks(ctx.cfg.nextcloud.board_id) - .await - .result - .expect("get stacks"); - - assert_eq!( - result, - vec![ - Stack { - id: NextcloudStackId::new(3), - title: NextcloudStackTitle::new("Done"), - order: NextcloudOrder::new(2), - board_id: NextcloudBoardId::new(1), - etag: NextcloudETag::new("97592874d17017ef4f620c9c2a490086") + let fs = given::a_filesystem(); + let ctx = FullCtx { + fs: fs.as_real(), + net: mock_net.into(), + prt: given::a_printer(), + cfg: AppConfig { + trello: given::a_trello_config(), + nextcloud: given::a_nextcloud_config(), }, - Stack { - id: NextcloudStackId::new(2), - title: NextcloudStackTitle::new("Doing"), - order: NextcloudOrder::new(1), - board_id: NextcloudBoardId::new(1), - etag: NextcloudETag::new("3da05f904903c88450b79e4f8f6e2160") - }, - Stack { - id: NextcloudStackId::new(1), - title: NextcloudStackTitle::new("To do"), - order: NextcloudOrder::new(0), - board_id: NextcloudBoardId::new(1), - etag: NextcloudETag::new("b567d287210fa4d9b108ac68d5b087c1") - } - ] - ); + }; + let deck_client = DeckClient::new(&ctx); + + //when + let result = deck_client + .get_stacks(ctx.cfg.nextcloud.board_id) + .await + .result + .expect("get stacks"); + + assert_peq!( + result, + vec![ + Stack { + id: NextcloudStackId::new(3), + title: NextcloudStackTitle::new("Done"), + order: NextcloudOrder::new(2), + board_id: NextcloudBoardId::new(1), + etag: NextcloudETag::new("97592874d17017ef4f620c9c2a490086") + }, + Stack { + id: NextcloudStackId::new(2), + title: NextcloudStackTitle::new("Doing"), + order: NextcloudOrder::new(1), + board_id: NextcloudBoardId::new(1), + etag: NextcloudETag::new("3da05f904903c88450b79e4f8f6e2160") + }, + Stack { + id: NextcloudStackId::new(1), + title: NextcloudStackTitle::new("To do"), + order: NextcloudOrder::new(0), + board_id: NextcloudBoardId::new(1), + etag: NextcloudETag::new("b567d287210fa4d9b108ac68d5b087c1") + } + ] + ); + } } } @@ -246,6 +261,10 @@ mod given { } } + pub fn a_network() -> MockNet { + kxio::net::mock() + } + pub fn a_printer() -> Printer { kxio::print::test() } diff --git a/src/nextcloud/tests/stack/list.rs b/src/nextcloud/tests/stack/list.rs new file mode 100644 index 0000000..f667270 --- /dev/null +++ b/src/nextcloud/tests/stack/list.rs @@ -0,0 +1,69 @@ +// +use super::*; + +#[rstest::fixture] +fn ctx() -> FullCtx { + let fs = given::a_filesystem(); + let nextcloud_config = given::a_nextcloud_config(); + + let mock_net = given::a_network(); + mock_net + .on() + .get(crate::f!( + "https://{}/index.php/apps/deck/api/v1.0/boards/{}/stacks", + nextcloud_config.hostname, + nextcloud_config.board_id + )) + .respond(StatusCode::OK) + .body(include_str!( + "../../../tests/responses/nextcloud-stack-list.json" + )) + .expect("mock request"); + + FullCtx { + fs: fs.as_real(), + net: mock_net.into(), + prt: given::a_printer(), + cfg: AppConfig { + trello: given::a_trello_config(), + nextcloud: nextcloud_config, + }, + } +} + +#[rstest::rstest] +#[test_log::test(tokio::test)] +async fn dump(ctx: FullCtx) { + //given + let prt = ctx.prt.clone(); + let prt = prt.as_test().unwrap(); + + //when + crate::nextcloud::stack::list(ctx, true) + .await + .expect("execute"); + + //then + let output = prt.output(); + assert_peq!( + output.trim(), + include_str!("../../../tests/responses/nextcloud-stack-list.json").trim() + ); +} + +#[rstest::rstest] +#[test_log::test(tokio::test)] +async fn no_dump(ctx: FullCtx) { + //given + let prt = ctx.prt.clone(); + let prt = prt.as_test().unwrap(); + + //when + crate::nextcloud::stack::list(ctx, false) + .await + .expect("execute"); + + //then + let output = prt.output(); + assert_peq!(output.trim(), ["1:To do", "2:Doing", "3:Done"].join("\n")); +} diff --git a/src/nextcloud/tests/stack/mod.rs b/src/nextcloud/tests/stack/mod.rs new file mode 100644 index 0000000..9d06791 --- /dev/null +++ b/src/nextcloud/tests/stack/mod.rs @@ -0,0 +1,4 @@ +// +use super::*; + +mod list;