Files
Marcos Paulo c78fd488cc
ci / ci (macos-latest) (push) Has been cancelled
ci / ci (ubuntu-latest) (push) Has been cancelled
ci / ci (windows-latest) (push) Has been cancelled
feat: registry core (model, guard, verify, store, net, install, commands), registry browser UI, signing tool, size profile and font dedupe, lazy Hebrew/Arabic fonts, htmlmd/srs/textdiff crates
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-21 17:28:10 -03:00

113 lines
4.9 KiB
Rust

//! Bounded download and index fetch of the add-on registry, against a fake transport.
mod addons_support;
use addons_support::{entry, index_json, url};
use notescraft_engine::addons::{FakeTransport, File, INDEX_URL, IndexCache, Response, Transport, Ureq, download_file, fetch_index, split_code};
use notescraft_syntax::validate::sha256_hex;
const BODY: &[u8] = b"hello grammar";
const CAP: u64 = 512 * 1024;
fn file(link: &str) -> File {
File { path: "a.txt".into(), size: BODY.len() as u64, sha256: sha256_hex(BODY), url: link.into() }
}
fn good() -> String {
url("grammar", "x", "1.0.0", "a.txt")
}
fn refused(link: &str) -> String {
let transport = FakeTransport::new().with(link, BODY);
download_file(&transport, &file(link), CAP).expect_err("refused").to_string()
}
#[test]
fn a_listed_file_downloads() {
let transport = FakeTransport::new().with(&good(), BODY);
assert_eq!(download_file(&transport, &file(&good()), CAP).unwrap(), BODY);
}
#[test]
fn hostile_links_never_reach_the_transport() {
for link in [
"https://evil.example.com/a.txt".to_owned(),
good().replacen("https", "http", 1),
good().replacen("https://", "https://user:pw@", 1),
good().replacen("git.marcospaulo.dev.br", "127.0.0.1", 1),
format!("{}?x=1", good()),
] {
let transport = FakeTransport::new().with(&link, BODY);
assert!(download_file(&transport, &file(&link), CAP).is_err(), "{link}");
assert!(transport.asked().is_empty(), "{link} was fetched");
}
assert!(refused("https://evil.example.com/a.txt").contains("registry"));
}
#[test]
fn a_redirect_status_is_a_failure() {
let transport = FakeTransport::new().with_response(&good(), Ok(Response { status: 302, etag: None, bytes: Vec::new() }));
let error = download_file(&transport, &file(&good()), CAP).expect_err("redirect").to_string();
assert!(error.contains("download_failed"), "{error}");
}
#[test]
fn a_body_one_byte_too_long_or_short_is_refused() {
let mut longer = BODY.to_vec();
longer.push(b'!');
let transport = FakeTransport::new().with(&good(), &longer);
assert!(download_file(&transport, &file(&good()), CAP).is_err());
let transport = FakeTransport::new().with(&good(), &BODY[..BODY.len() - 1]);
assert!(download_file(&transport, &file(&good()), CAP).is_err());
}
#[test]
fn a_wrong_hash_or_a_size_over_the_cap_is_refused() {
let transport = FakeTransport::new().with(&good(), b"HELLO grammar");
assert!(download_file(&transport, &file(&good()), CAP).unwrap_err().to_string().contains("sha256"));
let transport = FakeTransport::new().with(&good(), BODY);
assert!(download_file(&transport, &file(&good()), 3).unwrap_err().to_string().contains("cap"));
}
#[test]
fn no_network_maps_to_the_offline_code() {
let error = download_file(&FakeTransport::new(), &file(&good()), CAP).unwrap_err().to_string();
let message = error.strip_prefix("add-on: ").expect("an add-on error");
assert_eq!(split_code(message).0, "offline");
assert_eq!(split_code("a gate failed").0, "registry_refused");
}
#[test]
fn the_real_transport_refuses_plain_http_without_a_request() {
let error = Ureq::new().get("http://git.marcospaulo.dev.br/x", 10, None).expect_err("http").to_string();
assert!(error.contains("https"), "{error}");
}
#[test]
fn a_304_keeps_the_cache_and_a_failed_fetch_changes_nothing() {
let doc = index_json(&[entry("grammar", "x", "1.0.0", &[("a.txt", BODY)], &[])], &[]);
let first = FakeTransport::new().with_response(INDEX_URL, Ok(Response { status: 200, etag: Some("\"v1\"".into()), bytes: doc.clone() }));
let cache = fetch_index(&first, None, 100).unwrap();
assert_eq!((cache.fetched_at, cache.etag.as_deref()), (100, Some("\"v1\"")));
let again = FakeTransport::new().with_response(INDEX_URL, Ok(Response { status: 304, etag: None, bytes: Vec::new() }));
let kept = fetch_index(&again, Some(&cache), 200).unwrap();
assert_eq!((kept.fetched_at, kept.body.as_str(), kept.etag.as_deref()), (200, cache.body.as_str(), Some("\"v1\"")));
let down = fetch_index(&FakeTransport::new(), Some(&cache), 300).expect_err("offline").to_string();
assert!(down.contains("offline"), "{down}");
let junk = FakeTransport::new().with(INDEX_URL, b"not json");
assert!(fetch_index(&junk, Some(&cache), 300).is_err());
}
#[test]
fn the_cache_round_trips_on_disk() {
let dir = std::env::temp_dir().join(format!("notescraft-addons-net-{}", std::process::id()));
std::fs::create_dir_all(&dir).unwrap();
assert_eq!(IndexCache::load(&dir).unwrap(), None);
let cache = IndexCache { fetched_at: 5, etag: None, body: String::from_utf8(index_json(&[], &[])).unwrap() };
cache.save(&dir).unwrap();
assert_eq!(IndexCache::load(&dir).unwrap(), Some(cache));
std::fs::write(dir.join("index-cache.json"), b"{").unwrap();
assert!(IndexCache::load(&dir).is_err());
std::fs::remove_dir_all(&dir).unwrap();
}