From 84f9508813ac368bdce302db7f3a15bc6fce3fee Mon Sep 17 00:00:00 2001 From: Vika Date: Mon, 23 May 2022 08:54:42 +0300 Subject: templates: introduce unit tests These unit tests generate a random MF2-JSON post, convert it to MF2-HTML using the template and then read it back using the `microformats` crate. The only problem is that it has a nasty bug with overstuffing implied properties. This is being worked on: https://gitlab.com/maxburon/microformats-parser/-/issues/7 For now the tests marked as ignored because they fail. But the function itself that generates them should remain here for documentation and potential code sharing with the `microformats` crate, potentially even migrating to a subcrate there. --- Cargo.lock | 4 ++ templates/Cargo.toml | 7 +++ templates/src/lib.rs | 154 +++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 165 insertions(+) diff --git a/Cargo.lock b/Cargo.lock index 77c6077..7b2bbef 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1662,11 +1662,15 @@ version = "0.1.0" dependencies = [ "chrono", "ellipse", + "faker_rand", "http", "kittybox-util", "log 0.4.17", "markup", + "microformats", + "rand 0.8.5", "serde_json", + "test-logger", ] [[package]] diff --git a/templates/Cargo.toml b/templates/Cargo.toml index c4c7f46..fe8ac19 100644 --- a/templates/Cargo.toml +++ b/templates/Cargo.toml @@ -5,6 +5,13 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html +[dev-dependencies] +faker_rand = "^0.1.1" +rand = "^0.8.5" +test-logger = "^0.1.0" +[dev-dependencies.microformats] +version="^0.2.0" + [dependencies] ellipse = "^0.2.0" # Truncate and ellipsize strings in a human-friendly way http = "^0.2.7" # Hyper's strong HTTP types diff --git a/templates/src/lib.rs b/templates/src/lib.rs index c7b03ea..01c69ab 100644 --- a/templates/src/lib.rs +++ b/templates/src/lib.rs @@ -4,3 +4,157 @@ mod onboarding; pub use onboarding::OnboardingPage; mod login; pub use login::LoginPage; + +#[cfg(test)] +mod tests { + use serde_json::json; + use microformats::types::Document; + + enum PostType { + Note, + Article, + ReplyTo(serde_json::Value), + ReplyToLink(String), + LikeOf(serde_json::Value), + LikeOfLink(String) + } + + fn gen_hcard(domain: &str) -> serde_json::Value { + use faker_rand::en_us::names::FirstName; + + json!({ + "type": ["h-card"], + "properties": { + "name": [rand::random::().to_string()], + "photo": [format!("https://{domain}/media/me.png")], + "uid": [format!("https://{domain}/")], + "url": [format!("https://{domain}/")] + } + }) + } + + fn gen_random_post(domain: &str, kind: PostType) -> serde_json::Value { + use faker_rand::lorem::{Paragraph, Word, Sentence}; + + fn html(content: Paragraph) -> serde_json::Value { + json!({ + "html": format!("

{}

", content), + "value": content.to_string() + }) + } + + let uid = format!( + "https://{domain}/posts/{}-{}-{}", + rand::random::(), rand::random::(), rand::random::() + ); + let dt = chrono::offset::Local::now() + .to_rfc3339_opts(chrono::SecondsFormat::Secs, true); + + match kind { + PostType::Note => { + let content = rand::random::(); + + json!({ + "type": ["h-entry"], + "properties": { + "content": [html(content)], + "published": [dt], + "uid": [&uid], + "url": [&uid], + "author": [gen_hcard(domain)] + } + }) + } + PostType::Article => { + let content = rand::random::(); + let name = rand::random::(); + + json!({ + "type": ["h-entry"], + "properties": { + "content": [html(content)], + "published": [dt], + "uid": [&uid], + "url": [&uid], + "author": [gen_hcard(domain)], + "name": [name.to_string()] + } + }) + } + _ => todo!() + } + } + + #[test] + #[ignore = "see https://gitlab.com/maxburon/microformats-parser/-/issues/7"] + fn test_note() { + use microformats::types::PropertyValue; + use faker_rand::en_us::internet::Domain; + + test_logger::ensure_env_logger_initialized(); + + let mf2 = gen_random_post( + &rand::random::().to_string(), + PostType::Note + ); + + let html = crate::templates::Entry { + post: &mf2 + }.to_string(); + println!("\n```html\n{}\n```", &html); + let url: microformats::types::Url = mf2["properties"]["uid"][0].as_str() + .unwrap() + .parse() + .unwrap(); + let parsed: Document = microformats::from_html(&html, url.clone()).unwrap(); + + let item = parsed.get_item_by_url(&url).unwrap(); + println!("\n```json\n{}\n```", serde_json::to_string_pretty(&item).unwrap()); + if let PropertyValue::Item(item) = item { + let _item = item.borrow(); + let props = _item.properties.borrow(); + + if let PropertyValue::Fragment(content) = props.get("content").and_then(|v| v.first()).unwrap() { + assert_eq!(content.html, mf2["properties"]["content"][0]["html"].as_str().unwrap()); + } else { + unreachable!() + } + + assert!(props.contains_key("published")); + use microformats::types::temporal::Value as TemporalValue; + if let Some(PropertyValue::Temporal( + TemporalValue::Timestamp(item) + )) = props.get("published") + .and_then(|v| v.first()) + { + use chrono::{DateTime, FixedOffset, NaiveDateTime}; + + let offset = item.as_offset().unwrap().data; + let ndt: NaiveDateTime = item.as_date().unwrap().data + .and_time(item.as_time().unwrap().data) + - offset; + let dt = DateTime::::from_utc(ndt, offset); + + let expected: DateTime = chrono::DateTime::parse_from_rfc3339( + mf2["properties"]["published"][0].as_str().unwrap() + ).unwrap(); + + assert_eq!(dt, expected); + } else { + panic!("Failed to find datetime in properties!"); + } + + assert!(props.contains_key("uid")); + assert!(props.contains_key("url")); + assert!(props.get("url") + .unwrap() + .iter() + .any(|i| i == props.get("uid").and_then(|v| v.first()).unwrap())); + // XXX: fails because of https://gitlab.com/maxburon/microformats-parser/-/issues/7 + assert!(!props.contains_key("name")); + + } else { + unreachable!() + } + } +} -- cgit 1.4.1