use crate::NewsFlash;
use crate::config::{Config, ConfigHandlerExt, MockConfigHandlerExt};
use crate::feed_api::{FeedApi, MockFeedApi};
use crate::feed_api_implementations::local::metadata::LocalMetadata;
use crate::models::{Category, CategoryID, Feed, FeedID, NEWSFLASH_TOPLEVEL, Url};
use reqwest::Client;
use test_log::test;
fn mock_config() -> Box<dyn ConfigHandlerExt> {
let mut config_mock = Box::new(MockConfigHandlerExt::new());
config_mock.expect_load().returning(|_path| Ok(Config::default()));
config_mock
}
fn mock_api() -> Box<dyn FeedApi> {
let mut api = Box::new(MockFeedApi::new());
api.expect_is_logged_in().returning(|_client| Ok(true));
api.expect_add_category().returning(|_title, _parent, _client| {
let uuid = uuid::Uuid::new_v4();
Ok(CategoryID::from_owned(uuid.to_string()))
});
api.expect_add_feed().returning(|url, title, category_id, _client| {
let feed = Feed {
feed_id: FeedID::new(url.as_str()),
label: title.as_deref().unwrap_or("title").to_string(),
website: None,
feed_url: Some(url.clone()),
icon_url: None,
error_count: 0,
error_message: None,
};
let category = category_id.map(|category_id| Category {
category_id,
label: "parent".to_string(),
});
Ok((feed, category))
});
api.expect_remove_category().returning(|_id, _remove_children, _client| Ok(()));
api
}
fn build_news_flash(dir: &str) -> NewsFlash {
if std::fs::exists(dir).unwrap() {
std::fs::remove_dir_all(dir).unwrap();
}
let config_mock = mock_config();
let api = mock_api();
NewsFlash::builder()
.plugin(LocalMetadata::get_id())
.data_dir(dir)
.config_dir(dir)
.config_handler(config_mock)
.api_mock(api)
.create()
.unwrap()
}
#[test(tokio::test)]
async fn remove_category_recursive() {
let client = Client::new();
let news_flash = build_news_flash("./test-output/remove_category_recursive");
let (category_test, _mapping) = news_flash.add_category("test", None, &client).await.unwrap();
let (category_sub, _mapping) = news_flash.add_category("sub", Some(&category_test.category_id), &client).await.unwrap();
let (feed, _feed_mapping, _parent, _parent_mapping) = news_flash
.add_feed(
&Url::parse("https://example.com/feed").unwrap(),
Some("feed1".to_string()),
Some(category_sub.category_id),
&client,
)
.await
.unwrap();
let (feeds, _mappings) = news_flash.get_feeds().unwrap();
assert_eq!(feeds.len(), 1);
assert_eq!(feeds.first().unwrap().feed_id, feed.feed_id);
news_flash.remove_category(&category_test.category_id, true, &client).await.unwrap();
let (categories, mappings) = news_flash.get_categories().unwrap();
let (feeds, _mappings) = news_flash.get_feeds().unwrap();
tracing::debug!(?categories);
tracing::debug!(?mappings);
assert!(categories.is_empty());
assert!(mappings.is_empty());
assert!(feeds.is_empty());
}
#[test(tokio::test)]
async fn remove_category_keep_children() {
let client = Client::new();
let news_flash = build_news_flash("./test-output/remove_category_keep_children");
let (category_test, _mapping) = news_flash.add_category("test", None, &client).await.unwrap();
let (category_sub, _mapping) = news_flash.add_category("sub", Some(&category_test.category_id), &client).await.unwrap();
let (feed, _feed_mapping, _parent, _parent_mapping) = news_flash
.add_feed(
&Url::parse("https://example.com/feed").unwrap(),
Some("feed1".to_string()),
Some(category_sub.category_id.clone()),
&client,
)
.await
.unwrap();
news_flash.remove_category(&category_test.category_id, false, &client).await.unwrap();
let (categories, category_mappings) = news_flash.get_categories().unwrap();
let (feeds, feed_mappings) = news_flash.get_feeds().unwrap();
tracing::debug!(?categories);
tracing::debug!(?category_mappings);
assert_eq!(categories.len(), 1);
assert_eq!(category_mappings.len(), 1);
assert_eq!(feeds.len(), 1);
assert_eq!(categories.first().unwrap().category_id, category_sub.category_id);
assert_eq!(category_mappings.first().unwrap().category_id, category_sub.category_id);
assert_eq!(category_mappings.first().unwrap().parent_id, *NEWSFLASH_TOPLEVEL);
assert_eq!(feeds.first().unwrap().feed_id, feed.feed_id);
assert_eq!(feed_mappings.first().unwrap().feed_id, feed.feed_id);
assert_eq!(feed_mappings.first().unwrap().category_id, category_sub.category_id);
}
#[test(tokio::test)]
async fn add_multiple_categories_with_same_name() {
let client = Client::new();
let news_flash = build_news_flash("./test-output/add_multiple_categories_with_same_name");
let (category_test, _mapping) = news_flash.add_category("test", None, &client).await.unwrap();
let (category_sub, _mapping) = news_flash.add_category("sub", Some(&category_test.category_id), &client).await.unwrap();
let (category_sub_test, _mapping) = news_flash.add_category("test", Some(&category_sub.category_id), &client).await.unwrap();
let (categories, mappings) = news_flash.get_categories().unwrap();
tracing::debug!(?categories);
tracing::debug!(?mappings);
assert_eq!(categories.len(), 3);
assert_eq!(mappings.len(), 3);
assert_eq!(mappings.first().unwrap().category_id, category_test.category_id);
assert_eq!(mappings.first().unwrap().parent_id, *NEWSFLASH_TOPLEVEL);
assert_eq!(mappings.get(1).unwrap().category_id, category_sub.category_id);
assert_eq!(mappings.get(1).unwrap().parent_id, category_test.category_id);
assert_eq!(mappings.get(2).unwrap().category_id, category_sub_test.category_id);
assert_eq!(mappings.get(2).unwrap().parent_id, category_sub.category_id);
}