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

90 lines
4.4 KiB
Rust

//! Shared fixtures of the add-on tests: signed-looking entries, index documents and a fake
//! transport that serves their files. Signatures are not real here (tests use `FakeVerifier`).
#![allow(dead_code)] // each test target uses a different part
use std::sync::Arc;
use notescraft_engine::addons::{FakeTransport, Index, Response, Transport};
use notescraft_syntax::validate::sha256_hex;
use serde_json::{Value, json};
/// Where the first-party registry serves files from.
pub const BASE: &str = "https://git.marcospaulo.dev.br/masi/notescraft-registry/raw/branch/main/files";
/// A grammar the syntax crate accepts.
pub const TINY: &str = "%YAML 1.2\n---\nname: Tiny\nfile_extensions: [tiny]\nscope: source.tiny\ncontexts:\n main:\n - match: '\\bfoo\\b'\n scope: keyword.control.tiny\n";
/// A theme the themes crate accepts.
pub const THEME: &str = "id = \"mine\"\nname = \"Mine\"\nvariant = \"dark\"\n";
/// The smallest plugin module the host accepts (ABI v1, every command answers `{}`): the
/// installer dry-loads plugins, so a bare header is not enough.
pub fn wasm() -> &'static [u8] {
static MODULE: std::sync::OnceLock<Vec<u8>> = std::sync::OnceLock::new();
MODULE.get_or_init(|| {
let text = r#"(module
(memory (export "memory") 2)
(global $bump (mut i32) (i32.const 1024))
(data (i32.const 16) "{}")
(func (export "ns_alloc") (param $len i32) (result i32)
(local $ptr i32)
(local.set $ptr (global.get $bump))
(global.set $bump (i32.add (local.get $ptr) (local.get $len)))
(local.get $ptr))
(func (export "ns_free") (param i32 i32))
(func (export "ns_abi_version") (result i32) (i32.const 1))
(func (export "ns_on_load") (result i32) (i32.const 0))
(func (export "ns_on_unload") (result i32) (i32.const 0))
(func (export "ns_on_event") (param i32 i32) (result i32) (i32.const 0))
(func (export "ns_run_command") (param i32 i32 i32 i32) (result i64) (i64.const 68719476738)))"#;
wat::parse_str(text).unwrap_or_default()
})
}
/// A plugin manifest for `id` at `version` with `permissions`.
pub fn manifest(id: &str, version: &str, permissions: &[&str]) -> String {
json!({ "id": id, "name": "Dice", "version": version, "min_app_version": "0.1.0", "permissions": permissions, "commands": [{ "id": "roll", "name": "Roll" }] })
.to_string()
}
/// The download link of one file of an entry.
pub fn url(kind: &str, id: &str, version: &str, path: &str) -> String {
format!("{BASE}/{kind}/{id}/{version}/{path}")
}
/// An entry as the index writes it, with the real hashes and sizes of `files`.
pub fn entry(kind: &str, id: &str, version: &str, files: &[(&str, &[u8])], permissions: &[&str]) -> Value {
let listed: Vec<Value> = files
.iter()
.map(|(path, bytes)| json!({ "path": path, "size": bytes.len(), "sha256": sha256_hex(bytes), "url": url(kind, id, version, path) }))
.collect();
json!({
"id": id, "kind": kind, "title": id, "summary": "s", "version": version, "min_app_version": "0.1.0", "license": "MIT",
"aliases": [id], "permissions": permissions, "files": listed, "signature": { "key_id": "k1", "sig": "QUJD" },
})
}
/// An index document.
pub fn index_json(entries: &[Value], revoked: &[(&str, &str)]) -> Vec<u8> {
let revoked: Vec<Value> = revoked.iter().map(|(id, version)| json!({ "id": id, "version": version })).collect();
json!({ "version": 2, "generated_at": "2026-10-21T00:00:00Z", "entries": entries, "revoked": revoked }).to_string().into_bytes()
}
/// The parsed index of `entries`.
pub fn index(entries: &[Value], revoked: &[(&str, &str)]) -> Index {
Index::parse(&index_json(entries, revoked)).expect("the fixture index parses")
}
/// A transport serving the files of `entry` (as written by [`entry`]) from `files`.
pub fn serve(transport: FakeTransport, kind: &str, id: &str, version: &str, files: &[(&str, &[u8])]) -> FakeTransport {
files.iter().fold(transport, |t, (path, bytes)| t.with(&url(kind, id, version, path), bytes))
}
/// A transport shared between the test and the session that owns the box.
#[derive(Debug, Clone)]
pub struct Shared(pub Arc<FakeTransport>);
impl Transport for Shared {
fn get(&self, url: &str, max_bytes: u64, if_none_match: Option<&str>) -> notescraft_engine::Result<Response> {
self.0.get(url, max_bytes, if_none_match)
}
}