use std::sync::Mutex;
static TEST_LOCK: Mutex<()> = Mutex::new(());
#[cfg(test)]
mod tests {
#[test]
#[ignore = "requires git clone and network access to GitHub, not available on GitHub CI"]
fn test_git_clone_github() {
let _lock = super::TEST_LOCK.lock().unwrap();
let url = "uxntal://git@github.com:davehorner/uxn-games/tree/main/flap/flap.tal";
let parsed = uxn_tal::parse_uxntal_url(url);
assert_eq!(
parsed.repo_ref.as_ref().map(|r| r.url_git.clone()),
Some("git@github.com:davehorner/uxn-games".to_string())
);
assert_eq!(parsed.url_raw, url);
let cache_dir = dirs::cache_dir().unwrap_or_else(|| PathBuf::from(".cache"));
clean_cache(&cache_dir);
let result = resolve_and_fetch_entry(url);
assert!(
result.is_ok(),
"GitHub git@ clone failed: {:?}",
result.err()
);
let (entry, cache) = result.unwrap();
assert!(entry.exists(), "Entry file not found after git clone");
assert!(cache.exists(), "Cache dir not found after git clone");
}
#[test]
#[ignore = "requires network access to GitHub, not available on GitHub CI"]
fn test_https_github() {
let url = "https://github.com/davehorner/uxn-games/blob/main/flap/flap.tal";
let parsed = uxn_tal::parse_uxntal_url(url);
assert!(parsed
.repo_ref
.as_ref()
.map(|r| r.url_git.clone())
.unwrap_or_default()
.is_empty());
let cache_dir = dirs::cache_dir().unwrap_or_else(|| PathBuf::from(".cache"));
clean_cache(&cache_dir);
let result = resolve_and_fetch_entry(url);
assert!(
result.is_ok(),
"GitHub https fetch failed: {:?}",
result.err()
);
let (entry, cache) = result.unwrap();
assert!(entry.exists(), "Entry file not found after https fetch");
assert!(cache.exists(), "Cache dir not found after https fetch");
}
#[test]
#[ignore = "requires git clone and network access to git.sr.ht, not available on GitHub CI"]
fn test_parser_git_at_srht() {
let url = "uxntal://git@git.sr.ht:~rabbits/noodle/main/src/noodle.tal";
let parsed = uxn_tal::parse_uxntal_url(url);
assert_eq!(
parsed.repo_ref.as_ref().map(|r| r.url_git.clone()),
Some("git@git.sr.ht:~rabbits/noodle".to_string())
);
assert_eq!(
parsed.url,
"git@git.sr.ht:~rabbits/noodle/main/src/noodle.tal"
);
}
#[test]
#[ignore = "requires git clone and network access to git.sr.ht, not available on GitHub CI"]
fn test_parser_git_at_https_srht() {
let url = "uxntal://git@https://git.sr.ht/~rabbits/noodle/main/src/noodle.tal";
let parsed = uxn_tal::parse_uxntal_url(url);
assert_eq!(
parsed.repo_ref.as_ref().map(|r| r.url_git.clone()),
Some("https://git.sr.ht/~rabbits/noodle".to_string())
);
assert_eq!(
parsed.url,
"git@https://git.sr.ht/~rabbits/noodle/main/src/noodle.tal"
);
}
use std::fs;
use std::path::PathBuf;
use uxn_tal::fetch::downloader::resolve_and_fetch_entry;
fn clean_cache(path: &PathBuf) {
if path.exists() {
let _ = fs::remove_dir_all(path);
}
}
#[test]
#[ignore = "requires git clone and network access to git.sr.ht, not available on GitHub CI"]
fn test_git_clone_srht() {
let _lock = super::TEST_LOCK.lock().unwrap();
let url = "uxntal://git@git.sr.ht:~rabbits/noodle/main/src/noodle.tal";
let parsed = uxn_tal::parse_uxntal_url(url);
assert_eq!(
parsed.repo_ref.as_ref().map(|r| r.url_git.clone()),
Some("git@git.sr.ht:~rabbits/noodle".to_string())
);
assert_eq!(parsed.url_raw, url);
use uxn_tal::paths::uxntal_roms_get_path;
use uxn_tal_common::cache::hash_url;
let norm_url = parsed.url.as_str();
let cache_base = uxntal_roms_get_path().unwrap_or_else(|| PathBuf::from(".cache"));
let cache_dir = cache_base.join(format!("{}", hash_url(norm_url)));
println!(
"[TEST] Cleaning cache dir: {} (for normalized url: {})",
cache_dir.display(),
norm_url
);
clean_cache(&cache_dir);
let result = resolve_and_fetch_entry(url);
assert!(
result.is_ok(),
"SourceHut git clone failed: {:?}",
result.err()
);
let (entry, cache) = result.unwrap();
assert!(entry.exists(), "Entry file not found after git clone");
assert!(cache.exists(), "Cache dir not found after git clone");
fn print_dir_recursive(path: &std::path::Path, prefix: &str) {
if let Ok(entries) = std::fs::read_dir(path) {
for entry in entries.flatten() {
let p = entry.path();
println!(
"[TEST] {}{}",
prefix,
p.file_name().unwrap().to_string_lossy()
);
if p.is_dir() {
print_dir_recursive(&p, &format!("{} ", prefix));
}
}
}
}
use std::io::Write;
println!(
"[TEST] Recursive cache dir listing after clone (before assembler): {}",
cache.display()
);
print_dir_recursive(&cache, "");
std::io::stdout().flush().unwrap();
}
#[test]
#[ignore = "requires git clone and network access to git.sr.ht, not available on GitHub CI"]
fn test_git_https_srht() {
let _lock = super::TEST_LOCK.lock().unwrap();
let url = "uxntal://git@git.sr.ht:~rabbits/noodle/main/src/noodle.tal";
let parsed = uxn_tal::parse_uxntal_url(url);
assert_eq!(
parsed.repo_ref.as_ref().map(|r| r.url_git.clone()),
Some("git@git.sr.ht:~rabbits/noodle".to_string())
);
use uxn_tal::paths::uxntal_roms_get_path;
use uxn_tal_common::cache::hash_url;
let norm_url = parsed.url.as_str();
let cache_base = uxntal_roms_get_path().unwrap_or_else(|| PathBuf::from(".cache"));
let cache_dir = cache_base.join(format!("{}", hash_url(norm_url)));
println!(
"[TEST] Cleaning cache dir: {} (for normalized url: {})",
cache_dir.display(),
norm_url
);
clean_cache(&cache_dir);
let result = resolve_and_fetch_entry(url);
assert!(
result.is_ok(),
"SourceHut git clone failed: {:?}",
result.err()
);
let (entry, cache) = result.unwrap();
assert!(entry.exists(), "Entry file not found after git clone");
assert!(cache.exists(), "Cache dir not found after git clone");
}
#[test]
#[ignore = "requires git clone and network access to GitHub, not available on GitHub CI"]
fn test_protocol_parser_standard_api() {
let raw_url = "uxntal://git@github.com:davehorner/uxn-games/tree/main/flap/flap.tal";
let result = uxn_tal::ProtocolParser::parse(raw_url);
assert!(
result.repo_ref.is_some(),
"Git repository should be detected"
);
let repo_ref = result.repo_ref.unwrap();
assert_eq!(repo_ref.provider, "github");
assert_eq!(repo_ref.owner, "davehorner");
assert_eq!(repo_ref.repo, "uxn-games");
assert_eq!(repo_ref.branch, "main");
assert_eq!(repo_ref.path, "flap/flap.tal");
assert_eq!(repo_ref.url_git, "git@github.com:davehorner/uxn-games");
}
#[test]
#[ignore = "requires git clone and network access to GitHub, not available on GitHub CI"]
fn test_api_equivalence() {
let raw_url = "uxntal://git@github.com:davehorner/uxn-games/tree/main/flap/flap.tal";
let result1 = uxn_tal::ProtocolParser::parse(raw_url);
let result2 = uxn_tal::parse_uxntal_url(raw_url);
assert_eq!(result1.repo_ref.is_some(), result2.repo_ref.is_some());
if let (Some(ref1), Some(ref2)) = (&result1.repo_ref, &result2.repo_ref) {
assert_eq!(ref1.provider, ref2.provider);
assert_eq!(ref1.owner, ref2.owner);
assert_eq!(ref1.repo, ref2.repo);
assert_eq!(ref1.branch, ref2.branch);
assert_eq!(ref1.path, ref2.path);
assert_eq!(ref1.url_git, ref2.url_git);
}
assert_eq!(result1.url_raw, result2.url_raw);
assert_eq!(result1.url, result2.url);
assert_eq!(result1.protocol, result2.protocol);
}
#[test]
#[ignore = "requires git clone and network access to multiple git providers, not available on GitHub CI"]
fn test_comprehensive_url_parsing() {
let test_cases = vec![
("SourceHut SSH", "uxntal://git@git.sr.ht:~rabbits/noodle/main/src/noodle.tal", "sourcehut", "~rabbits", "noodle"),
("SourceHut HTTPS", "uxntal://git@https://git.sr.ht/~rabbits/noodle/main/src/noodle.tal", "sourcehut", "~rabbits", "noodle"),
("GitHub SSH", "uxntal://git@github.com:davehorner/uxn-games/tree/main/flap/flap.tal", "github", "davehorner", "uxn-games"),
("GitHub HTTPS", "uxntal://git@https://github.com/davehorner/uxn-games/tree/main/flap/flap.tal", "github", "davehorner", "uxn-games"),
("GitHub .git format", "uxntal://git@github.com:davehorner/uxn-cats.git/catclock.tal", "github", "davehorner", "uxn-cats"),
("Codeberg HTTPS", "uxntal://git@https://codeberg.org/yorshex/minesweeper-uxn/tree/main/src/minesweeper.tal", "codeberg", "yorshex", "minesweeper-uxn"),
];
for (description, url, expected_provider, expected_owner, expected_repo) in test_cases {
println!("Testing: {}", description);
let parsed = uxn_tal::ProtocolParser::parse(url);
assert!(
parsed.repo_ref.is_some(),
"Git repository should be detected for {}",
description
);
let repo_ref = parsed.repo_ref.unwrap();
assert_eq!(
repo_ref.provider, expected_provider,
"Provider mismatch for {}",
description
);
assert_eq!(
repo_ref.owner, expected_owner,
"Owner mismatch for {}",
description
);
assert_eq!(
repo_ref.repo, expected_repo,
"Repo mismatch for {}",
description
);
}
}
#[test]
#[ignore = "requires git clone and network access to multiple git providers, not available on GitHub CI"]
fn test_git_integration_comprehensive() {
let _lock = super::TEST_LOCK.lock().unwrap();
let test_urls = vec![
"uxntal://git@github.com:davehorner/uxn-games/tree/main/flap/flap.tal",
"uxntal://git@github.com:davehorner/uxn-cats.git/catclock.tal",
];
for url in test_urls {
println!("Testing comprehensive git integration for: {}", url);
let parsed = uxn_tal::ProtocolParser::parse(url);
assert!(parsed.repo_ref.is_some(), "Should parse git URL: {}", url);
let cache_dir = dirs::cache_dir().unwrap_or_else(|| PathBuf::from(".cache"));
clean_cache(&cache_dir);
let result = resolve_and_fetch_entry(url);
assert!(
result.is_ok(),
"Git resolution should succeed for {}: {:?}",
url,
result.err()
);
let (entry_path, cache_path) = result.unwrap();
assert!(
entry_path.exists(),
"Entry file should exist after git clone: {}",
entry_path.display()
);
assert!(
cache_path.exists(),
"Cache dir should exist after git clone: {}",
cache_path.display()
);
if entry_path.extension().and_then(|s| s.to_str()) == Some("tal") {
let content =
std::fs::read_to_string(&entry_path).expect("Should be able to read .tal file");
assert!(!content.trim().is_empty(), "TAL file should have content");
}
}
}
}