error-stack 0.8.0

A context-aware error-handling library that supports arbitrary attached user data
Documentation
#![cfg_attr(nightly, feature(error_generic_member_access))]

mod common;

use core::{any::TypeId, iter::zip, ops::ControlFlow, panic::Location};

use common::*;

#[test]
fn opaque_attachment() {
    let mut report = create_report()
        .attach_opaque(AttachmentA(10))
        .attach_opaque(AttachmentB(20));

    let flow = report.frames_mut(|frame| {
        let source = frame
            .sources_mut()
            .first_mut()
            .expect("No source frame found");
        let attachment = source
            .downcast_mut::<AttachmentA>()
            .expect("Wrong source frame");
        attachment.0 += 10;
        ControlFlow::Break(())
    });
    assert!(flow.is_break(), "No frame found");

    let frame = report.frames().next().expect("No frame found");
    assert_eq!(frame.sources().len(), 1);
    let source = frame.sources().first().expect("No source frame found");
    let attachment = source
        .downcast_ref::<AttachmentA>()
        .expect("Wrong source frame");
    assert_eq!(attachment.0, 20);
}

#[test]
fn sources() {
    let mut report_a = create_report().attach_opaque(AttachmentA(10)).expand();
    let report_b = create_report().attach_opaque(AttachmentA(20));
    report_a.push(report_b);
    let mut report = report_a.attach_opaque(AttachmentB(30));

    let flow = report.frames_mut(|frame| {
        assert_eq!(frame.sources().len(), 2);

        for source in frame.sources_mut() {
            let attachment = source
                .downcast_mut::<AttachmentA>()
                .expect("Wrong source frame");
            attachment.0 += 5;
        }
        ControlFlow::Break(())
    });
    assert!(flow.is_break(), "No frames");

    let frame = report.frames().next().expect("No frames");
    for (source, expect) in zip(frame.sources(), [15, 25]) {
        let attachment = source
            .downcast_ref::<AttachmentA>()
            .expect("Wrong source frame");
        assert_eq!(attachment.0, expect);
    }
}

#[test]
fn printable_attachment() {
    let mut report = create_report()
        .attach(PrintableA(10))
        .attach(PrintableB(20));

    let flow = report.frames_mut(|frame| {
        let source = frame
            .sources_mut()
            .first_mut()
            .expect("No source frame found");
        let attachment = source
            .downcast_mut::<PrintableA>()
            .expect("Wrong source frame");
        attachment.0 += 10;
        ControlFlow::Break(())
    });
    assert!(flow.is_break(), "No frame found");

    let frame = report.frames().next().expect("No frame found");
    assert_eq!(frame.sources().len(), 1);
    let source = frame.sources().first().expect("No source frame found");
    let attachment = source
        .downcast_ref::<PrintableA>()
        .expect("Wrong source frame");
    assert_eq!(attachment.0, 20);
}

#[test]
fn context() {
    let mut report = create_report().change_context(ContextA(10));

    let flow = report.frames_mut(|frame| {
        assert_eq!(frame.sources().len(), 1);
        assert!(frame.is::<Location>(), "not a location frame");

        let source = frame
            .sources_mut()
            .first_mut()
            .expect("no source frame found");

        let context = source
            .downcast_mut::<ContextA>()
            .expect("not a context frame");
        context.0 += 10;
        ControlFlow::Break(())
    });
    assert!(flow.is_break(), "No location frame found");

    let frame = report.frames().next().expect("No location frame found");
    assert_eq!(frame.sources().len(), 1);
    let source = frame.sources().first().expect("no source frame found");
    let context = source
        .downcast_ref::<ContextA>()
        .expect("not a context frame");
    assert_eq!(context.0, 20);
}

#[test]
fn type_id() {
    let report = create_report().attach_opaque(2_u32);
    let current = report.current_frame();

    assert_eq!(current.type_id(), TypeId::of::<u32>());

    let context = report
        .frames()
        .last()
        .expect("should have at least a single frame");
    assert_eq!(context.type_id(), TypeId::of::<RootError>());
}