Skip to content

Commit f5e1cf4

Browse files
committed
gnd: Test scaffold type mappings across scalars and arrays
Cover every schema-side type-mapping row in one event, and the mapping cast for a fixed-size address array end-to-end. The fixed-size array rows (`address[3]`, `uint256[3]`, `uint8[3]`, `bool[2]`, `string[2]`, `bytes32[4]`) regress-guard the string matcher that could not see `[N]` and scaffolded them to non-building fields.
1 parent 751ba06 commit f5e1cf4

3 files changed

Lines changed: 113 additions & 0 deletions

File tree

gnd/src/scaffold/manifest.rs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -623,4 +623,21 @@ mod tests {
623623
let fields: Vec<&str> = leaves.iter().map(|l| l.field.as_str()).collect();
624624
assert_eq!(fields, vec!["value", "value2", "value1"]);
625625
}
626+
627+
#[test]
628+
fn test_flatten_component_less_tuple_falls_back_to_bytes() {
629+
// alloy accepts a `tuple` with no components (solc never emits one), whose
630+
// selector type is the bare "tuple" and does not resolve. Scaffolding must
631+
// fall back to a single Bytes leaf, not panic like codegen's resolver.
632+
let input = EventParam {
633+
name: "data".to_string(),
634+
ty: "tuple".to_string(),
635+
components: vec![],
636+
..Default::default()
637+
};
638+
let leaves = flatten_event_inputs(&[input]);
639+
assert_eq!(leaves.len(), 1);
640+
assert_eq!(leaves[0].field, "data");
641+
assert_eq!(leaves[0].ty, DynSolType::Bytes);
642+
}
626643
}

gnd/src/scaffold/mapping.rs

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -533,6 +533,41 @@ mod tests {
533533
);
534534
}
535535

536+
#[test]
537+
fn test_generate_mapping_casts_fixed_size_address_array() {
538+
// A non-indexed `address[N]` reaches the entity as an array, so it needs
539+
// the same upcast as `address[]`; a fixed uint array does not.
540+
let abi = json!([
541+
{
542+
"type": "event",
543+
"name": "Signers",
544+
"inputs": [
545+
{"name": "owners", "type": "address[3]"},
546+
{"name": "amounts", "type": "uint256[3]"}
547+
]
548+
}
549+
]);
550+
551+
let options = ScaffoldOptions {
552+
contract_name: "Vault".to_string(),
553+
abi: Some(abi),
554+
index_events: true,
555+
..Default::default()
556+
};
557+
558+
let mapping = generate_mapping(&options);
559+
assert!(
560+
mapping.contains("entity.owners = changetype<Bytes[]>(event.params.owners)"),
561+
"{}",
562+
mapping
563+
);
564+
assert!(
565+
mapping.contains("entity.amounts = event.params.amounts\n"),
566+
"{}",
567+
mapping
568+
);
569+
}
570+
536571
#[test]
537572
fn test_needs_bytes_array_cast() {
538573
let cast = |t: &str| needs_bytes_array_cast(&t.parse::<DynSolType>().unwrap());

gnd/src/scaffold/schema.rs

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -280,6 +280,67 @@ mod tests {
280280
assert_eq!(graphql_type_of("uint64[]"), "[BigInt!]");
281281
}
282282

283+
#[test]
284+
fn test_generate_schema_covers_all_type_mappings() {
285+
// One event exercising every schema-side mapping row, including the
286+
// fixed-size arrays the old `ends_with("[]")` matcher could not see and
287+
// that scaffolded to non-building scalar fields.
288+
let param = |name: &str, ty: &str| json!({"name": name, "type": ty, "indexed": false});
289+
let abi = json!([
290+
{
291+
"type": "event",
292+
"name": "AllTypes",
293+
"inputs": [
294+
param("addr", "address"),
295+
param("flag", "bool"),
296+
param("text", "string"),
297+
param("tiny", "uint8"), // i32 band
298+
param("mid", "uint32"), // i64 band
299+
param("big", "uint256"), // BigInt
300+
param("addrsDyn", "address[]"),
301+
param("addrsFixed", "address[3]"),
302+
param("numsFixed", "uint256[3]"),
303+
param("tinyFixed", "uint8[3]"),
304+
param("flagsFixed", "bool[2]"),
305+
param("textFixed", "string[2]"),
306+
param("hashesFixed", "bytes32[4]"),
307+
param("tinyDyn", "int8[]"), // i32 band keeps Int
308+
param("midDyn", "int40[]"), // i64 band collapses to BigInt
309+
]
310+
}
311+
]);
312+
313+
let options = ScaffoldOptions {
314+
abi: Some(abi),
315+
index_events: true,
316+
..Default::default()
317+
};
318+
let schema = generate_schema(&options);
319+
320+
for (field, ty) in [
321+
("addr", "Bytes!"),
322+
("flag", "Boolean!"),
323+
("text", "String!"),
324+
("tiny", "Int!"),
325+
("mid", "Int8!"),
326+
("big", "BigInt!"),
327+
("addrsDyn", "[Bytes!]!"),
328+
("addrsFixed", "[Bytes!]!"),
329+
("numsFixed", "[BigInt!]!"),
330+
("tinyFixed", "[Int!]!"),
331+
("flagsFixed", "[Boolean!]!"),
332+
("textFixed", "[String!]!"),
333+
("hashesFixed", "[Bytes!]!"),
334+
("tinyDyn", "[Int!]!"),
335+
("midDyn", "[BigInt!]!"),
336+
] {
337+
assert!(
338+
schema.contains(&format!("{field}: {ty}")),
339+
"expected `{field}: {ty}` in:\n{schema}"
340+
);
341+
}
342+
}
343+
283344
#[test]
284345
fn test_generate_schema_unrolls_tuple() {
285346
let abi = json!([

0 commit comments

Comments
 (0)