diff --git a/docs/src/types/bits256.md b/docs/src/types/bits256.md index b5fd3112aa..09c8bdbc68 100644 --- a/docs/src/types/bits256.md +++ b/docs/src/types/bits256.md @@ -7,3 +7,7 @@ Here's an example: ```rust,ignore {{#include ../../../packages/fuels/tests/bindings.rs:256_arg}} ``` + +If you have a hexadecimal value as a string and wish to convert it to `Bits256`, you may do so with `from_hex_str`: + +{{#include ../../../packages/fuels-core/src/types/bits_256.rs:from_hex_str}} diff --git a/packages/fuels-core/src/code_gen/abigen.rs b/packages/fuels-core/src/code_gen/abigen.rs index 0ba950f4fb..6bf64130f1 100644 --- a/packages/fuels-core/src/code_gen/abigen.rs +++ b/packages/fuels-core/src/code_gen/abigen.rs @@ -147,6 +147,10 @@ impl Abigen { Ok(Self { contract_id: self.contract_id.clone(), wallet: wallet, logs_lookup: self.logs_lookup.clone() }) } + pub async fn get_balances(&self) -> Result, SDKError> { + self.wallet.get_provider()?.get_contract_balances(&self.contract_id).await.map_err(Into::into) + } + pub fn logs_with_type(&self, receipts: &[Receipt]) -> Result, SDKError> { extract_and_parse_logs(&self.logs_lookup, receipts) } diff --git a/packages/fuels-core/src/code_gen/custom_types.rs b/packages/fuels-core/src/code_gen/custom_types.rs index 1d4102cd1c..b5952928a7 100644 --- a/packages/fuels-core/src/code_gen/custom_types.rs +++ b/packages/fuels-core/src/code_gen/custom_types.rs @@ -16,477 +16,618 @@ pub use utils::{param_type_calls, single_param_type_call, Component}; // TODO(vnepveu): append extra `,` to last enum/struct field so it is aligned with rustfmt #[cfg(test)] mod tests { - // TODO: Move tests using the old abigen to the new one. - // Currently, they will be skipped. Even though we're not fully testing these at - // unit level, they're tested at integration level, in the main harness.rs file. - - // #[test] - // fn test_extract_custom_type_name_from_abi_property_bad_data() { - // let p: Property = Default::default(); - // let result = extract_custom_type_name_from_abi_property(&p, Some(CustomType::Enum)); - // assert!(matches!(result, Err(Error::InvalidData(_)))); - - // let p = Property { - // name: String::from("foo"), - // type_field: String::from("nowhitespacehere"), - // components: None, - // }; - // let result = extract_custom_type_name_from_abi_property(&p, Some(CustomType::Enum)); - // assert!(matches!(result, Err(Error::InvalidData(_)))); - // } - - // #[test] - // fn test_extract_struct_name_from_abi_property_wrong_type() { - // let p = Property { - // name: String::from("foo"), - // type_field: String::from("enum something"), - // components: None, - // }; - // let result = extract_custom_type_name_from_abi_property(&p, Some(CustomType::Struct)); - // assert!(matches!(result, Err(Error::InvalidType(_)))); - - // let p = Property { - // name: String::from("foo"), - // type_field: String::from("struct somethingelse"), - // components: None, - // }; - // let result = extract_custom_type_name_from_abi_property(&p, Some(CustomType::Enum)); - // assert!(matches!(result, Err(Error::InvalidType(_)))); - // } - - // #[test] - // fn test_extract_custom_type_name_from_abi_property() -> Result<(), Error> { - // let p = Property { - // name: String::from("foo"), - // type_field: String::from("struct bar"), - // components: None, - // }; - // let result = extract_custom_type_name_from_abi_property(&p, Some(CustomType::Struct)); - // assert_eq!(result?, "bar"); - - // let p = Property { - // name: String::from("foo"), - // type_field: String::from("enum bar"), - // components: None, - // }; - // let result = extract_custom_type_name_from_abi_property(&p, Some(CustomType::Enum)); - // assert_eq!(result?, "bar"); - // Ok(()) - // } - - // #[test] - // fn test_expand_custom_enum() -> Result<(), Error> { - // let p = Property { - // name: String::from("unused"), - // type_field: String::from("unused"), - // components: Some(vec![ - // Property { - // name: String::from("LongIsland"), - // type_field: String::from("u64"), - // components: None, - // }, - // Property { - // name: String::from("MoscowMule"), - // type_field: String::from("bool"), - // components: None, - // }, - // ]), - // }; - // let actual = expand_custom_enum("MatchaTea", &p)?.to_string(); - // let expected = TokenStream::from_str( - // r#" - // # [derive (Clone , Debug , Eq , PartialEq)] pub enum MatchaTea { LongIsland (u64) , MoscowMule (bool) } impl Parameterize for MatchaTea { fn param_type () -> ParamType { let mut types = Vec :: new () ; types . push (ParamType :: U64) ; types . push (ParamType :: Bool) ; let variants = EnumVariants :: new (types) . expect (concat ! ("Enum " , "MatchaTea" , " has no variants! 'abigen!' should not have succeeded!")) ; ParamType :: Enum (variants) } } impl Tokenizable for MatchaTea { fn into_token (self) -> Token { let (dis , tok) = match self { MatchaTea :: LongIsland (value) => (0u8 , Token :: U64 (value)) , MatchaTea :: MoscowMule (value) => (1u8 , Token :: Bool (value)) , } ; let variants = match Self :: param_type () { ParamType :: Enum (variants) => variants , other => panic ! ("Calling ::param_type() on a custom enum must return a ParamType::Enum but instead it returned: {}" , other) } ; let selector = (dis , tok , variants) ; Token :: Enum (Box :: new (selector)) } fn from_token (token : Token) -> Result < Self , SDKError > { if let Token :: Enum (enum_selector) = token { match * enum_selector { (0u8 , token , _) => Ok (MatchaTea :: LongIsland (< u64 > :: from_token (token) ?)) , (1u8 , token , _) => Ok (MatchaTea :: MoscowMule (< bool > :: from_token (token) ?)) , (_ , _ , _) => Err (SDKError :: InstantiationError (format ! ("Could not construct '{}'. Failed to match with discriminant selector {:?}" , "MatchaTea" , enum_selector))) } } else { Err (SDKError :: InstantiationError (format ! ("Could not construct '{}'. Expected a token of type Token::Enum, got {:?}" , "MatchaTea" , token))) } } } impl TryFrom < & [u8] > for MatchaTea { type Error = SDKError ; fn try_from (bytes : & [u8]) -> Result < Self , Self :: Error > { try_from_bytes (bytes) } } impl TryFrom < & Vec < u8 >> for MatchaTea { type Error = SDKError ; fn try_from (bytes : & Vec < u8 >) -> Result < Self , Self :: Error > { try_from_bytes (bytes) } } impl TryFrom < Vec < u8 >> for MatchaTea { type Error = SDKError ; fn try_from (bytes : Vec < u8 >) -> Result < Self , Self :: Error > { try_from_bytes (& bytes) } } - // "#, - // )?.to_string(); - - // assert_eq!(actual, expected); - // Ok(()) - // } - - // #[test] - // fn top_lvl_enum_w_no_variants_cannot_be_constructed() -> anyhow::Result<()> { - // assert_enum_cannot_be_constructed_from(Some(vec![]))?; - // assert_enum_cannot_be_constructed_from(None)?; - // Ok(()) - // } - // #[test] - // fn nested_enum_w_no_variants_cannot_be_constructed() -> anyhow::Result<()> { - // let nested_enum_w_components = |components| { - // Some(vec![Property { - // name: "SomeEmptyEnum".to_string(), - // type_field: "enum SomeEmptyEnum".to_string(), - // components, - // }]) - // }; - - // assert_enum_cannot_be_constructed_from(nested_enum_w_components(None))?; - // assert_enum_cannot_be_constructed_from(nested_enum_w_components(Some(vec![])))?; - - // Ok(()) - // } - - // fn assert_enum_cannot_be_constructed_from( - // components: Option>, - // ) -> anyhow::Result<()> { - // let property = Property { - // components, - // ..Property::default() - // }; - - // let err = expand_custom_enum("TheEmptyEnum", &property) - // .err() - // .ok_or_else(|| anyhow!("Was able to construct an enum without variants"))?; - - // assert!( - // matches!(err, Error::InvalidType(_)), - // "Expected the error to be of the type 'InvalidType'" - // ); - - // Ok(()) - // } - - // #[test] - // fn test_expand_struct_inside_enum() -> Result<(), Error> { - // let inner_struct = Property { - // name: String::from("Infrastructure"), - // type_field: String::from("struct Building"), - // components: Some(vec![ - // Property { - // name: String::from("Rooms"), - // type_field: String::from("u8"), - // components: None, - // }, - // Property { - // name: String::from("Floors"), - // type_field: String::from("u16"), - // components: None, - // }, - // ]), - // }; - // let enum_components = vec![ - // inner_struct, - // Property { - // name: "Service".to_string(), - // type_field: "u32".to_string(), - // components: None, - // }, - // ]; - // let p = Property { - // name: String::from("CityComponent"), - // type_field: String::from("enum CityComponent"), - // components: Some(enum_components), - // }; - // let actual = expand_custom_enum("Amsterdam", &p)?.to_string(); - // let expected = TokenStream::from_str( - // r#" - // # [derive (Clone , Debug , Eq , PartialEq)] pub enum Amsterdam { Infrastructure (Building) , Service (u32) } impl Parameterize for Amsterdam { fn param_type () -> ParamType { let mut types = Vec :: new () ; types . push (Building :: param_type ()) ; types . push (ParamType :: U32) ; let variants = EnumVariants :: new (types) . expect (concat ! ("Enum " , "Amsterdam" , " has no variants! 'abigen!' should not have succeeded!")) ; ParamType :: Enum (variants) } } impl Tokenizable for Amsterdam { fn into_token (self) -> Token { let (dis , tok) = match self { Amsterdam :: Infrastructure (inner_struct) => (0u8 , inner_struct . into_token ()) , Amsterdam :: Service (value) => (1u8 , Token :: U32 (value)) , } ; let variants = match Self :: param_type () { ParamType :: Enum (variants) => variants , other => panic ! ("Calling ::param_type() on a custom enum must return a ParamType::Enum but instead it returned: {}" , other) } ; let selector = (dis , tok , variants) ; Token :: Enum (Box :: new (selector)) } fn from_token (token : Token) -> Result < Self , SDKError > { if let Token :: Enum (enum_selector) = token { match * enum_selector { (0u8 , token , _) => { let variant_content = < Building > :: from_token (token) ? ; Ok (Amsterdam :: Infrastructure (variant_content)) } (1u8 , token , _) => Ok (Amsterdam :: Service (< u32 > :: from_token (token) ?)) , (_ , _ , _) => Err (SDKError :: InstantiationError (format ! ("Could not construct '{}'. Failed to match with discriminant selector {:?}" , "Amsterdam" , enum_selector))) } } else { Err (SDKError :: InstantiationError (format ! ("Could not construct '{}'. Expected a token of type Token::Enum, got {:?}" , "Amsterdam" , token))) } } } impl TryFrom < & [u8] > for Amsterdam { type Error = SDKError ; fn try_from (bytes : & [u8]) -> Result < Self , Self :: Error > { try_from_bytes (bytes) } } impl TryFrom < & Vec < u8 >> for Amsterdam { type Error = SDKError ; fn try_from (bytes : & Vec < u8 >) -> Result < Self , Self :: Error > { try_from_bytes (bytes) } } impl TryFrom < Vec < u8 >> for Amsterdam { type Error = SDKError ; fn try_from (bytes : Vec < u8 >) -> Result < Self , Self :: Error > { try_from_bytes (& bytes) } } - // "#, - // )?.to_string(); - - // assert_eq!(actual, expected); - // Ok(()) - // } - - // #[test] - // fn test_expand_array_inside_enum() -> Result<(), Error> { - // let enum_components = vec![Property { - // name: "SomeArr".to_string(), - // type_field: "[u64; 7]".to_string(), - // components: None, - // }]; - // let p = Property { - // name: String::from("unused"), - // type_field: String::from("unused"), - // components: Some(enum_components), - // }; - // let actual = expand_custom_enum("SomeEnum", &p)?.to_string(); - // let expected = TokenStream::from_str( - // r#" - // # [derive (Clone , Debug , Eq , PartialEq)] pub enum SomeEnum { SomeArr (:: std :: vec :: Vec < u64 >) } impl Parameterize for SomeEnum { fn param_type () -> ParamType { let mut types = Vec :: new () ; types . push (ParamType :: Array (Box :: new (ParamType :: U64) , 7)) ; let variants = EnumVariants :: new (types) . expect (concat ! ("Enum " , "SomeEnum" , " has no variants! 'abigen!' should not have succeeded!")) ; ParamType :: Enum (variants) } } impl Tokenizable for SomeEnum { fn into_token (self) -> Token { let (dis , tok) = match self { SomeEnum :: SomeArr (value) => (0u8 , Token :: Array (vec ! [value . into_token ()])) , } ; let variants = match Self :: param_type () { ParamType :: Enum (variants) => variants , other => panic ! ("Calling ::param_type() on a custom enum must return a ParamType::Enum but instead it returned: {}" , other) } ; let selector = (dis , tok , variants) ; Token :: Enum (Box :: new (selector)) } fn from_token (token : Token) -> Result < Self , SDKError > { if let Token :: Enum (enum_selector) = token { match * enum_selector { (0u8 , token , _) => Ok (SomeEnum :: SomeArr (< :: std :: vec :: Vec < u64 > > :: from_token (token) ?)) , (_ , _ , _) => Err (SDKError :: InstantiationError (format ! ("Could not construct '{}'. Failed to match with discriminant selector {:?}" , "SomeEnum" , enum_selector))) } } else { Err (SDKError :: InstantiationError (format ! ("Could not construct '{}'. Expected a token of type Token::Enum, got {:?}" , "SomeEnum" , token))) } } } impl TryFrom < & [u8] > for SomeEnum { type Error = SDKError ; fn try_from (bytes : & [u8]) -> Result < Self , Self :: Error > { try_from_bytes (bytes) } } impl TryFrom < & Vec < u8 >> for SomeEnum { type Error = SDKError ; fn try_from (bytes : & Vec < u8 >) -> Result < Self , Self :: Error > { try_from_bytes (bytes) } } impl TryFrom < Vec < u8 >> for SomeEnum { type Error = SDKError ; fn try_from (bytes : Vec < u8 >) -> Result < Self , Self :: Error > { try_from_bytes (& bytes) } } - // "#, - // )?.to_string(); - - // assert_eq!(actual, expected); - // Ok(()) - // } - - // #[test] - // fn test_expand_custom_enum_with_enum() -> Result<(), Error> { - // let p = Property { - // name: String::from("unused"), - // type_field: String::from("unused"), - // components: Some(vec![Property { - // name: String::from("El2"), - // type_field: String::from("enum EnumLevel2"), - // components: Some(vec![Property { - // name: String::from("El1"), - // type_field: String::from("enum EnumLevel1"), - // components: Some(vec![Property { - // name: String::from("Num"), - // type_field: String::from("u32"), - // components: None, - // }]), - // }]), - // }]), - // }; - // let actual = expand_custom_enum("EnumLevel3", &p)?.to_string(); - // let expected = TokenStream::from_str( - // r#" - // # [derive (Clone , Debug , Eq , PartialEq)] pub enum EnumLevel3 { El2 (EnumLevel2) } impl Parameterize for EnumLevel3 { fn param_type () -> ParamType { let mut types = Vec :: new () ; types . push (EnumLevel2 :: param_type ()) ; let variants = EnumVariants :: new (types) . expect (concat ! ("Enum " , "EnumLevel3" , " has no variants! 'abigen!' should not have succeeded!")) ; ParamType :: Enum (variants) } } impl Tokenizable for EnumLevel3 { fn into_token (self) -> Token { let (dis , tok) = match self { EnumLevel3 :: El2 (inner_enum) => (0u8 , inner_enum . into_token ()) , } ; let variants = match Self :: param_type () { ParamType :: Enum (variants) => variants , other => panic ! ("Calling ::param_type() on a custom enum must return a ParamType::Enum but instead it returned: {}" , other) } ; let selector = (dis , tok , variants) ; Token :: Enum (Box :: new (selector)) } fn from_token (token : Token) -> Result < Self , SDKError > { if let Token :: Enum (enum_selector) = token { match * enum_selector { (0u8 , token , _) => { let variant_content = < EnumLevel2 > :: from_token (token) ? ; Ok (EnumLevel3 :: El2 (variant_content)) } (_ , _ , _) => Err (SDKError :: InstantiationError (format ! ("Could not construct '{}'. Failed to match with discriminant selector {:?}" , "EnumLevel3" , enum_selector))) } } else { Err (SDKError :: InstantiationError (format ! ("Could not construct '{}'. Expected a token of type Token::Enum, got {:?}" , "EnumLevel3" , token))) } } } impl TryFrom < & [u8] > for EnumLevel3 { type Error = SDKError ; fn try_from (bytes : & [u8]) -> Result < Self , Self :: Error > { try_from_bytes (bytes) } } impl TryFrom < & Vec < u8 >> for EnumLevel3 { type Error = SDKError ; fn try_from (bytes : & Vec < u8 >) -> Result < Self , Self :: Error > { try_from_bytes (bytes) } } impl TryFrom < Vec < u8 >> for EnumLevel3 { type Error = SDKError ; fn try_from (bytes : Vec < u8 >) -> Result < Self , Self :: Error > { try_from_bytes (& bytes) } } - // "#, - // )?.to_string(); - - // assert_eq!(actual, expected); - // Ok(()) - // } - - // #[test] - // fn test_expand_custom_struct() -> Result<(), Error> { - // let p = Property { - // name: String::from("unused"), - // type_field: String::from("struct Cocktail"), - // components: Some(vec![ - // Property { - // name: String::from("long_island"), - // type_field: String::from("bool"), - // components: None, - // }, - // Property { - // name: String::from("cosmopolitan"), - // type_field: String::from("u64"), - // components: None, - // }, - // Property { - // name: String::from("mojito"), - // type_field: String::from("u32"), - // components: None, - // }, - // ]), - // }; - // let actual = expand_custom_struct(&p)?.to_string(); - // let expected = TokenStream::from_str( - // r#" - // # [derive (Clone , Debug , Eq , PartialEq)] pub struct Cocktail { pub long_island : bool , pub cosmopolitan : u64 , pub mojito : u32 } impl Parameterize for Cocktail { fn param_type () -> ParamType { let mut types = Vec :: new () ; types . push (ParamType :: Bool) ; types . push (ParamType :: U64) ; types . push (ParamType :: U32) ; ParamType :: Struct (types) } } impl Tokenizable for Cocktail { fn into_token (self) -> Token { let mut tokens = Vec :: new () ; tokens . push (Token :: Bool (self . long_island)) ; tokens . push (Token :: U64 (self . cosmopolitan)) ; tokens . push (Token :: U32 (self . mojito)) ; Token :: Struct (tokens) } fn from_token (token : Token) -> Result < Self , SDKError > { match token { Token :: Struct (tokens) => { let mut tokens_iter = tokens . into_iter () ; let mut next_token = move || { tokens_iter . next () . ok_or_else (|| { SDKError :: InstantiationError (format ! ("Ran out of tokens before '{}' has finished construction!" , "Cocktail")) }) } ; Ok (Self { long_island : < bool > :: from_token (next_token () ?) ? , cosmopolitan : < u64 > :: from_token (next_token () ?) ? , mojito : < u32 > :: from_token (next_token () ?) ? }) } , other => Err (SDKError :: InstantiationError (format ! ("Error while constructing '{}'. Expected token of type Token::Struct, got {:?}" , "Cocktail" , other))) , } } } impl TryFrom < & [u8] > for Cocktail { type Error = SDKError ; fn try_from (bytes : & [u8]) -> Result < Self , Self :: Error > { try_from_bytes (bytes) } } impl TryFrom < & Vec < u8 >> for Cocktail { type Error = SDKError ; fn try_from (bytes : & Vec < u8 >) -> Result < Self , Self :: Error > { try_from_bytes (bytes) } } impl TryFrom < Vec < u8 >> for Cocktail { type Error = SDKError ; fn try_from (bytes : Vec < u8 >) -> Result < Self , Self :: Error > { try_from_bytes (& bytes) } } - // "#, - // )?.to_string(); - - // assert_eq!(actual, expected); - // Ok(()) - // } - - // #[test] - // fn test_expand_custom_struct_with_struct() -> Result<(), Error> { - // let p = Property { - // name: String::from("unused"), - // type_field: String::from("struct Cocktail"), - // components: Some(vec![ - // Property { - // name: String::from("long_island"), - // type_field: String::from("struct Shaker"), - // components: Some(vec![ - // Property { - // name: String::from("cosmopolitan"), - // type_field: String::from("bool"), - // components: None, - // }, - // Property { - // name: String::from("bimbap"), - // type_field: String::from("u64"), - // components: None, - // }, - // ]), - // }, - // Property { - // name: String::from("mojito"), - // type_field: String::from("u32"), - // components: None, - // }, - // ]), - // }; - // let actual = expand_custom_struct(&p)?.to_string(); - // let expected = TokenStream::from_str( - // r#" - // # [derive (Clone , Debug , Eq , PartialEq)] pub struct Cocktail { pub long_island : Shaker , pub mojito : u32 } impl Parameterize for Cocktail { fn param_type () -> ParamType { let mut types = Vec :: new () ; types . push (Shaker :: param_type ()) ; types . push (ParamType :: U32) ; ParamType :: Struct (types) } } impl Tokenizable for Cocktail { fn into_token (self) -> Token { let mut tokens = Vec :: new () ; tokens . push (self . long_island . into_token ()) ; tokens . push (Token :: U32 (self . mojito)) ; Token :: Struct (tokens) } fn from_token (token : Token) -> Result < Self , SDKError > { match token { Token :: Struct (tokens) => { let mut tokens_iter = tokens . into_iter () ; let mut next_token = move || { tokens_iter . next () . ok_or_else (|| { SDKError :: InstantiationError (format ! ("Ran out of tokens before '{}' has finished construction!" , "Cocktail")) }) } ; Ok (Self { long_island : Shaker :: from_token (next_token () ?) ? , mojito : < u32 > :: from_token (next_token () ?) ? }) } , other => Err (SDKError :: InstantiationError (format ! ("Error while constructing '{}'. Expected token of type Token::Struct, got {:?}" , "Cocktail" , other))) , } } } impl TryFrom < & [u8] > for Cocktail { type Error = SDKError ; fn try_from (bytes : & [u8]) -> Result < Self , Self :: Error > { try_from_bytes (bytes) } } impl TryFrom < & Vec < u8 >> for Cocktail { type Error = SDKError ; fn try_from (bytes : & Vec < u8 >) -> Result < Self , Self :: Error > { try_from_bytes (bytes) } } impl TryFrom < Vec < u8 >> for Cocktail { type Error = SDKError ; fn try_from (bytes : Vec < u8 >) -> Result < Self , Self :: Error > { try_from_bytes (& bytes) } } - // "#, - // )?.to_string(); - - // assert_eq!(actual, expected); - // Ok(()) - // } - - // TODO: FIX ME - // #[test] - // fn test_expand_struct_new_abi() -> Result<(), Error> { - // let s = r#" - // { - // "types": [ - // { - // "typeId": 6, - // "type": "u64", - // "components": null, - // "typeParameters": null - // }, - // { - // "typeId": 8, - // "type": "b256", - // "components": null, - // "typeParameters": null - // }, - // { - // "typeId": 6, - // "type": "u64", - // "components": null, - // "typeParameters": null - // }, - // { - // "typeId": 8, - // "type": "b256", - // "components": null, - // "typeParameters": null - // }, - // { - // "typeId": 10, - // "type": "bool", - // "components": null, - // "typeParameters": null - // }, - // { - // "typeId": 12, - // "type": "struct MyStruct1", - // "components": [ - // { - // "name": "x", - // "type": 6, - // "typeArguments": null - // }, - // { - // "name": "y", - // "type": 8, - // "typeArguments": null - // } - // ], - // "typeParameters": null - // }, - // { - // "typeId": 6, - // "type": "u64", - // "components": null, - // "typeParameters": null - // }, - // { - // "typeId": 8, - // "type": "b256", - // "components": null, - // "typeParameters": null - // }, - // { - // "typeId": 2, - // "type": "struct MyStruct1", - // "components": [ - // { - // "name": "x", - // "type": 6, - // "typeArguments": null - // }, - // { - // "name": "y", - // "type": 8, - // "typeArguments": null - // } - // ], - // "typeParameters": null - // }, - // { - // "typeId": 3, - // "type": "struct MyStruct2", - // "components": [ - // { - // "name": "x", - // "type": 10, - // "typeArguments": null - // }, - // { - // "name": "y", - // "type": 12, - // "typeArguments": [] - // } - // ], - // "typeParameters": null - // }, - // { - // "typeId": 26, - // "type": "struct MyStruct1", - // "components": [ - // { - // "name": "x", - // "type": 6, - // "typeArguments": null - // }, - // { - // "name": "y", - // "type": 8, - // "typeArguments": null - // } - // ], - // "typeParameters": null - // } - // ], - // "functions": [ - // { - // "type": "function", - // "inputs": [ - // { - // "name": "s1", - // "type": 2, - // "typeArguments": [] - // }, - // { - // "name": "s2", - // "type": 3, - // "typeArguments": [] - // } - // ], - // "name": "some_abi_funct", - // "output": { - // "name": "", - // "type": 26, - // "typeArguments": [] - // } - // } - // ] - // } - // "#; - // let parsed_abi: ProgramABI = serde_json::from_str(s)?; - // let all_types = parsed_abi - // .types - // .into_iter() - // .map(|t| (t.type_id, t)) - // .collect::>(); - // - // let s1 = all_types.get(&2).unwrap(); - // - // let actual = expand_custom_struct(s1, &all_types)?.to_string(); - // - // let expected = TokenStream::from_str( - // r#" - // # [derive (Clone , Debug , Eq , PartialEq)] pub struct MyStruct1 { pub x : u64 , pub y : [u8 ; 32] } impl Parameterize for MyStruct1 { fn param_type () -> ParamType { let mut types = Vec :: new () ; types . push (ParamType :: U64) ; types . push (ParamType :: B256) ; ParamType :: Struct (types) } } impl Tokenizable for MyStruct1 { fn into_token (self) -> Token { let mut tokens = Vec :: new () ; tokens . push (Token :: U64 (self . x)) ; tokens . push (Token :: B256 (self . y)) ; Token :: Struct (tokens) } fn from_token (token : Token) -> Result < Self , SDKError > { match token { Token :: Struct (tokens) => { let mut tokens_iter = tokens . into_iter () ; let mut next_token = move || { tokens_iter . next () . ok_or_else (|| { SDKError :: InstantiationError (format ! ("Ran out of tokens before '{}' has finished construction!" , "MyStruct1")) }) } ; Ok (Self { x : < u64 > :: from_token (next_token () ?) ? , y : < [u8 ; 32] > :: from_token (next_token () ?) ? }) } , other => Err (SDKError :: InstantiationError (format ! ("Error while constructing '{}'. Expected token of type Token::Struct, got {:?}" , "MyStruct1" , other))) , } } } impl TryFrom < & [u8] > for MyStruct1 { type Error = SDKError ; fn try_from (bytes : & [u8]) -> Result < Self , Self :: Error > { try_from_bytes (bytes) } } impl TryFrom < & Vec < u8 >> for MyStruct1 { type Error = SDKError ; fn try_from (bytes : & Vec < u8 >) -> Result < Self , Self :: Error > { try_from_bytes (bytes) } } impl TryFrom < Vec < u8 >> for MyStruct1 { type Error = SDKError ; fn try_from (bytes : Vec < u8 >) -> Result < Self , Self :: Error > { try_from_bytes (& bytes) } } - // "#, - // )?.to_string(); - // - // assert_eq!(actual, expected); - // - // let s2 = all_types.get(&3).unwrap(); - // - // let actual = expand_custom_struct(s2, &all_types)?.to_string(); - // - // let expected = TokenStream::from_str( - // r#" - // # [derive (Clone , Debug , Eq , PartialEq)] pub struct MyStruct2 { pub x : bool , pub y : MyStruct1 } impl Parameterize for MyStruct2 { fn param_type () -> ParamType { let mut types = Vec :: new () ; types . push (ParamType :: Bool) ; types . push (MyStruct1 :: param_type ()) ; ParamType :: Struct (types) } } impl Tokenizable for MyStruct2 { fn into_token (self) -> Token { let mut tokens = Vec :: new () ; tokens . push (Token :: Bool (self . x)) ; tokens . push (self . y . into_token ()) ; Token :: Struct (tokens) } fn from_token (token : Token) -> Result < Self , SDKError > { match token { Token :: Struct (tokens) => { let mut tokens_iter = tokens . into_iter () ; let mut next_token = move || { tokens_iter . next () . ok_or_else (|| { SDKError :: InstantiationError (format ! ("Ran out of tokens before '{}' has finished construction!" , "MyStruct2")) }) } ; Ok (Self { x : < bool > :: from_token (next_token () ?) ? , y : MyStruct1 :: from_token (next_token () ?) ? }) } , other => Err (SDKError :: InstantiationError (format ! ("Error while constructing '{}'. Expected token of type Token::Struct, got {:?}" , "MyStruct2" , other))) , } } } impl TryFrom < & [u8] > for MyStruct2 { type Error = SDKError ; fn try_from (bytes : & [u8]) -> Result < Self , Self :: Error > { try_from_bytes (bytes) } } impl TryFrom < & Vec < u8 >> for MyStruct2 { type Error = SDKError ; fn try_from (bytes : & Vec < u8 >) -> Result < Self , Self :: Error > { try_from_bytes (bytes) } } impl TryFrom < Vec < u8 >> for MyStruct2 { type Error = SDKError ; fn try_from (bytes : Vec < u8 >) -> Result < Self , Self :: Error > { try_from_bytes (& bytes) } } - // "#, - // )?.to_string(); - // - // assert_eq!(actual, expected); - // - // Ok(()) - // } + use std::{collections::HashMap, str::FromStr}; + + use super::*; + use crate::Error; + + use anyhow::anyhow; + use fuels_types::{ProgramABI, TypeApplication, TypeDeclaration}; + use proc_macro2::TokenStream; + + #[test] + fn test_expand_custom_enum() -> Result<(), Error> { + let p = TypeDeclaration { + type_id: 0, + type_field: String::from("enum MatchaTea"), + components: Some(vec![ + TypeApplication { + name: String::from("LongIsland"), + type_id: 1, + ..Default::default() + }, + TypeApplication { + name: String::from("MoscowMule"), + type_id: 2, + ..Default::default() + }, + ]), + ..Default::default() + }; + let types = [ + (0, p.clone()), + ( + 1, + TypeDeclaration { + type_id: 1, + type_field: String::from("u64"), + ..Default::default() + }, + ), + ( + 2, + TypeDeclaration { + type_id: 2, + type_field: String::from("bool"), + ..Default::default() + }, + ), + ] + .into_iter() + .collect::>(); + let actual = expand_custom_enum(&p, &types)?.to_string(); + let expected = TokenStream::from_str( + r#" + # [derive (Clone , Debug , Eq , PartialEq)] pub enum MatchaTea < > { LongIsland (u64) , MoscowMule (bool) } impl < > Parameterize for MatchaTea < > { fn param_type () -> ParamType { let mut param_types = vec ! [] ; param_types . push (< u64 > :: param_type ()) ; param_types . push (< bool > :: param_type ()) ; let variants = EnumVariants :: new (param_types) . unwrap_or_else (| _ | panic ! ("{} has no variants which isn't allowed!" , "MatchaTea")) ; ParamType :: Enum { variants , generics : vec ! [] } } } impl < > Tokenizable for MatchaTea < > { fn from_token (token : Token) -> Result < Self , SDKError > where Self : Sized , { let gen_err = | msg | { SDKError :: InvalidData (format ! ("Error while instantiating {} from token! {}" , "MatchaTea" , msg)) } ; match token { Token :: Enum (selector) => { let (discriminant , variant_token , _) = * selector ; match discriminant { 0u8 => Ok (Self :: LongIsland (< u64 > :: from_token (variant_token) ?)) , 1u8 => Ok (Self :: MoscowMule (< bool > :: from_token (variant_token) ?)) , _ => Err (gen_err (format ! ("Discriminant {} doesn't point to any of the enums variants." , discriminant))) , } } _ => Err (gen_err (format ! ("Given token ({}) is not of the type Token::Enum!" , token))) , } } fn into_token (self) -> Token { let (discriminant , token) = match self { Self :: LongIsland (inner) => (0u8 , inner . into_token ()) , Self :: MoscowMule (inner) => (1u8 , inner . into_token ()) } ; let variants = match Self :: param_type () { ParamType :: Enum { variants , .. } => variants , other => panic ! ("Calling {}::param_type() must return a ParamType::Enum but instead it returned: {:?}" , "MatchaTea" , other) } ; Token :: Enum (Box :: new ((discriminant , token , variants))) } } impl < > TryFrom < & [u8] > for MatchaTea < > { type Error = SDKError ; fn try_from (bytes : & [u8]) -> Result < Self , Self :: Error > { try_from_bytes (bytes) } } impl < > TryFrom < & Vec < u8 >> for MatchaTea < > { type Error = SDKError ; fn try_from (bytes : & Vec < u8 >) -> Result < Self , Self :: Error > { try_from_bytes (& bytes) } } impl < > TryFrom < Vec < u8 >> for MatchaTea < > { type Error = SDKError ; fn try_from (bytes : Vec < u8 >) -> Result < Self , Self :: Error > { try_from_bytes (& bytes) } } + "#, + )? + .to_string(); + + assert_eq!(actual, expected); + Ok(()) + } + + #[test] + fn test_enum_with_no_variants_cannot_be_constructed() -> anyhow::Result<()> { + let p = TypeDeclaration { + type_id: 0, + type_field: "enum SomeEmptyEnum".to_string(), + components: Some(vec![]), + ..Default::default() + }; + let types = [(0, p.clone())].into_iter().collect::>(); + + let err = expand_custom_enum(&p, &types) + .err() + .ok_or_else(|| anyhow!("Was able to construct an enum without variants"))?; + + assert!( + matches!(err, Error::ParseTokenStreamError(_)), + "Expected the error to be of the type 'ParseTokenStreamError'" + ); + + Ok(()) + } + + #[test] + fn test_expand_struct_inside_enum() -> Result<(), Error> { + let inner_struct = TypeApplication { + name: String::from("Infrastructure"), + type_id: 1, + ..Default::default() + }; + let enum_components = vec![ + inner_struct, + TypeApplication { + name: "Service".to_string(), + type_id: 2, + ..Default::default() + }, + ]; + let p = TypeDeclaration { + type_id: 0, + type_field: String::from("enum Amsterdam"), + components: Some(enum_components), + ..Default::default() + }; + + let types = [ + (0, p.clone()), + ( + 1, + TypeDeclaration { + type_id: 1, + type_field: String::from("struct Building"), + components: Some(vec![ + TypeApplication { + name: String::from("Rooms"), + type_id: 3, + ..Default::default() + }, + TypeApplication { + name: String::from("Floors"), + type_id: 4, + ..Default::default() + }, + ]), + ..Default::default() + }, + ), + ( + 2, + TypeDeclaration { + type_id: 2, + type_field: String::from("u32"), + ..Default::default() + }, + ), + ( + 3, + TypeDeclaration { + type_id: 3, + type_field: String::from("u8"), + ..Default::default() + }, + ), + ( + 4, + TypeDeclaration { + type_id: 4, + type_field: String::from("u16"), + ..Default::default() + }, + ), + ] + .into_iter() + .collect::>(); + let actual = expand_custom_enum(&p, &types)?.to_string(); + let expected = TokenStream::from_str( + r#" + # [derive (Clone , Debug , Eq , PartialEq)] pub enum Amsterdam < > { Infrastructure (Building) , Service (u32) } impl < > Parameterize for Amsterdam < > { fn param_type () -> ParamType { let mut param_types = vec ! [] ; param_types . push (< Building > :: param_type ()) ; param_types . push (< u32 > :: param_type ()) ; let variants = EnumVariants :: new (param_types) . unwrap_or_else (| _ | panic ! ("{} has no variants which isn't allowed!" , "Amsterdam")) ; ParamType :: Enum { variants , generics : vec ! [] } } } impl < > Tokenizable for Amsterdam < > { fn from_token (token : Token) -> Result < Self , SDKError > where Self : Sized , { let gen_err = | msg | { SDKError :: InvalidData (format ! ("Error while instantiating {} from token! {}" , "Amsterdam" , msg)) } ; match token { Token :: Enum (selector) => { let (discriminant , variant_token , _) = * selector ; match discriminant { 0u8 => Ok (Self :: Infrastructure (< Building > :: from_token (variant_token) ?)) , 1u8 => Ok (Self :: Service (< u32 > :: from_token (variant_token) ?)) , _ => Err (gen_err (format ! ("Discriminant {} doesn't point to any of the enums variants." , discriminant))) , } } _ => Err (gen_err (format ! ("Given token ({}) is not of the type Token::Enum!" , token))) , } } fn into_token (self) -> Token { let (discriminant , token) = match self { Self :: Infrastructure (inner) => (0u8 , inner . into_token ()) , Self :: Service (inner) => (1u8 , inner . into_token ()) } ; let variants = match Self :: param_type () { ParamType :: Enum { variants , .. } => variants , other => panic ! ("Calling {}::param_type() must return a ParamType::Enum but instead it returned: {:?}" , "Amsterdam" , other) } ; Token :: Enum (Box :: new ((discriminant , token , variants))) } } impl < > TryFrom < & [u8] > for Amsterdam < > { type Error = SDKError ; fn try_from (bytes : & [u8]) -> Result < Self , Self :: Error > { try_from_bytes (bytes) } } impl < > TryFrom < & Vec < u8 >> for Amsterdam < > { type Error = SDKError ; fn try_from (bytes : & Vec < u8 >) -> Result < Self , Self :: Error > { try_from_bytes (& bytes) } } impl < > TryFrom < Vec < u8 >> for Amsterdam < > { type Error = SDKError ; fn try_from (bytes : Vec < u8 >) -> Result < Self , Self :: Error > { try_from_bytes (& bytes) } } + "#, + )?.to_string(); + + assert_eq!(actual, expected); + Ok(()) + } + + #[test] + fn test_expand_array_inside_enum() -> Result<(), Error> { + let enum_components = vec![TypeApplication { + name: "SomeArr".to_string(), + type_id: 1, + ..Default::default() + }]; + let p = TypeDeclaration { + type_id: 0, + type_field: String::from("enum SomeEnum"), + components: Some(enum_components), + ..Default::default() + }; + let types = [ + (0, p.clone()), + ( + 1, + TypeDeclaration { + type_id: 1, + type_field: "[u64; 7]".to_string(), + components: Some(vec![TypeApplication { + type_id: 2, + ..Default::default() + }]), + ..Default::default() + }, + ), + ( + 2, + TypeDeclaration { + type_id: 2, + type_field: "u64".to_string(), + ..Default::default() + }, + ), + ] + .into_iter() + .collect::>(); + let actual = expand_custom_enum(&p, &types)?.to_string(); + let expected = TokenStream::from_str( + r#" + # [derive (Clone , Debug , Eq , PartialEq)] pub enum SomeEnum < > { SomeArr ([u64 ; 7usize]) } impl < > Parameterize for SomeEnum < > { fn param_type () -> ParamType { let mut param_types = vec ! [] ; param_types . push (< [u64 ; 7usize] > :: param_type ()) ; let variants = EnumVariants :: new (param_types) . unwrap_or_else (| _ | panic ! ("{} has no variants which isn't allowed!" , "SomeEnum")) ; ParamType :: Enum { variants , generics : vec ! [] } } } impl < > Tokenizable for SomeEnum < > { fn from_token (token : Token) -> Result < Self , SDKError > where Self : Sized , { let gen_err = | msg | { SDKError :: InvalidData (format ! ("Error while instantiating {} from token! {}" , "SomeEnum" , msg)) } ; match token { Token :: Enum (selector) => { let (discriminant , variant_token , _) = * selector ; match discriminant { 0u8 => Ok (Self :: SomeArr (< [u64 ; 7usize] > :: from_token (variant_token) ?)) , _ => Err (gen_err (format ! ("Discriminant {} doesn't point to any of the enums variants." , discriminant))) , } } _ => Err (gen_err (format ! ("Given token ({}) is not of the type Token::Enum!" , token))) , } } fn into_token (self) -> Token { let (discriminant , token) = match self { Self :: SomeArr (inner) => (0u8 , inner . into_token ()) } ; let variants = match Self :: param_type () { ParamType :: Enum { variants , .. } => variants , other => panic ! ("Calling {}::param_type() must return a ParamType::Enum but instead it returned: {:?}" , "SomeEnum" , other) } ; Token :: Enum (Box :: new ((discriminant , token , variants))) } } impl < > TryFrom < & [u8] > for SomeEnum < > { type Error = SDKError ; fn try_from (bytes : & [u8]) -> Result < Self , Self :: Error > { try_from_bytes (bytes) } } impl < > TryFrom < & Vec < u8 >> for SomeEnum < > { type Error = SDKError ; fn try_from (bytes : & Vec < u8 >) -> Result < Self , Self :: Error > { try_from_bytes (& bytes) } } impl < > TryFrom < Vec < u8 >> for SomeEnum < > { type Error = SDKError ; fn try_from (bytes : Vec < u8 >) -> Result < Self , Self :: Error > { try_from_bytes (& bytes) } } + "#, + )?.to_string(); + + assert_eq!(actual, expected); + Ok(()) + } + + #[test] + fn test_expand_custom_enum_with_enum() -> Result<(), Error> { + let p = TypeDeclaration { + type_id: 3, + type_field: String::from("enum EnumLevel3"), + components: Some(vec![TypeApplication { + name: String::from("El2"), + type_id: 2, + ..Default::default() + }]), + ..Default::default() + }; + let types = [ + (3, p.clone()), + ( + 2, + TypeDeclaration { + type_id: 2, + type_field: String::from("enum EnumLevel2"), + components: Some(vec![TypeApplication { + name: String::from("El1"), + type_id: 1, + ..Default::default() + }]), + ..Default::default() + }, + ), + ( + 1, + TypeDeclaration { + type_id: 1, + type_field: String::from("enum EnumLevel1"), + components: Some(vec![TypeApplication { + name: String::from("Num"), + type_id: 0, + ..Default::default() + }]), + ..Default::default() + }, + ), + ( + 0, + TypeDeclaration { + type_id: 0, + type_field: String::from("u32"), + ..Default::default() + }, + ), + ] + .into_iter() + .collect::>(); + let actual = expand_custom_enum(&p, &types)?.to_string(); + let expected = TokenStream::from_str( + r#" + # [derive (Clone , Debug , Eq , PartialEq)] pub enum EnumLevel3 < > { El2 (EnumLevel2) } impl < > Parameterize for EnumLevel3 < > { fn param_type () -> ParamType { let mut param_types = vec ! [] ; param_types . push (< EnumLevel2 > :: param_type ()) ; let variants = EnumVariants :: new (param_types) . unwrap_or_else (| _ | panic ! ("{} has no variants which isn't allowed!" , "EnumLevel3")) ; ParamType :: Enum { variants , generics : vec ! [] } } } impl < > Tokenizable for EnumLevel3 < > { fn from_token (token : Token) -> Result < Self , SDKError > where Self : Sized , { let gen_err = | msg | { SDKError :: InvalidData (format ! ("Error while instantiating {} from token! {}" , "EnumLevel3" , msg)) } ; match token { Token :: Enum (selector) => { let (discriminant , variant_token , _) = * selector ; match discriminant { 0u8 => Ok (Self :: El2 (< EnumLevel2 > :: from_token (variant_token) ?)) , _ => Err (gen_err (format ! ("Discriminant {} doesn't point to any of the enums variants." , discriminant))) , } } _ => Err (gen_err (format ! ("Given token ({}) is not of the type Token::Enum!" , token))) , } } fn into_token (self) -> Token { let (discriminant , token) = match self { Self :: El2 (inner) => (0u8 , inner . into_token ()) } ; let variants = match Self :: param_type () { ParamType :: Enum { variants , .. } => variants , other => panic ! ("Calling {}::param_type() must return a ParamType::Enum but instead it returned: {:?}" , "EnumLevel3" , other) } ; Token :: Enum (Box :: new ((discriminant , token , variants))) } } impl < > TryFrom < & [u8] > for EnumLevel3 < > { type Error = SDKError ; fn try_from (bytes : & [u8]) -> Result < Self , Self :: Error > { try_from_bytes (bytes) } } impl < > TryFrom < & Vec < u8 >> for EnumLevel3 < > { type Error = SDKError ; fn try_from (bytes : & Vec < u8 >) -> Result < Self , Self :: Error > { try_from_bytes (& bytes) } } impl < > TryFrom < Vec < u8 >> for EnumLevel3 < > { type Error = SDKError ; fn try_from (bytes : Vec < u8 >) -> Result < Self , Self :: Error > { try_from_bytes (& bytes) } } + "#, + )?.to_string(); + + assert_eq!(actual, expected); + Ok(()) + } + + #[test] + fn test_expand_custom_struct() -> Result<(), Error> { + let p = TypeDeclaration { + type_field: String::from("struct Cocktail"), + components: Some(vec![ + TypeApplication { + name: String::from("long_island"), + type_id: 1, + ..Default::default() + }, + TypeApplication { + name: String::from("cosmopolitan"), + type_id: 2, + ..Default::default() + }, + TypeApplication { + name: String::from("mojito"), + type_id: 3, + ..Default::default() + }, + ]), + ..Default::default() + }; + let types = [ + (0, p.clone()), + ( + 1, + TypeDeclaration { + type_id: 1, + type_field: String::from("bool"), + ..Default::default() + }, + ), + ( + 2, + TypeDeclaration { + type_id: 2, + type_field: String::from("u64"), + ..Default::default() + }, + ), + ( + 3, + TypeDeclaration { + type_id: 3, + type_field: String::from("u32"), + ..Default::default() + }, + ), + ] + .into_iter() + .collect::>(); + let actual = expand_custom_struct(&p, &types)?.to_string(); + let expected = TokenStream::from_str( + r#" + # [derive (Clone , Debug , Eq , PartialEq)] pub struct Cocktail < > { pub long_island : bool , pub cosmopolitan : u64 , pub mojito : u32 } impl < > Parameterize for Cocktail < > { fn param_type () -> ParamType { let mut types = Vec :: new () ; types . push (< bool > :: param_type ()) ; types . push (< u64 > :: param_type ()) ; types . push (< u32 > :: param_type ()) ; ParamType :: Struct { fields : types , generics : vec ! [] } } } impl < > Tokenizable for Cocktail < > { fn into_token (self) -> Token { let mut tokens = Vec :: new () ; tokens . push (self . long_island . into_token ()) ; tokens . push (self . cosmopolitan . into_token ()) ; tokens . push (self . mojito . into_token ()) ; Token :: Struct (tokens) } fn from_token (token : Token) -> Result < Self , SDKError > { match token { Token :: Struct (tokens) => { let mut tokens_iter = tokens . into_iter () ; let mut next_token = move || { tokens_iter . next () . ok_or_else (|| { SDKError :: InstantiationError (format ! ("Ran out of tokens before '{}' has finished construction!" , "Cocktail")) }) } ; Ok (Self { long_island : < bool > :: from_token (next_token () ?) ? , cosmopolitan : < u64 > :: from_token (next_token () ?) ? , mojito : < u32 > :: from_token (next_token () ?) ? , }) } , other => Err (SDKError :: InstantiationError (format ! ("Error while constructing '{}'. Expected token of type Token::Struct, got {:?}" , "Cocktail" , other))) , } } } impl < > TryFrom < & [u8] > for Cocktail < > { type Error = SDKError ; fn try_from (bytes : & [u8]) -> Result < Self , Self :: Error > { try_from_bytes (bytes) } } impl < > TryFrom < & Vec < u8 >> for Cocktail < > { type Error = SDKError ; fn try_from (bytes : & Vec < u8 >) -> Result < Self , Self :: Error > { try_from_bytes (& bytes) } } impl < > TryFrom < Vec < u8 >> for Cocktail < > { type Error = SDKError ; fn try_from (bytes : Vec < u8 >) -> Result < Self , Self :: Error > { try_from_bytes (& bytes) } } + "#, + )?.to_string(); + + assert_eq!(actual, expected); + Ok(()) + } + + #[test] + fn test_struct_with_no_fields_cannot_be_constructed() -> anyhow::Result<()> { + let p = TypeDeclaration { + type_id: 0, + type_field: "struct SomeEmptyStruct".to_string(), + components: Some(vec![]), + ..Default::default() + }; + let types = [(0, p.clone())].into_iter().collect::>(); + + let err = expand_custom_struct(&p, &types) + .err() + .ok_or_else(|| anyhow!("Was able to construct a struct without fields"))?; + + assert!( + matches!(err, Error::ParseTokenStreamError(_)), + "Expected the error to be of the type 'ParseTokenStreamError'" + ); + + Ok(()) + } + + #[test] + fn test_expand_custom_struct_with_struct() -> Result<(), Error> { + let p = TypeDeclaration { + type_id: 0, + type_field: String::from("struct Cocktail"), + components: Some(vec![ + TypeApplication { + name: String::from("long_island"), + type_id: 1, + ..Default::default() + }, + TypeApplication { + name: String::from("mojito"), + type_id: 4, + ..Default::default() + }, + ]), + ..Default::default() + }; + let types = [ + (0, p.clone()), + ( + 1, + TypeDeclaration { + type_id: 1, + type_field: String::from("struct Shaker"), + components: Some(vec![ + TypeApplication { + name: String::from("cosmopolitan"), + type_id: 2, + ..Default::default() + }, + TypeApplication { + name: String::from("bimbap"), + type_id: 3, + ..Default::default() + }, + ]), + ..Default::default() + }, + ), + ( + 2, + TypeDeclaration { + type_id: 2, + type_field: String::from("bool"), + ..Default::default() + }, + ), + ( + 3, + TypeDeclaration { + type_id: 3, + type_field: String::from("u64"), + ..Default::default() + }, + ), + ( + 4, + TypeDeclaration { + type_id: 4, + type_field: String::from("u32"), + ..Default::default() + }, + ), + ] + .into_iter() + .collect::>(); + let actual = expand_custom_struct(&p, &types)?.to_string(); + let expected = TokenStream::from_str( + r#" + # [derive (Clone , Debug , Eq , PartialEq)] pub struct Cocktail < > { pub long_island : Shaker , pub mojito : u32 } impl < > Parameterize for Cocktail < > { fn param_type () -> ParamType { let mut types = Vec :: new () ; types . push (< Shaker > :: param_type ()) ; types . push (< u32 > :: param_type ()) ; ParamType :: Struct { fields : types , generics : vec ! [] } } } impl < > Tokenizable for Cocktail < > { fn into_token (self) -> Token { let mut tokens = Vec :: new () ; tokens . push (self . long_island . into_token ()) ; tokens . push (self . mojito . into_token ()) ; Token :: Struct (tokens) } fn from_token (token : Token) -> Result < Self , SDKError > { match token { Token :: Struct (tokens) => { let mut tokens_iter = tokens . into_iter () ; let mut next_token = move || { tokens_iter . next () . ok_or_else (|| { SDKError :: InstantiationError (format ! ("Ran out of tokens before '{}' has finished construction!" , "Cocktail")) }) } ; Ok (Self { long_island : < Shaker > :: from_token (next_token () ?) ? , mojito : < u32 > :: from_token (next_token () ?) ? , }) } , other => Err (SDKError :: InstantiationError (format ! ("Error while constructing '{}'. Expected token of type Token::Struct, got {:?}" , "Cocktail" , other))) , } } } impl < > TryFrom < & [u8] > for Cocktail < > { type Error = SDKError ; fn try_from (bytes : & [u8]) -> Result < Self , Self :: Error > { try_from_bytes (bytes) } } impl < > TryFrom < & Vec < u8 >> for Cocktail < > { type Error = SDKError ; fn try_from (bytes : & Vec < u8 >) -> Result < Self , Self :: Error > { try_from_bytes (& bytes) } } impl < > TryFrom < Vec < u8 >> for Cocktail < > { type Error = SDKError ; fn try_from (bytes : Vec < u8 >) -> Result < Self , Self :: Error > { try_from_bytes (& bytes) } } + "#, + )?.to_string(); + + assert_eq!(actual, expected); + Ok(()) + } + + #[test] + fn test_expand_struct_new_abi() -> Result<(), Error> { + let s = r#" + { + "types": [ + { + "typeId": 6, + "type": "u64", + "components": null, + "typeParameters": null + }, + { + "typeId": 8, + "type": "b256", + "components": null, + "typeParameters": null + }, + { + "typeId": 6, + "type": "u64", + "components": null, + "typeParameters": null + }, + { + "typeId": 8, + "type": "b256", + "components": null, + "typeParameters": null + }, + { + "typeId": 10, + "type": "bool", + "components": null, + "typeParameters": null + }, + { + "typeId": 12, + "type": "struct MyStruct1", + "components": [ + { + "name": "x", + "type": 6, + "typeArguments": null + }, + { + "name": "y", + "type": 8, + "typeArguments": null + } + ], + "typeParameters": null + }, + { + "typeId": 6, + "type": "u64", + "components": null, + "typeParameters": null + }, + { + "typeId": 8, + "type": "b256", + "components": null, + "typeParameters": null + }, + { + "typeId": 2, + "type": "struct MyStruct1", + "components": [ + { + "name": "x", + "type": 6, + "typeArguments": null + }, + { + "name": "y", + "type": 8, + "typeArguments": null + } + ], + "typeParameters": null + }, + { + "typeId": 3, + "type": "struct MyStruct2", + "components": [ + { + "name": "x", + "type": 10, + "typeArguments": null + }, + { + "name": "y", + "type": 12, + "typeArguments": [] + } + ], + "typeParameters": null + }, + { + "typeId": 26, + "type": "struct MyStruct1", + "components": [ + { + "name": "x", + "type": 6, + "typeArguments": null + }, + { + "name": "y", + "type": 8, + "typeArguments": null + } + ], + "typeParameters": null + } + ], + "functions": [ + { + "type": "function", + "inputs": [ + { + "name": "s1", + "type": 2, + "typeArguments": [] + }, + { + "name": "s2", + "type": 3, + "typeArguments": [] + } + ], + "name": "some_abi_funct", + "output": { + "name": "", + "type": 26, + "typeArguments": [] + } + } + ] + } + "#; + let parsed_abi: ProgramABI = serde_json::from_str(s)?; + let all_types = parsed_abi + .types + .into_iter() + .map(|t| (t.type_id, t)) + .collect::>(); + + let s1 = all_types.get(&2).unwrap(); + + let actual = expand_custom_struct(s1, &all_types)?.to_string(); + + let expected = TokenStream::from_str( + r#" + # [derive (Clone , Debug , Eq , PartialEq)] pub struct MyStruct1 < > { pub x : u64 , pub y : Bits256 } impl < > Parameterize for MyStruct1 < > { fn param_type () -> ParamType { let mut types = Vec :: new () ; types . push (< u64 > :: param_type ()) ; types . push (< Bits256 > :: param_type ()) ; ParamType :: Struct { fields : types , generics : vec ! [] } } } impl < > Tokenizable for MyStruct1 < > { fn into_token (self) -> Token { let mut tokens = Vec :: new () ; tokens . push (self . x . into_token ()) ; tokens . push (self . y . into_token ()) ; Token :: Struct (tokens) } fn from_token (token : Token) -> Result < Self , SDKError > { match token { Token :: Struct (tokens) => { let mut tokens_iter = tokens . into_iter () ; let mut next_token = move || { tokens_iter . next () . ok_or_else (|| { SDKError :: InstantiationError (format ! ("Ran out of tokens before '{}' has finished construction!" , "MyStruct1")) }) } ; Ok (Self { x : < u64 > :: from_token (next_token () ?) ? , y : < Bits256 > :: from_token (next_token () ?) ? , }) } , other => Err (SDKError :: InstantiationError (format ! ("Error while constructing '{}'. Expected token of type Token::Struct, got {:?}" , "MyStruct1" , other))) , } } } impl < > TryFrom < & [u8] > for MyStruct1 < > { type Error = SDKError ; fn try_from (bytes : & [u8]) -> Result < Self , Self :: Error > { try_from_bytes (bytes) } } impl < > TryFrom < & Vec < u8 >> for MyStruct1 < > { type Error = SDKError ; fn try_from (bytes : & Vec < u8 >) -> Result < Self , Self :: Error > { try_from_bytes (& bytes) } } impl < > TryFrom < Vec < u8 >> for MyStruct1 < > { type Error = SDKError ; fn try_from (bytes : Vec < u8 >) -> Result < Self , Self :: Error > { try_from_bytes (& bytes) } } + "#, + )?.to_string(); + + assert_eq!(actual, expected); + + let s2 = all_types.get(&3).unwrap(); + + let actual = expand_custom_struct(s2, &all_types)?.to_string(); + + let expected = TokenStream::from_str( + r#" + # [derive (Clone , Debug , Eq , PartialEq)] pub struct MyStruct2 < > { pub x : bool , pub y : MyStruct1 } impl < > Parameterize for MyStruct2 < > { fn param_type () -> ParamType { let mut types = Vec :: new () ; types . push (< bool > :: param_type ()) ; types . push (< MyStruct1 > :: param_type ()) ; ParamType :: Struct { fields : types , generics : vec ! [] } } } impl < > Tokenizable for MyStruct2 < > { fn into_token (self) -> Token { let mut tokens = Vec :: new () ; tokens . push (self . x . into_token ()) ; tokens . push (self . y . into_token ()) ; Token :: Struct (tokens) } fn from_token (token : Token) -> Result < Self , SDKError > { match token { Token :: Struct (tokens) => { let mut tokens_iter = tokens . into_iter () ; let mut next_token = move || { tokens_iter . next () . ok_or_else (|| { SDKError :: InstantiationError (format ! ("Ran out of tokens before '{}' has finished construction!" , "MyStruct2")) }) } ; Ok (Self { x : < bool > :: from_token (next_token () ?) ? , y : < MyStruct1 > :: from_token (next_token () ?) ? , }) } , other => Err (SDKError :: InstantiationError (format ! ("Error while constructing '{}'. Expected token of type Token::Struct, got {:?}" , "MyStruct2" , other))) , } } } impl < > TryFrom < & [u8] > for MyStruct2 < > { type Error = SDKError ; fn try_from (bytes : & [u8]) -> Result < Self , Self :: Error > { try_from_bytes (bytes) } } impl < > TryFrom < & Vec < u8 >> for MyStruct2 < > { type Error = SDKError ; fn try_from (bytes : & Vec < u8 >) -> Result < Self , Self :: Error > { try_from_bytes (& bytes) } } impl < > TryFrom < Vec < u8 >> for MyStruct2 < > { type Error = SDKError ; fn try_from (bytes : Vec < u8 >) -> Result < Self , Self :: Error > { try_from_bytes (& bytes) } } + "#, + )?.to_string(); + + assert_eq!(actual, expected); + + Ok(()) + } } diff --git a/packages/fuels-core/src/code_gen/functions_gen.rs b/packages/fuels-core/src/code_gen/functions_gen.rs index a70bdf031f..226ca41c89 100644 --- a/packages/fuels-core/src/code_gen/functions_gen.rs +++ b/packages/fuels-core/src/code_gen/functions_gen.rs @@ -108,7 +108,7 @@ pub fn expand_input_name(name: &str) -> Result { #[cfg(test)] mod tests { use super::*; - use fuels_types::ProgramABI; + use fuels_types::{ProgramABI, TypeApplication}; use std::str::FromStr; #[test] @@ -289,299 +289,312 @@ mod tests { Ok(()) } - // TODO: Move tests using the old abigen to the new one. - // Currently, they will be skipped. Even though we're not fully testing these at - // unit level, they're tested at integration level, in the main harness.rs file. - - // #[test] - // fn test_expand_function_simple() -> Result<(), Error> { - // let mut the_function = Function { - // type_field: "unused".to_string(), - // inputs: vec![], - // name: "HelloWorld".to_string(), - // outputs: vec![], - // }; - // the_function.inputs.push(Property { - // name: String::from("bimbam"), - // type_field: String::from("bool"), - // components: None, - // }); - // let result = expand_function(&the_function, &Default::default(), &Default::default()); - // let expected = TokenStream::from_str( - // r#" - // #[doc = "Calls the contract's `HelloWorld` (0x0000000097d4de45) function"] - // pub fn HelloWorld(&self, bimbam: bool) -> ContractCallHandler<()> { - // Contract::method_hash( - // &self.wallet.get_provider().expect("Provider not set up"), - // self.contract_id.clone(), - // &self.wallet, - // [0, 0, 0, 0, 151, 212, 222, 69], - // None, - // &[bimbam.into_token() ,] - // ) - // .expect("method not found (this should never happen)") - // } - // "#, - // ); - // let expected = expected?.to_string(); - - // assert_eq!(result?.to_string(), expected); - // Ok(()) - // } - - // #[test] - // fn test_expand_function_complex() -> Result<(), Error> { - // let mut the_function = Function { - // type_field: "function".to_string(), - // name: "hello_world".to_string(), - // inputs: vec![], - // outputs: vec![Property { - // name: String::from("stillnotused"), - // type_field: String::from("enum EntropyCirclesEnum"), - // components: Some(vec![ - // Property { - // name: String::from("Postcard"), - // type_field: String::from("bool"), - // components: None, - // }, - // Property { - // name: String::from("Teacup"), - // type_field: String::from("u64"), - // components: None, - // }, - // ]), - // }], - // }; - // the_function.inputs.push(Property { - // name: String::from("the_only_allowed_input"), - // type_field: String::from("struct BurgundyBeefStruct"), - // components: Some(vec![ - // Property { - // name: String::from("Beef"), - // type_field: String::from("bool"), - // components: None, - // }, - // Property { - // name: String::from("BurgundyWine"), - // type_field: String::from("u64"), - // components: None, - // }, - // ]), - // }); - // let mut custom_structs = HashMap::new(); - // custom_structs.insert( - // "BurgundyBeefStruct".to_string(), - // Property { - // name: "unused".to_string(), - // type_field: "struct SomeWeirdFrenchCuisine".to_string(), - // components: None, - // }, - // ); - // custom_structs.insert( - // "CoolIndieGame".to_string(), - // Property { - // name: "unused".to_string(), - // type_field: "struct CoolIndieGame".to_string(), - // components: None, - // }, - // ); - // let mut custom_enums = HashMap::new(); - // custom_enums.insert( - // "EntropyCirclesEnum".to_string(), - // Property { - // name: "unused".to_string(), - // type_field: "enum EntropyCirclesEnum".to_string(), - // components: None, - // }, - // ); - // let result = expand_function(&the_function, &custom_enums, &custom_structs); - // // Some more editing was required because it is not rustfmt-compatible (adding/removing parentheses or commas) - // let expected = TokenStream::from_str( - // r#" - // #[doc = "Calls the contract's `hello_world` (0x0000000076b25a24) function"] - // pub fn hello_world( - // &self, - // the_only_allowed_input: SomeWeirdFrenchCuisine - // ) -> ContractCallHandler { - // Contract::method_hash( - // &self.wallet.get_provider().expect("Provider not set up"), - // self.contract_id.clone(), - // &self.wallet, - // [0, 0, 0, 0, 118, 178, 90, 36], - // Some(ParamType::Enum(EnumVariants::new(vec![ParamType::Bool, ParamType::U64]).unwrap())), - // &[the_only_allowed_input.into_token() ,] - // ) - // .expect("method not found (this should never happen)") - // } - // "#, - // ); - // let expected = expected?.to_string(); - - // assert_eq!(result?.to_string(), expected); - // Ok(()) - // } + #[test] + fn test_expand_function_simple() -> Result<(), Error> { + let the_function = ABIFunction { + inputs: vec![TypeApplication { + name: String::from("bimbam"), + type_id: 1, + ..Default::default() + }], + name: "HelloWorld".to_string(), + ..Default::default() + }; + let types = [ + ( + 0, + TypeDeclaration { + type_id: 0, + type_field: String::from("()"), + ..Default::default() + }, + ), + ( + 1, + TypeDeclaration { + type_id: 1, + type_field: String::from("bool"), + ..Default::default() + }, + ), + ] + .into_iter() + .collect::>(); + let result = expand_function(&the_function, &types); + let expected = TokenStream::from_str( + r#" + #[doc = "Calls the contract's `HelloWorld` function"] + pub fn HelloWorld(&self, bimbam: bool) -> ContractCallHandler<()> { + let provider = self.wallet.get_provider().expect("Provider not set up"); + let encoded_fn_selector = resolve_fn_selector("HelloWorld", &[ :: param_type()]); + let tokens = [bimbam.into_token()]; + Contract::method_hash( + &provider, + self.contract_id.clone(), + &self.wallet, + encoded_fn_selector, + &tokens + ) + .expect("method not found (this should never happen)") + } + "#, + ); + let expected = expected?.to_string(); + + assert_eq!(result?.to_string(), expected); + Ok(()) + } - // --- expand_selector --- + #[test] + fn test_expand_function_complex() -> Result<(), Error> { + let the_function = ABIFunction { + inputs: vec![TypeApplication { + name: String::from("the_only_allowed_input"), + type_id: 4, + ..Default::default() + }], + name: "hello_world".to_string(), + output: TypeApplication { + name: String::from("stillnotused"), + type_id: 1, + ..Default::default() + }, + }; + let types = [ + ( + 1, + TypeDeclaration { + type_id: 1, + type_field: String::from("enum EntropyCirclesEnum"), + components: Some(vec![ + TypeApplication { + name: String::from("Postcard"), + type_id: 2, + ..Default::default() + }, + TypeApplication { + name: String::from("Teacup"), + type_id: 3, + ..Default::default() + }, + ]), + ..Default::default() + }, + ), + ( + 2, + TypeDeclaration { + type_id: 2, + type_field: String::from("bool"), + ..Default::default() + }, + ), + ( + 3, + TypeDeclaration { + type_id: 3, + type_field: String::from("u64"), + ..Default::default() + }, + ), + ( + 4, + TypeDeclaration { + type_id: 4, + type_field: String::from("struct SomeWeirdFrenchCuisine"), + components: Some(vec![ + TypeApplication { + name: String::from("Beef"), + type_id: 2, + ..Default::default() + }, + TypeApplication { + name: String::from("BurgundyWine"), + type_id: 3, + ..Default::default() + }, + ]), + ..Default::default() + }, + ), + ] + .into_iter() + .collect::>(); + let result = expand_function(&the_function, &types); + // Some more editing was required because it is not rustfmt-compatible (adding/removing parentheses or commas) + let expected = TokenStream::from_str( + r#" + #[doc = "Calls the contract's `hello_world` function"] + pub fn hello_world( + &self, + the_only_allowed_input: SomeWeirdFrenchCuisine + ) -> ContractCallHandler { + let provider = self.wallet.get_provider().expect("Provider not set up"); + let encoded_fn_selector = resolve_fn_selector("hello_world", &[ :: param_type()]); + let tokens = [the_only_allowed_input.into_token()]; + Contract::method_hash( + &provider, + self.contract_id.clone(), + &self.wallet, + encoded_fn_selector, + &tokens + ) + .expect("method not found (this should never happen)") + } + "#, + ); + let expected = expected?.to_string(); + + assert_eq!(result?.to_string(), expected); + Ok(()) + } - // --- expand_fn_outputs --- - // #[test] - // fn test_expand_fn_outputs() -> Result<(), Error> { - // let result = expand_fn_outputs(&[]); - // assert_eq!(result?.to_string(), "()"); - - // // Primitive type - // let result = expand_fn_outputs(&[Property { - // name: "unused".to_string(), - // type_field: "bool".to_string(), - // components: None, - // }]); - // assert_eq!(result?.to_string(), "bool"); - - // // Struct type - // let result = expand_fn_outputs(&[Property { - // name: "unused".to_string(), - // type_field: String::from("struct streaming_services"), - // components: Some(vec![ - // Property { - // name: String::from("unused"), - // type_field: String::from("thistypedoesntexist"), - // components: None, - // }, - // Property { - // name: String::from("unused"), - // type_field: String::from("thistypedoesntexist"), - // components: None, - // }, - // ]), - // }]); - // assert_eq!(result?.to_string(), "streaming_services"); - - // // Enum type - // let result = expand_fn_outputs(&[Property { - // name: "unused".to_string(), - // type_field: String::from("enum StreamingServices"), - // components: Some(vec![ - // Property { - // name: String::from("unused"), - // type_field: String::from("bool"), - // components: None, - // }, - // Property { - // name: String::from("unused"), - // type_field: String::from("u64"), - // components: None, - // }, - // ]), - // }]); - // assert_eq!(result?.to_string(), "StreamingServices"); - // Ok(()) - // } + // --- expand_selector --- // // --- expand_function_argument --- - // #[test] - // fn test_expand_function_arguments() -> Result<(), Error> { - // let hm: HashMap = HashMap::new(); - // let the_argument = Property { - // name: "some_argument".to_string(), - // type_field: String::from("u32"), - // components: None, - // }; - - // // All arguments are here - // let mut the_function = Function { - // type_field: "".to_string(), - // inputs: vec![], - // name: "".to_string(), - // outputs: vec![], - // }; - // the_function.inputs.push(the_argument); - - // let result = expand_function_arguments(&the_function, &hm, &hm); - // let (args, call_args) = result?; - // let result = format!("({},{})", args, call_args); - // let expected = "(, some_argument : u32,& [some_argument . into_token () ,])"; - - // assert_eq!(result, expected); - // Ok(()) - // } - - // #[test] - // fn test_expand_function_arguments_primitive() -> Result<(), Error> { - // let hm: HashMap = HashMap::new(); - // let mut the_function = Function { - // type_field: "function".to_string(), - // inputs: vec![], - // name: "pip_pop".to_string(), - // outputs: vec![], - // }; - - // the_function.inputs.push(Property { - // name: "bim_bam".to_string(), - // type_field: String::from("u64"), - // components: None, - // }); - // let result = expand_function_arguments(&the_function, &hm, &hm); - // let (args, call_args) = result?; - // let result = format!("({},{})", args, call_args); - - // assert_eq!(result, "(, bim_bam : u64,& [bim_bam . into_token () ,])"); - // Ok(()) - // } - - // #[test] - // fn test_expand_function_arguments_composite() -> Result<(), Error> { - // let mut function = Function { - // type_field: "zig_zag".to_string(), - // inputs: vec![], - // name: "PipPopFunction".to_string(), - // outputs: vec![], - // }; - // function.inputs.push(Property { - // name: "bim_bam".to_string(), - // type_field: String::from("struct CarMaker"), - // components: Some(vec![Property { - // name: "name".to_string(), - // type_field: "str[5]".to_string(), - // components: None, - // }]), - // }); - // let mut custom_structs = HashMap::new(); - // custom_structs.insert( - // "CarMaker".to_string(), - // Property { - // name: "unused".to_string(), - // type_field: "struct CarMaker".to_string(), - // components: None, - // }, - // ); - // let mut custom_enums = HashMap::new(); - // custom_enums.insert( - // "Cocktail".to_string(), - // Property { - // name: "Cocktail".to_string(), - // type_field: "enum Cocktail".to_string(), - // components: Some(vec![Property { - // name: "variant".to_string(), - // type_field: "u32".to_string(), - // components: None, - // }]), - // }, - // ); - - // let result = expand_function_arguments(&function, &custom_enums, &custom_structs); - // let (args, call_args) = result?; - // let result = format!("({},{})", args, call_args); - // let expected = r#"(, bim_bam : CarMaker,& [bim_bam . into_token () ,])"#; - // assert_eq!(result, expected); - - // function.inputs[0].type_field = "enum Cocktail".to_string(); - // let result = expand_function_arguments(&function, &custom_enums, &custom_structs); - // let (args, call_args) = result?; - // let result = format!("({},{})", args, call_args); - // let expected = r#"(, bim_bam : Cocktail,& [bim_bam . into_token () ,])"#; - // assert_eq!(result, expected); - // Ok(()) - // } + #[test] + fn test_expand_function_arguments() -> Result<(), Error> { + let the_argument = TypeApplication { + name: "some_argument".to_string(), + type_id: 0, + ..Default::default() + }; + + // All arguments are here + let the_function = ABIFunction { + inputs: vec![the_argument], + ..ABIFunction::default() + }; + + let types = [( + 0, + TypeDeclaration { + type_id: 0, + type_field: String::from("u32"), + ..Default::default() + }, + )] + .into_iter() + .collect::>(); + let result = function_arguments(&the_function, &types)?; + let component = &result[0]; + + assert_eq!(&component.field_name.to_string(), "some_argument"); + assert_eq!(&component.field_type.to_string(), "u32"); + + Ok(()) + } + + #[test] + fn test_expand_function_arguments_primitive() -> Result<(), Error> { + let the_function = ABIFunction { + inputs: vec![TypeApplication { + name: "bim_bam".to_string(), + type_id: 1, + ..Default::default() + }], + name: "pip_pop".to_string(), + ..Default::default() + }; + + let types = [ + ( + 0, + TypeDeclaration { + type_id: 0, + type_field: String::from("()"), + ..Default::default() + }, + ), + ( + 1, + TypeDeclaration { + type_id: 1, + type_field: String::from("u64"), + ..Default::default() + }, + ), + ] + .into_iter() + .collect::>(); + let result = function_arguments(&the_function, &types)?; + let component = &result[0]; + + assert_eq!(&component.field_name.to_string(), "bim_bam"); + assert_eq!(&component.field_type.to_string(), "u64"); + + Ok(()) + } + + #[test] + fn test_expand_function_arguments_composite() -> Result<(), Error> { + let mut function = ABIFunction { + inputs: vec![TypeApplication { + name: "bim_bam".to_string(), + type_id: 0, + ..Default::default() + }], + name: "PipPopFunction".to_string(), + ..Default::default() + }; + + let types = [ + ( + 0, + TypeDeclaration { + type_id: 0, + type_field: "struct CarMaker".to_string(), + components: Some(vec![TypeApplication { + name: "name".to_string(), + type_id: 1, + ..Default::default() + }]), + ..Default::default() + }, + ), + ( + 1, + TypeDeclaration { + type_id: 1, + type_field: "str[5]".to_string(), + ..Default::default() + }, + ), + ( + 2, + TypeDeclaration { + type_id: 2, + type_field: "enum Cocktail".to_string(), + components: Some(vec![TypeApplication { + name: "variant".to_string(), + type_id: 3, + ..Default::default() + }]), + ..Default::default() + }, + ), + ( + 3, + TypeDeclaration { + type_id: 3, + type_field: "u32".to_string(), + ..Default::default() + }, + ), + ] + .into_iter() + .collect::>(); + let result = function_arguments(&function, &types)?; + assert_eq!(&result[0].field_name.to_string(), "bim_bam"); + assert_eq!(&result[0].field_type.to_string(), "CarMaker"); + + function.inputs[0].type_id = 2; + let result = function_arguments(&function, &types)?; + assert_eq!(&result[0].field_name.to_string(), "bim_bam"); + assert_eq!(&result[0].field_type.to_string(), "Cocktail"); + + Ok(()) + } #[test] fn transform_name_to_snake_case() -> Result<(), Error> { @@ -599,113 +612,4 @@ mod tests { assert_eq!(result?.to_string(), "let_"); Ok(()) } - - // --- expand_input_param --- - // #[test] - // fn test_expand_input_param_primitive() -> Result<(), Error> { - // let def = Function::default(); - // let result = expand_input_param(&def, "unused", &ParamType::Bool, &None); - // assert_eq!(result?.to_string(), "bool"); - - // let result = expand_input_param(&def, "unused", &ParamType::U64, &None); - // assert_eq!(result?.to_string(), "u64"); - - // let result = expand_input_param(&def, "unused", &ParamType::String(10), &None); - // assert_eq!(result?.to_string(), "String"); - // Ok(()) - // } - - // #[test] - // fn test_expand_input_param_array() -> Result<(), Error> { - // let array_type = ParamType::Array(Box::new(ParamType::U64), 10); - // let result = expand_input_param(&Function::default(), "unused", &array_type, &None); - // assert_eq!(result?.to_string(), ":: std :: vec :: Vec < u64 >"); - // Ok(()) - // } - - // #[test] - // fn test_expand_input_param_custom_type() -> Result<(), Error> { - // let def = Function::default(); - // let struct_type = ParamType::Struct(vec![ParamType::Bool, ParamType::U64]); - // let struct_prop = Property { - // name: String::from("unused"), - // type_field: String::from("struct Babies"), - // components: None, - // }; - // let struct_name = Some(&struct_prop); - // let result = expand_input_param(&def, "unused", &struct_type, &struct_name); - // assert_eq!(result?.to_string(), "Babies"); - - // let enum_type = ParamType::Enum(EnumVariants::new(vec![ParamType::U8, ParamType::U32])?); - // let enum_prop = Property { - // name: String::from("unused"), - // type_field: String::from("enum Babies"), - // components: None, - // }; - // let enum_name = Some(&enum_prop); - // let result = expand_input_param(&def, "unused", &enum_type, &enum_name); - // assert_eq!(result?.to_string(), "Babies"); - // Ok(()) - // } - - // #[test] - // fn test_expand_input_param_struct_wrong_name() { - // let def = Function::default(); - // let struct_type = ParamType::Struct(vec![ParamType::Bool, ParamType::U64]); - // let struct_prop = Property { - // name: String::from("unused"), - // type_field: String::from("not_the_right_format"), - // components: None, - // }; - // let struct_name = Some(&struct_prop); - // let result = expand_input_param(&def, "unused", &struct_type, &struct_name); - // assert!(matches!(result, Err(Error::InvalidData(_)))); - // } - - // #[test] - // fn test_expand_input_param_struct_with_enum_name() { - // let def = Function::default(); - // let struct_type = ParamType::Struct(vec![ParamType::Bool, ParamType::U64]); - // let struct_prop = Property { - // name: String::from("unused"), - // type_field: String::from("enum Butitsastruct"), - // components: None, - // }; - // let struct_name = Some(&struct_prop); - // let result = expand_input_param(&def, "unused", &struct_type, &struct_name); - // assert!(matches!(result, Err(Error::InvalidType(_)))); - // } - - // #[test] - // fn can_have_b256_mixed_in_tuple_w_custom_types() -> anyhow::Result<()> { - // let test_struct_component = Property { - // name: "__tuple_element".to_string(), - // type_field: "struct TestStruct".to_string(), - // components: Some(vec![Property { - // name: "value".to_string(), - // type_field: "u64".to_string(), - // components: None, - // }]), - // }; - // let b256_component = Property { - // name: "__tuple_element".to_string(), - // type_field: "b256".to_string(), - // components: None, - // }; - - // let property = Property { - // name: "".to_string(), - // type_field: "(struct TestStruct, b256)".to_string(), - // components: Some(vec![test_struct_component, b256_component]), - // }; - - // let stream = expand_fn_outputs(slice::from_ref(&property))?; - - // let actual = stream.to_string(); - // let expected = "(TestStruct , [u8 ; 32])"; - - // assert_eq!(actual, expected); - - // Ok(()) - // } } diff --git a/packages/fuels-core/src/tokenizer.rs b/packages/fuels-core/src/tokenizer.rs index 2bf0bbc0b4..738f378c7a 100644 --- a/packages/fuels-core/src/tokenizer.rs +++ b/packages/fuels-core/src/tokenizer.rs @@ -406,81 +406,99 @@ mod tests { use super::*; use crate::Tokenizable; - // TODO: Move tests using the old abigen to the new one. - // Currently, they will be skipped. Even though we're not fully testing these at - // unit level, they're tested at integration level, in the main harness.rs file. - - // #[test] - // fn tokenize_struct_excess_value_elements_expected_error() -> Result<(), Error> { - // let params = Property { - // name: "input".to_string(), - // type_field: "struct MyStruct".to_string(), - // components: Some(vec![ - // Property { - // name: "num".to_string(), - // type_field: "u64".to_string(), - // components: None, - // }, - // Property { - // name: "arr".to_string(), - // type_field: "[u64; 3]".to_string(), - // components: None, - // }, - // ]), - // }; - - // if let ParamType::Struct(struct_params) = ParamType::parse_custom_type_param(¶ms)? { - // let error_message = Tokenizer::tokenize_struct("(0, [0,0,0], 0, 0)", &struct_params) - // .unwrap_err() - // .to_string(); - - // assert_eq!( - // "Invalid data: struct value contains more elements than the parameter types provided", - // error_message - // ); - - // let error_message = Tokenizer::tokenize_struct("(0, [0,0,0], 0)", &struct_params) - // .unwrap_err() - // .to_string(); - - // assert_eq!( - // "Invalid data: struct value contains more elements than the parameter types provided", - // error_message - // ); - // } - // Ok(()) - // } - // #[test] - // fn tokenize_struct_excess_quotes_expected_error() -> Result<(), Error> { - // let params = Property { - // name: "input".to_string(), - // type_field: "struct MyStruct".to_string(), - // components: Some(vec![ - // Property { - // name: "num".to_string(), - // type_field: "u64".to_string(), - // components: None, - // }, - // Property { - // name: "arr".to_string(), - // type_field: "[u64; 3]".to_string(), - // components: None, - // }, - // ]), - // }; - - // if let ParamType::Struct(struct_params) = ParamType::parse_custom_type_param(¶ms)? { - // let error_message = Tokenizer::tokenize_struct("(0, \"[0,0,0])", &struct_params) - // .unwrap_err() - // .to_string(); - - // assert_eq!( - // "Invalid data: struct value string has excess quotes", - // error_message - // ); - // } - // Ok(()) - // } + #[test] + fn tokenize_struct_excess_value_elements_expected_error() -> Result<(), Error> { + let struct_params = [ + ParamType::U64, + ParamType::Array(Box::new(ParamType::U64), 3), + ]; + let error_message = Tokenizer::tokenize_struct("(0, [0,0,0], 0, 0)", &struct_params) + .unwrap_err() + .to_string(); + + assert_eq!( + "Invalid data: struct value contains more elements than the parameter types provided", + error_message + ); + + let error_message = Tokenizer::tokenize_struct("(0, [0,0,0], 0)", &struct_params) + .unwrap_err() + .to_string(); + + assert_eq!( + "Invalid data: struct value contains more elements than the parameter types provided", + error_message + ); + Ok(()) + } + + #[test] + fn tokenize_struct_excess_quotes_expected_error() -> Result<(), Error> { + let struct_params = [ + ParamType::U64, + ParamType::Array(Box::new(ParamType::U64), 3), + ]; + let error_message = Tokenizer::tokenize_struct("(0, \"[0,0,0])", &struct_params) + .unwrap_err() + .to_string(); + + assert_eq!( + "Invalid data: struct value string has excess quotes", + error_message + ); + Ok(()) + } + + #[test] + fn tokenize_struct_invalid_start_end_bracket_expected_error() -> Result<(), Error> { + let struct_params = [ + ParamType::U64, + ParamType::Array(Box::new(ParamType::U64), 3), + ]; + let error_message = Tokenizer::tokenize_struct("0, [0,0,0])", &struct_params) + .unwrap_err() + .to_string(); + + assert_eq!( + "Invalid data: struct value string must start and end with round brackets", + error_message + ); + Ok(()) + } + + #[test] + fn tokenize_struct_excess_opening_bracket_expected_error() -> Result<(), Error> { + let struct_params = [ + ParamType::U64, + ParamType::Array(Box::new(ParamType::U64), 3), + ]; + let error_message = Tokenizer::tokenize_struct("((0, [0,0,0])", &struct_params) + .unwrap_err() + .to_string(); + + assert_eq!( + "Invalid data: struct value string has excess opening brackets", + error_message + ); + Ok(()) + } + + #[test] + fn tokenize_struct_excess_closing_bracket_expected_error() -> Result<(), Error> { + let struct_params = [ + ParamType::U64, + ParamType::Array(Box::new(ParamType::U64), 3), + ]; + let error_message = Tokenizer::tokenize_struct("(0, [0,0,0]))", &struct_params) + .unwrap_err() + .to_string(); + + assert_eq!( + "Invalid data: struct value string has excess closing brackets", + error_message + ); + Ok(()) + } #[test] fn tokenize_uint_types_expected_error() { @@ -530,174 +548,99 @@ mod tests { assert!(error_message.contains("Parse hex error: Invalid character")); } - // #[test] - // fn tokenize_tuple_invalid_start_end_bracket_expected_error() -> Result<(), Error> { - // let params = Property { - // name: "input".to_string(), - // type_field: "(u64, [u64; 3])".to_string(), - // components: Some(vec![ - // Property { - // name: "__tuple_element".to_string(), - // type_field: "u64".to_string(), - // components: None, - // }, - // Property { - // name: "__tuple_element".to_string(), - // type_field: "[u64; 3]".to_string(), - // components: None, - // }, - // ]), - // }; - - // if let ParamType::Tuple(tuple_params) = ParamType::parse_tuple_param(¶ms)? { - // let error_message = Tokenizer::tokenize_tuple("0, [0,0,0])", &tuple_params) - // .unwrap_err() - // .to_string(); - - // assert_eq!( - // "Invalid data: tuple value string must start and end with round brackets", - // error_message - // ); - // } - // Ok(()) - // } - - // #[test] - // fn tokenize_tuple_excess_opening_bracket_expected_error() -> Result<(), Error> { - // let params = Property { - // name: "input".to_string(), - // type_field: "(u64, [u64; 3])".to_string(), - // components: Some(vec![ - // Property { - // name: "__tuple_element".to_string(), - // type_field: "u64".to_string(), - // components: None, - // }, - // Property { - // name: "__tuple_element".to_string(), - // type_field: "[u64; 3]".to_string(), - // components: None, - // }, - // ]), - // }; - - // if let ParamType::Tuple(tuple_params) = ParamType::parse_tuple_param(¶ms)? { - // let error_message = Tokenizer::tokenize_tuple("((0, [0,0,0])", &tuple_params) - // .unwrap_err() - // .to_string(); - - // assert_eq!( - // "Invalid data: tuple value string has excess opening brackets", - // error_message - // ); - // } - // Ok(()) - // } - - // #[test] - // fn tokenize_tuple_excess_closing_bracket_expected_error() -> Result<(), Error> { - // let params = Property { - // name: "input".to_string(), - // type_field: "(u64, [u64; 3])".to_string(), - // components: Some(vec![ - // Property { - // name: "__tuple_element".to_string(), - // type_field: "u64".to_string(), - // components: None, - // }, - // Property { - // name: "__tuple_element".to_string(), - // type_field: "[u64; 3]".to_string(), - // components: None, - // }, - // ]), - // }; - - // if let ParamType::Tuple(tuple_params) = ParamType::parse_tuple_param(¶ms)? { - // let error_message = Tokenizer::tokenize_tuple("(0, [0,0,0]))", &tuple_params) - // .unwrap_err() - // .to_string(); - - // assert_eq!( - // "Invalid data: tuple value string has excess closing brackets", - // error_message - // ); - // } - // Ok(()) - // } - - // #[test] - // fn tokenize_tuple_excess_quotes_expected_error() -> Result<(), Error> { - // let params = Property { - // name: "input".to_string(), - // type_field: "(u64, [u64; 3])".to_string(), - // components: Some(vec![ - // Property { - // name: "__tuple_element".to_string(), - // type_field: "u64".to_string(), - // components: None, - // }, - // Property { - // name: "__tuple_element".to_string(), - // type_field: "[u64; 3]".to_string(), - // components: None, - // }, - // ]), - // }; - - // if let ParamType::Tuple(tuple_params) = ParamType::parse_tuple_param(¶ms)? { - // let error_message = Tokenizer::tokenize_tuple("(0, \"[0,0,0])", &tuple_params) - // .unwrap_err() - // .to_string(); - - // assert_eq!( - // "Invalid data: tuple value string has excess quotes", - // error_message - // ); - // } - // Ok(()) - // } - - // #[test] - // fn tokenize_tuple_excess_value_elements_expected_error() -> Result<(), Error> { - // let params = Property { - // name: "input".to_string(), - // type_field: "(u64, [u64; 3])".to_string(), - // components: Some(vec![ - // Property { - // name: "__tuple_element".to_string(), - // type_field: "u64".to_string(), - // components: None, - // }, - // Property { - // name: "__tuple_element".to_string(), - // type_field: "[u64; 3]".to_string(), - // components: None, - // }, - // ]), - // }; - - // if let ParamType::Tuple(tuple_params) = ParamType::parse_tuple_param(¶ms)? { - // let error_message = Tokenizer::tokenize_tuple("(0, [0,0,0], 0, 0)", &tuple_params) - // .unwrap_err() - // .to_string(); - - // assert_eq!( - // "Invalid data: tuple value contains more elements than the parameter types provided", - // error_message - // ); - - // let error_message = Tokenizer::tokenize_tuple("(0, [0,0,0], 0)", &tuple_params) - // .unwrap_err() - // .to_string(); - - // assert_eq!( - // "Invalid data: tuple value contains more elements than the parameter types provided", - // error_message - // ); - // } - // Ok(()) - // } + #[test] + fn tokenize_tuple_invalid_start_end_bracket_expected_error() -> Result<(), Error> { + let tuple_params = [ParamType::Tuple(vec![ + ParamType::U64, + ParamType::Array(Box::new(ParamType::U64), 3), + ])]; + let error_message = Tokenizer::tokenize_tuple("0, [0,0,0])", &tuple_params) + .unwrap_err() + .to_string(); + + assert_eq!( + "Invalid data: tuple value string must start and end with round brackets", + error_message + ); + Ok(()) + } + + #[test] + fn tokenize_tuple_excess_opening_bracket_expected_error() -> Result<(), Error> { + let tuple_params = [ParamType::Tuple(vec![ + ParamType::U64, + ParamType::Array(Box::new(ParamType::U64), 3), + ])]; + let error_message = Tokenizer::tokenize_tuple("((0, [0,0,0])", &tuple_params) + .unwrap_err() + .to_string(); + + assert_eq!( + "Invalid data: tuple value string has excess opening brackets", + error_message + ); + Ok(()) + } + + #[test] + fn tokenize_tuple_excess_closing_bracket_expected_error() -> Result<(), Error> { + let tuple_params = [ + ParamType::U64, + ParamType::Array(Box::new(ParamType::U64), 3), + ]; + let error_message = Tokenizer::tokenize_tuple("(0, [0,0,0]))", &tuple_params) + .unwrap_err() + .to_string(); + + assert_eq!( + "Invalid data: tuple value string has excess closing brackets", + error_message + ); + Ok(()) + } + + #[test] + fn tokenize_tuple_excess_quotes_expected_error() -> Result<(), Error> { + let tuple_params = [ + ParamType::U64, + ParamType::Array(Box::new(ParamType::U64), 3), + ]; + let error_message = Tokenizer::tokenize_tuple("(0, \"[0,0,0])", &tuple_params) + .unwrap_err() + .to_string(); + + assert_eq!( + "Invalid data: tuple value string has excess quotes", + error_message + ); + Ok(()) + } + + #[test] + fn tokenize_tuple_excess_value_elements_expected_error() -> Result<(), Error> { + let tuple_params = [ + ParamType::U64, + ParamType::Array(Box::new(ParamType::U64), 3), + ]; + let error_message = Tokenizer::tokenize_tuple("(0, [0,0,0], 0, 0)", &tuple_params) + .unwrap_err() + .to_string(); + + assert_eq!( + "Invalid data: tuple value contains more elements than the parameter types provided", + error_message + ); + + let error_message = Tokenizer::tokenize_tuple("(0, [0,0,0], 0)", &tuple_params) + .unwrap_err() + .to_string(); + + assert_eq!( + "Invalid data: tuple value contains more elements than the parameter types provided", + error_message + ); + Ok(()) + } #[test] fn tokenize_array_invalid_start_end_bracket_expected_error() { @@ -754,102 +697,6 @@ mod tests { ); } - // #[test] - // fn tokenize_struct_invalid_start_end_bracket_expected_error() -> Result<(), Error> { - // let params = Property { - // name: "input".to_string(), - // type_field: "struct MyStruct".to_string(), - // components: Some(vec![ - // Property { - // name: "num".to_string(), - // type_field: "u64".to_string(), - // components: None, - // }, - // Property { - // name: "arr".to_string(), - // type_field: "[u64; 3]".to_string(), - // components: None, - // }, - // ]), - // }; - - // if let ParamType::Struct(struct_params) = ParamType::parse_custom_type_param(¶ms)? { - // let error_message = Tokenizer::tokenize_struct("0, [0,0,0])", &struct_params) - // .unwrap_err() - // .to_string(); - - // assert_eq!( - // "Invalid data: struct value string must start and end with round brackets", - // error_message - // ); - // } - // Ok(()) - // } - - // #[test] - // fn tokenize_struct_excess_opening_bracket_expected_error() -> Result<(), Error> { - // let params = Property { - // name: "input".to_string(), - // type_field: "struct MyStruct".to_string(), - // components: Some(vec![ - // Property { - // name: "num".to_string(), - // type_field: "u64".to_string(), - // components: None, - // }, - // Property { - // name: "arr".to_string(), - // type_field: "[u64; 3]".to_string(), - // components: None, - // }, - // ]), - // }; - - // if let ParamType::Struct(struct_params) = ParamType::parse_custom_type_param(¶ms)? { - // let error_message = Tokenizer::tokenize_struct("((0, [0,0,0])", &struct_params) - // .unwrap_err() - // .to_string(); - - // assert_eq!( - // "Invalid data: struct value string has excess opening brackets", - // error_message - // ); - // } - // Ok(()) - // } - - // #[test] - // fn tokenize_struct_excess_closing_bracket_expected_error() -> Result<(), Error> { - // let params = Property { - // name: "input".to_string(), - // type_field: "struct MyStruct".to_string(), - // components: Some(vec![ - // Property { - // name: "num".to_string(), - // type_field: "u64".to_string(), - // components: None, - // }, - // Property { - // name: "arr".to_string(), - // type_field: "[u64; 3]".to_string(), - // components: None, - // }, - // ]), - // }; - - // if let ParamType::Struct(struct_params) = ParamType::parse_custom_type_param(¶ms)? { - // let error_message = Tokenizer::tokenize_struct("(0, [0,0,0]))", &struct_params) - // .unwrap_err() - // .to_string(); - - // assert_eq!( - // "Invalid data: struct value string has excess closing brackets", - // error_message - // ); - // } - // Ok(()) - // } - #[test] fn tokenize_array() -> Result<(), Error> { let value = "[[1,2],[3],4]"; diff --git a/packages/fuels-core/src/types/bits_256.rs b/packages/fuels-core/src/types/bits_256.rs index 2f436b48e0..0ed4994ba5 100644 --- a/packages/fuels-core/src/types/bits_256.rs +++ b/packages/fuels-core/src/types/bits_256.rs @@ -8,6 +8,24 @@ use fuels_types::param_types::ParamType; #[derive(Debug, PartialEq, Eq, Copy, Clone)] pub struct Bits256(pub [u8; 32]); +impl Bits256 { + /// Create a new `Bits256` from a string representation of a hex. + /// Accepts both `0x` prefixed and non-prefixed hex strings. + pub fn from_hex_str(hex: &str) -> Result { + let hex = if let Some(stripped_hex) = hex.strip_prefix("0x") { + stripped_hex + } else { + hex + }; + + let mut bytes = [0u8; 32]; + hex::decode_to_slice(hex, &mut bytes as &mut [u8]).map_err(|e| { + Error::InvalidData(format!("Could not convert hex str '{hex}' to Bits256! {e}")) + })?; + Ok(Bits256(bytes)) + } +} + impl Parameterize for Bits256 { fn param_type() -> ParamType { ParamType::B256 @@ -31,3 +49,57 @@ impl Tokenizable for Bits256 { Token::B256(self.0) } } + +#[cfg(test)] +mod tests { + use super::*; + use crate::Tokenizable; + use fuels_types::param_types::ParamType; + + #[test] + fn test_param_type() { + assert_eq!(Bits256::param_type(), ParamType::B256); + } + + #[test] + fn test_from_token() -> Result<(), Error> { + let data = [0u8; 32]; + let token = Token::B256(data); + + let bits256 = Bits256::from_token(token)?; + + assert_eq!(bits256.0, data); + + Ok(()) + } + + #[test] + fn test_into_token() { + let data = [0u8; 32]; + let bits256 = Bits256(data); + + let token = bits256.into_token(); + + assert_eq!(token, Token::B256(data)); + } + + #[test] + fn from_hex_str() -> Result<(), Error> { + // ANCHOR: from_hex_str + let hex_str = "0101010101010101010101010101010101010101010101010101010101010101"; + + let bits256 = Bits256::from_hex_str(hex_str)?; + + assert_eq!(bits256.0, [1u8; 32]); + + // With the `0x0` prefix + let hex_str = "0x0101010101010101010101010101010101010101010101010101010101010101"; + + let bits256 = Bits256::from_hex_str(hex_str)?; + + assert_eq!(bits256.0, [1u8; 32]); + // ANCHOR_END: from_hex_str + + Ok(()) + } +} diff --git a/packages/fuels/tests/contracts.rs b/packages/fuels/tests/contracts.rs index 47f55cac06..7977507b36 100644 --- a/packages/fuels/tests/contracts.rs +++ b/packages/fuels/tests/contracts.rs @@ -577,3 +577,44 @@ async fn test_output_variable_estimation_multicall() -> Result<(), Error> { Ok(()) } + +#[tokio::test] +async fn test_contract_instance_get_balances() -> Result<(), Error> { + let mut wallet = WalletUnlocked::new_random(None); + let (coins, asset_ids) = setup_multiple_assets_coins(wallet.address(), 2, 4, 8); + let random_asset_id = &asset_ids[1]; + let (provider, _) = setup_test_provider(coins.clone(), vec![], None).await; + wallet.set_provider(provider.clone()); + + setup_contract_test!( + contract_instance, + None, + "packages/fuels/tests/contracts/contract_test" + ); + let contract_id = contract_instance.get_contract_id(); + + // Check the current balance of the contract with id 'contract_id' + let contract_balances = contract_instance.get_balances().await?; + assert!(contract_balances.is_empty()); + + // Transfer an amount to the contract + let amount = 8; + let _receipts = wallet + .force_transfer_to_contract( + contract_id, + amount, + *random_asset_id, + TxParameters::default(), + ) + .await?; + + // Check that the contract now has 1 coin + let contract_balances = contract_instance.get_balances().await?; + assert_eq!(contract_balances.len(), 1); + + let random_asset_id_key = format!("{:#x}", random_asset_id); + let random_asset_balance = contract_balances.get(&random_asset_id_key).unwrap(); + assert_eq!(*random_asset_balance, amount); + + Ok(()) +} diff --git a/scripts/check-docs/src/lib.rs b/scripts/check-docs/src/lib.rs index 7e41dd40fe..d38286b3ee 100644 --- a/scripts/check-docs/src/lib.rs +++ b/scripts/check-docs/src/lib.rs @@ -181,11 +181,11 @@ pub fn extract_starts_and_ends( pub fn search_for_patterns_in_project(pattern: &str) -> anyhow::Result { let grep_project = std::process::Command::new("grep") + .arg("-H") // print filename + .arg("-n") // print line-number + .arg("-r") // search recursively .arg("--binary-files=without-match") - .arg("--with-filename") - .arg("--dereference-recursive") - .arg("--line-number") - .arg("--exclude-dir=scripts") + .arg("--exclude-dir=check-docs") .arg(pattern) .arg(".") .output()