use web_search::providers::{all_descriptor_engines, EngineDescriptor};
use web_search::SearchOptions;
fn descriptor(id: &str) -> EngineDescriptor {
all_descriptor_engines()
.into_iter()
.find(|d| d.id == id)
.unwrap_or_else(|| panic!("no descriptor for {id}"))
}
fn parse(id: &str, body: &str) -> Vec<web_search::SearchResult> {
let d = descriptor(id);
(d.parse)(body, 10, &SearchOptions::default())
}
#[test]
fn catalog_contains_all_engines() {
let ids: Vec<&str> = all_descriptor_engines().iter().map(|d| d.id).collect();
assert_eq!(ids.len(), 32);
for id in [
"wikipedia",
"wikidata",
"wiktionary",
"wikinews",
"internet-archive",
"dbpedia",
"openlibrary",
"semantic-scholar",
"openalex",
"crossref",
"searx",
"arxiv",
"europepmc",
"doaj",
"github",
"hackernews",
"gitlab",
"codeberg",
"gitee",
"bitbucket",
"gitflic",
"brave",
"mojeek",
"ecosia",
"startpage",
"yahoo",
"yandex",
"cambridge-dictionary",
"merriam-webster",
"dictionary-com",
"collins-dictionary",
"lite",
] {
assert!(ids.contains(&id), "missing descriptor {id}");
}
}
#[test]
fn wikipedia_parses_pages() {
let body = r#"{"pages":[
{"key":"Cat","title":"Cat","excerpt":"A small <b>cat</b>"},
{"key":"Dog","title":"Dog","description":"A dog"}
]}"#;
let results = parse("wikipedia", body);
assert_eq!(results.len(), 2);
assert_eq!(results[0].title, "Cat");
assert_eq!(results[0].url, "https://en.wikipedia.org/wiki/Cat");
assert_eq!(results[0].snippet, "A small cat");
assert_eq!(results[0].rank, 1);
assert_eq!(results[1].snippet, "A dog");
}
#[test]
fn github_parses_repositories() {
let body = r#"{"items":[
{"full_name":"rust-lang/rust","html_url":"https://github.com/rust-lang/rust","description":"The Rust language"}
]}"#;
let results = parse("github", body);
assert_eq!(results.len(), 1);
assert_eq!(results[0].title, "rust-lang/rust");
assert_eq!(results[0].url, "https://github.com/rust-lang/rust");
assert_eq!(results[0].source, "github");
}
#[test]
fn crossref_builds_doi_urls() {
let body = r#"{"message":{"items":[
{"title":["A Paper"],"DOI":"10.1/abc","container-title":["Journal"]}
]}}"#;
let results = parse("crossref", body);
assert_eq!(results.len(), 1);
assert_eq!(results[0].url, "https://doi.org/10.1/abc");
assert_eq!(results[0].title, "A Paper");
assert_eq!(results[0].snippet, "Journal");
}
#[test]
fn openalex_reconstructs_inverted_abstract() {
let body = r#"{"results":[
{"display_name":"Quantum","id":"https://openalex.org/W1",
"abstract_inverted_index":{"Hello":[0],"quantum":[2],"world":[1]}}
]}"#;
let results = parse("openalex", body);
assert_eq!(results.len(), 1);
assert_eq!(results[0].title, "Quantum");
assert_eq!(results[0].url, "https://openalex.org/W1");
assert_eq!(results[0].snippet, "Hello world quantum");
}
#[test]
fn arxiv_parses_atom_feed() {
let body = r#"<feed>
<entry>
<title>Deep Learning</title>
<id>http://arxiv.org/abs/1234.5678</id>
<summary>A study of deep nets.</summary>
</entry>
<entry>
<title>No Id Entry</title>
<summary>skipped</summary>
</entry>
</feed>"#;
let results = parse("arxiv", body);
assert_eq!(results.len(), 1);
assert_eq!(results[0].title, "Deep Learning");
assert_eq!(results[0].url, "http://arxiv.org/abs/1234.5678");
assert_eq!(results[0].snippet, "A study of deep nets.");
}
#[test]
fn yahoo_resolves_redirect_hrefs() {
let body = r#"<h3 class="title">
<a href="https://r.search.yahoo.com/_ylt=abc/RU=https%3A%2F%2Fexample.com%2Fpage/RK=2/">Example Page</a>
</h3>"#;
let results = parse("yahoo", body);
assert_eq!(results.len(), 1);
assert_eq!(results[0].url, "https://example.com/page");
assert_eq!(results[0].title, "Example Page");
}
#[test]
fn lite_parses_result_links_and_dedupes() {
let body = r#"
<a class="result-link" href="https://example.com/a">First</a>
<a class="result-link" href="https://example.com/a">Duplicate</a>
<a class="result-link" href="https://example.com/b">Second</a>
<a class="result-link" href="https://duckduckgo.com/ad">Ad</a>
"#;
let results = parse("lite", body);
assert_eq!(results.len(), 2);
assert_eq!(results[0].url, "https://example.com/a");
assert_eq!(results[0].title, "First");
assert_eq!(results[1].url, "https://example.com/b");
}
#[test]
fn internet_archive_builds_details_urls() {
let body = r#"{"response":{"docs":[
{"identifier":"some-item","title":"Some Item","description":"A scanned book"}
]}}"#;
let results = parse("internet-archive", body);
assert_eq!(results.len(), 1);
assert_eq!(results[0].url, "https://archive.org/details/some-item");
assert_eq!(results[0].title, "Some Item");
assert_eq!(results[0].source, "internet-archive");
}
#[test]
fn semantic_scholar_falls_back_to_paper_url() {
let body = r#"{"data":[
{"title":"Graph Paper","paperId":"abc123","abstract":"On graphs."},
{"title":"Direct","url":"https://example.com/p","abstract":"x"}
]}"#;
let results = parse("semantic-scholar", body);
assert_eq!(results.len(), 2);
assert_eq!(
results[0].url,
"https://www.semanticscholar.org/paper/abc123"
);
assert_eq!(results[1].url, "https://example.com/p");
}
#[test]
fn gitlab_parses_projects_from_array_body() {
let body = r#"[
{"path_with_namespace":"group/proj","web_url":"https://gitlab.com/group/proj","description":"A project"}
]"#;
let results = parse("gitlab", body);
assert_eq!(results.len(), 1);
assert_eq!(results[0].title, "group/proj");
assert_eq!(results[0].url, "https://gitlab.com/group/proj");
}
#[test]
fn codeberg_parses_projects_from_data_container() {
let body = r#"{"data":[
{"full_name":"user/repo","html_url":"https://codeberg.org/user/repo","description":"A repo"}
]}"#;
let results = parse("codeberg", body);
assert_eq!(results.len(), 1);
assert_eq!(results[0].title, "user/repo");
assert_eq!(results[0].url, "https://codeberg.org/user/repo");
}
#[test]
fn dictionary_parses_canonical_definition() {
let body = r#"<html><head>
<link rel="canonical" href="https://dictionary.cambridge.org/dictionary/english/quantum" />
<meta property="og:title" content="QUANTUM | meaning" />
<meta name="description" content="the smallest amount of something" />
</head><body></body></html>"#;
let results = parse("cambridge-dictionary", body);
assert_eq!(results.len(), 1);
assert_eq!(
results[0].url,
"https://dictionary.cambridge.org/dictionary/english/quantum"
);
assert_eq!(results[0].title, "QUANTUM | meaning");
assert_eq!(results[0].snippet, "the smallest amount of something");
assert_eq!(results[0].source, "cambridge-dictionary");
}
#[test]
fn yandex_parses_organic_links() {
let body =
r#"<a class="Link OrganicTitle-Link" href="https://example.org/page">Example Result</a>"#;
let results = parse("yandex", body);
assert_eq!(results.len(), 1);
assert_eq!(results[0].url, "https://example.org/page");
assert_eq!(results[0].title, "Example Result");
}
#[test]
fn parsers_return_empty_on_malformed_bodies() {
assert!(parse("wikipedia", "not json").is_empty());
assert!(parse("github", "{}").is_empty());
assert!(parse("arxiv", "<feed></feed>").is_empty());
assert!(parse("lite", "<html></html>").is_empty());
}
#[test]
fn limit_is_respected() {
let d = descriptor("wikipedia");
let body = r#"{"pages":[
{"key":"A","title":"A"},{"key":"B","title":"B"},{"key":"C","title":"C"}
]}"#;
let results = (d.parse)(body, 2, &SearchOptions::default());
assert_eq!(results.len(), 2);
}