diff --git a/config.rs b/config.rs new file mode 100644 index 0000000..0fa7025 --- /dev/null +++ b/config.rs @@ -0,0 +1,35 @@ +use scootaloo::parse_toml; + +#[test] +fn parse_good_toml() { + let tConfig = TwitterConfig { + username: "test", + consumer_key: "foo", + consumer_secret: "bar", + access_key: "secret", + access_secret: "super secret", + }; + + let mConfig = MastodonConfig { + base: "https://www.example.com", + client_id: "my_id", + client_secret: "this is secret", + redirect: "ooo:oooo:o", + token: "super secret", + }; + + let sConfig = ScootalooConfig { + db_path: "/tmp/scootaloo/scootaloo.db", + cache_path: "/tmp", + }; + + let test_config = Config { + twitter: tConfig, + mastodon: mConfig, + scootaloo: sConfig, + }; + + let parsed_config = parse_toml("tests/right_config.toml"); + + assert_eq!(parsed_config, test_config); +} diff --git a/src/lib.rs b/src/lib.rs index c2b2e9d..643ffd5 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,6 +1,6 @@ // auto-imports mod error; -use error::ScootalooError; +use crate::error::ScootalooError; mod config; use config::Config; diff --git a/src/main.rs b/src/main.rs index 77bb07d..e700c1e 100644 --- a/src/main.rs +++ b/src/main.rs @@ -61,7 +61,7 @@ fn main() { }, ("init", Some(sub_m)) => { let config = parse_toml(sub_m.value_of("config").unwrap_or(DEFAULT_CONFIG_PATH)); - init_db(&config).unwrap(); + init_db(&config.scootaloo).unwrap(); return; }, _ => (), diff --git a/src/mastodon.rs b/src/mastodon.rs index 3f93e9d..d81a963 100644 --- a/src/mastodon.rs +++ b/src/mastodon.rs @@ -1,6 +1,5 @@ // auto imports use crate::config::MastodonConfig; -use crate::twitter::decode_urls; // std use std::{ @@ -16,7 +15,7 @@ use htmlescape::decode_html; // egg-mode use egg_mode::{ tweet::Tweet, - entities::MentionEntity, + entities::{UrlEntity, MentionEntity}, }; // elefren @@ -39,6 +38,20 @@ fn twitter_mentions(ums: &Vec) -> HashMap { decoded_mentions } +/// Decodes urls from UrlEntities +fn decode_urls(urls: &Vec) -> HashMap { + let mut decoded_urls = HashMap::new(); + + for url in urls { + if url.expanded_url.is_some() { + // unwrap is safe here as we just verified that there is something inside expanded_url + decoded_urls.insert(String::from(&url.url), String::from(url.expanded_url.as_deref().unwrap())); + } + } + + decoded_urls +} + /// Gets Mastodon Data pub fn get_mastodon_token(masto: &MastodonConfig) -> Mastodon { let data = Data { @@ -104,3 +117,52 @@ pub fn register(host: &str) { println!("Please insert the following block at the end of your configuration file:\n[mastodon]\n{}", toml); } +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_twitter_mentions() { + let mention_entity = MentionEntity { + id: 12345, + range: (1, 3), + name: String::from("Ta Mere l0l"), + screen_name: String::from("tamerelol"), + }; + + let twitter_ums = vec![mention_entity]; + + let mut expected_mentions = HashMap::new(); + expected_mentions.insert(String::from("@tamerelol"), String::from("@tamerelol@twitter.com")); + + let decoded_mentions = twitter_mentions(&twitter_ums); + + assert_eq!(expected_mentions, decoded_mentions); + } + + #[test] + fn test_decode_urls() { + let url_entity1 = UrlEntity { + display_url: String::from("tamerelol"), + expanded_url: Some(String::from("https://www.nintendojo.fr/dojobar")), + range: (1, 3), + url: String::from("https://t.me/tamerelol"), + }; + + let url_entity2 = UrlEntity { + display_url: String::from("tamerelol"), + expanded_url: None, + range: (1, 3), + url: String::from("https://t.me/tamerelol"), + }; + + let twitter_urls = vec![url_entity1, url_entity2]; + + let mut expected_urls = HashMap::new(); + expected_urls.insert(String::from("https://t.me/tamerelol"), String::from("https://www.nintendojo.fr/dojobar")); + + let decoded_urls = decode_urls(&twitter_urls); + + assert_eq!(expected_urls, decoded_urls); + } +} diff --git a/src/state.rs b/src/state.rs index bc9f482..42b2f16 100644 --- a/src/state.rs +++ b/src/state.rs @@ -1,5 +1,5 @@ // auto-imports -use crate::config::Config; +use crate::config::ScootalooConfig; // std use std::{ @@ -10,6 +10,9 @@ use std::{ // log use log::debug; +// rusqlite +use rusqlite::{Connection, OpenFlags, params}; + /// Reads last tweet id from a file pub fn read_state(s: &str) -> Option { let state = read_to_string(s); @@ -31,8 +34,68 @@ pub fn write_state(f: &str, s: u64) -> Result<(), std::io::Error> { * Main functions *********/ /// Initiates the DB from path -pub fn init_db(config: &Config) -> Result<(), Box> { - println!("config.scootaloo.db_path: {}", config.scootaloo.db_path); +pub fn init_db(config: &ScootalooConfig) -> Result<(), Box> { + let conn = Connection::open(&config.db_path)?; + + conn.execute( + "CREATE TABLE IF NOT EXISTS tweet_to_toot ( + tweet_id INTEGER PRIMARY KEY, + toot_id TEXT UNIQUE + )", + [], + )?; + Ok(()) } +#[cfg(test)] +mod tests { + use super::*; + use std::{ + fs::remove_file, + path::Path, + }; + + #[test] + fn test_init_db() { + let scootaloo_config = ScootalooConfig { + db_path: String::from("/tmp/test_init_db.sqlite"), + cache_path: String::from("/tmp/scootaloo"), + }; + + init_db(&scootaloo_config).unwrap(); + + // check that file exist + assert!(Path::new(&scootaloo_config.db_path).exists()); + + // open said file + let conn = Connection::open_with_flags(&scootaloo_config.db_path, OpenFlags::SQLITE_OPEN_READ_ONLY).unwrap(); + + conn.execute( + "SELECT * from tweet_to_toot;", + [], + ).unwrap(); + + conn.close().unwrap(); + remove_file(&scootaloo_config.db_path).unwrap(); + } + + #[test] + fn test_read_state() { + let scootaloo_config = ScootalooConfig { + db_path: String::from("/tmp/test_read_state.sqlite"), + cache_path: String::from("/tmp/scootaloo"), + }; + + init_db(&scootaloo_config).unwrap(); + + let conn = Connection::open(&scootaloo_config.db_path).unwrap(); + + conn.execute( + "INSERT INTO tweet_to_toot (tweet_id, toot_id) VALUES (?1, ?2)", + params![123456789 as u64, String::from("987654321")], + ).unwrap(); + + + } +} diff --git a/src/twitter.rs b/src/twitter.rs index f44c071..5821bb0 100644 --- a/src/twitter.rs +++ b/src/twitter.rs @@ -4,16 +4,13 @@ use crate::config::TwitterConfig; use crate::util::cache_media; // std -use std::{ - error::Error, - collections::HashMap, -}; +use std::error::Error; // egg-mode use egg_mode::{ Token, KeyPair, - entities::{UrlEntity, MediaEntity, MediaType}, + entities::{MediaEntity, MediaType}, user::UserID, tweet::{ Tweet, @@ -43,20 +40,6 @@ pub async fn get_user_timeline(config: &TwitterConfig, token: Token, lid: Option Ok(feed.to_vec()) } -/// Decodes urls from UrlEntities -pub fn decode_urls(urls: &Vec) -> HashMap { - let mut decoded_urls = HashMap::new(); - - for url in urls { - if url.expanded_url.is_some() { - // unwrap is safe here as we just verified that there is something inside expanded_url - decoded_urls.insert(String::from(&url.url), String::from(url.expanded_url.as_deref().unwrap())); - } - } - - decoded_urls -} - /// Retrieves a single media from a tweet and store it in a temporary file pub async fn get_tweet_media(m: &MediaEntity, t: &str) -> Result> { match m.media_type { diff --git a/tests/bad_test.toml b/tests/bad_test.toml new file mode 100644 index 0000000..907b308 --- /dev/null +++ b/tests/bad_test.toml @@ -0,0 +1 @@ +blah diff --git a/tests/config.rs b/tests/config.rs new file mode 100644 index 0000000..ce1e1a7 --- /dev/null +++ b/tests/config.rs @@ -0,0 +1,33 @@ +use scootaloo::parse_toml; + +#[test] +fn test_parse_good_toml() { + let parse_good_toml = parse_toml("tests/good_test.toml"); + + assert_eq!(parse_good_toml.scootaloo.db_path, "/var/random/scootaloo.sqlite"); + assert_eq!(parse_good_toml.scootaloo.cache_path, "/tmp/scootaloo"); + + assert_eq!(parse_good_toml.twitter.username, "tamerelol"); + assert_eq!(parse_good_toml.twitter.consumer_key, "rand consumer key"); + assert_eq!(parse_good_toml.twitter.consumer_secret, "secret"); + assert_eq!(parse_good_toml.twitter.access_key, "rand access key"); + assert_eq!(parse_good_toml.twitter.access_secret, "super secret"); + + assert_eq!(parse_good_toml.mastodon.base, "https://m.nintendojo.fr"); + assert_eq!(parse_good_toml.mastodon.client_id, "rand client id"); + assert_eq!(parse_good_toml.mastodon.client_secret, "secret"); + assert_eq!(parse_good_toml.mastodon.redirect, "urn:ietf:wg:oauth:2.0:oob"); + assert_eq!(parse_good_toml.mastodon.token, "super secret"); +} + +#[test] +#[should_panic(expected = "Cannot open config file tests/no_file.toml: No such file or directory (os error 2)")] +fn test_parse_no_toml() { + let _parse_no_toml = parse_toml("tests/no_file.toml"); +} + +#[test] +#[should_panic(expected = "Cannot parse TOML file tests/bad_test.toml: expected an equals, found a newline at line 1 column 5")] +fn test_parse_bad_toml() { + let _parse_bad_toml = parse_toml("tests/bad_test.toml"); +} diff --git a/tests/good_test.toml b/tests/good_test.toml new file mode 100644 index 0000000..f29d112 --- /dev/null +++ b/tests/good_test.toml @@ -0,0 +1,19 @@ +[scootaloo] + +db_path="/var/random/scootaloo.sqlite" +cache_path="/tmp/scootaloo" + +[twitter] +username="tamerelol" + +consumer_key="rand consumer key" +consumer_secret="secret" +access_key="rand access key" +access_secret="super secret" + +[mastodon] +base = "https://m.nintendojo.fr" +client_id = "rand client id" +client_secret = "secret" +redirect = "urn:ietf:wg:oauth:2.0:oob" +token = "super secret"