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

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

How can I mock a Macro attribute in Rust

问题

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

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

// lib.rs
extern crate proc_macro;
use proc_macro::TokenStream;

mod macros;

#[proc_macro_attribute]
pub fn my_macro(args: TokenStream, input: TokenStream) -> TokenStream {
      proc_macro::TokenStream::from(quote!(
          pub struct MyModifiedStruct{
            #[account()]
            pub field1: u8
          }
      ))
}

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

// tests/my_test.rs

#[test]
fn test_my_macro() {
    #[my_macro]
    pub struct MyStruct{}

    let my_struct = MyStruct{field1:1} 
    assert_eq!(my_struct.field1, 1)
}

在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:

// lib.rs
extern crate proc_macro;
use proc_macro::TokenStream;

mod macros;

#[proc_macro_attribute]
pub fn my_macro(args: TokenStream, input: TokenStream) -> TokenStream {
      proc_macro::TokenStream::from(quote!(
          pub struct MyModifiedStruct{
            #[account()]
            pub field1: u8
          }
      ))
}

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

// tests/my_test.rs

#[test]
fn test_my_macro() {
    #[my_macro]
    pub struct MyStruct{}

    let my_struct = MyStruct{field1:1} 
    assert_eq!(my_struct.field1, 1)

}

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:

extern crate proc_macro;
use proc_macro::TokenStream;

mod macros;

#[proc_macro_attribute]
pub fn my_macro(args: TokenStream, input: TokenStream) -> TokenStream {
      proc_macro::TokenStream::from(quote!(
          pub struct MyModifiedStruct{
            #[account()]
            pub field1: u8
          }
      ))
}

#[proc_macro_attribute]
pub fn account(_args: TokenStream, input: TokenStream) -> TokenStream {
    input
}

tests/my_test.rs:

// tests/my_test.rs
use your_crate::{my_macro, account};

#[test]
fn test_my_macro() {
    #[my_macro]
    pub struct MyStruct{}

    let my_struct = MyStruct{field1:1} 
    assert_eq!(my_struct.field1, 1)
}
英文:

> 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:

extern crate proc_macro;
use proc_macro::TokenStream;

mod macros;

#[proc_macro_attribute]
pub fn my_macro(args: TokenStream, input: TokenStream) -> TokenStream {
      proc_macro::TokenStream::from(quote!(
          pub struct MyModifiedStruct{
            #[account()]
            pub field1: u8
          }
      ))
}

#[proc_macro_attribute]
pub fn account(_args: TokenStream, input: TokenStream) -> TokenStream {
    input
}

tests/my_test.rs:

// tests/my_test.rs
use your_crate::{my_macro, account};

#[test]
fn test_my_macro() {
    #[my_macro]
    pub struct MyStruct{}

    let my_struct = MyStruct{field1:1} 
    assert_eq!(my_struct.field1, 1)

}

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:

确定