Can I change the line number displayed in a panic?

NUnit is a C # unit-test framework that allows you to write code as follows:

Assert.That(someInt, Is.EqualTo(42));
Assert.That(someList, Has.Member(someMember));

I like this code because it is easy to read, like English.


I play with Rust to find out if I can create a library that gives the same feelings:

use std::fmt::Debug;

struct Is;

enum Verb<T> {
    EqualTo(T),
}

impl Is {
    fn equal_to<T>(&self, obj: T) -> Verb<T> {
        Verb::EqualTo(obj)
    }
}

#[allow(non_upper_case_globals)]
const is: Is = Is{};

fn assert_that<T: Eq + Debug>(obj: T, verb: Verb<T>) {
    match verb {
        Verb::EqualTo(rhs)    => assert_eq!(obj, rhs),
    }
}

fn main() {
    assert_that(42, is.equal_to(42));
    assert_that(42, is.equal_to(0));
}

This is good, but on the one hand: when the panic code is in assert_that(42, is.equal_to(0)), the line specified by the panic is a line assert_eq!(obj, rhs)(i.e. in the library instead of the user code). I know this is normal, but I would have a more helpful post.

How to indicate the number of the right line in a panic?

+4
source share
2 answers

, panic!.

-RFC, , "" . , , .

! Rust? , panic!, , .


, , panic::set_hook. .

use std::cell::Cell;

thread_local! {
    static ASSERT_LOCATION: Cell<Option<(&'static str, u32)>> = Cell::new(None)
}

fn report_my_error(info: &std::panic::PanicInfo) {
    match info.location() {
        Some(location) => {
            let file = location.file();
            let line = location.line();
            println!("The panic actually happened at: {}, {}", file, line);
        }
        None => println!("I don't know where the panic actually happened"),
    }

    ASSERT_LOCATION.with(|location| if let Some((file, line)) = location.get() {
        println!(
            "But I'm going to tell you it happened at {}, {}",
            file,
            line
        );
    });

    if let Some(msg) = info.payload().downcast_ref::<&str>() {
        println!("The error message was: {}", msg);
    }
}

#[test]
fn alpha() {
    std::panic::set_hook(Box::new(report_my_error));

    ASSERT_LOCATION.with(|location| {
        location.set(Some((file!(), line!())));
    });

    panic!("This was only a test")
}

, , . , None, .

, , , , . , , :

assert_that!(42, is.equal_to(0));

:

assert_that(file!(), line!(), 42, is.equal_to(0));

, , assert_that.

+2

spectral, , Rust. , , , line!() file!() , assert_that!, .

:

#[test]
fn example() {
    assert_that!(2).is_equal_to(4);
}

, , :

failures:

---- utils::tests::example stdout ----
        thread 'utils::tests::example' panicked at '
        expected: <4>
        but was: <2>

        at location: src/utils.rs:344
', /home/example/.cargo/registry/src/github.com-1ecc6299db9ec823/spectral-0.6.0/src/lib.rs:343
note: Run with `RUST_BACKTRACE=1` for a backtrace.


failures:
    utils::tests::example

test result: FAILED. 61 passed; 1 failed; 0 ignored; 0 measured
0

Source: https://habr.com/ru/post/1681253/


All Articles