@@ -15,7 +15,7 @@ create or replace package body ut_suite_builder is
1515 See the License for the specific language governing permissions and
1616 limitations under the License.
1717 */
18-
18+
1919 subtype t_annotation_text is varchar2(4000);
2020 subtype t_annotation_name is varchar2(4000);
2121 subtype t_object_name is varchar2(500);
@@ -315,13 +315,13 @@ create or replace package body ut_suite_builder is
315315 l_annotation_pos := a_throws_ann_text.next(l_annotation_pos);
316316 end loop;
317317 end;
318-
318+
319319 procedure add_tags_to_suite_item(
320320 a_suite in out nocopy ut_suite,
321321 a_tags_ann_text tt_annotation_texts,
322322 a_list in out nocopy ut_varchar2_rows,
323323 a_procedure_name t_object_name := null
324- ) is
324+ ) is
325325 l_annotation_pos binary_integer;
326326 l_tags_list ut_varchar2_list := ut_varchar2_list();
327327 l_tag_items ut_varchar2_list;
@@ -354,7 +354,7 @@ create or replace package body ut_suite_builder is
354354 --remove empty strings from table list e.g. tag1,,tag2 and convert to rows
355355 a_list := ut_utils.convert_collection( ut_utils.filter_list(set(l_tags_list),ut_utils.gc_word_no_space) );
356356 end;
357-
357+
358358 procedure set_seq_no(
359359 a_list in out nocopy ut_executables
360360 ) is
@@ -533,16 +533,16 @@ create or replace package body ut_suite_builder is
533533 );
534534 set_seq_no(l_test.after_test_list);
535535 end if;
536-
536+
537537 if l_proc_annotations.exists( gc_tags) then
538538 add_tags_to_suite_item(a_suite, l_proc_annotations( gc_tags), l_test.tags, a_procedure_name);
539539 end if;
540-
540+
541541 if l_proc_annotations.exists( gc_throws) then
542542 add_to_throws_numbers_list(a_suite, l_test.expected_error_codes, a_procedure_name, l_proc_annotations( gc_throws));
543543 end if;
544544 l_test.disabled_flag := ut_utils.boolean_to_int( l_proc_annotations.exists( gc_disabled));
545-
545+
546546 a_suite_items.extend;
547547 a_suite_items( a_suite_items.last ) := l_test;
548548
@@ -687,7 +687,7 @@ create or replace package body ut_suite_builder is
687687 if a_annotations.by_name.exists(gc_aftereach) then
688688 l_after_each_list := add_executables( a_suite.object_owner, a_suite.object_name, a_annotations.by_name(gc_aftereach), gc_aftereach );
689689 end if;
690-
690+
691691 if a_annotations.by_name.exists(gc_tags) then
692692 add_tags_to_suite_item(a_suite, a_annotations.by_name(gc_tags),a_suite.tags);
693693 end if;
@@ -704,21 +704,59 @@ create or replace package body ut_suite_builder is
704704 set_seq_no(a_suite.after_all_list);
705705 end;
706706
707+ function get_next_annotation_of_type(
708+ a_start_position t_annotation_position,
709+ a_annotation_type varchar2,
710+ a_package_annotations in tt_annotations_by_name
711+ ) return t_annotation_position is
712+ l_result t_annotation_position;
713+ begin
714+ if a_package_annotations.exists(a_annotation_type) then
715+ l_result := a_package_annotations(a_annotation_type).first;
716+ while l_result <= a_start_position loop
717+ l_result := a_package_annotations(a_annotation_type).next(l_result);
718+ end loop;
719+ end if;
720+ return l_result;
721+ end;
722+
707723 function get_endcontext_position(
708724 a_context_ann_pos t_annotation_position,
709- a_package_annotations in out nocopy tt_annotations_by_name
725+ a_package_annotations in tt_annotations_by_line
710726 ) return t_annotation_position is
711727 l_result t_annotation_position;
728+ l_open_count integer := 1;
729+ l_idx t_annotation_position := a_package_annotations.next(a_context_ann_pos);
712730 begin
713- if a_package_annotations.exists(gc_endcontext) then
714- l_result := a_package_annotations(gc_endcontext).first;
715- while l_result <= a_context_ann_pos loop
716- l_result := a_package_annotations(gc_endcontext).next(l_result);
717- end loop;
731+ while l_open_count > 0 and l_idx is not null loop
732+ if ( a_package_annotations(l_idx).name = gc_context ) then
733+ l_open_count := l_open_count+1;
734+ elsif ( a_package_annotations(l_idx).name = gc_endcontext ) then
735+ l_open_count := l_open_count-1;
736+ l_result := l_idx;
737+ end if;
738+ l_idx := a_package_annotations.next(l_idx);
739+ end loop;
740+ if ( l_open_count > 0 ) then
741+ l_result := null;
718742 end if;
719743 return l_result;
720744 end;
721745
746+ function has_nested_context(
747+ a_context_ann_pos t_annotation_position,
748+ a_package_annotations in tt_annotations_by_name
749+ ) return boolean is
750+ l_next_endcontext_pos t_annotation_position := 0;
751+ l_next_context_pos t_annotation_position := 0;
752+ begin
753+ if ( a_package_annotations.exists(gc_endcontext) and a_package_annotations.exists(gc_context)) then
754+ l_next_endcontext_pos := get_next_annotation_of_type(a_context_ann_pos, gc_endcontext, a_package_annotations);
755+ l_next_context_pos := a_package_annotations(gc_context).next(a_context_ann_pos);
756+ end if;
757+ return ( l_next_context_pos < l_next_endcontext_pos );
758+ end;
759+
722760 function get_annotations_in_context(
723761 a_annotations t_annotations_info,
724762 a_context_pos t_annotation_position,
@@ -753,7 +791,8 @@ create or replace package body ut_suite_builder is
753791 a_parent in out nocopy ut_suite,
754792 a_annotations in out nocopy t_annotations_info,
755793 a_suite_items out nocopy ut_suite_items,
756- a_parent_context_pos in integer := 0
794+ a_parent_context_pos in integer := 0,
795+ a_parent_end_context_pos in integer default null
757796 ) is
758797 l_context_pos t_annotation_position;
759798 l_next_context_pos t_annotation_position;
@@ -768,26 +807,36 @@ create or replace package body ut_suite_builder is
768807 l_default_context_name t_object_name;
769808 function get_context_name(
770809 a_parent in out nocopy ut_suite,
771- a_context_names in tt_annotation_texts,
772- a_start_position binary_integer,
773- a_end_position binary_integer
810+ a_start_position binary_integer
774811 ) return varchar2 is
775812 l_result t_annotation_name;
776813 l_found boolean;
814+ l_end_position binary_integer;
777815 l_annotation_pos binary_integer;
816+ l_context_names tt_annotation_texts;
778817 begin
779- l_annotation_pos := a_context_names.first;
780- while l_annotation_pos is not null loop
781- if l_annotation_pos > a_start_position and l_annotation_pos < a_end_position then
782- if l_found then
783- add_annotation_ignored_warning(a_parent, gc_name,'Duplicate annotation %%%.', l_annotation_pos);
784- else
785- l_result := a_context_names(l_annotation_pos);
818+ if a_annotations.by_name.exists(gc_name) then
819+ l_context_names := a_annotations.by_name( gc_name );
820+ -- Maximum end-position to look for %name annotation is either the next %context or the next %endcontext annotation
821+ l_end_position :=
822+ least(
823+ coalesce( get_next_annotation_of_type(a_start_position, gc_endcontext, a_annotations.by_name), a_annotations.by_line.last ),
824+ coalesce( get_next_annotation_of_type(a_start_position, gc_context, a_annotations.by_name), a_annotations.by_line.last )
825+ );
826+ l_annotation_pos := l_context_names.first;
827+
828+ while l_annotation_pos is not null loop
829+ if l_annotation_pos > a_start_position and l_annotation_pos < l_end_position then
830+ if l_found then
831+ add_annotation_ignored_warning(a_parent, gc_name,'Duplicate annotation %%%.', l_annotation_pos);
832+ else
833+ l_result := l_context_names(l_annotation_pos);
834+ end if;
835+ l_found := true;
786836 end if;
787- l_found := true;
788- end if;
789- l_annotation_pos := a_context_names.next(l_annotation_pos);
790- end loop;
837+ l_annotation_pos := l_context_names.next(l_annotation_pos);
838+ end loop;
839+ end if;
791840 return l_result;
792841 end;
793842 begin
@@ -801,21 +850,9 @@ create or replace package body ut_suite_builder is
801850 while l_context_pos is not null loop
802851 l_default_context_name := 'nested_context_#'||l_context_no;
803852 l_context_name := null;
804- l_end_context_pos := get_endcontext_position(l_context_pos, a_annotations.by_name );
805-
853+ l_end_context_pos := get_endcontext_position(l_context_pos, a_annotations.by_line );
806854 l_next_context_pos := a_annotations.by_name(gc_context).next(l_context_pos);
807- if a_annotations.by_name.exists(gc_name) then
808- l_context_name :=
809- get_context_name(
810- a_parent,
811- a_annotations.by_name( gc_name ),
812- l_context_pos,
813- least(
814- coalesce( l_end_context_pos, a_annotations.by_line.last ),
815- coalesce( l_next_context_pos, a_annotations.by_line.last )
816- )
817- );
818- end if;
855+ l_context_name := get_context_name(a_parent, l_context_pos);
819856 if not regexp_like( l_context_name, '^(\w|[$#])+$' ) or l_context_name is null then
820857 if not regexp_like( l_context_name, '^(\w|[$#])+$' ) then
821858 a_parent.put_warning(
@@ -841,9 +878,8 @@ create or replace package body ut_suite_builder is
841878 l_context.parse_time := a_annotations.parse_time;
842879
843880 --if nested context found
844- if l_next_context_pos < l_end_context_pos or l_end_context_pos is null then
845- get_context_items( l_context, a_annotations, l_context_items, l_context_pos );
846- l_end_context_pos := get_endcontext_position(l_context_pos, a_annotations.by_name );
881+ if has_nested_context(l_context_pos, a_annotations.by_name) then
882+ get_context_items( l_context, a_annotations, l_context_items, l_context_pos, l_end_context_pos );
847883 else
848884 l_context_items := ut_suite_items();
849885 end if;
@@ -870,6 +906,10 @@ create or replace package body ut_suite_builder is
870906 exit when not a_annotations.by_name.exists( gc_context);
871907
872908 l_context_pos := a_annotations.by_name( gc_context).next( l_context_pos);
909+ -- don't go on when the next context is outside the parent's context boundaries
910+ if (a_parent_end_context_pos <= l_context_pos ) then
911+ l_context_pos := null;
912+ end if;
873913 l_context_no := l_context_no + 1;
874914 end loop;
875915 end;
0 commit comments