#![allow(clippy::unwrap_used, clippy::expect_used, clippy::panic)]
use tapes_harnesses::plugin::codex_app::{
CODEX_APP_TEMPLATES, HookPluginIdentity, render_hooks_manifest, render_plugin_manifest,
};
#[test]
fn a_consumer_can_render_a_complete_plugin_from_the_public_api() {
let identity = HookPluginIdentity::new("acme-codex", "1.4.2")
.with_description("Keeps Codex connected to acmed.")
.with_display_name("Acme for Codex")
.with_short_description("Keep Codex connected to Acme.")
.with_long_description("Forwards allowlisted lifecycle metadata to local acmed.")
.with_developer_name("Acme, Inc.");
let plugin_manifest = render_plugin_manifest(&identity);
let hooks_manifest = render_hooks_manifest(r#"/bin/sh "${PLUGIN_ROOT}/scripts/capture-hook""#);
for (what, rendered) in [
("plugin.json", &plugin_manifest),
("hooks.json", &hooks_manifest),
] {
assert!(
!rendered.contains("__TAPES_"),
"{what} still carries an unfilled slot:\n{rendered}"
);
serde_json::from_str::<serde_json::Value>(rendered)
.unwrap_or_else(|e| panic!("{what} is not valid JSON: {e}\n{rendered}"));
}
let parsed: serde_json::Value = serde_json::from_str(&plugin_manifest).unwrap();
assert_eq!(parsed["name"], "acme-codex");
assert_eq!(parsed["version"], "1.4.2");
assert_eq!(parsed["interface"]["displayName"], "Acme for Codex");
assert_eq!(parsed["interface"]["developerName"], "Acme, Inc.");
assert_eq!(parsed["author"]["name"], "Acme, Inc.");
}
#[test]
fn a_consumer_can_render_from_the_constructor_alone() {
let rendered = render_plugin_manifest(&HookPluginIdentity::new("acme-codex", "1.4.2"));
let parsed: serde_json::Value = serde_json::from_str(&rendered).unwrap();
assert!(!rendered.contains("__TAPES_"));
assert_eq!(parsed["name"], "acme-codex");
assert_eq!(parsed["interface"]["displayName"], "acme-codex");
}
#[test]
fn a_consumer_can_read_the_identity_it_built() {
let identity = HookPluginIdentity::new("acme-codex", "1.4.2").with_developer_name("Acme, Inc.");
assert_eq!(identity.name, "acme-codex");
assert_eq!(identity.version, "1.4.2");
assert_eq!(identity.developer_name, "Acme, Inc.");
}
#[test]
fn an_installer_reaches_the_templates_through_the_registry_and_renders_them() {
let harness = tapes_harnesses::harness::find("codex-app").expect("codex-app is registered");
let templates = match harness.plugin() {
tapes_harnesses::harness::PluginDelivery::HookManifestTemplates(templates) => templates,
other => panic!("codex-app declares {other:?}, not hook manifest templates"),
};
assert_eq!(*templates, CODEX_APP_TEMPLATES);
assert!(templates.plugin_manifest.contains("__TAPES_"));
assert!(templates.hooks_manifest.contains("__TAPES_"));
let identity = HookPluginIdentity::new("acme-codex", "1.4.2");
assert!(!render_plugin_manifest(&identity).contains("__TAPES_"));
assert!(!render_hooks_manifest("/usr/bin/acme-hook").contains("__TAPES_"));
}
#[test]
fn a_consumer_can_package_a_complete_marketplace_from_the_public_api() {
use tapes_harnesses::plugin::codex_app::manager;
let plugin_name = "acme-codex";
let files: Vec<(std::path::PathBuf, String)> = vec![
(
std::path::PathBuf::from(manager::MARKETPLACE_MANIFEST_PATH),
manager::render_marketplace_manifest(
&manager::MarketplaceIdentity::new("acme", plugin_name).with_display_name("Acme"),
),
),
(
manager::plugin_manifest_path(plugin_name),
render_plugin_manifest(&HookPluginIdentity::new(plugin_name, "1.4.2")),
),
(
manager::hooks_manifest_path(plugin_name),
render_hooks_manifest("/usr/bin/acme-hook"),
),
];
let root = tempfile::tempdir().unwrap();
for (relative, contents) in &files {
let path = root.path().join(relative);
std::fs::create_dir_all(path.parent().unwrap()).unwrap();
std::fs::write(&path, contents).unwrap();
assert!(
!contents.contains("__TAPES_"),
"{} carries an unfilled slot",
relative.display()
);
serde_json::from_str::<serde_json::Value>(contents)
.unwrap_or_else(|e| panic!("{} is not valid JSON: {e}", relative.display()));
}
let marketplace: serde_json::Value = serde_json::from_str(&files[0].1).unwrap();
let offered = marketplace["plugins"][0]["source"]["path"]
.as_str()
.unwrap();
let offered = root.path().join(offered.trim_start_matches("./"));
assert!(offered.is_dir(), "{} is not a directory", offered.display());
assert!(offered.join(".codex-plugin").join("plugin.json").is_file());
let manager = manager::PluginManager::new("codex", root.path(), "acme", plugin_name);
assert_eq!(manager.plugin_spec(), "acme-codex@acme");
assert_eq!(
manager.manual_commands()[0],
format!("codex plugin marketplace add {}", root.path().display())
);
}