是否有可能改变整个恐慌信息? [英] Is it possible to change the whole panic message?

查看:23
本文介绍了是否有可能改变整个恐慌信息?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

NUnit 是一个 C# 单元测试框架,允许您编写如下代码:

NUnit is a C# unit-test framework that permits you to write code like this:

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

我喜欢这种代码,因为它看起来像英文一样容易阅读.

I like this kind of code because it is easily readable by looking like English.

我正在玩 Rust,看看我是否可以创建一个提供相同感觉的库:

I am playing with Rust to see 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));
}

这很好,但有一点:当代码在 assert_that(42, is.equal_to(0)) 处发生恐慌时,恐慌给出的行是 assert_eq 的行!(obj, rhs)(ie 在库中而不是用户代码).我知道这种行为很正常,但我会有更有用的信息.

This is good, but for one thing: when the code panics at assert_that(42, is.equal_to(0)), the line given by the panic is the line of assert_eq!(obj, rhs) (i.e. in the library instead of user's code). I know this behavior is normal, but I would have a more useful message.

如何在panic中指明正确的行号?

How to indicate the right line number in the panic?

推荐答案

没有直接的方法来调整 panic! 打印的行号.

There's no direct way to adjust the line number that panic! prints.

一个 proto-RFC 添加一个属性,允许某些方法要从回溯中隐藏".有可能这样的属性也会影响行号,但目前还不清楚.

There is a proto-RFC to add an attribute that would allow certain methods to be "hidden" from backtraces. It's possible that such an attribute would also affect the line number, but it's unclear.

panic怎么写!像 Rust 中的宏? 描述了如何编写自己的 panic! 宏,但它选择拆除整个进程,而不仅仅是当前线程.

How to write a panic! like macro in Rust? describes how you could write your own panic! macro, but it chooses to tear down the entire process, not just the current thread.

重要的是你只想控制消息,这可以通过 panic::set_hook.您可以通过线程局部变量将来自测试的旁道信息传递给紧急处理程序.

The important thing is that you just want to control the message, which is possible via panic::set_hook. You can pass side-channel information from the test to the panic handler via thread locals.

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 以避免位置信息在线程之间泄漏.

You need to ensure your panic handler is set in each test and then set the location information. You may also want to update the panic handler to set the location information back to None to avoid location information leaking between threads.

您可能希望编写自己的宏,用户可以在测试中使用该宏来隐式设置行号.与此类似的语法可以为这个设置代码提供一个存在的地方:

You will likely want to write your own macro that the user can use in the test to set the line number implicitly. Syntax similar to this could give a place for this setup code to live:

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

可以扩展到:

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

我可能会在 assert_that 中设置恐慌处理程序.

And I'd probably set that panic handler inside of assert_that.

这篇关于是否有可能改变整个恐慌信息?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆