use research_master::mcp::server::McpServer;
use research_master::models::{SearchQuery, SourceType};
use research_master::sources::{SourceCapabilities, SourceRegistry};
use std::sync::Arc;
fn setup_api_keys() {
std::env::set_var("ACM_API_KEY", "test_key_for_integration_tests");
std::env::set_var("SPRINGER_API_KEY", "test_key_for_integration_tests");
std::env::set_var("MDPI_API_KEY", "test_key_for_integration_tests");
std::env::set_var("IEEE_XPLORE_API_KEY", "test_key_for_integration_tests");
std::env::set_var("JSTOR_API_KEY", "test_key_for_integration_tests");
}
fn cleanup_api_keys() {
std::env::remove_var("ACM_API_KEY");
std::env::remove_var("SPRINGER_API_KEY");
std::env::remove_var("MDPI_API_KEY");
std::env::remove_var("IEEE_XPLORE_API_KEY");
std::env::remove_var("JSTOR_API_KEY");
}
fn with_api_keys<F>(test: F)
where
F: FnOnce(),
{
setup_api_keys();
test();
cleanup_api_keys();
}
fn expected_source_count() -> usize {
let mut count = 0;
if cfg!(feature = "source-arxiv") {
count += 1;
}
if cfg!(feature = "source-pubmed") {
count += 1;
}
if cfg!(feature = "source-biorxiv") {
count += 1;
}
if cfg!(feature = "source-semantic") {
count += 1;
}
if cfg!(feature = "source-openalex") {
count += 1;
}
if cfg!(feature = "source-crossref") {
count += 1;
}
if cfg!(feature = "source-iacr") {
count += 1;
}
if cfg!(feature = "source-pmc") {
count += 1;
}
if cfg!(feature = "source-hal") {
count += 1;
}
if cfg!(feature = "source-dblp") {
count += 1;
}
if cfg!(feature = "source-ssrn") {
count += 1;
}
if cfg!(feature = "source-dimensions") {
count += 1;
}
if cfg!(feature = "source-ieee_xplore") {
count += 1;
}
if cfg!(feature = "source-europe_pmc") {
count += 1;
}
if cfg!(feature = "source-core-repo") {
count += 1;
}
if cfg!(feature = "source-zenodo") {
count += 1;
}
if cfg!(feature = "source-unpaywall") {
count += 1;
}
if cfg!(feature = "source-mdpi") {
count += 1;
}
if cfg!(feature = "source-jstor") {
count += 1;
}
if cfg!(feature = "source-scispace") {
count += 1;
}
if cfg!(feature = "source-acm") {
count += 1;
}
if cfg!(feature = "source-connected_papers") {
count += 1;
}
if cfg!(feature = "source-doaj") {
count += 1;
}
if cfg!(feature = "source-worldwidescience") {
count += 1;
}
if cfg!(feature = "source-osf") {
count += 1;
}
if cfg!(feature = "source-base") {
count += 1;
}
if cfg!(feature = "source-springer") {
count += 1;
}
if cfg!(feature = "source-google_scholar") {
count += 1;
}
count
}
#[tokio::test]
async fn test_server_initialization() {
with_api_keys(|| {
let registry = SourceRegistry::new();
let server = McpServer::new(Arc::new(registry));
assert!(server.is_ok());
});
}
#[tokio::test]
async fn test_all_sources_registered() {
with_api_keys(|| {
let registry = SourceRegistry::new();
let sources: Vec<_> = registry.all().collect();
let expected = expected_source_count();
assert_eq!(sources.len(), expected);
let source_ids: Vec<&str> = sources.iter().map(|s| s.id()).collect();
assert!(source_ids.contains(&"arxiv"));
assert!(source_ids.contains(&"pubmed"));
assert!(source_ids.contains(&"biorxiv"));
assert!(source_ids.contains(&"semantic"));
assert!(source_ids.contains(&"openalex"));
assert!(source_ids.contains(&"crossref"));
assert!(source_ids.contains(&"iacr"));
assert!(source_ids.contains(&"pmc"));
assert!(source_ids.contains(&"hal"));
assert!(source_ids.contains(&"dblp"));
assert!(source_ids.contains(&"ssrn"));
assert!(source_ids.contains(&"dimensions"));
assert!(source_ids.contains(&"ieee_xplore"));
if cfg!(feature = "source-europe_pmc") {
assert!(source_ids.contains(&"europe_pmc"));
} else {
assert!(!source_ids.contains(&"europe_pmc"));
}
assert!(source_ids.contains(&"core"));
assert!(source_ids.contains(&"zenodo"));
assert!(source_ids.contains(&"unpaywall"));
assert!(source_ids.contains(&"mdpi"));
assert!(source_ids.contains(&"jstor"));
assert!(source_ids.contains(&"scispace"));
assert!(source_ids.contains(&"acm"));
assert!(source_ids.contains(&"connected_papers"));
assert!(source_ids.contains(&"doaj"));
assert!(source_ids.contains(&"worldwidescience"));
assert!(source_ids.contains(&"osf"));
assert!(source_ids.contains(&"base"));
assert!(source_ids.contains(&"springer"));
if cfg!(feature = "source-google_scholar") {
assert!(source_ids.contains(&"google_scholar"));
} else {
assert!(!source_ids.contains(&"google_scholar"));
}
});
}
#[tokio::test]
async fn test_source_capabilities() {
let registry = SourceRegistry::new();
let arxiv = registry.get("arxiv");
assert!(arxiv.is_some());
let caps = arxiv.unwrap().capabilities();
assert!(caps.contains(SourceCapabilities::SEARCH));
assert!(caps.contains(SourceCapabilities::DOWNLOAD));
assert!(caps.contains(SourceCapabilities::READ));
let crossref = registry.get("crossref");
assert!(crossref.is_some());
let caps = crossref.unwrap().capabilities();
assert!(caps.contains(SourceCapabilities::SEARCH));
assert!(caps.contains(SourceCapabilities::DOI_LOOKUP));
}
#[test]
fn test_search_query_builder() {
let query = SearchQuery::new("machine learning")
.max_results(20)
.year("2020-")
.author("Hinton");
assert_eq!(query.query, "machine learning");
assert_eq!(query.max_results, 20);
assert_eq!(query.year, Some("2020-".to_string()));
assert_eq!(query.author, Some("Hinton".to_string()));
}
#[test]
fn test_source_type() {
assert_eq!(SourceType::Arxiv.to_string(), "arXiv");
assert_eq!(SourceType::PubMed.to_string(), "PubMed");
assert_eq!(SourceType::SemanticScholar.to_string(), "Semantic Scholar");
}
#[test]
fn test_invalid_query_handling() {
let query = SearchQuery::new("").max_results(10);
assert_eq!(query.query, "");
assert_eq!(query.max_results, 10);
let query = SearchQuery::new("test").max_results(10000);
assert_eq!(query.max_results, 10000);
}
#[tokio::test]
async fn test_get_source_by_name() {
with_api_keys(|| {
let registry = SourceRegistry::new();
assert!(registry.get("arxiv").is_some());
assert!(registry.get("pubmed").is_some());
assert!(registry.get("semantic").is_some());
assert!(registry.get("nonexistent").is_none());
});
}
#[tokio::test]
async fn test_get_sources_by_capability() {
with_api_keys(|| {
let registry = SourceRegistry::new();
let searchable = registry.with_capability(SourceCapabilities::SEARCH);
assert!(!searchable.is_empty());
assert!(searchable.len() >= 8);
let doi_lookup = registry.with_capability(SourceCapabilities::DOI_LOOKUP);
assert!(!doi_lookup.is_empty());
});
}
#[tokio::test]
async fn test_registry_helper_methods() {
with_api_keys(|| {
let registry = SourceRegistry::new();
assert!(registry.has("arxiv"));
assert!(!registry.has("nonexistent"));
assert_eq!(registry.len(), expected_source_count());
assert!(!registry.is_empty());
let searchable = registry.searchable();
assert!(!searchable.is_empty());
let downloadable = registry.downloadable();
assert!(!downloadable.is_empty());
});
}
#[tokio::test]
async fn test_source_metadata() {
let registry = SourceRegistry::new();
let arxiv = registry.get("arxiv").unwrap();
assert_eq!(arxiv.id(), "arxiv");
assert_eq!(arxiv.name(), "arXiv");
}
#[test]
fn test_paper_model() {
use research_master::models::PaperBuilder;
let paper = PaperBuilder::new(
"1234.5678",
"Test Paper",
"https://example.com",
SourceType::Arxiv,
)
.authors("John Doe; Jane Smith")
.abstract_text("This is a test abstract.")
.doi("10.1234/test")
.published_date("2024")
.citations(42)
.build();
assert_eq!(paper.paper_id, "1234.5678");
assert_eq!(paper.title, "Test Paper");
assert_eq!(paper.authors, "John Doe; Jane Smith");
assert_eq!(paper.r#abstract, "This is a test abstract.");
assert_eq!(paper.doi, Some("10.1234/test".to_string()));
assert_eq!(paper.citations, Some(42));
assert_eq!(paper.primary_id(), "10.1234/test");
assert_eq!(paper.author_list(), vec!["John Doe", "Jane Smith"]);
assert!(!paper.has_pdf()); }
#[test]
fn test_paper_with_pdf() {
use research_master::models::PaperBuilder;
let paper = PaperBuilder::new("1234", "Test", "https://example.com", SourceType::Arxiv)
.pdf_url("https://example.com/paper.pdf")
.build();
assert!(paper.has_pdf());
assert_eq!(
paper.pdf_url,
Some("https://example.com/paper.pdf".to_string())
);
}
#[test]
fn test_paper_categories_keywords() {
use research_master::models::PaperBuilder;
let paper = PaperBuilder::new("1234", "Test", "https://example.com", SourceType::Arxiv)
.categories("Machine Learning; AI")
.keywords("deep learning; neural networks")
.build();
assert_eq!(paper.category_list(), vec!["Machine Learning", "AI"]);
assert_eq!(
paper.keyword_list(),
vec!["deep learning", "neural networks"]
);
}
#[tokio::test]
async fn test_registry_ids() {
let registry = SourceRegistry::new();
let ids: Vec<&str> = registry.ids().collect();
assert_eq!(ids.len(), expected_source_count());
assert!(ids.contains(&"arxiv"));
assert!(ids.contains(&"pubmed"));
assert!(ids.contains(&"semantic"));
}