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.
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)
}
Related
I've got a project that builds for ios, android and wasm targets, when I build for ios and android everything works but when I build for wasm I get the following error;
Im unsure what this error message actually means, I'm using an external crate libc, here's the code from my src/string.rs file
use libc::size_t;
// Helper struct that is used to give strings to C.
#[repr(C)]
pub struct StringPtr {
pub ptr: *const u8,
pub len: size_t,
}
impl<'a> From<&'a str> for StringPtr {
fn from(s: &'a str) -> Self {
StringPtr {
ptr: s.as_ptr(),
len: s.len() as size_t,
}
}
}
impl StringPtr {
pub fn as_str(&self) -> &str {
use std::{slice, str};
unsafe {
let slice = slice::from_raw_parts(self.ptr, self.len);
str::from_utf8(slice).unwrap()
}
}
}
and inside my lib.rs file I've got the following to import my string.rs file
extern crate libc;
mod string;
use string::StringPtr;
It's also worth noting that I am using cfg to conditionally include different code for different targets, maybe this is part of the problem?
i'm trying to acces a struct from the lib i'm creating to perform some unit tests.
here is a sample of the code:
src/token_deserializer.rs
use serde::Deserialize;
#[derive(Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct Token {
pub payment_data: PaymentData,
}
#[derive(Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct PaymentData {
pub data: String,
pub signature: String,
pub header: String,
pub version: String,
}
src/lib.rs
use serde_json::from_str;
use token_deserializer::Token;
pub mod token_deserializer;
pub fn deserialize_token(token: &str) -> Token{
let object: Token = from_str(token).expect("JSON was not well-formatted");
return object;
}
tests/mytest.rs
#[cfg(test)]
mod tests {
use std::fs::File;
use apple_pay_token_decryptor::deserialize_token;
use apple_pay_token_decryptor::Token;
#[test]
fn test_token_deserialization(){
let mut file = File::open("text.json").unwrap();
let mut data = String::new();
let object: Token = deserialize_token(&data);
}
}
Here i can't manage to import Token for my test => error[E0603]: struct `Token` is private
Do i need to import it in lib.rs or something else ?
Inside your test, you refer to apple_pay_token_decryptor::Token. You may think it is resolved to the pub struct Token, but in fact, it is not. Instead, it refers to this use in src/lib.rs:
use token_deserializer::Token;
And while both the struct and the token_deserializer module are public - this import is private (it is not pub use, i.e. a reexport). But it's still there. And thus the compiler complains about you using a private type.
To fix, that you either have to reexport Token - i.e. make that pub use token_deserializer::Token;, or fix the test to import the struct directly from token_deserializer:
use apple_pay_token_decryptor::token_deserializer::Token;
I have an external geometry crate that defines a rectangle struct made of floats and an external sdl2 crate that defines a rectangle struct made of integers.
The following code is how I would expect to convert a geometry::Rect to an sdl2::SdlRect using the std::convert::From trait:
extern crate geometry;
extern crate sdl2;
fn main() {
let geo_rect = geometry::Rect::default();
let sdl_rect = sdl2::SdlRect::from(geo_rect);
}
impl From<geometry::Rect> for sdl2::SdlRect {
fn from (rect: geometry::Rect) -> sdl2::SdlRect {
sdl2::SdlRect {
x: rect.x as i32,
y: rect.y as i32,
w: rect.w as i32,
h: rect.h as i32,
}
}
}
Unfortunately, this doesn't compile because either the trait I'm implementing or the struct it's being implemented for must come from the current crate. The only solution I've found that works is to define a MyFrom trait that mirrors the functionality of the std::convert::From trait:
extern crate geometry;
extern crate sdl2;
fn main() {
let geo_rect = geometry::Rect::default();
let sdl_rect = sdl2::SdlRect::my_from(geo_rect);
}
pub trait MyFrom<T> {
fn my_from(T) -> Self;
}
impl MyFrom<geometry::Rect> for sdl2::SdlRect {
fn my_from (rect: geometry::Rect) -> sdl2::SdlRect {
sdl2::SdlRect {
x: rect.x as i32,
y: rect.y as i32,
w: rect.w as i32,
h: rect.h as i32,
}
}
}
I'm not particularly happy with this solution because knowing when to call my_from instead of from will get confusing down the line. Is there another way for me to solve this using more idiomatic Rust?
Better define your own rectangle type that wraps an externally defined rectangle, and use the standard From trait.
This is one possible use of the newtype pattern.
The situation is (severely simplified) this (playpen):
mod tokentree {
pub struct TokenTree;
mod serialize {
use std::collections::BTreeMap;
use super::TokenTree;
#[derive(Debug)]
pub struct InternStr;
pub trait InternStrsExt {
fn intern_strs(&self) -> BTreeMap<&str, InternStr>;
}
impl InternStrsExt for [TokenTree] {
fn intern_strs(&self) -> BTreeMap<&str, InternStr> { BTreeMap::new() }
}
}
pub use self::serialize::{InternStrsExt, InternStr};
}
use tokentree::*;
fn main() {
println!("{:?}", [TokenTree].intern_strs());
}
I get the following error (both on nightly and beta):
<anon>:20:22: 20:47 error: source trait is inaccessible
<anon>:20 println!("{:?}", [TokenTree].intern_strs());
^~~~~~~~~~~~~~~~~~~~~~~~~
My problem is that I don't even know what this is supposed to mean.
It needs a pub declaration. Also your declarations are all over the place. Recommended form is to stick your pub mod declarations first, then, use.
Here is the working example.
mod tokentree {
pub struct TokenTree;
pub mod serialize {
use std::collections::BTreeMap;
use super::TokenTree;
#[derive(Debug)]
pub struct InternStr;
pub trait InternStrsExt {
fn intern_strs(&self) -> BTreeMap<&str, InternStr>;
}
impl InternStrsExt for [TokenTree] {
fn intern_strs(&self) -> BTreeMap<&str, InternStr> { BTreeMap::new() }
}
}
pub use self::serialize::{InternStrsExt, InternStr};
}
pub use tokentree::*;
fn main() {
println!("{:?}", [TokenTree].intern_strs());
}
(playpen)
What happened here is that you stumbled upon following glitches:
https://github.com/rust-lang/rust/issues/18241
https://github.com/rust-lang/rust/issues/16264
You can't export your traits from a private module. That's why you need to change mod serialize into pub mod serialize. For example this playpen example demonstrates that exporting struct Export works, but un-commenting the println! will make it stop compiling, because we used a trait.
Tip: One thing that helps me with the visibility rules is to generate doc files and see which doc files are visible.
I have some c functions with a struct pointer argument.
extern "C" {
fn InitSomeStruct() -> *SomeStruct;
fn SomeFunction(v: *SomeStruct);
fn DestroySomeStruct(v: *SomeStruct);
}
fn main() {
unsafe {
let s = InitSomeStruct();
SomeFunction(s);
DestroySomeStruct(s);
}
}
The implementation of SomeStruct is unknown.
How to declare and use external struct like SomeStruct from the rust code?
The convention is to use an empty enum for opaque FFI types, that is:
enum SomeStruct {}
An empty struct like struct SomeStruct; is also used sometimes.