I have a struct which encapsulates a serial port in the following manner.
struct DevicePort {
reader: BufReader<Box<dyn SerialPort>>,
writer: Box<dyn SerialPort>,
}
impl TryFrom<Box<dyn SerialPort>> for DevicePort {
type Error = anyhow::Error;
fn try_from(value: Box<dyn SerialPort>) -> Result<Self> {
let clone = value.try_clone()?;
Ok(DevicePort {
reader: BufReader::new(value),
writer: clone,
})
}
}
impl DevicePort {
// Functions sending data and processing the responses
}
I would like to mock this serial port instance such that I get to control its responses during testing. I have attempted to do this using the mockall crate but using automock macro simply fails compilation with the error automock does not support this item type.
Is there a way I can still do this using this crate or any other method?
Related
I'm currently writing some unsafe code that requires some degree of manually managing lifetimes, and exposing those lifetimes to external users. I've been writing tests, and while it's pretty easy to write tests to verify the correctness of code that compiles (at least to the extent that the potential for undefined behavior allows), I've been looking to ensure certain types of unsound code can't compile.
Say I have the following contrived example:
pub struct MyBox<T> {
ptr: *mut T,
}
impl<T> MyBox<T> {
fn new(t: T) -> Self {
MyBox {
ptr: Box::into_raw(Box::new(t)),
}
}
fn get(&self) -> &T {
unsafe { &*self.ptr }
}
}
impl<T> Drop for MyBox<T> {
fn drop(&mut self) {
unsafe { Box::from_raw(self.ptr) }
}
}
fn test<'a>() -> &'a i32 {
MyBox::new(7).get()
}
How can I ensure that the test function continues to fail to compile from rust's test framework?
Obviously, just throwing the erroneous code into a separate file and using the actual test function as glorified build script works, but that gets really boilerplatey and awkward, especially when there are more than just one or two bad examples I would like to test. If it helps, I don't care about the specifics of the error, just that an error exists.
You can write it as a doctest with compile_fail attr so that you can write multiple tests that expect to fail at the same time in a comment.
/// ```compile_fail,E0515
/// use path_to::MyBox;
///
/// fn test<'a>() -> &'a i32 {
/// MyBox::new(7).get()
/// }
/// ```
fn _doc_test() {}
,E0515 indicates the error number you expect, which avoids any other errors that would make the test false negative. (This error number check will be ignored if cargo is not running as nightly)
Note that this requires your crate to be a lib instead of a bin, as bin is not currently supported by doctests. (issue #50784)
Another way, if you do care about the specific error the compiler emits, is to use trybuild.
You can write your test function in a doc-test with the compile_fail annotation:
pub struct MyBox<T> {
ptr: *mut T,
}
/// ```compile_fail
/// fn test<'a>() -> &'a i32 {
/// playground::MyBox::new(7).get()
/// }
/// ```
impl<T> MyBox<T> {
fn new(t: T) -> Self {
MyBox {
ptr: Box::into_raw(Box::new(t)),
}
}
fn get(&self) -> &T {
unsafe { &*self.ptr }
}
}
impl<T> Drop for MyBox<T> {
fn drop(&mut self) {
unsafe { Box::from_raw(self.ptr) }
}
}
Playground
Note though that you can only test public functions that way.
I created a module/crate for all the database access that I need to do for an application.
pub struct Db {
client: db_client
}
impl Db {
pub fn new(client: db_client) -> Self {
return Self {
client: client
}
}
pub async fn func_1(&self, params: type) {
...
}
}
#[cfg(test)]
mod tests {
#[actix_rt::test]
async fn test_func_1() {
// create client object
// create Db object
// call desired function
...
}
}
For every test I have to create the object anew before I can actually test the desired function. There is no setup or teardown function in rust tests. How do you avoid recreating the client connection in every test? By the way, obtaining the client connection requires a async/await call. I tried the solutions in this post: How to run setup code before any tests run in Rust? but I couldn't get it to work.
I have two error types that are defined in external crates. Let's call them foo::Error and bar::Error. Because they are both defined externally, I cannot create a direct From or Into conversion between the two.
In my own crate, I'm using implementing a trait from bar, which expects return values of Result<T, bar::Error>. In the methods of my implementation, I'm calling functions from foo, which return many Result<T, foo::Error> types.
I would like to map these foo::Error errors to bar::Error errors, so that my trait implementation is neat, but the best that I can do is create a separate shim error, and then have a clunky .map_err(ShimErr::from)? on everything. This can start to litter up my code if I'm calling many foo:: functions in my implementation.
use foo;
use bar;
struct ShimErr(foo::Error);
impl From<foo::Error> for ShimErr {
fn from(e: foo::Error) -> Self {
Self(e)
}
}
impl From<ShimErr> for bar::Error {
fn from(e: ShimErr) -> Self {
Self{}
}
}
struct MyTraitImpl {}
impl bar::SomeTrait for MyTraitImpl {
fn do_something() -> Result<i32, bar::Error> {
// FIXME: THIS IS CLUNKY
let foo_val: i32 = foo::call_something().map_err(ShimErr::from)?;
Ok(foo_val * 2)
}
}
Is there a better way? In an ideal world, there would be a way to just use ?
If I remove map_err and try to use ? directly:
error[E0277]: `?` couldn't convert the error to `bar::Error`
--> shimtest.rs:32:49
|
32 | let foo_val: i32 = foo::call_something()?;
| ^ the trait `std::convert::From<foo::Error>` is not implemented for `bar::Error`
|
= note: the question mark operation (`?`) implicitly performs a conversion on the error value using the `From` trait
= help: the following implementations were found:
<bar::Error as std::convert::From<ShimErr>>
= note: required by `std::convert::From::from`
The way I handle multiple different errors from other crates would be to make my own Error enum and use that instead of other errors directly.
So instead of a tuple struct that only contains foo::Error, you can create an enum that can have both foo::Error and bar::Error. After this, you can convert all the errors to the custom enum error with ?.
In certain cases, I think you'll still need to use something like .map_err(Into::into) occasionally, but usually only when the variable being returned is a Result with an external error.
use bar::Error as BarError;
use foo::Error as FooError;
use std::fmt::{Display, Formatter, Result as FmtResult};
use std::result::Result as StdResult;
/// Common result type that uses the custom error
pub type Result<T> = StdResult<T, Error>;
/// Common error type used as a holder for errors from various other libraries.
#[derive(Debug)]
pub enum Error {
Bar(BarError),
Foo(FooError),
}
impl From<BarError> for Error {
fn from(err: BarError) -> Error {
Error::Bar(err)
}
}
impl From<FooError> for Error {
fn from(err: FooError) -> Error {
Error::Foo(err)
}
}
impl Display for Error {
fn fmt(&self, f: &mut Formatter) -> FmtResult {
match *self {
Error::Bar(ref inner) => inner.fmt(f),
Error::Foo(ref inner) => inner.fmt(f),
}
}
}
impl StdError for Error {
fn description(&self) -> &str {
match *self {
Error::Bar(ref inner) => inner.description(),
Error::Foo(ref inner) => inner.description(),
}
}
}
Now you can use the custom Result and Error as follows.
// this Result is now our custom Result type with custom error
// same as std::result::Result<i32, Error> (with Error as our custom error)
fn do_something() -> Result<i32> {
let foo_val: i32 = foo::call_something()?; // should convert to our custom error
Ok(foo_val * 2)
}
fn do_something_else() -> Result<i32> {
// directly returning a Result<> with a different error type will need map_err
foo::call_something().map_err(Into::into)
}
I started working with ws, and I would like to split the Handler trait implementation into multiple files.
So I wrote this in one file, on_open.rs:
impl Handler for Client {
fn on_open(&mut self, _: Handshake) -> Result<()> {
println!("Socket opened");
Ok(())
}
}
And this in another file, on_message.rs:
impl Handler for Client {
fn on_message(&mut self, msg: Message) -> Result<()> {
println!("Server got message '{}'. ", msg);
Ok(())
}
}
While compiling it I got the following error:
error[E0119]: conflicting implementations of trait `ws::handler::Handler` for type `models::client::Client`:
--> src\sockets\on_message.rs:9:1
|
9 | impl Handler for Client {
| ^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `models::client::Client`
|
::: src\sockets\on_open.rs:8:1
|
8 | impl Handler for Client {
| ----------------------- first implementation here
I'd like to have the files to be separated so that each developer can work on a separate one. Is there a way to achieve this or am I forced to have the full trait implementation in a single file?
Although you can have multiple impl blocks for the same object, you can't have two which are exactly the same, hence the error of conflicting implementations indicated by E0119:
Since a trait cannot be implemented multiple times, this is an error.
(If the trait could be specialised because it takes any number of generic type arguments the situation would be very much different because every specialisation would be a different impl block. However even then you wouldn't be able to have the same specialisation implemented more than once.)
If you would like to split the functionality into separate files, you could do that, but in a slightly different way than you originally thought. You could split the Client's impl block instead of the Handler implementation as the following minimal and compilable example demonstrates. (Try it in the playground!)
As you can see, the Handler trait is implemented for Client in one place, but all the implementations of Client are split into multiple files/modules and the Handler implementation is just referencing those:
mod handler
{
pub type Result<T> = ::std::result::Result<T, HandlerError>;
pub struct HandlerError;
pub trait Handler
{
fn on_open(&mut self, h: usize) -> Result<()>;
fn on_message(&mut self, m: bool) -> Result<()>;
}
}
mod client
{
use super::handler::{ self, Handler };
struct Client
{
h: usize,
m: bool,
}
impl Handler for Client
{
fn on_open(&mut self, h: usize) -> handler::Result<()>
{
self.handle_on_open(h)
}
fn on_message(&mut self, m: bool) -> handler::Result<()>
{
self.handle_on_message(m)
}
}
mod open
{
use super::super::handler;
use super::Client;
impl Client
{
pub fn handle_on_open(&mut self, h: usize) -> handler::Result<()>
{
self.h = h;
Ok(())
}
}
}
mod message
{
use super::super::handler;
use super::Client;
impl Client
{
pub fn handle_on_message(&mut self, m: bool) -> handler::Result<()>
{
self.m = m;
Ok(())
}
}
}
}
Thanks for #Peter's answer, I re-wrote my code as below, and it is working fine:
socket.rs
use ws::Handler;
use crate::models::client::Client;
use ws::{Message, Request, Response, Result, CloseCode, Handshake};
impl Handler for Client {
fn on_open(&mut self, hs: Handshake) -> Result<()> {
self.handle_on_open(hs)
}
fn on_message(&mut self, msg: Message) -> Result<()> {
self.handle_on_message(msg)
}
fn on_close(&mut self, code: CloseCode, reason: &str) {
self.handle_on_close(code, reason)
}
fn on_request(&mut self, req: &Request) -> Result<(Response)> {
self.handle_on_request(req)
}
}
sockets/on_open.rs
use crate::models::client::Client;
use crate::CLIENTS;
use crate::models::{truck::Truck};
use ws::{Result, Handshake};
impl Client {
pub fn handle_on_open(&mut self, _: Handshake) -> Result<()> {
println!("socket is opened");
Ok(())
}
}
I want to implement the fmt::Display for a nested struct commonly used in my code.
// The root structure
pub struct WhisperFile<'a> {
pub path: &'a str,
pub handle: RefCell<File>,
pub header: Header
}
pub struct Header{
pub metadata: metadata::Metadata,
pub archive_infos: Vec<archive_info::ArchiveInfo>
}
pub struct Metadata {
// SNIP
}
pub struct ArchiveInfo {
// SNIP
}
As you can see, this is a non-trivial tree of data. The archive_infos property on Header can be quite long when presented as one line.
I would like to emit something along the lines of
WhisperFile ({PATH})
Metadata
...
ArchiveInfo (0)
...
ArchiveInfo (N)
...
But when I try to display Vec<ArchiveInfo> I get that Display is not implemented. I can implement fmt::Display for ArchiveInfo but that's not enough since fmt::Display is not implemented for the parent container Vec. If I implement fmt::Display for collections::vec::Vec<ArchiveInfo> I get the impl does not reference any types defined in this crate; only traits defined in the current crate can be implemented for arbitrary types.
I have tried iterating over the vec and calling write!() but I couldn't figure out what the control flow should look like. I think write!() needs to be return value of the function but that breaks down with multiple calls.
How can I pretty print a Vec of my structures?
As this error states, you cannot implement a trait for a type you don't own:
the impl does not reference any types defined in this crate; only traits defined in the current crate can be implemented for arbitrary types
However, you can implement Display for your wrapper type. The piece you are missing is to use the try! macro or the try operator ?:
use std::fmt;
struct Foo(Vec<u8>);
impl fmt::Display for Foo {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "Values:\n")?;
for v in &self.0 {
write!(f, "\t{}", v)?;
}
Ok(())
}
}
fn main() {
let f = Foo(vec![42]);
println!("{}", f);
}