Skip to content

Commit

Permalink
improve code and add tests
Browse files Browse the repository at this point in the history
  • Loading branch information
loloicci committed Mar 6, 2024
1 parent 908b554 commit bec688d
Show file tree
Hide file tree
Showing 2 changed files with 135 additions and 13 deletions.
136 changes: 129 additions & 7 deletions packages/derive/src/into_event.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ fn scan_to_string_fn(field: &Field) -> Result<Option<proc_macro2::TokenStream>>
if filtered.is_empty() {
Ok(None)
} else {
Ok(Some(filtered[0].tokens.clone()))
Ok(Some(filtered[0].parse_args()?))
}
}

Expand All @@ -35,7 +35,7 @@ fn has_use_to_string(field: &Field) -> Result<bool> {
if filtered.clone().any(|a| !a.tokens.is_empty()) {
return Err(Error::new(
field.span(),
"[IntoEvent] attribute `use_to_string` has some value. If you intend to specify the cast function to string, use `to_string_fn` instead.",
"[IntoEvent] An attribute `use_to_string` has some value. If you intend to specify the cast function to string, use `to_string_fn` instead.",
));
}
Ok(filtered.next().is_some())
Expand Down Expand Up @@ -88,12 +88,11 @@ fn make_init_from_struct(id: Ident, struct_data: DataStruct) -> Result<proc_macr
Ok(gen)
}

/// derive `IntoEvent` from a derive input. The input needs to be a struct.
pub fn derive_into_event(input: DeriveInput) -> TokenStream {
fn derive_into_event_impl(input: DeriveInput) -> proc_macro2::TokenStream {
match input.data {
syn::Data::Struct(struct_data) => make_init_from_struct(input.ident, struct_data)
.unwrap_or_else(|e| e.to_compile_error())
.into(),
syn::Data::Struct(struct_data) => {
make_init_from_struct(input.ident, struct_data).unwrap_or_else(|e| e.to_compile_error())
}
syn::Data::Enum(enum_data) => Error::new(
enum_data.enum_token.span,
"[IntoEvent] `derive(IntoEvent)` cannot be applied to Enum.",
Expand All @@ -108,3 +107,126 @@ pub fn derive_into_event(input: DeriveInput) -> TokenStream {
.into(),
}
}

/// derive `IntoEvent` from a derive input. The input needs to be a struct.
pub fn derive_into_event(input: DeriveInput) -> TokenStream {
derive_into_event_impl(input).into()
}

#[cfg(test)]
mod tests {
use super::*;
use proc_macro2::TokenStream;
use syn::parse_quote;

fn expect_compile_error(ts: TokenStream, msg: &str) {
assert!(
ts.to_string().starts_with("compile_error ! {"),
"Code does not raise compile error: `{}`",
ts.to_string()
);

assert!(
ts.to_string().contains(msg),
"Error does not have expected message \"{}\": `{}`",
msg,
ts.to_string()
);
}

#[test]
fn test_doc_example() {
let input: DeriveInput = parse_quote! {
struct StructName {
field_name_1: field_type_1,
#[use_to_string]
field_name_2: field_type_2,
#[to_string_fn(cast_fn_3)]
field_name_3: field_type_3,
}
};
let result_implement = derive_into_event_impl(input);
let expected: TokenStream = parse_quote! {
impl Into<cosmwasm_std::Event> for StructName {
fn into(self) -> cosmwasm_std::Event {
cosmwasm_std::Event::new("struct_name")
.add_attribute(stringify!(field_name_1), self.field_name_1)
.add_attribute(stringify!(field_name_2), self.field_name_2.to_string())
.add_attribute(stringify!(field_name_3), cast_fn_3 (self.field_name_3))
}
}
};
assert_eq!(expected.to_string(), result_implement.to_string())
}

#[test]
fn test_error_multiple_to_string_functions() {
let input: DeriveInput = parse_quote! {
struct StructName {
#[to_string_fn(cast_fn_1)]
#[to_string_fn(cast_fn_1)]
field_name_1: field_type_1,
}
};
let result_implement = derive_into_event_impl(input);
expect_compile_error(
result_implement,
"[IntoEvent] Only one or zero `to_string_fn`",
);
}

#[test]
fn test_error_use_to_string_has_value() {
let input: DeriveInput = parse_quote! {
struct StructName {
#[use_to_string(foo)]
field_name_1: field_type_1,
}
};
let result_implement = derive_into_event_impl(input);
expect_compile_error(
result_implement,
"[IntoEvent] An attribute `use_to_string` has some value",
);
}

#[test]
fn test_error_both_two_attributes_is_used() {
let input: DeriveInput = parse_quote! {
struct StructName {
#[use_to_string]
#[to_string_fn(cast_fn_1)]
field_name_1: field_type_1,
}
};
let result_implement = derive_into_event_impl(input);
expect_compile_error(
result_implement,
"[IntoEvent] Both `use_to_string` and `to_string_fn`",
);
}

#[test]
fn test_error_derive_enum() {
let input: DeriveInput = parse_quote! {
enum Enum {}
};
let result_implement = derive_into_event_impl(input);
expect_compile_error(
result_implement,
"[IntoEvent] `derive(IntoEvent)` cannot be applied to Enum",
);
}

#[test]
fn test_error_derive_union() {
let input: DeriveInput = parse_quote! {
union Union {}
};
let result_implement = derive_into_event_impl(input);
expect_compile_error(
result_implement,
"[IntoEvent] `derive(IntoEvent)` cannot be applied to Union",
);
}
}
12 changes: 6 additions & 6 deletions packages/derive/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -109,12 +109,12 @@ pub fn entry_point(_attr: TokenStream, mut item: TokenStream) -> TokenStream {
/// Output AST:
///
/// ```no_test
/// impl Into<cosmwasm::Event> for `StructName` {
/// fn into(self) -> Event {
/// Event::new("struct_name")
/// .add_attribute("field_name_1", self.field_value_1)
/// .add_attribute("field_name_2", self.field_value_2.to_string())
/// .add_attribute("field_name_3", casting_fn(self.field_value_3))
/// impl Into<cosmwasm_std::Event> for StructName {
/// fn into(self) -> cosmwasm_std::Event {
/// cosmwasm_std::Event::new("struct_name")
/// .add_attribute("field_name_1", self.field_name_1)
/// .add_attribute("field_name_2", self.field_name_2.to_string())
/// .add_attribute("field_name_3", cast_fn_3(self.field_name_3))
/// }
/// }
/// ```
Expand Down

0 comments on commit bec688d

Please sign in to comment.