Files
Marcos Paulo cac6b0ed39
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 consumers (grammar, theme, pack), seed reader, wasm plugin host with approval, wanted scan, STIX and Lottie store lookups, plugin auto-disable persistence
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-21 18:35:47 -03:00

81 lines
3.8 KiB
Rust

//! The pack consumer: one pack carries grammars and themes to their consumers, installs and
//! removes as one unit, and one bad file fails the whole pack.
mod addons_support;
mod common;
use std::sync::{Arc, Mutex};
use addons_support::{Shared, TINY, entry, index_json, serve};
use common::{TempVault, temp_config, temp_vault};
use notescraft_engine::addons::{FakeTransport, FakeVerifier, INDEX_URL, Response};
use notescraft_engine::{Error, Registry, Session, register_core};
use notescraft_syntax::load;
use serde_json::{Value, json};
/// The highlighter's grammar list is process-wide, so these tests take turns.
static TURN: Mutex<()> = Mutex::new(());
const OTHER: &str = "%YAML 1.2\n---\nname: Other\nfile_extensions: [other]\nscope: source.other\ncontexts:\n main:\n - match: '\\bbar\\b'\n scope: keyword.control.other\n";
const THEME: &str = "id = \"packed\"\nname = \"Packed\"\nvariant = \"light\"\n";
struct Fixture {
reg: Registry<Session>,
session: Session,
config: std::path::PathBuf,
_guards: (TempVault, TempVault),
}
fn fixture(name: &str, files: &[(&str, &[u8])]) -> Fixture {
let (vault, config) = (temp_vault(name), temp_config(name));
let mut session = Session::open(vault.path()).unwrap();
session.use_settings_dir(config.path());
let listed = [entry("pack", "starter", "1.0.0", files, &[])];
let net = FakeTransport::new().with_response(INDEX_URL, Ok(Response { status: 200, etag: None, bytes: index_json(&listed, &[]) }));
session.set_addons_transport(Box::new(Shared(Arc::new(serve(net, "pack", "starter", "1.0.0", files)))));
session.set_addons_verifier(Box::new(FakeVerifier { accept: true }));
let mut reg = Registry::new();
register_core(&mut reg).unwrap();
let config_path = config.path().to_path_buf();
Fixture { reg, session, config: config_path, _guards: (vault, config) }
}
impl Fixture {
fn run(&mut self, id: &str, params: &Value) -> Result<Value, Error> {
self.reg.run(id, &mut self.session, params)
}
}
#[test]
fn a_pack_feeds_the_grammar_and_theme_consumers_and_removes_as_one_unit() {
let _turn = TURN.lock().unwrap_or_else(std::sync::PoisonError::into_inner);
let files: [(&str, &[u8]); 3] =
[("grammars/tiny.sublime-syntax", TINY.as_bytes()), ("grammars/other.sublime-syntax", OTHER.as_bytes()), ("themes/packed.toml", THEME.as_bytes())];
let mut f = fixture("pk-ok", &files);
f.run("registry.check", &json!({})).unwrap();
f.run("registry.install", &json!({ "kind": "pack", "id": "starter" })).unwrap();
f.session.load_grammars();
assert!(load::is_known("tiny") && load::is_known("other"));
assert_eq!(f.session.theme_named("packed").map(|t| t.name), Some("Packed".to_owned()));
f.run("registry.remove", &json!({ "kind": "pack", "id": "starter" })).unwrap();
f.session.load_grammars();
assert!(!load::is_known("tiny") && !load::is_known("other"));
assert!(f.session.theme_named("packed").is_none());
}
#[test]
fn one_bad_file_fails_the_whole_pack() {
let _turn = TURN.lock().unwrap_or_else(std::sync::PoisonError::into_inner);
let files: [(&str, &[u8]); 3] =
[("grammars/tiny.sublime-syntax", TINY.as_bytes()), ("grammars/other.sublime-syntax", b"not a grammar: ["), ("themes/packed.toml", THEME.as_bytes())];
let mut f = fixture("pk-bad", &files);
f.run("registry.check", &json!({})).unwrap();
assert!(f.run("registry.install", &json!({ "kind": "pack", "id": "starter" })).is_err());
f.session.load_grammars();
assert!(!load::is_known("tiny"), "the good grammar was not installed either");
assert!(f.session.theme_named("packed").is_none());
assert!(!f.config.join("registry/store/pack/starter").exists());
let state = std::fs::read_to_string(f.config.join("registry/state.json")).unwrap_or_default();
assert!(!state.contains("starter"));
}