:- use_module(library(condition)).

% helper predicates
restarter_foo(foo, bar).
restarter_oops(oops(Y), Y).

a1(X) :-
    b(X).

a2(X) :-
    handle(b(X), restarter_foo).

a3(X) :-
    handle(b2(X), restarter_oops).

b(X) :-
    handle(c(X), restarter_oops).

b2(X) :-
    handle(c(X), oops(_), shortcut).

c(Restarts) :-
    findall( Restart
           , signal(oops(ok), Restart)
           , Restarts
           ).



:- use_module(library(tap)).

% add tests showing common usage
'det handler in parent' :-
    a1(X),
    X == [ok].

'det handler in parent, grandparent handler ignored' :-
    a2(X),
    X == [ok].

'no handlers present'(throws(oops(ok))) :-
    c(_).

'no handlers present: default' :-
    Condition = obscure,
    signal(Condition,default,Restart),
    Restart == default.

'no handlers present: var' :-
    signal(obscure,Restart,Restart),
    var(Restart).

'using handle/3 variant' :-
    b2(X),
    X == [shortcut].

'multiple handlers match' :-
    a3(X),
    X == [shortcut, ok].  % innermost first


'add and remove handlers' :-
    add_handler(restarter_foo, Ref),
    signal(foo, R1),
    signal(foo, R2),
    rm_handler(Ref),

    signal(foo, nothing, R3),
    R1 == bar,
    R2 == bar,
    R3 == nothing.
