use super::*;
use crate::codec::to_bytes;
use dpp_plugin_traits::{
AbiVersion, METRIC_CO2E_SCORE, PluginCapabilities, PluginComplianceStatus, PluginFieldError,
PluginIdentity, PluginResult, SchemaVersionRange,
};
use serde_json::{Value, json};
#[derive(Default)]
struct DummyPlugin;
impl DppSectorPlugin for DummyPlugin {
fn plugin_identity(&self) -> PluginIdentity {
PluginIdentity {
sector: "dummy",
name: "Dummy",
version: "0.1.0",
description: "Minimal plugin exercising every glue path",
}
}
fn schema_version_range(&self) -> SchemaVersionRange {
SchemaVersionRange {
min_version: "1.0.0".into(),
max_version: "1.0.0".into(),
}
}
fn validate_input(&self, input: &PluginInput) -> Result<(), PluginError> {
if input.get("ok").is_some() {
Ok(())
} else {
Err(PluginError::ValidationErrors(vec![PluginFieldError {
field: "/ok".into(),
code: "missing".into(),
message: "ok is required".into(),
}]))
}
}
fn calculate_metrics(&self, input: &PluginInput) -> Result<PluginResult, PluginError> {
self.validate_input(input)?;
Ok(PluginResult::new(PluginComplianceStatus::NotAssessed)
.maybe_metric(METRIC_CO2E_SCORE, input.get("co2e").and_then(Value::as_f64)))
}
fn generate_passport(&self, input: PluginInput) -> Result<Value, PluginError> {
self.validate_input(&input)?;
Ok(input)
}
}
fn parse(bytes: &[u8]) -> Value {
serde_json::from_slice(bytes).expect("glue emits valid JSON")
}
#[test]
fn describe_emits_capabilities() {
let json = parse(&describe_bytes(&DummyPlugin));
assert_eq!(json["abiVersion"]["major"], 1);
assert!(json["supportedSchemas"].is_array());
let back: PluginCapabilities = serde_json::from_value(json).unwrap();
assert_eq!(back.abi_version, AbiVersion::current());
}
#[test]
fn metadata_emits_meta() {
let json = parse(&metadata_bytes(&DummyPlugin));
assert_eq!(json["sector"], "dummy");
}
#[test]
fn calculate_metrics_ok_envelope() {
let input = json!({ "ok": true, "co2e": 42.0 });
let json = parse(&calculate_metrics_bytes(&DummyPlugin, &to_bytes(&input)));
assert_eq!(json["ok"]["metrics"]["co2e_score"], 42.0);
assert_eq!(json["ok"]["complianceStatus"], "NOT_ASSESSED");
}
#[test]
fn calculate_metrics_validation_error_envelope() {
let input = json!({ "co2e": 42.0 }); let json = parse(&calculate_metrics_bytes(&DummyPlugin, &to_bytes(&input)));
assert!(json.get("error").is_some());
assert!(json.get("ok").is_none());
}
#[test]
fn validate_error_on_malformed_json() {
let json = parse(&validate_bytes(&DummyPlugin, b"not json {{{"));
let back: AbiResult = serde_json::from_value(json).unwrap();
assert!(!back.is_ok());
}
#[test]
fn validate_ok_envelope_is_null() {
let input = json!({ "ok": true });
let json = parse(&validate_bytes(&DummyPlugin, &to_bytes(&input)));
assert!(json["ok"].is_null());
}
#[test]
fn generate_passport_passthrough() {
let input = json!({ "ok": true, "gtin": "12345678901231" });
let json = parse(&generate_passport_bytes(&DummyPlugin, &to_bytes(&input)));
assert_eq!(json["ok"]["gtin"], "12345678901231");
}
#[test]
fn validate_error_when_input_parses_but_is_rejected() {
let input = json!({ "missing": "ok" });
let json = parse(&validate_bytes(&DummyPlugin, &to_bytes(&input)));
assert!(json.get("error").is_some());
assert!(json.get("ok").is_none());
}
#[test]
fn generate_passport_error_when_input_parses_but_is_rejected() {
let input = json!({ "missing": "ok" });
let json = parse(&generate_passport_bytes(&DummyPlugin, &to_bytes(&input)));
assert!(json.get("error").is_some());
assert!(json.get("ok").is_none());
}
export_plugin!(DummyPlugin);
fn out_len(packed: u64) -> usize {
(packed & 0xFFFF_FFFF) as usize
}
#[test]
fn macro_alloc_dealloc_are_callable() {
assert_eq!(alloc(0), 0);
let _ = alloc(8);
dealloc(0, 0);
}
#[test]
#[cfg(not(target_pointer_width = "32"))]
fn read_input_never_dereferences_truncated_pointer_on_host() {
let bytes = unsafe { crate::abi::read_input(0xDEAD_BEEF, 16) };
assert!(
bytes.is_empty(),
"must not deref a truncated pointer on host"
);
}
#[test]
#[cfg(not(target_pointer_width = "32"))]
fn host_alloc_does_not_hand_out_truncated_pointer_on_host() {
assert_eq!(crate::abi::host_alloc(8), 0);
}
#[test]
fn macro_metadata_and_describe_pack_glue_output() {
assert_eq!(out_len(metadata()), metadata_bytes(&DummyPlugin).len());
assert_eq!(out_len(describe()), describe_bytes(&DummyPlugin).len());
}
#[test]
fn macro_input_exports_pack_error_envelope_for_empty_input() {
assert_eq!(
out_len(validate(0, 0)),
validate_bytes(&DummyPlugin, &[]).len()
);
assert_eq!(
out_len(calculate_metrics(0, 0)),
calculate_metrics_bytes(&DummyPlugin, &[]).len()
);
assert_eq!(
out_len(generate_passport(0, 0)),
generate_passport_bytes(&DummyPlugin, &[]).len()
);
}