//! The `wai` binary's registry commands and its candidate refusal, run as a //! user runs them. No codec feature is needed (`--test cli_registry`). //! //! - `wai registry export --check` passes on the committed tree and fails, writing //! nothing, on a tree whose export has drifted; `wai registry export` repairs it. //! - `wai wrap` refuses a candidate capability (SPEC ยง5, *Candidate capabilities*) //! in every place an envelope can name one, and writes nothing. //! - `wai inspect` and `wai capabilities` claim native decode only in a build that //! has it (the `codecs` feature). use std::path::{Path, PathBuf}; use std::process::{Command, Output}; fn wai(args: &[&str]) -> Output { Command::new(env!("CARGO_BIN_EXE_wai")).args(args).output().expect("run wai") } fn scratch_dir(name: &str) -> PathBuf { let dir = Path::new(env!("CARGO_TARGET_TMPDIR")).join("cli_registry").join(name); let _ = std::fs::remove_dir_all(&dir); std::fs::create_dir_all(&dir).unwrap(); dir } fn wai_dir() -> PathBuf { Path::new(env!("CARGO_MANIFEST_DIR")).join("..") } /// The files the export covers, relative to `wai/`. const EXPORTED: &[&str] = &[ "registry/capabilities.json", "registry/capabilities.schema.json", "vocab/v2.ttl", "vocab/v2.jsonld", "vocab/v2.shapes.ttl", "REGISTRY.md", ]; /// A copy of the exported files of the committed tree under a scratch root. fn copy_tree(name: &str) -> PathBuf { let root = scratch_dir(name); for rel in EXPORTED { let to = root.join(rel); std::fs::create_dir_all(to.parent().unwrap()).unwrap(); std::fs::copy(wai_dir().join(rel), &to).unwrap(); } root } #[test] fn registry_export_check_passes_on_the_committed_tree() { let run = wai(&["registry", "export", "--check"]); assert!(run.status.success(), "{}{}", String::from_utf8_lossy(&run.stdout), String::from_utf8_lossy(&run.stderr)); } #[test] fn registry_export_check_fails_on_drift_and_export_repairs_it() { let root = copy_tree("drift"); let root_s = root.to_str().unwrap(); let json = root.join("registry/capabilities.json"); let good = std::fs::read(&json).unwrap(); let edited = String::from_utf8(good.clone()).unwrap().replacen("\"patent-pool\"", "\"royalty-free\"", 1); std::fs::write(&json, &edited).unwrap(); // The REGISTRY.md generated region drifts too. let md = root.join("REGISTRY.md"); let md_good = std::fs::read_to_string(&md).unwrap(); std::fs::write(&md, md_good.replacen("| candidate |", "| registered |", 1)).unwrap(); let run = wai(&["registry", "export", "--root", root_s, "--check"]); let stderr = String::from_utf8_lossy(&run.stderr); assert_eq!(run.status.code(), Some(1), "drift exits 1: {stderr}"); assert!(stderr.contains("registry/capabilities.json") && stderr.contains("REGISTRY.md"), "{stderr}"); assert!(stderr.contains("registry export"), "the message says how to regenerate: {stderr}"); assert_eq!(std::fs::read_to_string(&json).unwrap(), edited, "--check writes nothing"); let run = wai(&["registry", "export", "--root", root_s]); assert!(run.status.success(), "{}", String::from_utf8_lossy(&run.stderr)); assert_eq!(std::fs::read(&json).unwrap(), good, "export restores the committed bytes"); assert_eq!(std::fs::read_to_string(&md).unwrap(), md_good); assert!(wai(&["registry", "export", "--root", root_s, "--check"]).status.success()); } #[test] fn registry_without_a_subcommand_is_refused() { let run = wai(&["registry"]); assert!(!run.status.success()); assert!(String::from_utf8_lossy(&run.stderr).contains("registry export")); } /// A payload file in a directory of the calling test's own: tests run in /// parallel, and `scratch_dir` empties the directory it returns. fn payload(test: &str) -> PathBuf { let dir = scratch_dir(&format!("payload-{test}")); let p = dir.join("bytes"); std::fs::write(&p, b"opaque payload bytes").unwrap(); p } #[test] fn wrap_refuses_a_candidate_and_writes_nothing() { let p = payload("wrap_refuses_a_candidate_and_writes_nothing"); let p = p.to_str().unwrap(); let companion = scratch_dir("companion").join("hdr"); std::fs::write(&companion, b"metadata").unwrap(); let companion = companion.to_str().unwrap(); let cases: [(&str, Vec<&str>); 6] = [ // WAI1: as the capability, with and without --intent, and as the fallback. ("wai.splat.sog", vec![]), ("wai.tensor.nnc", vec!["--intent", "improve"]), ("wai.image.png", vec!["--fallback", "wai.splat.sog"]), // WAI2: as the base rendition, and as a companion in either intent. ("wai.splat.sog", vec!["--companion", "wai.meta.hdr10plus", companion]), ("wai.video.av1", vec!["--companion", "wai.splat.sog", companion]), ("wai.video.av1", vec!["--intent", "improve", "--companion", "wai.tensor.nnc", companion]), ]; for (i, (cap, extra)) in cases.iter().enumerate() { let out = scratch_dir(&format!("refuse{i}")).join("out.wai"); let mut args = vec!["wrap", cap, p, "-o", out.to_str().unwrap()]; args.extend(extra.iter()); let run = wai(&args); let stderr = String::from_utf8_lossy(&run.stderr); assert!(!run.status.success(), "{cap} {extra:?}: wrap must refuse; stderr: {stderr}"); assert!(stderr.contains("is a candidate capability") && stderr.contains("SPEC"), "{cap} {extra:?}: {stderr}"); assert!(!out.exists(), "{cap} {extra:?}: a refused wrap must not write an envelope"); } // A registered, pinned capability still wraps. let out = scratch_dir("accept").join("out.wai"); let run = wai(&["wrap", "wai.pc.gpcc", p, "-o", out.to_str().unwrap()]); assert!(run.status.success(), "{}", String::from_utf8_lossy(&run.stderr)); assert!(out.exists()); } #[test] fn wrap_writes_the_registry_media_class() { let p = payload("wrap_writes_the_registry_media_class"); for (cap, media, extra) in [ ("wai.mesh.draco", "volumetric", &[][..]), ("wai.neural.bmshj2018", "image", &["--intent", "improve"][..]), ("wai.film.reel", "video", &[][..]), ] { let out = scratch_dir(&format!("media-{media}")).join("out.wai"); let mut args = vec!["wrap", cap, p.to_str().unwrap(), "-o", out.to_str().unwrap()]; args.extend(extra.iter()); let run = wai(&args); assert!(run.status.success(), "{cap}: {}", String::from_utf8_lossy(&run.stderr)); let env = wai::container::Wai::read(&out).unwrap(); assert_eq!(env.media(), media, "{cap}"); } } /// `inspect` and `capabilities` take their native set from what the binary was /// built with: without the `codecs` feature, `decode` is unavailable, so neither /// may say a PNG envelope decodes here or list PNG as native. #[test] fn inspect_and_capabilities_claim_native_decode_only_with_codecs() { let p = payload("inspect_and_capabilities_claim_native_decode_only_with_codecs"); let out = scratch_dir("inspect").join("png.wai"); let run = wai(&["wrap", "wai.image.png", p.to_str().unwrap(), "-o", out.to_str().unwrap(), "--intent", "improve"]); assert!(run.status.success(), "{}", String::from_utf8_lossy(&run.stderr)); let run = wai(&["inspect", out.to_str().unwrap()]); assert!(run.status.success(), "{}", String::from_utf8_lossy(&run.stderr)); let inspect = String::from_utf8_lossy(&run.stdout).into_owned(); let run = wai(&["capabilities"]); assert!(run.status.success()); let caps = String::from_utf8_lossy(&run.stdout).into_owned(); let png_row = caps.lines().find(|l| l.trim_start().starts_with("wai.image.png ")).expect("a png row"); if cfg!(feature = "codecs") { assert!(inspect.contains("DECODABLE via primary capability"), "{inspect}"); assert!(png_row.contains(" native "), "{png_row}"); } else { assert!(!inspect.contains("DECODABLE"), "{inspect}"); assert!(!inspect.contains("this sink advertises it"), "{inspect}"); assert!(inspect.contains("decodes nothing natively"), "{inspect}"); assert!(png_row.contains("sink-supplied") && !png_row.contains(" native "), "{png_row}"); assert!(caps.contains("decodes nothing natively"), "{caps}"); } }