103 lines
4.6 KiB
Rust
103 lines
4.6 KiB
Rust
//! The theme consumer: themes installed from the add-on store join the user themes, and a
|
|
//! selected theme that is gone falls back to a built-in with a diagnostic.
|
|
|
|
mod addons_support;
|
|
mod common;
|
|
|
|
use std::sync::Arc;
|
|
|
|
use addons_support::{Shared, entry, index_json, serve};
|
|
use common::{TempVault, temp_config, temp_vault};
|
|
use notescraft_engine::addons::{FakeTransport, FakeVerifier, INDEX_URL, Response};
|
|
use notescraft_engine::{Registry, Session, register_core};
|
|
use serde_json::{Value, json};
|
|
|
|
fn theme_text(id: &str, name: &str, variant: &str) -> String {
|
|
format!("id = \"{id}\"\nname = \"{name}\"\nvariant = \"{variant}\"\n")
|
|
}
|
|
|
|
struct Fixture {
|
|
reg: Registry<Session>,
|
|
session: Session,
|
|
config: std::path::PathBuf,
|
|
_guards: (TempVault, TempVault),
|
|
}
|
|
|
|
/// A session whose index lists the themes `(id, text)`.
|
|
fn fixture(name: &str, themes: &[(&str, String)]) -> 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 files: Vec<(String, String)> = themes.iter().map(|(id, text)| (format!("{id}.toml"), text.clone())).collect();
|
|
let entries: Vec<Value> = themes.iter().zip(&files).map(|((id, _), (path, text))| entry("theme", id, "1.0.0", &[(path, text.as_bytes())], &[])).collect();
|
|
let mut net = FakeTransport::new().with_response(INDEX_URL, Ok(Response { status: 200, etag: None, bytes: index_json(&entries, &[]) }));
|
|
for ((id, _), (path, text)) in themes.iter().zip(&files) {
|
|
net = serve(net, "theme", id, "1.0.0", &[(path, text.as_bytes())]);
|
|
}
|
|
session.set_addons_transport(Box::new(Shared(Arc::new(net))));
|
|
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 ok(&mut self, id: &str, params: &Value) -> Value {
|
|
self.reg.run(id, &mut self.session, params).unwrap_or_else(|e| panic!("{id}: {e}"))
|
|
}
|
|
|
|
fn install(&mut self, id: &str) {
|
|
self.ok("registry.check", &json!({}));
|
|
self.ok("registry.install", &json!({ "kind": "theme", "id": id }));
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn an_installed_theme_resolves_and_is_listed() {
|
|
let mut f = fixture("th-ok", &[("mine", theme_text("mine", "Mine", "dark"))]);
|
|
assert!(f.session.theme_named("mine").is_none());
|
|
f.install("mine");
|
|
assert_eq!(f.session.theme_named("mine").map(|t| t.name), Some("Mine".to_owned()));
|
|
assert!(f.session.themes().contains(&"mine".to_owned()));
|
|
f.session.set_theme("mine").unwrap();
|
|
assert_eq!(f.session.theme().unwrap().id, "mine");
|
|
}
|
|
|
|
#[test]
|
|
fn a_missing_selected_theme_falls_back_to_the_builtin_of_its_variant_with_a_diagnostic() {
|
|
let mut f = fixture("th-gone", &[("mine", theme_text("mine", "Mine", "dark")), ("sun-light", theme_text("sun-light", "Sun", "light"))]);
|
|
f.ok("registry.check", &json!({}));
|
|
for id in ["mine", "sun-light"] {
|
|
f.ok("registry.install", &json!({ "kind": "theme", "id": id }));
|
|
}
|
|
f.session.set_theme("mine").unwrap();
|
|
f.ok("registry.remove", &json!({ "kind": "theme", "id": "mine" }));
|
|
assert_eq!(f.session.theme().unwrap().id, "dark");
|
|
assert!(f.session.diagnostics().iter().any(|d| d.contains("`mine`") && d.contains("`dark`")), "{:?}", f.session.diagnostics());
|
|
f.session.set_theme("sun-light").unwrap();
|
|
f.ok("registry.remove", &json!({ "kind": "theme", "id": "sun-light" }));
|
|
assert_eq!(f.session.theme().unwrap().id, "light");
|
|
}
|
|
|
|
#[test]
|
|
fn a_settings_folder_theme_beats_a_store_theme_of_the_same_id() {
|
|
let mut f = fixture("th-dup", &[("mine", theme_text("mine", "Store", "dark"))]);
|
|
f.install("mine");
|
|
std::fs::create_dir_all(f.config.join("themes")).unwrap();
|
|
std::fs::write(f.config.join("themes/zzz.toml"), theme_text("mine", "Folder", "dark")).unwrap();
|
|
assert_eq!(f.session.theme_named("mine").map(|t| t.name), Some("Folder".to_owned()));
|
|
assert_eq!(f.session.themes().iter().filter(|id| *id == "mine").count(), 1);
|
|
}
|
|
|
|
#[test]
|
|
fn a_store_theme_never_takes_a_builtin_id_and_a_corrupt_file_is_skipped() {
|
|
let mut f = fixture("th-bad", &[("mine", theme_text("mine", "Mine", "dark"))]);
|
|
f.install("mine");
|
|
let file = f.config.join("registry/store/theme/mine/1.0.0/mine.toml");
|
|
std::fs::write(&file, theme_text("dark", "Impostor", "dark")).unwrap();
|
|
assert_eq!(f.session.theme_named("dark").map(|t| t.name), notescraft_themes::builtin("dark").map(|t| t.name));
|
|
std::fs::write(&file, "not [ toml").unwrap();
|
|
assert_eq!(f.session.user_themes().len(), 0);
|
|
}
|