diff --git a/ci/render/src/lib.rs b/ci/render/src/lib.rs index 7716849..c2268bf 100644 --- a/ci/render/src/lib.rs +++ b/ci/render/src/lib.rs @@ -147,6 +147,41 @@ pub fn format_stats(stats: StatsRaw) -> BTreeMap { mod tests { use super::*; + fn parsed_entry(name: &str) -> ParsedEntry { + ParsedEntry { + name: name.into(), + categories: [types::Category::Fuzzer].into_iter().collect(), + tags: ["rust".into()].into_iter().collect(), + license: "MIT".into(), + types: ["cli".into()].into_iter().collect(), + homepage: "https://example.com/fuzzer".into(), + source: None, + pricing: None, + plans: None, + description: "A fuzzer.".into(), + discussion: None, + deprecated: None, + resources: None, + reviews: None, + demos: None, + wrapper: None, + } + } + + #[test] + fn rejects_blank_tool_names() { + let tags = [Tag { + name: "Rust".into(), + value: "rust".into(), + tag_type: Type::Language, + }]; + + for name in ["", " \t\n"] { + assert!(Entry::from_parsed(parsed_entry(name), &tags).is_err()); + } + assert!(Entry::from_parsed(parsed_entry("Example Fuzzer"), &tags).is_ok()); + } + #[test] fn test_slugify() { assert_eq!(slugify("this is a test"), "this-is-a-test".to_string()); diff --git a/ci/render/src/lints.rs b/ci/render/src/lints.rs index d5e25b4..2539b5c 100644 --- a/ci/render/src/lints.rs +++ b/ci/render/src/lints.rs @@ -4,11 +4,13 @@ use crate::types::ParsedEntry; use crate::types::Tag; pub fn name(entry: &ParsedEntry, _: &[Tag]) -> Result<()> { - if entry.name.len() <= 50 { + if entry.name.trim().is_empty() { + Err(anyhow!("Name of entry must not be blank")) + } else if entry.name.len() <= 50 { Ok(()) } else { Err(anyhow!( - "Name of entry may be at most 50 characters long, but {} is {} long", + "Name of entry may be at most 50 UTF-8 bytes long, but {} is {} bytes long", entry.name, entry.name.len() ))