use serde_json::Value;
use strum::EnumString;
use crate::error::Error;
#[derive(Copy, Clone, EnumString, strum::Display)]
#[strum(serialize_all = "kebab-case")]
pub enum ArtifactComponent {
Abi,
Bytecode,
DeployedBytecode,
}
impl ArtifactComponent {
pub fn artifact_key(self) -> &'static str {
match self {
ArtifactComponent::Abi => "abi",
ArtifactComponent::Bytecode => "bytecode",
ArtifactComponent::DeployedBytecode => "deployedBytecode",
}
}
}
pub fn extract_artifact_component_json(
component: ArtifactComponent,
data: &[u8],
) -> Result<Value, Error> {
let json = serde_json::from_str::<Value>(std::str::from_utf8(data)?)?;
let key = component.artifact_key();
json.get(key)
.cloned()
.ok_or_else(|| Error::InvalidInput(format!("artifact has no \"{}\" component", key)))
}
#[cfg(all(test, not(target_family = "wasm")))]
mod tests {
use super::*;
fn artifact_json() -> Vec<u8> {
serde_json::json!({
"abi": [{ "type": "function", "name": "foo" }],
"bytecode": { "object": "0x6001" },
"deployedBytecode": { "object": "0x6002" }
})
.to_string()
.into_bytes()
}
#[test]
fn test_extract_each_component() {
let data = artifact_json();
assert_eq!(
extract_artifact_component_json(ArtifactComponent::Abi, &data).unwrap(),
serde_json::json!([{ "type": "function", "name": "foo" }])
);
assert_eq!(
extract_artifact_component_json(ArtifactComponent::Bytecode, &data).unwrap(),
serde_json::json!({ "object": "0x6001" })
);
assert_eq!(
extract_artifact_component_json(ArtifactComponent::DeployedBytecode, &data).unwrap(),
serde_json::json!({ "object": "0x6002" })
);
}
#[test]
fn test_artifact_key_per_component() {
assert_eq!(ArtifactComponent::Abi.artifact_key(), "abi");
assert_eq!(ArtifactComponent::Bytecode.artifact_key(), "bytecode");
assert_eq!(
ArtifactComponent::DeployedBytecode.artifact_key(),
"deployedBytecode"
);
}
#[test]
fn test_missing_component_errors() {
for (component, key) in [
(ArtifactComponent::Abi, "abi"),
(ArtifactComponent::Bytecode, "bytecode"),
(ArtifactComponent::DeployedBytecode, "deployedBytecode"),
] {
let err = extract_artifact_component_json(component, b"{}").unwrap_err();
assert_eq!(
err.to_string(),
format!("invalid input: artifact has no \"{}\" component", key)
);
}
}
#[test]
fn test_missing_component_errors_beside_present_siblings() {
let data = br#"{"bytecode":{"object":"0x60"},"deployedBytecode":{"object":"0x60"}}"#;
assert!(extract_artifact_component_json(ArtifactComponent::Abi, data).is_err());
assert!(extract_artifact_component_json(ArtifactComponent::Bytecode, data).is_ok());
}
#[test]
fn test_explicit_null_component_is_returned() {
assert_eq!(
extract_artifact_component_json(ArtifactComponent::Abi, br#"{"abi":null}"#).unwrap(),
Value::Null
);
}
#[test]
fn test_non_object_artifact_errors() {
assert!(extract_artifact_component_json(ArtifactComponent::Abi, b"[]").is_err());
assert!(extract_artifact_component_json(ArtifactComponent::Abi, b"null").is_err());
assert!(extract_artifact_component_json(ArtifactComponent::Abi, br#""abi""#).is_err());
}
#[test]
fn test_invalid_input_errors() {
assert!(extract_artifact_component_json(ArtifactComponent::Abi, &[0xff, 0xfe]).is_err());
assert!(extract_artifact_component_json(ArtifactComponent::Abi, b"not json").is_err());
}
}