use chrono::NaiveDate;
use shiplog_ingest_github::GithubIngestor;
use shiplog_ports::Ingestor;
fn date(y: i32, m: u32, d: u32) -> NaiveDate {
NaiveDate::from_ymd_opt(y, m, d).unwrap()
}
#[test]
fn ingest_errors_when_since_far_after_until() {
let ing = GithubIngestor::new("user".into(), date(2030, 1, 1), date(2020, 1, 1));
let err = ing.ingest().unwrap_err();
assert!(
err.to_string().contains("since must be < until"),
"unexpected: {err}"
);
}
#[test]
fn ingest_errors_when_since_is_one_day_after_until() {
let ing = GithubIngestor::new("user".into(), date(2025, 6, 2), date(2025, 6, 1));
let err = ing.ingest().unwrap_err();
assert!(
err.to_string().contains("since must be < until"),
"unexpected: {err}"
);
}
#[test]
fn created_mode_can_be_set() {
let mut ing = GithubIngestor::new("user".into(), date(2025, 1, 1), date(2025, 2, 1));
ing.mode = "created".to_string();
assert_eq!(ing.mode, "created");
}
#[test]
fn custom_api_base_is_preserved() {
let mut ing = GithubIngestor::new("user".into(), date(2025, 1, 1), date(2025, 2, 1));
ing.api_base = "https://ghes.corp/api/v3".to_string();
assert_eq!(ing.api_base, "https://ghes.corp/api/v3");
}
#[test]
fn empty_user_does_not_panic_on_construction() {
let ing = GithubIngestor::new(String::new(), date(2025, 1, 1), date(2025, 2, 1));
assert!(ing.user.is_empty());
}
#[test]
fn with_cache_on_read_only_path_errors_gracefully() {
let result = GithubIngestor::new("user".into(), date(2025, 1, 1), date(2025, 2, 1))
.with_cache("\0invalid\0path");
assert!(
result.is_err(),
"creating cache at invalid path should fail"
);
}
#[test]
fn with_in_memory_cache_then_file_cache_replaces() {
let temp = tempfile::tempdir().unwrap();
let ing = GithubIngestor::new("user".into(), date(2025, 1, 1), date(2025, 2, 1))
.with_in_memory_cache()
.unwrap()
.with_cache(temp.path())
.unwrap();
assert!(ing.cache.is_some());
assert!(temp.path().join("github-api-cache.db").exists());
}
#[test]
fn ingest_errors_when_since_equals_until() {
let ing = GithubIngestor::new("user".into(), date(2025, 6, 1), date(2025, 6, 1));
let err = ing.ingest().unwrap_err();
let msg = err.to_string();
assert!(
msg.contains("since must be < until"),
"same-day range should fail: {msg}"
);
}
#[test]
fn date_validation_error_is_not_empty() {
let ing = GithubIngestor::new("user".into(), date(2025, 12, 31), date(2025, 1, 1));
let err = ing.ingest().unwrap_err();
let msg = err.to_string();
assert!(!msg.is_empty(), "error message should not be empty");
assert!(msg.len() > 10, "error message should be descriptive: {msg}");
}
#[test]
fn custom_api_base_with_trailing_slash_is_preserved() {
let mut ing = GithubIngestor::new("user".into(), date(2025, 1, 1), date(2025, 2, 1));
ing.api_base = "https://ghes.corp/api/v3/".to_string();
assert_eq!(ing.api_base, "https://ghes.corp/api/v3/");
}
#[test]
fn default_api_base_is_github_dot_com() {
let ing = GithubIngestor::new("user".into(), date(2025, 1, 1), date(2025, 2, 1));
assert_eq!(ing.api_base, "https://api.github.com");
}
#[test]
fn default_mode_is_merged() {
let ing = GithubIngestor::new("user".into(), date(2025, 1, 1), date(2025, 2, 1));
assert_eq!(ing.mode, "merged");
}
#[test]
fn default_include_reviews_is_false() {
let ing = GithubIngestor::new("user".into(), date(2025, 1, 1), date(2025, 2, 1));
assert!(!ing.include_reviews);
}
#[test]
fn default_throttle_is_zero() {
let ing = GithubIngestor::new("user".into(), date(2025, 1, 1), date(2025, 2, 1));
assert_eq!(ing.throttle_ms, 0);
}
#[test]
fn default_token_is_none() {
let ing = GithubIngestor::new("user".into(), date(2025, 1, 1), date(2025, 2, 1));
assert!(ing.token.is_none());
}
#[test]
fn default_cache_is_none() {
let ing = GithubIngestor::new("user".into(), date(2025, 1, 1), date(2025, 2, 1));
assert!(ing.cache.is_none());
}
#[test]
fn cache_error_message_contains_context() {
let result = GithubIngestor::new("user".into(), date(2025, 1, 1), date(2025, 2, 1))
.with_cache("\0invalid\0path");
if let Err(e) = result {
let msg = format!("{e:#}");
assert!(
!msg.is_empty(),
"cache error should have a non-empty message"
);
}
}
#[test]
fn in_memory_cache_succeeds_without_filesystem() {
let result = GithubIngestor::new("user".into(), date(2025, 1, 1), date(2025, 2, 1))
.with_in_memory_cache();
assert!(result.is_ok(), "in-memory cache should always succeed");
assert!(result.unwrap().cache.is_some());
}