Skip to content

Commit d08e28e

Browse files
committed
feat: add new serializeJson cheatcode that receives an id and a json string
1 parent c976619 commit d08e28e

File tree

5 files changed

+132
-27
lines changed

5 files changed

+132
-27
lines changed

crates/abi/abi/HEVM.sol

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -212,6 +212,7 @@ parseJsonBytes(string, string)(bytes)
212212
parseJsonBytesArray(string, string)(bytes[])
213213
parseJsonBytes32(string, string)(bytes32)
214214
parseJsonBytes32Array(string, string)(bytes32[])
215+
serializeJson(string,string)(string)
215216
serializeBool(string,string,bool)(string)
216217
serializeBool(string,string,bool[])(string)
217218
serializeUint(string,string,uint256)(string)

crates/abi/src/bindings/hevm.rs

Lines changed: 78 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/evm/src/executor/inspector/cheatcodes/ext.rs

Lines changed: 40 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -387,29 +387,41 @@ fn parse_json_keys(json_str: &str, key: &str) -> Result {
387387
Ok(abi_encoded.into())
388388
}
389389

390-
/// Serializes a key:value pair to a specific object. By calling this function multiple times,
390+
/// Serializes a key:value pair to a specific object. If the key is None, the value is expected to
391+
/// be an object, which will be set as the root object for the provided object key, overriding
392+
/// the whole root object if the object key already exists. By calling this function multiple times,
391393
/// the user can serialize multiple KV pairs to the same object. The value can be of any type, even
392-
/// a new object in itself. The function will return
393-
/// a stringified version of the object, so that the user can use that as a value to a new
394-
/// invocation of the same function with a new object key. This enables the user to reuse the same
395-
/// function to crate arbitrarily complex object structures (JSON).
394+
/// a new object in itself. The function will return a stringified version of the object, so that
395+
/// the user can use that as a value to a new invocation of the same function with a new object key.
396+
/// This enables the user to reuse the same function to crate arbitrarily complex object structures
397+
/// (JSON).
396398
fn serialize_json(
397399
state: &mut Cheatcodes,
398400
object_key: &str,
399-
value_key: &str,
401+
value_key: Option<&str>,
400402
value: &str,
401403
) -> Result {
402-
let parsed_value =
403-
serde_json::from_str(value).unwrap_or_else(|_| Value::String(value.to_string()));
404-
let json = if let Some(serialization) = state.serialized_jsons.get_mut(object_key) {
405-
serialization.insert(value_key.to_string(), parsed_value);
406-
serialization.clone()
404+
let json = if let Some(key) = value_key {
405+
let parsed_value =
406+
serde_json::from_str(value).unwrap_or_else(|_| Value::String(value.to_string()));
407+
if let Some(serialization) = state.serialized_jsons.get_mut(object_key) {
408+
serialization.insert(key.to_string(), parsed_value);
409+
serialization.clone()
410+
} else {
411+
let mut serialization = BTreeMap::new();
412+
serialization.insert(key.to_string(), parsed_value);
413+
state.serialized_jsons.insert(object_key.to_string(), serialization.clone());
414+
serialization.clone()
415+
}
407416
} else {
408-
let mut serialization = BTreeMap::new();
409-
serialization.insert(value_key.to_string(), parsed_value);
417+
// value must be a JSON object
418+
let parsed_value: BTreeMap<String, Value> = serde_json::from_str(value)
419+
.map_err(|err| fmt_err!("Failed to parse JSON object: {err}"))?;
420+
let serialization = parsed_value;
410421
state.serialized_jsons.insert(object_key.to_string(), serialization.clone());
411422
serialization.clone()
412423
};
424+
413425
let stringified = serde_json::to_string(&json)
414426
.map_err(|err| fmt_err!("Failed to stringify hashmap: {err}"))?;
415427
Ok(abi::encode(&[Token::String(stringified)]).into())
@@ -634,47 +646,48 @@ pub fn apply(state: &mut Cheatcodes, call: &HEVMCalls) -> Option<Result> {
634646
HEVMCalls::ParseJsonBytes32Array(inner) => {
635647
parse_json(&inner.0, &inner.1, Some(ParamType::FixedBytes(32)))
636648
}
649+
HEVMCalls::SerializeJson(inner) => serialize_json(state, &inner.0, None, &inner.1.pretty()),
637650
HEVMCalls::SerializeBool0(inner) => {
638-
serialize_json(state, &inner.0, &inner.1, &inner.2.pretty())
651+
serialize_json(state, &inner.0, Some(&inner.1), &inner.2.pretty())
639652
}
640653
HEVMCalls::SerializeBool1(inner) => {
641-
serialize_json(state, &inner.0, &inner.1, &array_eval_to_str(&inner.2))
654+
serialize_json(state, &inner.0, Some(&inner.1), &array_eval_to_str(&inner.2))
642655
}
643656
HEVMCalls::SerializeUint0(inner) => {
644-
serialize_json(state, &inner.0, &inner.1, &inner.2.pretty())
657+
serialize_json(state, &inner.0, Some(&inner.1), &inner.2.pretty())
645658
}
646659
HEVMCalls::SerializeUint1(inner) => {
647-
serialize_json(state, &inner.0, &inner.1, &array_eval_to_str(&inner.2))
660+
serialize_json(state, &inner.0, Some(&inner.1), &array_eval_to_str(&inner.2))
648661
}
649662
HEVMCalls::SerializeInt0(inner) => {
650-
serialize_json(state, &inner.0, &inner.1, &inner.2.pretty())
663+
serialize_json(state, &inner.0, Some(&inner.1), &inner.2.pretty())
651664
}
652665
HEVMCalls::SerializeInt1(inner) => {
653-
serialize_json(state, &inner.0, &inner.1, &array_eval_to_str(&inner.2))
666+
serialize_json(state, &inner.0, Some(&inner.1), &array_eval_to_str(&inner.2))
654667
}
655668
HEVMCalls::SerializeAddress0(inner) => {
656-
serialize_json(state, &inner.0, &inner.1, &inner.2.pretty())
669+
serialize_json(state, &inner.0, Some(&inner.1), &inner.2.pretty())
657670
}
658671
HEVMCalls::SerializeAddress1(inner) => {
659-
serialize_json(state, &inner.0, &inner.1, &array_str_to_str(&inner.2))
672+
serialize_json(state, &inner.0, Some(&inner.1), &array_str_to_str(&inner.2))
660673
}
661674
HEVMCalls::SerializeBytes320(inner) => {
662-
serialize_json(state, &inner.0, &inner.1, &inner.2.pretty())
675+
serialize_json(state, &inner.0, Some(&inner.1), &inner.2.pretty())
663676
}
664677
HEVMCalls::SerializeBytes321(inner) => {
665-
serialize_json(state, &inner.0, &inner.1, &array_str_to_str(&inner.2))
678+
serialize_json(state, &inner.0, Some(&inner.1), &array_str_to_str(&inner.2))
666679
}
667680
HEVMCalls::SerializeString0(inner) => {
668-
serialize_json(state, &inner.0, &inner.1, &inner.2.pretty())
681+
serialize_json(state, &inner.0, Some(&inner.1), &inner.2.pretty())
669682
}
670683
HEVMCalls::SerializeString1(inner) => {
671-
serialize_json(state, &inner.0, &inner.1, &array_str_to_str(&inner.2))
684+
serialize_json(state, &inner.0, Some(&inner.1), &array_str_to_str(&inner.2))
672685
}
673686
HEVMCalls::SerializeBytes0(inner) => {
674-
serialize_json(state, &inner.0, &inner.1, &inner.2.pretty())
687+
serialize_json(state, &inner.0, Some(&inner.1), &inner.2.pretty())
675688
}
676689
HEVMCalls::SerializeBytes1(inner) => {
677-
serialize_json(state, &inner.0, &inner.1, &array_str_to_str(&inner.2))
690+
serialize_json(state, &inner.0, Some(&inner.1), &array_str_to_str(&inner.2))
678691
}
679692
HEVMCalls::Sleep(inner) => sleep(&inner.0),
680693
HEVMCalls::WriteJson0(inner) => write_json(state, &inner.0, &inner.1, None),

testdata/cheats/Json.t.sol

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -240,6 +240,17 @@ contract WriteJsonTest is DSTest {
240240
vm.removeFile(path);
241241
}
242242

243+
function test_serializeRootObject() public {
244+
string memory serialized = vm.serializeJson(json1, '{"foo": "bar"}');
245+
assertEq(serialized, '{"foo":"bar"}');
246+
serialized = vm.serializeBool(json1, "boolean", true);
247+
assertEq(vm.parseJsonString(serialized, ".foo"), "bar");
248+
assertEq(vm.parseJsonBool(serialized, ".boolean"), true);
249+
250+
string memory overwritten = vm.serializeJson(json1, '{"value": 123}');
251+
assertEq(overwritten, '{"value":123}');
252+
}
253+
243254
struct simpleJson {
244255
uint256 a;
245256
string b;

testdata/cheats/Vm.sol

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -612,6 +612,8 @@ interface Vm {
612612

613613
function parseJsonBytes32Array(string calldata, string calldata) external returns (bytes32[] memory);
614614

615+
function serializeJson(string calldata, string calldata) external returns (string memory);
616+
615617
function serializeBool(string calldata, string calldata, bool) external returns (string memory);
616618

617619
function serializeUint(string calldata, string calldata, uint256) external returns (string memory);

0 commit comments

Comments
 (0)