Reputation: 2654
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.
Upvotes: 6
Views: 847
Reputation: 70810
Another way, if you do care about the specific error the compiler emits, is to use trybuild.
Upvotes: 3
Reputation: 3763
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)
Upvotes: 5
Reputation: 27186
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) }
}
}
Note though that you can only test public functions that way.
Upvotes: 1