-- CB40005.A -- -- Grant of Unlimited Rights -- -- Under contracts F33600-87-D-0337, F33600-84-D-0280, MDA903-79-C-0687, -- F08630-91-C-0015, and DCA100-97-D-0025, the U.S. Government obtained -- unlimited rights in the software and documentation contained herein. -- Unlimited rights are defined in DFAR 252.227-7013(a)(19). By making -- this public release, the Government intends to confer upon all -- recipients unlimited rights equal to those held by the Government. -- These rights include rights to use, duplicate, release or disclose the -- released technical data and computer software in whole or in part, in -- any manner and for any purpose whatsoever, and to have or permit others -- to do so. -- -- DISCLAIMER -- -- ALL MATERIALS OR INFORMATION HEREIN RELEASED, MADE AVAILABLE OR -- DISCLOSED ARE AS IS. THE GOVERNMENT MAKES NO EXPRESS OR IMPLIED -- WARRANTY AS TO ANY MATTER WHATSOEVER, INCLUDING THE CONDITIONS OF THE -- SOFTWARE, DOCUMENTATION OR OTHER INFORMATION RELEASED, MADE AVAILABLE -- OR DISCLOSED, OR THE OWNERSHIP, MERCHANTABILITY, OR FITNESS FOR A -- PARTICULAR PURPOSE OF SAID MATERIAL. --* -- -- OBJECTIVE: -- Check that exceptions raised in non-generic code can be handled by -- a procedure in a generic package. Check that the exception identity -- can be properly retrieved from the generic code and used by the -- non-generic code. -- -- TEST DESCRIPTION: -- This test models a possible usage paradigm for the type: -- Ada.Exceptions.Exception_Occurrence. -- -- A generic package takes access to procedure types (allowing it to -- be used at any accessibility level) and defines a "fail soft" -- procedure that takes designators to a procedure to call, a -- procedure to call in the event that it fails, and a function to -- call to determine the next action. -- -- In the event an exception occurs on the call to the first procedure, -- the exception is stored in a stack; along with the designator to the -- procedure that caused it; allowing the procedure to be called again, -- or the exception to be re-raised. -- -- A full implementation of such a tool would use a more robust storage -- mechanism, and would provide a more flexible interface. -- -- -- CHANGE HISTORY: -- 29 MAR 96 SAIC Initial version -- 12 NOV 96 SAIC Revised for 2.1 release -- --! ----------------------------------------------------------------- CB40005_0 with Ada.Exceptions; generic type Proc_Pointer is access procedure; type Func_Pointer is access function return Proc_Pointer; package CB40005_0 is -- Fail_Soft procedure Fail_Soft_Call( Proc_To_Call : Proc_Pointer; Proc_To_Call_On_Exception : Proc_Pointer := null; Retry_Routine : Func_Pointer := null ); function Top_Event_Exception return Ada.Exceptions.Exception_Occurrence; function Top_Event_Procedure return Proc_Pointer; procedure Pop_Event; function Event_Stack_Size return Natural; end CB40005_0; -- Fail_Soft -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- CB40005_0 with Report; package body CB40005_0 is type History_Event is record Exception_Event : Ada.Exceptions.Exception_Occurrence_Access; Procedure_Called : Proc_Pointer; end record; procedure Store_Event( Proc_Called : Proc_Pointer; Error : Ada.Exceptions.Exception_Occurrence ); procedure Fail_Soft_Call( Proc_To_Call : Proc_Pointer; Proc_To_Call_On_Exception : Proc_Pointer := null; Retry_Routine : Func_Pointer := null ) is Current_Proc_To_Call : Proc_Pointer := Proc_To_Call; begin while Current_Proc_To_Call /= null loop begin Current_Proc_To_Call.all; -- call procedure through pointer Current_Proc_To_Call := null; exception when Capture: others => Store_Event( Current_Proc_To_Call, Capture ); if Proc_To_Call_On_Exception /= null then Proc_To_Call_On_Exception.all; end if; if Retry_Routine /= null then Current_Proc_To_Call := Retry_Routine.all; else Current_Proc_To_Call := null; end if; end; end loop; end Fail_Soft_Call; Stack : array(1..10) of History_Event; -- minimal, sufficient for testing Stack_Top : Natural := 0; procedure Store_Event( Proc_Called : Proc_Pointer; Error : Ada.Exceptions.Exception_Occurrence ) is begin Stack_Top := Stack_Top +1; Stack(Stack_Top) := ( Ada.Exceptions.Save_Occurrence(Error), Proc_Called ); end Store_Event; function Top_Event_Exception return Ada.Exceptions.Exception_Occurrence is begin if Stack_Top > 0 then return Stack(Stack_Top).Exception_Event.all; else return Ada.Exceptions.Null_Occurrence; end if; end Top_Event_Exception; function Top_Event_Procedure return Proc_Pointer is begin if Stack_Top > 0 then return Stack(Stack_Top).Procedure_Called; else return null; end if; end Top_Event_Procedure; procedure Pop_Event is begin if Stack_Top > 0 then Stack_Top := Stack_Top -1; else Report.Failed("Stack Error"); end if; end Pop_Event; function Event_Stack_Size return Natural is begin return Stack_Top; end Event_Stack_Size; end CB40005_0; ------------------------------------------------------------------- CB40005 with Report; with TCTouch; with CB40005_0; with Ada.Exceptions; procedure CB40005 is type Proc_Pointer is access procedure; type Func_Pointer is access function return Proc_Pointer; package Fail_Soft is new CB40005_0(Proc_Pointer, Func_Pointer); procedure Cause_Standard_Exception; procedure Cause_Visible_Exception; procedure Cause_Invisible_Exception; Exception_Procedure_Pointer : Proc_Pointer; Visible_Exception : exception; procedure Action_On_Exception; function Retry_Procedure return Proc_Pointer; Raise_Error : Boolean; -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- procedure Cause_Standard_Exception is begin TCTouch.Touch('S'); --------------------------------------------------- S if Raise_Error then raise Constraint_Error; end if; end Cause_Standard_Exception; procedure Cause_Visible_Exception is begin TCTouch.Touch('V'); --------------------------------------------------- V if Raise_Error then raise Visible_Exception; end if; end Cause_Visible_Exception; procedure Cause_Invisible_Exception is Invisible_Exception : exception; begin TCTouch.Touch('I'); --------------------------------------------------- I if Raise_Error then raise Invisible_Exception; end if; end Cause_Invisible_Exception; procedure Action_On_Exception is begin TCTouch.Touch('A'); --------------------------------------------------- A end Action_On_Exception; function Retry_Procedure return Proc_Pointer is begin TCTouch.Touch('R'); --------------------------------------------------- R return Action_On_Exception'Access; end Retry_Procedure; -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- begin -- Main test procedure. Report.Test ("CB40005", "Check that exceptions raised in non-generic " & "code can be handled by a procedure in a generic " & "package. Check that the exception identity can " & "be properly retrieved from the generic code and " & "used by the non-generic code" ); -- first, check that the no exception cases cause no action on the stack Raise_Error := False; Fail_Soft.Fail_Soft_Call( Cause_Standard_Exception'Access ); -- S Fail_Soft.Fail_Soft_Call( Cause_Visible_Exception'Access, -- V Action_On_Exception'Access, Retry_Procedure'Access ); Fail_Soft.Fail_Soft_Call( Cause_Invisible_Exception'Access, -- I null, Retry_Procedure'Access ); TCTouch.Assert( Fail_Soft.Event_Stack_Size = 0, "Empty stack"); TCTouch.Validate( "SVI", "Non error case check" ); -- second, check that error cases add to the stack Raise_Error := True; Fail_Soft.Fail_Soft_Call( Cause_Standard_Exception'Access ); -- S Fail_Soft.Fail_Soft_Call( Cause_Visible_Exception'Access, -- V Action_On_Exception'Access, -- A Retry_Procedure'Access ); -- RA Fail_Soft.Fail_Soft_Call( Cause_Invisible_Exception'Access, -- I null, Retry_Procedure'Access ); -- RA TCTouch.Assert( Fail_Soft.Event_Stack_Size = 3, "Stack = 3"); TCTouch.Validate( "SVARAIRA", "Error case check" ); -- check that the exceptions and procedure were stored correctly -- on the stack Raise_Error := False; -- return procedure pointer from top of stack and call the procedure -- through that pointer: Fail_Soft.Top_Event_Procedure.all; TCTouch.Validate( "I", "Invisible case unwind" ); begin Ada.Exceptions.Raise_Exception( Ada.Exceptions.Exception_Identity(Fail_Soft.Top_Event_Exception) ); Report.Failed("1: Exception not raised"); exception when Constraint_Error => Report.Failed("1: Raised Constraint_Error"); when Visible_Exception => Report.Failed("1: Raised Visible_Exception"); when others => null; -- expected case end; Fail_Soft.Pop_Event; -- return procedure pointer from top of stack and call the procedure -- through that pointer: Fail_Soft.Top_Event_Procedure.all; TCTouch.Validate( "V", "Visible case unwind" ); begin Ada.Exceptions.Raise_Exception( Ada.Exceptions.Exception_Identity(Fail_Soft.Top_Event_Exception) ); Report.Failed("2: Exception not raised"); exception when Constraint_Error => Report.Failed("2: Raised Constraint_Error"); when Visible_Exception => null; -- expected case when others => Report.Failed("2: Raised Invisible_Exception"); end; Fail_Soft.Pop_Event; Fail_Soft.Top_Event_Procedure.all; TCTouch.Validate( "S", "Standard case unwind" ); begin Ada.Exceptions.Raise_Exception( Ada.Exceptions.Exception_Identity(Fail_Soft.Top_Event_Exception) ); Report.Failed("3: Exception not raised"); exception when Constraint_Error => null; -- expected case when Visible_Exception => Report.Failed("3: Raised Visible_Exception"); when others => Report.Failed("3: Raised Invisible_Exception"); end; Fail_Soft.Pop_Event; TCTouch.Assert( Fail_Soft.Event_Stack_Size = 0, "Stack empty after pops"); Report.Result; end CB40005;