我如你所愿,只提供翻译,不多加内容: 如何在Rust中模拟宏属性?

huangapple go评论88阅读模式
英文:

How can I mock a Macro attribute in Rust

问题

如何在Rust中进行测试时模拟一个宏属性,是否有某个库可以简化这个过程?

例如,#[my_macro] 修改了一个结构体,应用了另一个宏 #[account()] 到其中的一个字段,这个宏不在我的库中存在,但存在于使用我的宏的程序中:

  1. // lib.rs
  2. extern crate proc_macro;
  3. use proc_macro::TokenStream;
  4. mod macros;
  5. #[proc_macro_attribute]
  6. pub fn my_macro(args: TokenStream, input: TokenStream) -> TokenStream {
  7. proc_macro::TokenStream::from(quote!(
  8. pub struct MyModifiedStruct{
  9. #[account()]
  10. pub field1: u8
  11. }
  12. ))
  13. }

现在,如何在不为我的库中的#[account()]依赖项而导致错误的情况下测试my_macro

  1. // tests/my_test.rs
  2. #[test]
  3. fn test_my_macro() {
  4. #[my_macro]
  5. pub struct MyStruct{}
  6. let my_struct = MyStruct{field1:1}
  7. assert_eq!(my_struct.field1, 1)
  8. }

在Python中,我通常会模拟#[account()]属性,但不确定如何在Rust中进行这样的操作。

英文:

How can I mock a macro attribute when testing in Rust, is there some library to facilitate this?

For instance #[my_macro] modifies a struct applying another macro #[account()] to one of his fields, this macro doesn't exist in my library but exists in the programs which are using my macro:

  1. // lib.rs
  2. extern crate proc_macro;
  3. use proc_macro::TokenStream;
  4. mod macros;
  5. #[proc_macro_attribute]
  6. pub fn my_macro(args: TokenStream, input: TokenStream) -> TokenStream {
  7. proc_macro::TokenStream::from(quote!(
  8. pub struct MyModifiedStruct{
  9. #[account()]
  10. pub field1: u8
  11. }
  12. ))
  13. }

Now how can I test my_macro without getting an error for not having the #[account()] dependency in my library?

  1. // tests/my_test.rs
  2. #[test]
  3. fn test_my_macro() {
  4. #[my_macro]
  5. pub struct MyStruct{}
  6. let my_struct = MyStruct{field1:1}
  7. assert_eq!(my_struct.field1, 1)
  8. }

My normal approach in Python would be mocking the #[account()] attribute, but not sure how can that be done in Rust.

答案1

得分: 1

我通常在Python中的正常方法是模拟 #[account()] 属性,但不确定如何在Rust中实现。

你可以在与 #[my_macro] 定义相同的 proc-macro crate 中实现 #[account] 属性宏的模拟版本,并将其导入到你在使用 #[my_macro] 的范围内:

lib.rs:

  1. extern crate proc_macro;
  2. use proc_macro::TokenStream;
  3. mod macros;
  4. #[proc_macro_attribute]
  5. pub fn my_macro(args: TokenStream, input: TokenStream) -> TokenStream {
  6. proc_macro::TokenStream::from(quote!(
  7. pub struct MyModifiedStruct{
  8. #[account()]
  9. pub field1: u8
  10. }
  11. ))
  12. }
  13. #[proc_macro_attribute]
  14. pub fn account(_args: TokenStream, input: TokenStream) -> TokenStream {
  15. input
  16. }

tests/my_test.rs:

  1. // tests/my_test.rs
  2. use your_crate::{my_macro, account};
  3. #[test]
  4. fn test_my_macro() {
  5. #[my_macro]
  6. pub struct MyStruct{}
  7. let my_struct = MyStruct{field1:1}
  8. assert_eq!(my_struct.field1, 1)
  9. }
英文:

> My normal approach in Python would be mocking the #[account()] attribute, but not sure how can that be done in Rust.

You could implement a mock version of your #[account] attribute macro in the same proc-macro crate as #[my_macro] is defined and import it into the scope you are using #[my_macro] in:

lib.rs:

  1. extern crate proc_macro;
  2. use proc_macro::TokenStream;
  3. mod macros;
  4. #[proc_macro_attribute]
  5. pub fn my_macro(args: TokenStream, input: TokenStream) -> TokenStream {
  6. proc_macro::TokenStream::from(quote!(
  7. pub struct MyModifiedStruct{
  8. #[account()]
  9. pub field1: u8
  10. }
  11. ))
  12. }
  13. #[proc_macro_attribute]
  14. pub fn account(_args: TokenStream, input: TokenStream) -> TokenStream {
  15. input
  16. }

tests/my_test.rs:

  1. // tests/my_test.rs
  2. use your_crate::{my_macro, account};
  3. #[test]
  4. fn test_my_macro() {
  5. #[my_macro]
  6. pub struct MyStruct{}
  7. let my_struct = MyStruct{field1:1}
  8. assert_eq!(my_struct.field1, 1)
  9. }

huangapple
  • 本文由 发表于 2023年2月18日 12:27:12
  • 转载请务必保留本文链接:https://go.coder-hub.com/75491192.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定