From 9057adddc33db71dfb91dad9618f87f20b67f33f Mon Sep 17 00:00:00 2001 From: Paul Campbell Date: Fri, 28 Jul 2023 18:35:41 +0100 Subject: [PATCH] i5-add-tests (part 2) (#7) closes kemitix/podal#5 Reviewed-on: https://git.kemitix.net/kemitix/podal/pulls/7 Co-authored-by: Paul Campbell Co-committed-by: Paul Campbell --- src/feed/find.rs | 45 ++++++++++++++-- src/feed/get.rs | 6 +-- src/feed/mod.rs | 12 +++-- src/fetch.rs | 12 +++++ src/history/add.rs | 72 ++++++++++++++++++++++++++ src/history/find.rs | 83 ++++++++++++++++++++++++++++++ src/history/mod.rs | 5 ++ src/lib.rs | 36 ++++++------- src/main.rs | 22 ++++++-- src/subscriptions.rs | 20 ++----- src/test_utils.rs | 25 +++++++++ test/data/downloads.txt | 2 + test/data/empty.txt | 0 test/data/with-embedded-llamma.txt | 3 ++ test/data/with-llamma.txt | 3 ++ test/data/without-llamma.txt | 2 + 16 files changed, 300 insertions(+), 48 deletions(-) create mode 100644 src/test_utils.rs create mode 100644 test/data/downloads.txt create mode 100644 test/data/empty.txt create mode 100644 test/data/with-embedded-llamma.txt create mode 100644 test/data/with-llamma.txt create mode 100644 test/data/without-llamma.txt diff --git a/src/feed/find.rs b/src/feed/find.rs index b735e05..f37ce84 100644 --- a/src/feed/find.rs +++ b/src/feed/find.rs @@ -1,14 +1,16 @@ use crate::prelude::*; -pub fn find(site: &str, channel_name: &str) -> Result { +use crate::fetch::FetchGet; + +pub fn find(site: &str, channel_name: &str, e: &FetchGet) -> Result { if let Some(channel_prefix) = channel_name.chars().next() { if channel_prefix != '@' { return Err(format!("Channel Name must begin with an '@': {}", channel_name).into()); } } let channel_url = format!("{}{}", site, channel_name); - let response = reqwest::blocking::get(channel_url)?; - let rss_url = scraper::Html::parse_document(&response.text()?) + let response = (e)(&channel_url)?; + let rss_url = scraper::Html::parse_document(&response) .select(&scraper::Selector::parse("link[title='RSS']").unwrap()) .next() .unwrap() @@ -18,3 +20,40 @@ pub fn find(site: &str, channel_name: &str) -> Result { .to_string(); Ok(rss_url) } + +#[cfg(test)] +mod tests { + use crate::fetch::Response; + + use super::*; + #[test] + fn finds_rss_url() -> Result<()> { + //given + let fetch_get = &(get as FetchGet); + //when + let result = find("site", "@channel", fetch_get)?; + //then + assert_eq!(result, "the-rss-url"); + Ok(()) + } + + #[test] + fn error_if_channel_name_is_invalid() -> Result<()> { + //given + let fetch_get = &(get as FetchGet); + //when + let result = find("site", "invalid-channel-name", fetch_get); + //then + assert!(result.is_err()); + Ok(()) + } + + fn get(_url: &str) -> Result { + Ok(r#" + + + + "# + .to_string()) + } +} diff --git a/src/feed/get.rs b/src/feed/get.rs index dad28b0..1a7ea40 100644 --- a/src/feed/get.rs +++ b/src/feed/get.rs @@ -1,8 +1,8 @@ -use atom_syndication::Feed; - use crate::prelude::*; -pub fn get(url: &str) -> Result { +use atom_syndication::Feed; + +pub fn reqwest_blocking_get(url: &str) -> Result { let content = reqwest::blocking::get(url)?.bytes()?; let channel = Feed::read_from(&content[..])?; Ok(channel) diff --git a/src/feed/mod.rs b/src/feed/mod.rs index 8b43067..253bf26 100644 --- a/src/feed/mod.rs +++ b/src/feed/mod.rs @@ -1,12 +1,18 @@ use crate::prelude::*; +use crate::fetch::FetchGet; + mod find; mod get; +use atom_syndication::Feed; pub use find::find; -pub use get::get; +pub use get::reqwest_blocking_get; -type Feed = atom_syndication::Feed; +pub struct FeedEnv { + pub find: FeedFind, + pub get: FeedGet, +} -pub type FeedFind = fn(&str, &str) -> Result; +pub type FeedFind = fn(&str, &str, &FetchGet) -> Result; pub type FeedGet = fn(&str) -> Result; diff --git a/src/fetch.rs b/src/fetch.rs index 1f95f96..b0d47fd 100644 --- a/src/fetch.rs +++ b/src/fetch.rs @@ -3,7 +3,13 @@ use crate::prelude::*; use atom_syndication::Link; use std::process::Command; +pub struct FetchEnv { + pub download: FetchDownload, + pub get: FetchGet, +} + pub type FetchDownload = fn(&Link) -> Result<()>; +pub type FetchGet = fn(&str) -> Result; pub fn download(link: &Link) -> Result<()> { let cmd = "yt-dlp"; @@ -20,3 +26,9 @@ pub fn download(link: &Link) -> Result<()> { } Ok(()) } + +pub type Response = String; + +pub fn get(url: &str) -> Result { + Ok(reqwest::blocking::get(url)?.text()?) +} diff --git a/src/history/add.rs b/src/history/add.rs index e904004..756edf2 100644 --- a/src/history/add.rs +++ b/src/history/add.rs @@ -15,3 +15,75 @@ pub fn add(link: &Link, file_name: &str) -> Result<()> { writeln!(file, "{}", link.href)?; Ok(()) } + +#[cfg(test)] +mod tests { + + use crate::{ + history::Link, + test_utils::{create_text_file, read_text_file}, + }; + + use super::*; + + #[test] + fn creates_file_if_missing() -> Result<()> { + //given + let (dir, file_name) = + create_text_file("download.txt", include_bytes!("../../test/data/empty.txt"))?; + std::fs::remove_file(&file_name)?; + + let link = Link { + href: "foo".to_string(), + rel: "bar".to_string(), + hreflang: None, + mime_type: None, + title: None, + length: None, + }; + //when + add(&link, &file_name)?; + + //then + let content: Vec = read_text_file(&file_name)?; + drop(dir); + + let expected = vec!["foo".to_string()]; + assert_eq!(content, expected); + + Ok(()) + } + + #[test] + fn appends_to_exising_file() -> Result<()> { + // given + let (dir, file_name) = create_text_file( + "download.txt", + include_bytes!("../../test/data/downloads.txt"), + )?; + + let link = Link { + href: "foo".to_string(), + rel: "bar".to_string(), + hreflang: None, + mime_type: None, + title: None, + length: None, + }; + //when + add(&link, &file_name)?; + + //then + let content: Vec = read_text_file(&file_name)?; + drop(dir); + + let expected = vec![ + "line-1".to_string(), + "line-2".to_string(), + "foo".to_string(), + ]; + assert_eq!(content, expected); + + Ok(()) + } +} diff --git a/src/history/find.rs b/src/history/find.rs index 5b760b8..c1dd584 100644 --- a/src/history/find.rs +++ b/src/history/find.rs @@ -15,3 +15,86 @@ pub fn find(link: &Link, file_name: &str) -> Result { } Ok(false) // is not already downloaded } + +#[cfg(test)] +mod test { + use crate::{history::Link, test_utils::create_text_file}; + + use super::*; + #[test] + fn true_if_line_exists() -> Result<()> { + //given + let (dir, file_name) = + create_text_file("file", include_bytes!("../../test/data/with-llamma.txt"))?; + let link = Link { + href: "llamma".to_string(), + rel: "".to_string(), + hreflang: None, + mime_type: None, + title: None, + length: None, + }; + + //when + let result = find(&link, &file_name)?; + + //then + drop(dir); + + assert_eq!(result, true); + + Ok(()) + } + + #[test] + fn false_if_line_absent() -> Result<()> { + //given + let (dir, file_name) = + create_text_file("file", include_bytes!("../../test/data/without-llamma.txt"))?; + let link = Link { + href: "llamma".to_string(), + rel: "".to_string(), + hreflang: None, + mime_type: None, + title: None, + length: None, + }; + + //when + let result = find(&link, &file_name)?; + + //then + drop(dir); + + assert_eq!(result, false); + + Ok(()) + } + + #[test] + fn false_if_embedded_within_line() -> Result<()> { + //given + let (dir, file_name) = create_text_file( + "file", + include_bytes!("../../test/data/with-embedded-llamma.txt"), + )?; + let link = Link { + href: "llamma".to_string(), + rel: "".to_string(), + hreflang: None, + mime_type: None, + title: None, + length: None, + }; + + //when + let result = find(&link, &file_name)?; + + //then + drop(dir); + + assert_eq!(result, false); + + Ok(()) + } +} diff --git a/src/history/mod.rs b/src/history/mod.rs index e36428d..d6f7255 100644 --- a/src/history/mod.rs +++ b/src/history/mod.rs @@ -8,5 +8,10 @@ pub use find::find; type Link = atom_syndication::Link; +pub struct HistoryEnv { + pub find: HistoryFind, + pub add: HistoryAdd, +} + pub type HistoryFind = fn(&Link, &str) -> Result; pub type HistoryAdd = fn(&Link, &str) -> Result<()>; diff --git a/src/lib.rs b/src/lib.rs index ee239ca..ce77f4d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -5,30 +5,30 @@ pub mod history; pub mod prelude; mod subscriptions; -use feed::{FeedFind, FeedGet}; -use fetch::FetchDownload; -use history::{HistoryAdd, HistoryFind}; +#[cfg(test)] +mod test_utils; + +use feed::FeedEnv; +use fetch::FetchEnv; +use history::HistoryEnv; use prelude::*; -pub fn run( - subscriptions: &str, - history: &str, - site: &str, - feed_find: FeedFind, - feed_get: FeedGet, - history_find: HistoryFind, - history_add: HistoryAdd, - fetch_download: FetchDownload, -) -> Result<()> { +pub struct Env { + pub feed: FeedEnv, + pub history: HistoryEnv, + pub fetch: FetchEnv, +} + +pub fn run(subscriptions: &str, history: &str, site: &str, e: Env) -> Result<()> { for channel_name in subscriptions::lines_from(subscriptions)? { println!("Channel: {}", channel_name); - let feed_url = feed_find(site, &channel_name)?; - for entry in feed_get(&feed_url)?.entries() { + let feed_url = (e.feed.find)(site, &channel_name, &e.fetch.get)?; + for entry in (e.feed.get)(&feed_url)?.entries() { if let Some(link) = entry.links().get(0).cloned() { - if !history_find(&link, history)? { + if !(e.history.find)(&link, history)? { println!("Downloading {}: {}", &channel_name, entry.title().as_str()); - fetch_download(&link)?; - history_add(&link, history)?; + (e.fetch.download)(&link)?; + (e.history.add)(&link, history)?; } } } diff --git a/src/main.rs b/src/main.rs index 3e4a741..8e7f6c5 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,5 +1,7 @@ use podal::prelude::*; +use podal::{feed::FeedEnv, fetch::FetchEnv, history::HistoryEnv}; + fn main() -> Result<()> { println!("Podal"); let subscriptions = "subscriptions.txt"; @@ -10,11 +12,21 @@ fn main() -> Result<()> { subscriptions, history, site, - podal::feed::find, - podal::feed::get, - podal::history::find, - podal::history::add, - podal::fetch::download, + podal::Env { + feed: FeedEnv { + find: podal::feed::find, + get: podal::feed::reqwest_blocking_get, + }, + + history: HistoryEnv { + find: podal::history::find, + add: podal::history::add, + }, + fetch: FetchEnv { + download: podal::fetch::download, + get: podal::fetch::get, + }, + }, )?; println!("Done"); diff --git a/src/subscriptions.rs b/src/subscriptions.rs index 5e5a955..5ecc379 100644 --- a/src/subscriptions.rs +++ b/src/subscriptions.rs @@ -7,11 +7,9 @@ pub fn lines_from(file_name: &str) -> Result> { let file = File::open(file_name)?; let reader = BufReader::new(file); let mut lines = vec![]; - for line in reader.lines() { - if let Ok(line) = line { - if line.starts_with('@') { - lines.push(line); - } + for line in reader.lines().flatten() { + if line.starts_with('@') { + lines.push(line); } } Ok(lines) @@ -19,9 +17,8 @@ pub fn lines_from(file_name: &str) -> Result> { #[cfg(test)] mod tests { - use std::{fs::File, io::Write, str::from_utf8}; - use tempfile::{tempdir, TempDir}; + use crate::test_utils::create_text_file; use super::*; @@ -75,13 +72,4 @@ mod tests { assert_eq!(result, ["@sub1", "@sub3"]); Ok(()) } - - fn create_text_file(name: &str, data: &[u8]) -> Result<(TempDir, String)> { - let data = from_utf8(data)?; - let dir = tempdir()?; - let filename = format!("{}", &dir.path().join(name).display()); - let file = File::create(&filename)?; - write!(&file, "{data}")?; - Ok((dir, filename)) - } } diff --git a/src/test_utils.rs b/src/test_utils.rs new file mode 100644 index 0000000..305ae44 --- /dev/null +++ b/src/test_utils.rs @@ -0,0 +1,25 @@ +use std::{ + fs::{read_to_string, File}, + io::Write, + str::from_utf8, +}; + +use tempfile::{tempdir, TempDir}; + +use crate::prelude::*; + +pub fn create_text_file(name: &str, data: &[u8]) -> Result<(TempDir, String)> { + let data = from_utf8(data)?; + let dir = tempdir()?; + let filename = format!("{}", &dir.path().join(name).display()); + let file = File::create(&filename)?; + write!(&file, "{data}")?; + Ok((dir, filename)) +} + +pub fn read_text_file(file_name: &str) -> Result> { + Ok(read_to_string(file_name)? + .lines() + .map(String::from) + .collect()) +} diff --git a/test/data/downloads.txt b/test/data/downloads.txt new file mode 100644 index 0000000..1f26067 --- /dev/null +++ b/test/data/downloads.txt @@ -0,0 +1,2 @@ +line-1 +line-2 diff --git a/test/data/empty.txt b/test/data/empty.txt new file mode 100644 index 0000000..e69de29 diff --git a/test/data/with-embedded-llamma.txt b/test/data/with-embedded-llamma.txt new file mode 100644 index 0000000..3574d2b --- /dev/null +++ b/test/data/with-embedded-llamma.txt @@ -0,0 +1,3 @@ +this is a text file +embedded llamma +it has three lines diff --git a/test/data/with-llamma.txt b/test/data/with-llamma.txt new file mode 100644 index 0000000..cad2d82 --- /dev/null +++ b/test/data/with-llamma.txt @@ -0,0 +1,3 @@ +this is a text file +llamma +it has three lines diff --git a/test/data/without-llamma.txt b/test/data/without-llamma.txt new file mode 100644 index 0000000..61a0ef5 --- /dev/null +++ b/test/data/without-llamma.txt @@ -0,0 +1,2 @@ +this is a text file +it has three lines