#![allow(clippy::expect_used)]
use std::path::PathBuf;
use polyplug::loader::manifest::{ManifestData, ManifestDependency};
use polyplug_codegen::{GenerateConfig, GenerateOutput, Lang, Side};
const API_TOML: &str = "\
[[plugin_contract]]
name = \"pipeline.Decoder\"
version = \"1.0.0\"
[[plugin_contract.functions]]
name = \"decode\"
return = \"StringView\"
";
const DEPENDENCIES_TOML: &str = "\
[[plugin]]
name = \"decoder\"
implements = [\"pipeline.Decoder@1.0\"]
[[dependency]]
kind = \"contract\"
contract = \"image.Transcoder\"
min_version = \"2.0\"
[[dependency]]
kind = \"bundle\"
bundle = \"codec-bundle\"
contract = \"audio.Encoder\"
min_version = \"1.0\"
";
fn bundle_toml_for_lang(lang: Lang) -> String {
let (runtime, file_block): (&str, &str) = match lang {
Lang::Rust => (
"native",
"[bundle.file]\nlinux.x86_64 = \"libdep.so\"\nmacos.x86_64 = \"libdep.dylib\"\nmacos.aarch64 = \"libdep.dylib\"\nwindows.x86_64 = \"dep.dll\"\n",
),
Lang::Cpp => (
"native",
"[bundle.file]\nlinux.x86_64 = \"libdep.so\"\nmacos.x86_64 = \"libdep.dylib\"\nmacos.aarch64 = \"libdep.dylib\"\nwindows.x86_64 = \"dep.dll\"\n",
),
Lang::CSharp => ("csharp", "file = \"libdep.dll\"\n"),
Lang::Python => ("python", "file = \"plugin.py\"\n"),
Lang::Lua => ("lua", "file = \"plugin.lua\"\n"),
Lang::JsQuickJs => ("js-quickjs", "file = \"plugin.js\"\n"),
};
format!(
"[bundle]\nname = \"dep_roundtrip\"\nversion = \"1.0.0\"\napi = \"api.toml\"\nloader = \"{runtime}\"\n{file_block}\n{DEPENDENCIES_TOML}"
)
}
fn generate_manifest_for_lang(lang: Lang) -> String {
let tmp_dir: PathBuf = std::env::temp_dir().join(format!(
"polyplugc_dep_roundtrip_{:?}_{}",
lang,
std::process::id()
));
let _ = std::fs::remove_dir_all(&tmp_dir);
std::fs::create_dir_all(&tmp_dir).expect("create tmp dir");
let api_path: PathBuf = tmp_dir.join("api.toml");
let bundle_path: PathBuf = tmp_dir.join("bundle.toml");
std::fs::write(&api_path, API_TOML).expect("write api.toml");
std::fs::write(&bundle_path, bundle_toml_for_lang(lang)).expect("write bundle.toml");
let config: GenerateConfig = GenerateConfig {
api_toml: bundle_path,
lang,
side: Side::Guest,
out_dir: tmp_dir.join("out"),
};
let output: GenerateOutput = polyplugc::generate(config).expect("generate guest");
let manifest_file = output
.files
.into_iter()
.find(|f| {
f.path
.file_name()
.map(|n| n == "manifest.toml")
.unwrap_or(false)
})
.expect("manifest.toml must be generated");
manifest_file.content
}
fn assert_manifest_roundtrips(manifest_toml: &str) {
let parsed: ManifestData =
ManifestData::parse_from_str(manifest_toml).expect("runtime parser must accept manifest");
let deps: Vec<ManifestDependency> = parsed.resolved_dependencies();
assert_eq!(
deps.len(),
2,
"both dependencies must survive resolution (ByBundle without bundle_id would be dropped):\n{manifest_toml}"
);
let mut saw_by_contract: bool = false;
let mut saw_by_bundle: bool = false;
for dep in &deps {
match dep {
ManifestDependency::ByContract {
contract,
contract_id,
..
} => {
saw_by_contract = true;
assert_eq!(contract, "image.Transcoder");
assert_ne!(
contract_id.id(),
0,
"ByContract dep must carry a non-zero contract_id"
);
}
ManifestDependency::ByBundle {
bundle,
bundle_id,
contract,
contract_id,
..
} => {
saw_by_bundle = true;
assert_eq!(bundle, "codec-bundle");
assert_eq!(contract, "audio.Encoder");
assert_ne!(
bundle_id.id(),
0,
"ByBundle dep must carry a non-zero bundle_id"
);
assert_ne!(
contract_id.id(),
0,
"ByBundle dep must carry a non-zero contract_id"
);
}
}
}
assert!(saw_by_contract, "expected a ByContract dependency");
assert!(saw_by_bundle, "expected a ByBundle dependency");
}
#[test]
fn rust_manifest_dependencies_roundtrip() {
assert_manifest_roundtrips(&generate_manifest_for_lang(Lang::Rust));
}
#[test]
fn cpp_manifest_dependencies_roundtrip() {
assert_manifest_roundtrips(&generate_manifest_for_lang(Lang::Cpp));
}
#[test]
fn csharp_manifest_dependencies_roundtrip() {
assert_manifest_roundtrips(&generate_manifest_for_lang(Lang::CSharp));
}
#[test]
fn python_manifest_dependencies_roundtrip() {
assert_manifest_roundtrips(&generate_manifest_for_lang(Lang::Python));
}
#[test]
fn lua_manifest_dependencies_roundtrip() {
assert_manifest_roundtrips(&generate_manifest_for_lang(Lang::Lua));
}
#[test]
fn js_manifest_dependencies_roundtrip() {
assert_manifest_roundtrips(&generate_manifest_for_lang(Lang::JsQuickJs));
}