diff --git a/subxt/src/events.rs b/subxt/src/events.rs index d7f5fb9e93..e637774d9a 100644 --- a/subxt/src/events.rs +++ b/subxt/src/events.rs @@ -373,10 +373,17 @@ pub enum EventsDecodingError { mod tests { use super::*; use crate::{ + error::GenericError::{ + Codec, + EventsDecoding, + Other, + }, + events::EventsDecodingError::UnsupportedPrimitive, Config, DefaultConfig, Phase, }; + use assert_matches::assert_matches; use codec::Encode; use frame_metadata::{ v14::{ @@ -643,4 +650,185 @@ mod tests { bitvec::bitvec![Msb0, u64; 0, 1, 1, 0, 1, 0, 1, 0, 0], ); } + + #[test] + fn decode_primitive() { + decode_and_consume_type_consumes_all_bytes(false); + decode_and_consume_type_consumes_all_bytes(true); + + let dummy_data = vec![0u8]; + let dummy_cursor = &mut &*dummy_data; + let (id, reg) = singleton_type_registry::(); + let res = decode_and_consume_type(id.id(), ®, dummy_cursor); + assert_matches!( + res, + Err(EventsDecoding(UnsupportedPrimitive(TypeDefPrimitive::Char))) + ); + + decode_and_consume_type_consumes_all_bytes("str".to_string()); + + decode_and_consume_type_consumes_all_bytes(1u8); + decode_and_consume_type_consumes_all_bytes(1i8); + + decode_and_consume_type_consumes_all_bytes(1u16); + decode_and_consume_type_consumes_all_bytes(1i16); + + decode_and_consume_type_consumes_all_bytes(1u32); + decode_and_consume_type_consumes_all_bytes(1i32); + + decode_and_consume_type_consumes_all_bytes(1u64); + decode_and_consume_type_consumes_all_bytes(1i64); + + decode_and_consume_type_consumes_all_bytes(1u128); + decode_and_consume_type_consumes_all_bytes(1i128); + } + + #[test] + fn decode_tuple() { + decode_and_consume_type_consumes_all_bytes(()); + + decode_and_consume_type_consumes_all_bytes((true,)); + + decode_and_consume_type_consumes_all_bytes((true, "str")); + + // Incomplete bytes for decoding + let dummy_data = false.encode(); + let dummy_cursor = &mut &*dummy_data; + let (id, reg) = singleton_type_registry::<(bool, &'static str)>(); + let res = decode_and_consume_type(id.id(), ®, dummy_cursor); + assert_matches!(res, Err(Codec(_))); + + // Incomplete bytes for decoding, with invalid char type + let dummy_data = (false, "str", 0u8).encode(); + let dummy_cursor = &mut &*dummy_data; + let (id, reg) = singleton_type_registry::<(bool, &'static str, char)>(); + let res = decode_and_consume_type(id.id(), ®, dummy_cursor); + assert_matches!( + res, + Err(EventsDecoding(UnsupportedPrimitive(TypeDefPrimitive::Char))) + ); + // The last byte (0x0 u8) should not be consumed + assert_eq!(dummy_cursor.len(), 1); + } + + #[test] + fn decode_array_and_seq() { + decode_and_consume_type_consumes_all_bytes([0]); + decode_and_consume_type_consumes_all_bytes([1, 2, 3, 4, 5]); + decode_and_consume_type_consumes_all_bytes([0; 500]); + decode_and_consume_type_consumes_all_bytes(["str", "abc", "cde"]); + + decode_and_consume_type_consumes_all_bytes(vec![0]); + decode_and_consume_type_consumes_all_bytes(vec![1, 2, 3, 4, 5]); + decode_and_consume_type_consumes_all_bytes(vec!["str", "abc", "cde"]); + } + + #[test] + fn decode_variant() { + #[derive(Clone, Encode, TypeInfo)] + enum EnumVar { + A, + B((&'static str, u8)), + C { named: i16 }, + } + const INVALID_TYPE_ID: u32 = 1024; + + decode_and_consume_type_consumes_all_bytes(EnumVar::A); + decode_and_consume_type_consumes_all_bytes(EnumVar::B(("str", 1))); + decode_and_consume_type_consumes_all_bytes(EnumVar::C { named: 1 }); + + // Invalid variant index + let dummy_data = 3u8.encode(); + let dummy_cursor = &mut &*dummy_data; + let (id, reg) = singleton_type_registry::(); + let res = decode_and_consume_type(id.id(), ®, dummy_cursor); + assert_matches!(res, Err(Other(_))); + + // Valid index, incomplete data + let dummy_data = 2u8.encode(); + let dummy_cursor = &mut &*dummy_data; + let res = decode_and_consume_type(id.id(), ®, dummy_cursor); + assert_matches!(res, Err(Codec(_))); + + let res = decode_and_consume_type(INVALID_TYPE_ID, ®, dummy_cursor); + assert_matches!(res, Err(crate::error::GenericError::Metadata(_))); + } + + #[test] + fn decode_composite() { + #[derive(Clone, Encode, TypeInfo)] + struct Composite {} + decode_and_consume_type_consumes_all_bytes(Composite {}); + + #[derive(Clone, Encode, TypeInfo)] + struct CompositeV2 { + id: u32, + name: String, + } + decode_and_consume_type_consumes_all_bytes(CompositeV2 { + id: 10, + name: "str".to_string(), + }); + + #[derive(Clone, Encode, TypeInfo)] + struct CompositeV3 { + id: u32, + extra: T, + } + decode_and_consume_type_consumes_all_bytes(CompositeV3 { + id: 10, + extra: vec![0, 1, 2], + }); + decode_and_consume_type_consumes_all_bytes(CompositeV3 { + id: 10, + extra: bitvec::bitvec![Lsb0, u8; 0, 1, 1, 0, 1], + }); + decode_and_consume_type_consumes_all_bytes(CompositeV3 { + id: 10, + extra: ("str", 1), + }); + decode_and_consume_type_consumes_all_bytes(CompositeV3 { + id: 10, + extra: CompositeV2 { + id: 2, + name: "str".to_string(), + }, + }); + + #[derive(Clone, Encode, TypeInfo)] + struct CompositeV4(u32, bool); + decode_and_consume_type_consumes_all_bytes(CompositeV4(1, true)); + + #[derive(Clone, Encode, TypeInfo)] + struct CompositeV5(u32); + decode_and_consume_type_consumes_all_bytes(CompositeV5(1)); + } + + #[test] + fn decode_compact() { + #[derive(Clone, Encode, TypeInfo)] + enum Compact { + A(#[codec(compact)] u32), + } + decode_and_consume_type_consumes_all_bytes(Compact::A(1)); + + #[derive(Clone, Encode, TypeInfo)] + struct CompactV2(#[codec(compact)] u32); + decode_and_consume_type_consumes_all_bytes(CompactV2(1)); + + #[derive(Clone, Encode, TypeInfo)] + struct CompactV3 { + #[codec(compact)] + val: u32, + } + decode_and_consume_type_consumes_all_bytes(CompactV3 { val: 1 }); + + #[derive(Clone, Encode, TypeInfo)] + struct CompactV4 { + #[codec(compact)] + val: T, + } + decode_and_consume_type_consumes_all_bytes(CompactV4 { val: 0u8 }); + decode_and_consume_type_consumes_all_bytes(CompactV4 { val: 1u16 }); + } } diff --git a/test-runtime/README.md b/test-runtime/README.md index 9763412df2..07cc531360 100644 --- a/test-runtime/README.md +++ b/test-runtime/README.md @@ -3,8 +3,8 @@ The logic for this crate exists mainly in the `build.rs` file. At compile time, this crate will: -- Spin up a local `substrate` binary (set the `SUBSTRATE_NODE_PATH` env var to point to a custom binary, otehrwise it'll look for `substrate` on your PATH). +- Spin up a local `substrate` binary (set the `SUBSTRATE_NODE_PATH` env var to point to a custom binary, otherwise it'll look for `substrate` on your PATH). - Obtain metadata from this node. - Export the metadata and a `node_runtime` module which has been annotated using the `subxt` proc macro and is based off the above metadata. -The reason for doing this is that our integration tests (which also spin up a Substrate node) can then use the generated `subxt` types from the exact node being tested against, so that we don't have to worry about metadata getting out of sync with the binary under test. \ No newline at end of file +The reason for doing this is that our integration tests (which also spin up a Substrate node) can then use the generated `subxt` types from the exact node being tested against, so that we don't have to worry about metadata getting out of sync with the binary under test. diff --git a/test-runtime/build.rs b/test-runtime/build.rs index e82f8863ec..300bd82fe9 100644 --- a/test-runtime/build.rs +++ b/test-runtime/build.rs @@ -58,6 +58,10 @@ async fn run() { .spawn(); let mut cmd = match cmd { Ok(cmd) => KillOnDrop(cmd), + Err(ref e) if e.kind() == std::io::ErrorKind::NotFound => { + panic!("A substrate binary should be installed on your path for testing purposes. \ + See https://github.com/paritytech/subxt/tree/master#integration-testing") + } Err(e) => { panic!("Cannot spawn substrate command '{}': {}", substrate_bin, e) } @@ -164,7 +168,7 @@ fn next_open_port() -> Option { } } -/// If the substrate process isn't explicilty killed on drop, +/// If the substrate process isn't explicitly killed on drop, /// it seems that panics that occur while the command is running /// will leave it running and block the build step from ever finishing. /// Wrapping it in this prevents this from happening.