rain_metadata/meta/
normalize.rs1use super::{
2 KnownMeta,
3 super::error::Error,
4 types::{
5 op::v1::OpMeta, authoring::v1::AuthoringMeta, solidity_abi::v2::SolidityAbiMeta,
6 interpreter_caller::v1::InterpreterCallerMeta,
7 },
8};
9
10fn normalize_json<'de, T>(data: &'de [u8]) -> Result<Vec<u8>, Error>
11where
12 T: serde::Deserialize<'de> + serde::Serialize + validator::Validate,
13{
14 let parsed = serde_json::from_str::<T>(std::str::from_utf8(data)?)?;
15 parsed.validate()?;
16 Ok(serde_json::to_string(&parsed)?.as_bytes().to_vec())
17}
18
19impl KnownMeta {
20 pub fn normalize(&self, data: &[u8]) -> Result<Vec<u8>, Error> {
22 Ok(match self {
23 KnownMeta::OpV1 => normalize_json::<OpMeta>(data)?,
24 KnownMeta::SolidityAbiV2 => normalize_json::<SolidityAbiMeta>(data)?,
25 KnownMeta::InterpreterCallerMetaV1 => normalize_json::<InterpreterCallerMeta>(data)?,
26 KnownMeta::AuthoringMetaV1 => {
27 match AuthoringMeta::abi_decode(data) {
31 Ok(am) => am.abi_encode_validate()?,
32 _ => AuthoringMeta::abi_encode_validate(
33 &serde_json::from_str::<AuthoringMeta>(std::str::from_utf8(data)?)?,
34 )?,
35 }
36 }
37 _ => data.to_vec(),
40 })
41 }
42}
43
44#[cfg(all(test, not(target_family = "wasm")))]
45mod tests {
46 use crate::error::Error;
47 use crate::meta::types::authoring::v1::{AuthoringMeta, AuthoringMetaItem};
48 use crate::meta::KnownMeta;
49
50 #[test]
52 fn test_normalize_op_v1_canonicalizes() {
53 let spaced = b"{ \"name\" : \"add\" ,\n \"desc\" : \"adds numbers\" }";
54 let normalized = KnownMeta::OpV1.normalize(spaced).unwrap();
55 assert_eq!(
56 String::from_utf8(normalized).unwrap(),
57 r#"{"name":"add","desc":"adds numbers","operand":[],"inputs":[],"outputs":[],"aliases":[]}"#
58 );
59 }
60
61 #[test]
64 fn test_normalize_op_v1_rejects_invalid_symbol() {
65 let invalid = br#"{"name":"NOT_A_RAIN_SYMBOL"}"#;
66 assert!(matches!(
67 KnownMeta::OpV1.normalize(invalid),
68 Err(Error::ValidationErrors(_))
69 ));
70 }
71
72 #[test]
74 fn test_normalize_solidity_abi_v2_rejects_bad_input() {
75 assert!(matches!(
76 KnownMeta::SolidityAbiV2.normalize(b"not json at all"),
77 Err(Error::SerdeJsonError(_))
78 ));
79 assert!(matches!(
80 KnownMeta::SolidityAbiV2.normalize(&[0xff, 0xfe]),
81 Err(Error::Utf8Error(_))
82 ));
83 }
84
85 #[test]
87 fn test_normalize_solidity_abi_v2_canonicalizes() {
88 assert_eq!(
89 KnownMeta::SolidityAbiV2.normalize(b"[ ]").unwrap(),
90 b"[]".to_vec()
91 );
92 }
93
94 #[test]
97 fn test_normalize_interpreter_caller_rejects_empty_methods() {
98 let invalid = br#"{"name":"Test Caller","abiName":"TestCaller","methods":[]}"#;
99 assert!(matches!(
100 KnownMeta::InterpreterCallerMetaV1.normalize(invalid),
101 Err(Error::ValidationErrors(_))
102 ));
103 }
104
105 #[test]
107 fn test_normalize_passthrough_for_binary_metas() {
108 let data = vec![0x00, 0x01, 0xff];
109 assert_eq!(
110 KnownMeta::ExpressionDeployerV2BytecodeV1
111 .normalize(&data)
112 .unwrap(),
113 data
114 );
115 }
116
117 fn sample_authoring_meta() -> AuthoringMeta {
118 serde_json::from_str(
119 r#"[{"word":"stack","description":"Copies an existing value from the stack.","operandParserOffset":16}]"#,
120 )
121 .unwrap()
122 }
123
124 #[test]
127 fn test_normalize_authoring_meta_v1_abi_path() {
128 let authoring_meta = sample_authoring_meta();
129 let abi = authoring_meta.abi_encode_validate().unwrap();
130 let normalized = KnownMeta::AuthoringMetaV1.normalize(&abi).unwrap();
131 assert_eq!(normalized, abi);
132 }
133
134 #[test]
137 fn test_normalize_authoring_meta_v1_abi_invalid_rejected() {
138 let invalid = AuthoringMeta(vec![AuthoringMetaItem {
139 word: "NOTKEBAB".to_string(),
140 operand_parser_offset: 0,
141 description: "some description".to_string(),
142 }]);
143 let abi = invalid.abi_encode().unwrap();
145 let result = KnownMeta::AuthoringMetaV1.normalize(&abi);
146 assert!(matches!(result, Err(Error::ValidationErrors(_))));
147 }
148
149 #[test]
152 fn test_normalize_authoring_meta_v1_json_fallback() {
153 let json = r#"[{"word":"stack","description":"Copies an existing value from the stack.","operandParserOffset":16}]"#;
154 let expected = sample_authoring_meta().abi_encode_validate().unwrap();
155 let normalized = KnownMeta::AuthoringMetaV1
156 .normalize(json.as_bytes())
157 .unwrap();
158 assert_eq!(normalized, expected);
159 assert_ne!(normalized, json.as_bytes().to_vec());
160 }
161
162 #[test]
165 fn test_normalize_default_arm_passthrough() {
166 let data = b"some dotrain text".to_vec();
167 assert_eq!(KnownMeta::DotrainV1.normalize(&data).unwrap(), data);
168 let binary = vec![0xffu8, 0x00, 0x01];
169 assert_eq!(KnownMeta::RainlangV1.normalize(&binary).unwrap(), binary);
170 }
171}