2016-07-21 9 views
4

私のoverflower_supportクレートのテストでは、私はすでにstd::panic::catch_unwind(_)を使って処理されているパニックの偽の報告がたくさんあることがわかりました。これは起こり得る実際のエラーをあいまいにするので、少し不幸です。メッセージは次のようになります。これらの気が散るのメッセージを鎮めるためにQuickCheckテストでパニックを静かにキャッチする方法はありますか?

thread 'safe' panicked at 'arithmetic overflow', src/lib.rs:56 

、私はパニックハンドラをハイジャックdont_panic(..)機能を導入し、閉鎖を呼び出し、閉鎖の結果を返す、行われたときにパニックハンドラをリセットします。それは次のようになります。

fn dont_panic<F, A, R>(args: A, f: F) -> R 
    where F: Fn(A) -> R 
{ 
    let p = panic::take_hook(); 
    panic::set_hook(Box::new(|_|())); 
    let result = f(args); 
    panic::set_hook(p); 
    result 
} 

しかし、やや意外に希望のメッセージをquells、だけでなく、私には明らかに価値があるquickcheckのエラー出力だけでなく、をチェックする関数内で、この関数を使用して。これは、テストを1つのスレッドに限定している場合でも発生します。

#[test] 
fn test_some_panic() { 
    fn check(x: usize) -> bool { 
     let expected = if x < 256 { Some(x) } else { None }; 
     let actual = dont_panic(|| panic::catch_unwind(|| { assert!(x < 256); x }).ok()); 
     expected == actual 
    } 
    quickcheck(check as fn(usize) -> bool); 
} 

どのように見えるQuickCheckのパニックを維持しながら、私は自分のコードからキャッチパニックを隠すことができますか?

+1

あなたは、コードの再現性の例が含まれてもらえますか? 'dont_panic'に' quickcheck :: quickcheck'をラップしているなら、 'quickcheck'の契約が失敗したときにパニックに陥るので、あなたのハンドラがエラーメッセージを押しつぶしていることに意味があります。おそらく、あなたは「QuickCheck.quicktest」からより多くの走行距離を得るかもしれません。これは、パンチングの代わりに「結果」を返します。 – BurntSushi5

+0

'font check((usize、usize)) - > bool'関数内の' dont_panic(..) 'に' panic :: catch_unwind(_) '呼び出しをラップしています。これは' quickcheck :: quickcheck ' – llogiq

+0

ほとんどの完全な例を追加しました(' std :: panic;を使うと実行する必要があります)。 – llogiq

答えて

1

私のアプローチには二つの問題がありました:

  1. テストが並行して実行(および-j 1がパニックメッセージを鎮めるために無効見えるようquickcheckは、 、独自のいくつかの並列処理を追加するように見えるが)。
  2. catch_unwind(_)がある場合、メッセージは書き込まれます(またはset_hook(_)によって抑制されません)。 は問題になりません。

しかし、パニックハンドラのファイルに基づいて区別するためのdpc.pwの考えは、 スポットオンでした。どこかでパニックがsrc/lib.rsから来た場合

use std::panic; 
use std::sync::{Once, ONCE_INIT}; 

static HANDLER : Once = ONCE_INIT; 

fn install_handler() { 
    HANDLER.call_once(|| { 
     let p = panic::take_hook(); 
     panic::set_hook(Box::new(move|info| { 
      if info.location().map_or(false, |l| l.file() != "src/lib.rs" && 
        !l.file().ends_with("/num/mod.rs")) { 
       p(info); 
      } 
     })); 
    }) 
} 

これは( は私overflower_supportコードである)パニックメッセージを鎮めるだろうか。私は私がフルでここに再現quickcheck(_)を呼び出す 前install_handler()関数を呼び出すために私のアプローチを変更しました/num/mod.rs( Rust libcoreコードもパニックになる可能性があるため)。あなたがOnceを省略することができますが、これはハンドラ複数に 回を追加し、 試験性能を悪化させている間、かなりスタックトレースのサイズを増加させる

注意。私は同じ問題といくつかの他に会った、と私はそれらを解決するためにクレートを書くことになった

2

デフォルトパニックハンドラは、stderrに無条件にパニック情報を出力しています。

あなたはregister your own handlerになります。

+0

それは私が 'dont_panic(_)'で行うことです。しかし、残念ながら、これは撮影された後でもパニック情報を隠すように見えます。 – llogiq

+1

ああまあ、あなたが使用する方法がない限り、例えば。スレッドのローカルフラグ、またはパニックハンドラに渡された 'PanicInfo'が何らかの形で他のものから伝えられるように、私は他の方法はないと思います。 –

1

:それで

panic-control

、あなたの例では、「静かに実行することによって解決されるかもしれません「スレッド(あなたは、具体的catch_unwindを使用することに興味がなかったと仮定した場合):

use panic_control::spawn_quiet; 

#[test] 
fn test_some_panic() { 
    fn check(x: usize) -> bool { 
     let expected = if x < 256 { Some(x) } else { None }; 
     let h = spawn_quiet(|| { assert!(x < 256); x }); 
     let actual = h.join().ok(); 
     expected == actual 
    } 
    quickcheck(check as fn(usize) -> bool); 
} 
関連する問題