diff --git a/Cargo.lock b/Cargo.lock index 8b97008..f94ad01 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -99,6 +99,7 @@ name = "memona-plugin-ftp" version = "0.1.2" dependencies = [ "memona-plugin-sdk", + "tokio", ] [[package]] @@ -108,6 +109,12 @@ dependencies = [ "wit-bindgen", ] +[[package]] +name = "pin-project-lite" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd" + [[package]] name = "prettyplease" version = "0.3.0" @@ -195,6 +202,27 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "tokio" +version = "1.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "202caea871b69668250d242070849eb495be178ed697a3e98aebce5bc81a0bed" +dependencies = [ + "pin-project-lite", + "tokio-macros", +] + +[[package]] +name = "tokio-macros" +version = "2.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78773a2a397f451582ce068015985c33193cf6dea8b74d2a639fe457b2f07b0e" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "unicode-ident" version = "1.0.26" diff --git a/Cargo.toml b/Cargo.toml index de78c21..12289e4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,6 +10,9 @@ crate-type = ["cdylib", "rlib"] [dependencies] memona-plugin-sdk = { path = "sdk" } +[dev-dependencies] +tokio = { version = "1", features = ["macros", "rt"] } + [lints] workspace = true diff --git a/src/control.rs b/src/control.rs index 4cfbbba..30ee037 100644 --- a/src/control.rs +++ b/src/control.rs @@ -64,7 +64,9 @@ fn names_a_conflict(text: &str) -> bool { .collect(); words.contains(&"exists") || words.contains(&"nonempty") - || words.windows(2).any(|pair| matches!(pair, ["not" | "non", "empty"])) + || words + .windows(2) + .any(|pair| matches!(pair, ["not" | "non", "empty"])) } /// What the first reply to a transfer command means. A transfer answers with @@ -255,7 +257,10 @@ mod tests { )); // The same two conditions as other servers phrase them. assert!(matches!( - refusal(550, "550 Cannot create a file when that file already exists."), + refusal( + 550, + "550 Cannot create a file when that file already exists." + ), Err(ErrorCode::Conflict) )); assert!(matches!( diff --git a/src/lib.rs b/src/lib.rs index 0d3be11..3eb4ad2 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -31,10 +31,11 @@ struct Ftp; fn text(setting: Option<&Setting>) -> Option { match setting { - Some(Setting::Text(value)) | Some(Setting::Secret(value)) => { + Some(Setting::Text(value)) => { let value = value.trim().to_owned(); (!value.is_empty()).then_some(value) } + Some(Setting::Secret(value)) => Some(value.clone()), Some(Setting::Toggle(_)) | None => None, } } @@ -394,3 +395,24 @@ impl Guest for Ftp { } memona_plugin_sdk::export!(Ftp); + +#[cfg(test)] +mod tests { + use super::text; + use memona_plugin_sdk::Setting; + + #[tokio::test] + async fn secret_credentials_preserve_significant_whitespace() { + for password in [" ftp fixture secret ", " ", ""] { + assert_eq!( + text(Some(&Setting::Secret(password.to_owned()))), + Some(password.to_owned()) + ); + } + assert_eq!( + text(Some(&Setting::Text(" server.example ".to_owned()))), + Some("server.example".to_owned()) + ); + assert_eq!(text(Some(&Setting::Text(" ".to_owned()))), None); + } +} diff --git a/src/listing.rs b/src/listing.rs index 607dc82..badf192 100644 --- a/src/listing.rs +++ b/src/listing.rs @@ -12,7 +12,6 @@ struct Facts<'a> { fn facts(line: &str) -> Option> { let (facts, name) = line.split_once(' ')?; - let name = name.trim(); if name.is_empty() { return None; } @@ -106,6 +105,21 @@ mod tests { use super::{machine_entry, machine_info, page}; use memona_plugin_sdk::{EntryKind, ErrorCode}; + #[tokio::test] + async fn listing_names_preserve_significant_whitespace() + -> Result<(), ErrorCode> { + let listing = b"type=file;size=1; report.md \r\ntype=dir; spaced folder \r\ntype=file;size=2; \r\n"; + let listed = page(listing, 0, 10)?; + let names: Vec<&str> = listed + .entries + .iter() + .map(|entry| entry.name.as_str()) + .collect(); + assert_eq!(names, [" report.md ", " spaced folder ", " "]); + assert!(listed.cursor.is_none()); + Ok(()) + } + #[test] fn reads_kind_and_size_and_skips_the_directory_itself() -> Result<(), &'static str> {