1-- 2-- Copyright (c) 2007-2011 Tero Koskinen <tero.koskinen@iki.fi> 3-- 4-- Permission to use, copy, modify, and distribute this software for any 5-- purpose with or without fee is hereby granted, provided that the above 6-- copyright notice and this permission notice appear in all copies. 7-- 8-- THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9-- WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10-- MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11-- ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12-- WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13-- ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14-- OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15-- 16 17with GNAT.Traceback.Symbolic; 18with GNAT.Regpat; 19with Ada.Strings; 20with Ada.Unchecked_Deallocation; 21with Ada.Exceptions; 22with Ahven.Long_AStrings; 23 24package body Ahven.Framework is 25 use Ahven.AStrings; 26 27 -- Convert an exception into a traceback, but truncate it at the first 28 -- line matching "0x.* in ahven.framework" as this is unwanted trace. 29 function Filtered_Traceback (E : in Ada.Exceptions.Exception_Occurrence) 30 return String is 31 ftb : constant String := GNAT.Traceback.Symbolic.Symbolic_Traceback (E); 32 pat : constant String := "(0x[0-9a-f]* in ahven\.framework)"; 33 reg : constant GNAT.Regpat.Pattern_Matcher := GNAT.Regpat.Compile (pat); 34 result : GNAT.Regpat.Match_Array (0 .. 1); 35 use type GNAT.Regpat.Match_Location; 36 begin 37 GNAT.Regpat.Match (reg, ftb, result); 38 if result (0) = GNAT.Regpat.No_Match then 39 return ftb; 40 else 41 return ftb (1 .. result (1).First - 2); 42 end if; 43 end Filtered_Traceback; 44 45 -- A few local procedures, so we do not need to duplicate code. 46 procedure Free_Test is 47 new Ada.Unchecked_Deallocation (Object => Test'Class, 48 Name => Test_Class_Access); 49 50 generic 51 with procedure Action is <>; 52 procedure Execute_Internal 53 (Test_Object : in out Test'Class; 54 Listener_Object : in out Listeners.Result_Listener'Class); 55 -- Logic for Execute procedures. Action is specified by the caller. 56 57 -- Helper function to reduce some typing. 58 function To_Bounded (Source : String) return AStrings.Bounded_String is 59 begin 60 return To_Bounded_String (Source => Source, 61 Drop => Ada.Strings.Right); 62 end To_Bounded; 63 64 function Name_In_List (Name : AStrings.Bounded_String; 65 List_Of_Names : Name_List.List) 66 return Boolean is 67 use type Name_List.Cursor; 68 69 Pos : Name_List.Cursor := Name_List.First (List_Of_Names); 70 begin 71 loop 72 exit when not Name_List.Is_Valid (Pos); 73 74 if Name_List.Data (Pos) = Name then 75 return True; 76 end if; 77 78 Pos := Name_List.Next (Pos); 79 end loop; 80 return False; 81 end Name_In_List; 82 83 function Name_In_List (Name : String; List_Of_Names : Name_List.List) 84 return Boolean is 85 begin 86 return Name_In_List (To_Bounded (Name), List_Of_Names); 87 end Name_In_List; 88 89 90 ----------- Indefinite_Test_List ------------------- 91 92 93 package body Indefinite_Test_List is 94 procedure Remove (Ptr : Node_Access) is 95 procedure Free is 96 new Ada.Unchecked_Deallocation (Object => Node, 97 Name => Node_Access); 98 My_Ptr : Node_Access := Ptr; 99 begin 100 Ptr.Next := null; 101 Free_Test (My_Ptr.Data); 102 My_Ptr.Data := null; 103 Free (My_Ptr); 104 end Remove; 105 106 procedure Append (Target : in out List; 107 Node_Data : Test'Class) is 108 New_Node : constant Node_Access := 109 new Node'(Data => new Test'Class'(Node_Data), Next => null); 110 begin 111 if Target.Last = null then 112 Target.Last := New_Node; 113 Target.First := New_Node; 114 else 115 Target.Last.Next := New_Node; 116 Target.Last := New_Node; 117 end if; 118 end Append; 119 120 procedure Clear (Target : in out List) is 121 Current_Node : Node_Access := Target.First; 122 Next_Node : Node_Access := null; 123 begin 124 while Current_Node /= null loop 125 Next_Node := Current_Node.Next; 126 Remove (Current_Node); 127 Current_Node := Next_Node; 128 end loop; 129 130 Target.First := null; 131 Target.Last := null; 132 end Clear; 133 134 procedure For_Each (Target : List) is 135 Current_Node : Node_Access := Target.First; 136 begin 137 while Current_Node /= null loop 138 Action (Current_Node.Data.all); 139 Current_Node := Current_Node.Next; 140 end loop; 141 end For_Each; 142 143 procedure Initialize (Target : in out List) is 144 begin 145 Target.Last := null; 146 Target.First := null; 147 end Initialize; 148 149 procedure Finalize (Target : in out List) is 150 begin 151 Clear (Target); 152 end Finalize; 153 154 procedure Adjust (Target : in out List) is 155 Target_Last : Node_Access := null; 156 Target_First : Node_Access := null; 157 Current : Node_Access := Target.First; 158 New_Node : Node_Access; 159 begin 160 while Current /= null loop 161 New_Node := new Node'(Data => new Test'Class'(Current.Data.all), 162 Next => null); 163 164 if Target_Last = null then 165 Target_First := New_Node; 166 else 167 Target_Last.Next := New_Node; 168 end if; 169 Target_Last := New_Node; 170 171 Current := Current.Next; 172 end loop; 173 Target.First := Target_First; 174 Target.Last := Target_Last; 175 end Adjust; 176 end Indefinite_Test_List; 177 178 179 ----------- Test type ------------------- 180 181 182 procedure Set_Up (T : in out Test) is 183 begin 184 null; -- empty by default 185 end Set_Up; 186 187 procedure Tear_Down (T : in out Test) is 188 begin 189 null; -- empty by default 190 end Tear_Down; 191 192 procedure Run (T : in out Test; 193 Listener : in out Listeners.Result_Listener'Class) is 194 begin 195 Run (T => Test'Class (T), Listener => Listener, Timeout => 0.0); 196 end Run; 197 198 procedure Run (T : in out Test; 199 Test_Names : Name_List.List; 200 Listener : in out Listeners.Result_Listener'Class) is 201 begin 202 Run (T => Test'Class (T), 203 Test_Names => Test_Names, 204 Listener => Listener, 205 Timeout => 0.0); 206 end Run; 207 208 procedure Execute_Internal 209 (Test_Object : in out Test'Class; 210 Listener_Object : in out Listeners.Result_Listener'Class) 211 is 212 use Ahven.Listeners; 213 begin 214 -- This Start_Test here is called for Test_Suites and Test_Cases. 215 -- Info includes only the name of the test suite/case. 216 -- 217 -- There is a separate Start_Test/End_Test pair for test routines 218 -- in the Run (T : in out Test_Case; ...) procedure. 219 Listeners.Start_Test 220 (Listener_Object, 221 (Phase => TEST_BEGIN, 222 Test_Name => To_Bounded_String (Get_Name (Test_Object)), 223 Test_Kind => CONTAINER)); 224 225 Action; 226 227 -- Like Start_Test, only for Test_Suites and Test_Cases. 228 Listeners.End_Test 229 (Listener_Object, 230 (Phase => TEST_END, 231 Test_Name => To_Bounded_String (Get_Name (Test_Object)), 232 Test_Kind => CONTAINER)); 233 end Execute_Internal; 234 235 function Test_Count (T : Test; Test_Name : String) return Test_Count_Type 236 is 237 A_List : Name_List.List := Name_List.Empty_List; 238 begin 239 Name_List.Append (A_List, To_Bounded (Test_Name)); 240 241 return Test_Count (Test'Class (T), A_List); 242 end Test_Count; 243 244 procedure Execute (T : in out Test'Class; 245 Listener : in out Listeners.Result_Listener'Class; 246 Timeout : Test_Duration) is 247 procedure Run_Impl is 248 begin 249 Run (T, Listener, Timeout); 250 end Run_Impl; 251 252 procedure Execute_Impl is new Execute_Internal (Action => Run_Impl); 253 begin 254 Execute_Impl (Test_Object => T, Listener_Object => Listener); 255 end Execute; 256 257 procedure Execute (T : in out Test'Class; 258 Test_Names : Name_List.List; 259 Listener : in out Listeners.Result_Listener'Class; 260 Timeout : Test_Duration) is 261 procedure Run_Impl is 262 begin 263 Run (T => T, 264 Test_Names => Test_Names, 265 Listener => Listener, 266 Timeout => Timeout); 267 end Run_Impl; 268 269 procedure Execute_Impl is new Execute_Internal (Action => Run_Impl); 270 begin 271 Execute_Impl (Test_Object => T, Listener_Object => Listener); 272 end Execute; 273 274 275 ----------- Test_Case ------------------------------ 276 277 278 -- Wrap an "object" routine inside a Test_Command record 279 -- and add it to the test command list. 280 -- 281 -- Name of the test will be silently cut if it does not 282 -- fit completely into AStrings.Bounded_String. 283 procedure Add_Test_Routine (T : in out Test_Case'Class; 284 Routine : Object_Test_Routine_Access; 285 Name : String) 286 is 287 Command : constant Test_Command := 288 (Command_Kind => OBJECT, 289 Name => To_Bounded (Source => Name), 290 Object_Routine => Routine); 291 begin 292 Test_Command_List.Append (T.Routines, Command); 293 end Add_Test_Routine; 294 295 -- Wrap a "simple" routine inside a Test_Command record 296 -- and add it to the test command list. 297 -- 298 -- Name of the test will be silently cut if it does not 299 -- fit completely into AStrings.Bounded_String. 300 procedure Add_Test_Routine (T : in out Test_Case'Class; 301 Routine : Simple_Test_Routine_Access; 302 Name : String) 303 is 304 Command : constant Test_Command := 305 (Command_Kind => SIMPLE, 306 Name => To_Bounded (Source => Name), 307 Simple_Routine => Routine); 308 begin 309 Test_Command_List.Append (T.Routines, Command); 310 end Add_Test_Routine; 311 312 -- The heart of the package. 313 -- Run one test routine (well, Command at this point) and 314 -- notify listeners about the result. 315 procedure Run_Command (Command : Test_Command; 316 Info : Listeners.Context; 317 Timeout : Test_Duration; 318 Listener : in out Listeners.Result_Listener'Class; 319 T : in out Test_Case'Class) is 320 use Ahven.Listeners; 321 use Ahven.Long_AStrings; 322 323 type Test_Status is 324 (TEST_PASS, TEST_FAIL, TEST_ERROR, TEST_TIMEOUT, TEST_SKIP); 325 326 protected type Test_Results is 327 function Get_Status return Test_Status; 328 procedure Set_Status (Value : Test_Status); 329 330 function Get_Message return AStrings.Bounded_String; 331 procedure Set_Message (Value : AStrings.Bounded_String); 332 333 function Get_Long_Message return Long_AStrings.Bounded_String; 334 procedure Set_Long_Message (Value : Long_AStrings.Bounded_String); 335 private 336 Status : Test_Status := TEST_ERROR; 337 Message : AStrings.Bounded_String; 338 Long_Message : Long_AStrings.Bounded_String; 339 end Test_Results; 340 341 protected body Test_Results is 342 function Get_Status return Test_Status is 343 begin 344 return Status; 345 end Get_Status; 346 347 procedure Set_Status (Value : Test_Status) is 348 begin 349 Status := Value; 350 end Set_Status; 351 352 function Get_Message return AStrings.Bounded_String is 353 begin 354 return Message; 355 end Get_Message; 356 357 procedure Set_Message (Value : AStrings.Bounded_String) is 358 begin 359 Message := Value; 360 end Set_Message; 361 362 function Get_Long_Message return Long_AStrings.Bounded_String is 363 begin 364 return Long_Message; 365 end Get_Long_Message; 366 367 procedure Set_Long_Message (Value : Long_AStrings.Bounded_String) is 368 begin 369 Long_Message := Value; 370 end Set_Long_Message; 371 end Test_Results; 372 373 Result : Test_Results; 374 375 task type Command_Task is 376 entry Start_Command; 377 entry End_Command; 378 end Command_Task; 379 380 procedure Run_A_Command is 381 procedure Set_Status (S : Test_Status; 382 Message : String; 383 Long_Message : String; 384 R : in out Test_Results) 385 is 386 begin 387 R.Set_Status (S); 388 R.Set_Message (To_Bounded (Source => Message)); 389 R.Set_Long_Message (To_Bounded_String 390 (Source => Long_Message, 391 Drop => Ada.Strings.Right)); 392 end Set_Status; 393 begin 394 begin 395 Run (Command, T); 396 Result.Set_Status (TEST_PASS); 397 exception 398 when E : Assertion_Error => 399 Set_Status 400 (S => TEST_FAIL, 401 Message => Ada.Exceptions.Exception_Message (E), 402 Long_Message => Filtered_Traceback (E), 403 R => Result); 404 when E : Test_Skipped_Error => 405 Set_Status 406 (S => TEST_SKIP, 407 Message => Ada.Exceptions.Exception_Message (E), 408 Long_Message => Filtered_Traceback (E), 409 R => Result); 410 when E : others => 411 Set_Status 412 (S => TEST_ERROR, 413 Message => Ada.Exceptions.Exception_Message (E), 414 Long_Message => Filtered_Traceback (E), 415 R => Result); 416 end; 417 end Run_A_Command; 418 419 task body Command_Task is 420 begin 421 accept Start_Command; 422 Run_A_Command; 423 accept End_Command; 424 end Command_Task; 425 426 Status : Test_Status; 427 428 begin 429 if Timeout > 0.0 then 430 declare 431 Command_Runner : Command_Task; 432 begin 433 Command_Runner.Start_Command; 434 select 435 Command_Runner.End_Command; 436 or 437 delay Duration (Timeout); 438 abort Command_Runner; 439 Result.Set_Status (TEST_TIMEOUT); 440 end select; 441 end; 442 else 443 Run_A_Command; 444 end if; 445 Status := Result.Get_Status; 446 447 case Status is 448 when TEST_PASS => 449 Listeners.Add_Pass (Listener, Info); 450 when TEST_FAIL => 451 Listeners.Add_Failure 452 (Listener, 453 (Phase => TEST_RUN, 454 Test_Name => Info.Test_Name, 455 Test_Kind => CONTAINER, 456 Routine_Name => Info.Routine_Name, 457 Message => Result.Get_Message, 458 Long_Message => Long_AStrings.Null_Bounded_String)); 459 when TEST_ERROR => 460 Listeners.Add_Error 461 (Listener, 462 (Phase => Listeners.TEST_RUN, 463 Test_Name => Info.Test_Name, 464 Test_Kind => CONTAINER, 465 Routine_Name => Info.Routine_Name, 466 Message => Result.Get_Message, 467 Long_Message => Result.Get_Long_Message)); 468 when TEST_TIMEOUT => 469 Listeners.Add_Error 470 (Listener, 471 (Phase => Listeners.TEST_RUN, 472 Test_Name => Info.Test_Name, 473 Test_Kind => CONTAINER, 474 Routine_Name => Info.Routine_Name, 475 Message => To_Bounded_String ("TIMEOUT"), 476 Long_Message => Long_AStrings.Null_Bounded_String)); 477 when TEST_SKIP => 478 Listeners.Add_Skipped 479 (Listener, 480 (Phase => TEST_RUN, 481 Test_Name => Info.Test_Name, 482 Test_Kind => CONTAINER, 483 Routine_Name => Info.Routine_Name, 484 Message => Result.Get_Message, 485 Long_Message => Long_AStrings.Null_Bounded_String)); 486 end case; 487 end Run_Command; 488 489 function Get_Name (T : Test_Case) return String is 490 begin 491 return To_String (T.Name); 492 end Get_Name; 493 494 procedure Run_Internal 495 (T : in out Test_Case; 496 Listener : in out Listeners.Result_Listener'Class; 497 Command : Test_Command; 498 Test_Name : String; 499 Routine_Name : String; 500 Timeout : Test_Duration) 501 is 502 use Ahven.Listeners; 503 begin 504 Listeners.Start_Test 505 (Listener, 506 (Phase => Ahven.Listeners.TEST_BEGIN, 507 Test_Name => To_Bounded_String (Test_Name), 508 Test_Kind => ROUTINE)); 509 Run_Command (Command => Command, 510 Info => 511 (Phase => Listeners.TEST_RUN, 512 Test_Name => To_Bounded_String (Test_Name), 513 Test_Kind => ROUTINE, 514 Routine_Name => 515 To_Bounded_String (Routine_Name), 516 Message => AStrings.Null_Bounded_String, 517 Long_Message => Long_AStrings.Null_Bounded_String), 518 Timeout => Timeout, 519 Listener => Listener, 520 T => T); 521 Listeners.End_Test 522 (Listener, 523 (Phase => Ahven.Listeners.TEST_END, 524 Test_Name => To_Bounded_String (Test_Name), 525 Test_Kind => ROUTINE)); 526 end Run_Internal; 527 528 -- Run procedure for Test_Case. 529 -- 530 -- Loops over the test routine list and executes the routines. 531 procedure Run (T : in out Test_Case; 532 Listener : in out Listeners.Result_Listener'Class; 533 Timeout : Test_Duration) 534 is 535 procedure Exec (Cmd : in out Test_Command) is 536 begin 537 Run_Internal (T => T, 538 Listener => Listener, 539 Command => Cmd, 540 Timeout => Timeout, 541 Test_Name => Get_Name (T), 542 Routine_Name => To_String (Cmd.Name)); 543 end Exec; 544 545 procedure Run_All is new Test_Command_List.For_Each 546 (Action => Exec); 547 begin 548 Run_All (T.Routines); 549 end Run; 550 551 -- Purpose of the procedure is to run all 552 -- test routines with name Test_Name. 553 procedure Run (T : in out Test_Case; 554 Test_Names : Name_List.List; 555 Listener : in out Listeners.Result_Listener'Class; 556 Timeout : Test_Duration) 557 is 558 procedure Exec (Cmd : in out Test_Command) is 559 begin 560 if Name_In_List (Cmd.Name, Test_Names) then 561 Run_Internal (T => T, 562 Listener => Listener, 563 Command => Cmd, 564 Timeout => Timeout, 565 Test_Name => Get_Name (T), 566 Routine_Name => To_String (Cmd.Name)); 567 end if; 568 end Exec; 569 570 procedure Run_All is new Test_Command_List.For_Each (Action => Exec); 571 begin 572 Run_All (T.Routines); 573 end Run; 574 575 function Test_Count (T : Test_Case) return Test_Count_Type is 576 begin 577 return Test_Count_Type (Test_Command_List.Length (T.Routines)); 578 end Test_Count; 579 580 function Test_Count (T : Test_Case; Test_Names : Name_List.List) 581 return Test_Count_Type 582 is 583 use Test_Command_List; 584 585 Counter : Test_Count_Type := 0; 586 587 procedure Increase (Cmd : in out Test_Command) is 588 begin 589 if Name_In_List (Cmd.Name, Test_Names) then 590 Counter := Counter + 1; 591 end if; 592 end Increase; 593 594 procedure Count_Commands is new 595 Test_Command_List.For_Each (Action => Increase); 596 begin 597 Count_Commands (T.Routines); 598 599 return Counter; 600 end Test_Count; 601 602 procedure Finalize (T : in out Test_Case) is 603 begin 604 Test_Command_List.Clear (T.Routines); 605 end Finalize; 606 607 procedure Set_Name (T : in out Test_Case; Name : String) is 608 begin 609 T.Name := To_Bounded (Source => Name); 610 end Set_Name; 611 612 613 ----------- Test_Suite ----------------------------- 614 615 616 function Create_Suite (Suite_Name : String) 617 return Test_Suite_Access is 618 begin 619 return 620 new Test_Suite' 621 (Ada.Finalization.Controlled with 622 Suite_Name => To_Bounded (Source => Suite_Name), 623 Test_Cases => Test_List.Empty_List, 624 Static_Test_Cases => Indefinite_Test_List.Empty_List); 625 end Create_Suite; 626 627 function Create_Suite (Suite_Name : String) 628 return Test_Suite is 629 begin 630 return (Ada.Finalization.Controlled with 631 Suite_Name => To_Bounded (Source => Suite_Name), 632 Test_Cases => Test_List.Empty_List, 633 Static_Test_Cases => Indefinite_Test_List.Empty_List); 634 end Create_Suite; 635 636 procedure Add_Test (Suite : in out Test_Suite; T : Test_Class_Access) is 637 begin 638 Test_List.Append (Suite.Test_Cases, (Ptr => T)); 639 end Add_Test; 640 641 procedure Add_Test (Suite : in out Test_Suite; T : Test_Suite_Access) is 642 begin 643 Add_Test (Suite, Test_Class_Access (T)); 644 end Add_Test; 645 646 procedure Add_Static_Test 647 (Suite : in out Test_Suite; T : Test'Class) is 648 begin 649 Indefinite_Test_List.Append (Suite.Static_Test_Cases, T); 650 end Add_Static_Test; 651 652 function Get_Name (T : Test_Suite) return String is 653 begin 654 return To_String (T.Suite_Name); 655 end Get_Name; 656 657 procedure Run (T : in out Test_Suite; 658 Listener : in out Listeners.Result_Listener'Class; 659 Timeout : Test_Duration) 660 is 661 -- Some nested procedure exercises here. 662 -- 663 -- Execute_Cases is for normal test list 664 -- and Execute_Static_Cases is for indefinite test list. 665 666 -- A helper procedure which runs Execute for the given test. 667 procedure Execute_Test (Current : in out Test'Class) is 668 begin 669 Execute (Current, Listener, Timeout); 670 end Execute_Test; 671 672 procedure Execute_Test_Ptr (Current : in out Test_Class_Wrapper) is 673 begin 674 Execute (Current.Ptr.all, Listener, Timeout); 675 end Execute_Test_Ptr; 676 677 procedure Execute_Static_Cases is 678 new Indefinite_Test_List.For_Each (Action => Execute_Test); 679 procedure Execute_Cases is 680 new Test_List.For_Each (Action => Execute_Test_Ptr); 681 begin 682 Execute_Cases (T.Test_Cases); 683 Execute_Static_Cases (T.Static_Test_Cases); 684 end Run; 685 686 procedure Run (T : in out Test_Suite; 687 Test_Names : Name_List.List; 688 Listener : in out Listeners.Result_Listener'Class; 689 Timeout : Test_Duration) 690 is 691 procedure Execute_Test (Current : in out Test'Class) is 692 begin 693 if Name_In_List (Get_Name (Current), Test_Names) then 694 Execute (T => Current, Listener => Listener, Timeout => Timeout); 695 else 696 Execute (T => Current, 697 Test_Names => Test_Names, 698 Listener => Listener, 699 Timeout => Timeout); 700 end if; 701 end Execute_Test; 702 703 procedure Execute_Test_Ptr (Current : in out Test_Class_Wrapper) is 704 begin 705 Execute_Test (Current.Ptr.all); 706 end Execute_Test_Ptr; 707 708 procedure Execute_Cases is 709 new Test_List.For_Each (Action => Execute_Test_Ptr); 710 711 procedure Execute_Static_Cases is 712 new Indefinite_Test_List.For_Each (Action => Execute_Test); 713 begin 714 if Name_In_List (T.Suite_Name, Test_Names) then 715 Run (T, Listener, Timeout); 716 else 717 Execute_Cases (T.Test_Cases); 718 Execute_Static_Cases (T.Static_Test_Cases); 719 end if; 720 end Run; 721 722 function Test_Count (T : Test_Suite) return Test_Count_Type is 723 Counter : Test_Count_Type := 0; 724 725 procedure Inc_Counter (Test_Obj : in out Test'Class) is 726 begin 727 Counter := Counter + Test_Count (Test_Obj); 728 end Inc_Counter; 729 730 procedure Inc_Counter_Ptr (Wrapper : in out Test_Class_Wrapper) is 731 begin 732 Inc_Counter (Wrapper.Ptr.all); 733 end Inc_Counter_Ptr; 734 begin 735 declare 736 use Test_List; 737 procedure Count_All is new For_Each (Action => Inc_Counter_Ptr); 738 begin 739 Count_All (T.Test_Cases); 740 end; 741 742 declare 743 use Indefinite_Test_List; 744 procedure Count_All is new For_Each (Action => Inc_Counter); 745 begin 746 Count_All (T.Static_Test_Cases); 747 end; 748 749 return Counter; 750 end Test_Count; 751 752 function Test_Count (T : Test_Suite; Test_Names : Name_List.List) 753 return Test_Count_Type is 754 Counter : Test_Count_Type := 0; 755 756 procedure Handle_Test (Test_Object : in out Test'Class) is 757 begin 758 if Name_In_List (Get_Name (Test_Object), Test_Names) then 759 Counter := Counter + Test_Count (Test_Object); 760 else 761 Counter := Counter + Test_Count (Test_Object, Test_Names); 762 end if; 763 end Handle_Test; 764 765 procedure Handle_Test_Ptr (Obj : in out Test_Class_Wrapper) is 766 begin 767 Handle_Test (Obj.Ptr.all); 768 end Handle_Test_Ptr; 769 770 procedure Count_Static is 771 new Indefinite_Test_List.For_Each (Action => Handle_Test); 772 procedure Count_Tests is 773 new Test_List.For_Each (Action => Handle_Test_Ptr); 774 begin 775 if Name_In_List (T.Suite_Name, Test_Names) then 776 return Test_Count (T); 777 end if; 778 779 Count_Tests (T.Test_Cases); 780 Count_Static (T.Static_Test_Cases); 781 782 return Counter; 783 end Test_Count; 784 785 procedure Adjust (T : in out Test_Suite) is 786 use Test_List; 787 788 New_List : List := Empty_List; 789 790 procedure Create_Copy (Item : in out Test_Class_Wrapper) is 791 begin 792 Append (New_List, (Ptr => new Test'Class'(Item.Ptr.all))); 793 end Create_Copy; 794 795 procedure Copy_All is new For_Each (Action => Create_Copy); 796 begin 797 Copy_All (T.Test_Cases); 798 799 T.Test_Cases := New_List; 800 end Adjust; 801 802 procedure Finalize (T : in out Test_Suite) is 803 use Test_List; 804 805 procedure Free_Item (Item : in out Test_Class_Wrapper) is 806 begin 807 Free_Test (Item.Ptr); 808 end Free_Item; 809 810 procedure Free_All is new For_Each (Action => Free_Item); 811 812 begin 813 Free_All (T.Test_Cases); 814 Clear (T.Test_Cases); 815 end Finalize; 816 817 procedure Release_Suite (T : Test_Suite_Access) is 818 procedure Free is 819 new Ada.Unchecked_Deallocation (Object => Test_Suite, 820 Name => Test_Suite_Access); 821 Ptr : Test_Suite_Access := T; 822 begin 823 Free (Ptr); 824 end Release_Suite; 825 826 procedure Run (Command : Test_Command; T : in out Test_Case'Class) is 827 begin 828 case Command.Command_Kind is 829 when SIMPLE => 830 Command.Simple_Routine.all; 831 when OBJECT => 832 Set_Up (T); 833 Command.Object_Routine.all (T); 834 Tear_Down (T); 835 end case; 836 end Run; 837end Ahven.Framework; 838