From 440929621556cc3e3f1e2beaf4938ae5c3210663 Mon Sep 17 00:00:00 2001 From: Zev Averbach Date: Tue, 30 May 2023 08:01:37 +0200 Subject: [PATCH] validate_url is implemented and tested --- Cargo.lock | 35 ++++++++++++++++++++++++++ Cargo.toml | 1 + src/main.rs | 71 ++++++++++++++++++++++++++++++++++++++++++++++------- 3 files changed, 98 insertions(+), 9 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 15effcb..33f31d8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,6 +2,41 @@ # It is not intended for manual editing. version = 3 +[[package]] +name = "aho-corasick" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67fc08ce920c31afb70f013dcce1bfc3a3195de6a228474e45e1f145b36f8d04" +dependencies = [ + "memchr", +] + [[package]] name = "blargh" version = "0.1.0" +dependencies = [ + "regex", +] + +[[package]] +name = "memchr" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" + +[[package]] +name = "regex" +version = "1.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81ca098a9821bd52d6b24fd8b10bd081f47d39c22778cafaa75a2857a62c6390" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "436b050e76ed2903236f032a59761c1eb99e1b0aead2c257922771dab1fc8c78" diff --git a/Cargo.toml b/Cargo.toml index 3462ec6..e77b37f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,3 +4,4 @@ version = "0.1.0" edition = "2021" [dependencies] +regex = "1.8.3" diff --git a/src/main.rs b/src/main.rs index ee28ca5..6b896fb 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,23 +1,34 @@ // TODO: blog drafts (list) use std::env::{args, var}; +use std::io::stdin; use std::path::Path; use std::process::{exit, Command}; -use std::io::stdin; + +use regex::Regex; const SUBCOMMANDS: [&str; 1] = ["new"]; fn main() { let args: Vec = args().collect(); validate_args(&args); - let subcommand = &args[1]; + let handle = get_handler(&args); + handle(args); +} - if subcommand == "new" { - handle_new(args); - exit(0); +fn get_handler(args: &Vec) -> fn(Vec) { + match args[1].as_str() { + "new" => handle_new, + _ => no_match_in_handler, } } +fn no_match_in_handler(args: Vec) { + eprintln!("no match in handler for subcommand {}", args[1]); + exit(1); +} + fn create_markdown_file_and_open_in_editor(url: String) { + // TODO: make this a const let editor: String = var("EDITOR").expect("Please set the EDITOR environment variable"); println!("create_markdown_file_and_open_in_editor"); } @@ -30,14 +41,19 @@ fn convert_to_html_and_preview_and_push_to_bucket(markdown_filepath: String) { println!("convert_to_html_and_preview_and_push_to_bucket"); } -fn validate_url(url: &String) { - // is it in an allowed form? +fn validate_url(url: &String) -> Result<&str, &str>{ + let valid_url = Regex::new("^\\b([-a-zA-Z0-9@:%._\\+~#?&//=]*)$").unwrap(); + if valid_url.is_match(url) { + return Ok("valid URL") + } + Err("invalid URL") } fn handle_new(args: Vec) { let mut is_markdown = false; let mut url = String::new(); let mut url_or_fn = String::new(); + if args.len() == 2 { println!("what do you want the blog post's URL to be?"); match stdin().read_line(&mut url) { @@ -60,10 +76,16 @@ fn handle_new(args: Vec) { } }; let url = url.trim().to_string(); - validate_url(&url); + match validate_url(&url) { + Err(_) => { + eprintln!("please provide either a url or a markdown filepath"); + exit(1); + }, + Ok(_) => (), + }; match url_exists(&url) { "draft" => { - eprintln!("this URL already exists! do \"blog edit {url}\" to edit it or \"blog publish {url}\" to publish it"); + eprintln!("this URL already exists! do `blog edit {url}` to edit it or `blog publish {url}` to publish it"); exit(1); }, "published" => { @@ -97,3 +119,34 @@ fn validate_args(args: &Vec) { exit(1); } } + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn validate_url_ok() { + let url = "mygreatblogpost".to_string(); + assert!(validate_url(&url).is_ok()); + let url = "my-great-blogpost".to_string(); + assert!(validate_url(&url).is_ok()); + let url = "my%20great-blogpost".to_string(); + assert!(validate_url(&url).is_ok()); + let url = "my%0Agreat-blogpost".to_string(); + assert!(validate_url(&url).is_ok()); + let url = "/posts/my%0Agreat-blogpost".to_string(); + assert!(validate_url(&url).is_ok()); + } + + #[test] + fn validate_url_is_err() { + let url = "my>-great-blogpost".to_string(); + assert!(validate_url(&url).is_err()); + let url = "my[-]great-blogpost".to_string(); + assert!(validate_url(&url).is_err()); + let url = "my-great-blogpost*".to_string(); + assert!(validate_url(&url).is_err()); + } + + // more tests... +}