Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
0daab33
Checkpoint
lwasylow Mar 28, 2023
adbc76e
Address too long identified in 11g.
lwasylow Mar 28, 2023
1478b0d
Adding validation for tag expression
lwasylow Mar 29, 2023
b5ad747
Comment out to see why its failing.
lwasylow Mar 29, 2023
06cb054
Revert "Comment out to see why its failing."
lwasylow Mar 29, 2023
e87d39f
Adding validate function, with no calls
lwasylow Mar 29, 2023
97537de
Remove a & from text
lwasylow Mar 29, 2023
2a0f99a
Extra changes and added tests
lwasylow Mar 31, 2023
5b46140
Merge branch 'develop' of https://github.com/utPLSQL/utPLSQL into fea…
lwasylow Mar 31, 2023
b30688c
Address sonar coverage issues.
lwasylow Apr 1, 2023
0c41a0f
Adding tests covering exception of invalid tags
lwasylow Apr 1, 2023
543685d
Removing that , we will not implement that, there is no benefit at th…
lwasylow Apr 1, 2023
0d3cfa1
Removing force
lwasylow Apr 1, 2023
20e3177
Changing to use Dijkstra algorithm to parse infix notation into postf…
lwasylow Apr 10, 2023
f51cc99
Missing slash at end of type
lwasylow Apr 10, 2023
4b8e2ab
Cleanup.
lwasylow Apr 10, 2023
84e8684
Update tests after removed function
lwasylow Apr 10, 2023
2e7a766
Tidy up tests
lwasylow Apr 10, 2023
cbdf83a
Added ut_stack to uninstall
lwasylow Apr 10, 2023
436eb5b
Addressing test failures and sonar smells
lwasylow Apr 11, 2023
3d77514
Update name
lwasylow Apr 11, 2023
bf6959f
Update tests and code
lwasylow Apr 11, 2023
d8233ff
fixing typo in docs
lwasylow Apr 12, 2023
bd860f6
Removed unused variable
lwasylow Apr 12, 2023
313d5e9
Stage 1 Resolving PR comments
lwasylow Apr 13, 2023
02a071c
Separate tag logic.
lwasylow Apr 13, 2023
b8b66ee
Fix uninstall
lwasylow Apr 14, 2023
077fdb1
Various PR fixe
lwasylow Apr 14, 2023
01e5364
Update tests and code
lwasylow Apr 15, 2023
dc0b4a6
Addressing changes via PR review.
lwasylow Apr 18, 2023
ef1c02b
Update docs
lwasylow Apr 18, 2023
1551ea5
Adding any and none
lwasylow Apr 25, 2023
9dee7e0
Update docs
lwasylow Apr 26, 2023
beb9a3a
Resolving PR
lwasylow Apr 27, 2023
46ffe73
Update note
lwasylow Apr 27, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions docs/userguide/annotations.md
Original file line number Diff line number Diff line change
Expand Up @@ -1634,6 +1634,7 @@ Tags must follow the below naming convention:
- tag cannot start with a dash, e.g. `-some-stuff` is **not** a valid tag
- tag cannot contain spaces, e.g. `test of batch`. To create a multi-word tag use underscores or dashes, e.g. `test_of_batch`, `test-of-batch`
Comment thread
lwasylow marked this conversation as resolved.
Resolved
- leading and trailing spaces are ignored in tag name, e.g. `--%tags( tag1 , tag2 )` becomes `tag1` and `tag2` tag names
- tag cannot be one of two reserved words : `none` and `any`, any tags with that will not be considered.
Comment thread
lwasylow marked this conversation as resolved.
Resolved


### Suitepath
Expand Down
75 changes: 75 additions & 0 deletions docs/userguide/running-unit-tests.md
Original file line number Diff line number Diff line change
Expand Up @@ -325,6 +325,8 @@ Multiple tags are separated by comma.

Tag expressions are boolean expressions created by combining tags with the `!`, `&`, `|` operators. Tag expressions can be grouped using `(` and `)` braces. Grouping tag expressions affects operator precedence.

Two special expressions are supported, `any` and `none`, which select all tests with any tags at all, and all tests without any tags, respectively. These special expressions may be combined with other expressions just like normal tags. When using `none` be aware that if the suite is tagged it will exclude any tests and children belonging to that suite.
Comment thread
lwasylow marked this conversation as resolved.
Resolved

| Operator | Meaning |
| -------- | --------|
| ! | not |
Expand Down Expand Up @@ -450,6 +452,79 @@ The above calls will execute all suites/contexts/tests that are marked with any
Given the above example package `ut_sample_test`, only `ut_sample_test.ut_test` will be executed.


### Sample execution with `any` and `none`

Given a sample test package:

```sql linenums="1"
create or replace package ut_sample_test is

--%suite(Sample Test Suite)

--%test(Compare Ref Cursors)
--%tags(complex,fast)
procedure ut_refcursors1;

--%test(Run equality test)
--%tags(simple,fast)
procedure ut_test;

--%test(Run equality test no tag)
procedure ut_test_no_tag;

end ut_sample_test;
/

create or replace package body ut_sample_test is

procedure ut_refcursors1 is
v_actual sys_refcursor;
v_expected sys_refcursor;
begin
open v_expected for select 1 as test from dual;
open v_actual for select 2 as test from dual;

ut.expect(v_actual).to_equal(v_expected);
end;

procedure ut_test is
begin
ut.expect(1).to_equal(0);
end;

procedure ut_test_no_tag is
begin
ut.expect(1).to_equal(0);
end;

end ut_sample_test;
/
```

```sql linenums="1"
select * from table(ut.run(a_path => 'ut_sample_test',a_tags => 'none'));
```

The above call will execute tests `ut_test_no_tag`

```sql linenums="1"
select * from table(ut.run(a_path => 'ut_sample_test',a_tags => 'any'));
```

The above call will execute tests `ut_test` and `ut_refcursors1`

```sql linenums="1"
select * from table(ut.run(a_path => 'ut_sample_test',a_tags => 'none|simple'));
```

The above call will execute tests `ut_test_no_tag` and `ut_test`

```sql linenums="1"
select * from table(ut.run(a_tags => 'none|!simple'));
```

The above call will execute tests `ut_test_no_tag` and `ut_refcursors1`

## Keeping uncommitted data after test-run

utPLSQL by default runs tests in autonomous transaction and performs automatic rollback to assure that tests do not impact one-another and do not have impact on the current session in your IDE.
Expand Down
15 changes: 12 additions & 3 deletions source/core/ut_suite_tag_filter.pkb
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,10 @@ create or replace package body ut_suite_tag_filter is
gc_operators constant ut_varchar2_list := ut_varchar2_list('|','&','!');
gc_unary_operators constant ut_varchar2_list := ut_varchar2_list('!'); -- right side associative operator
gc_binary_operators constant ut_varchar2_list := ut_varchar2_list('|','&'); -- left side associative operator
gc_reserved_tag_words constant ut_varchar2_list := ut_varchar2_list('none','any');
gc_tags_column_name constant varchar2(250) := 'tags';
gc_exception_msg constant varchar2(200) := 'Invalid tag expression';

type t_precedence_table is table of number index by varchar2(1);
g_precedence t_precedence_table;

Expand Down Expand Up @@ -172,8 +173,17 @@ create or replace package body ut_suite_tag_filter is
begin
l_idx := a_postfix_exp.first;
while ( l_idx is not null) loop
--If the token we got is a none or any keyword
if a_postfix_exp(l_idx) member of gc_reserved_tag_words then

l_infix_stack.push(
case
when a_postfix_exp(l_idx) = 'none' then '('||a_tags_column_name||' is empty or '||a_tags_column_name||' is null)'
Comment thread
lwasylow marked this conversation as resolved.
Resolved
else a_tags_column_name||' is not empty'
end
);
--If token is operand but also single tag
if regexp_count(a_postfix_exp(l_idx),'[!()|&]') = 0 then
elsif regexp_count(a_postfix_exp(l_idx),'[!()|&]') = 0 then
l_infix_stack.push(q'[']'||a_postfix_exp(l_idx)||q'[']'||l_member_token);
--If token is unary operator not
elsif a_postfix_exp(l_idx) member of gc_unary_operators then
Expand Down Expand Up @@ -256,7 +266,6 @@ with
where ]'||l_tags||q'[
)
) t where c.id = t.id and r_num = 1 ]';

execute immediate l_sql bulk collect into l_suite_tags using a_suite_items;
return l_suite_tags;
end;
Expand Down
160 changes: 158 additions & 2 deletions test/ut3_tester_helper/run_helper.pkb
Original file line number Diff line number Diff line change
Expand Up @@ -431,12 +431,162 @@ create or replace package body run_helper is
end test_tag_pkg_3;
]';

execute immediate q'[create or replace package suite1_level1_pkg is

--%suite(suite1_level1)
--%suitepath(any_none)
--%rollback(manual)

--%test(Test 1 from Suite1 on level 1)
--%tags(suite1,level1,test1,test1_level1)
procedure test1_level1;

--%test(Test 2 from Suite1 on level 1)
procedure test2_level1;

end suite1_level1_pkg;
]';

execute immediate q'[create or replace package body suite1_level1_pkg is
procedure test1_level1 is
begin
dbms_output.put_line('suite1_level1_pkg.test1_level1 executed');
end;
procedure test2_level1 is
begin
dbms_output.put_line('suite1_level1_pkg.test2_level1 executed');
end;
end suite1_level1_pkg;
]';

execute immediate q'[create or replace package suite1_1_level2_pkg is

--%suite(suite1_1_level2)
--%suitepath(any_none.suite1_level1)
--%rollback(manual)

--%test(Test 1 from Suite1_2 on level 2)
--%tags(level2,test1,test1_level2)
procedure suite1_1_test1_level2;

--%test(Test 2 from Suite1_2 on level 2)
procedure suite1_1_test2_level2;

end suite1_1_level2_pkg;
]';

execute immediate q'[create or replace package body suite1_1_level2_pkg is
procedure suite1_1_test1_level2 is
begin
dbms_output.put_line('suite1_1_level2_pkg.suite1_1_test1_level2 executed');
end;
procedure suite1_1_test2_level2 is
begin
dbms_output.put_line('suite1_1_level2_pkg.suite1_1_test2_level2 executed');
end;
end suite1_1_level2_pkg;
]';

execute immediate q'[create or replace package suite1_2_level2_pkg is

--%suite(suite1_2_level2)
--%tags(level2,suite1_2,suites)
--%suitepath(any_none.suite1_level1)
--%rollback(manual)

--%test(Test 1 from Suite1_2 on level 2)
procedure suite1_2_test1_level2;

--%test(Test 2 from Suite1_2 on level 2)
--%tags(level2,test2,test2_level2)
procedure suite1_2_test2_level1;

end suite1_2_level2_pkg;
]';

execute immediate q'[create or replace package body suite1_2_level2_pkg is
procedure suite1_2_test1_level2 is
begin
dbms_output.put_line('suite1_2_level2_pkg.suite1_2_test1_level2 executed');
end;
procedure suite1_2_test2_level1 is
begin
dbms_output.put_line('suite1_2_level2_pkg.suite1_2_test2_level1 executed');
end;
end suite1_2_level2_pkg;
]';

execute immediate q'[create or replace package suite2_level1_pkg is

--%suite(suite2_level1)
--%tags(level1,suite2,suites)
--%suitepath(any_none)
--%rollback(manual)

--%test(Test 1 from Suite1 on level 1)
--%tags(suite2,level1,test1,test1_level1)
procedure test1_level1;

--%test(Test 2 from Suite1 on level 1)
procedure test2_level1;

end suite2_level1_pkg;
]';

execute immediate q'[create or replace package body suite2_level1_pkg is
procedure test1_level1 is
begin
dbms_output.put_line('suite2_level1_pkg.test1_level1 executed');
end;
procedure test2_level1 is
begin
dbms_output.put_line('suite2_level1_pkg.test2_level1 executed');
end;
end suite2_level1_pkg;
]';

execute immediate q'[create or replace package suite2_2_level2_pkg is

--%suite(suite2_2_level2)
--%tags(level2,suite2_2,suites)
--%suitepath(any_none.suite2_level1)
--%rollback(manual)

--%test(Test 1 from Suite2_2 on level 2)
procedure suite2_2_test1_level2;

--%test(Test 2 from Suite2_2 on level 2)
--%tags(level2,test2,test2_level2)
procedure suite2_2_test2_level2;

end suite2_2_level2_pkg;
]';

execute immediate q'[create or replace package body suite2_2_level2_pkg is
procedure suite2_2_test1_level2 is
begin
dbms_output.put_line('suite2_2_level2_pkg.suite2_2_test1_level2 executed');
end;
procedure suite2_2_test2_level2 is
begin
dbms_output.put_line('suite2_2_level2_pkg.suite2_2_test2_level2 executed');
end;
end suite2_2_level2_pkg;
]';


execute immediate q'[grant execute on test_package_1 to public]';
execute immediate q'[grant execute on test_package_2 to public]';
execute immediate q'[grant execute on test_package_3 to public]';
execute immediate q'[grant execute on test_tag_pkg_1 to public]';
execute immediate q'[grant execute on test_tag_pkg_2 to public]';
execute immediate q'[grant execute on test_tag_pkg_3 to public]';
execute immediate q'[grant execute on test_tag_pkg_3 to public]';

execute immediate q'[grant execute on suite1_level1_pkg to public]';
execute immediate q'[grant execute on suite1_1_level2_pkg to public]';
execute immediate q'[grant execute on suite1_2_level2_pkg to public]';
execute immediate q'[grant execute on suite2_level1_pkg to public]';
execute immediate q'[grant execute on suite2_2_level2_pkg to public]';
end;

procedure drop_ut3_user_tests is
Expand All @@ -447,7 +597,13 @@ create or replace package body run_helper is
execute immediate q'[drop package test_package_3]';
execute immediate q'[drop package test_tag_pkg_1]';
execute immediate q'[drop package test_tag_pkg_2]';
execute immediate q'[drop package test_tag_pkg_3]';
execute immediate q'[drop package test_tag_pkg_3]';

execute immediate q'[drop package suite2_2_level2_pkg]';
execute immediate q'[drop package suite2_level1_pkg]';
execute immediate q'[drop package suite1_2_level2_pkg]';
execute immediate q'[drop package suite1_level1_pkg]';
execute immediate q'[drop package suite1_1_level2_pkg]';
end;

procedure create_test_suite is
Expand Down
25 changes: 25 additions & 0 deletions test/ut3_user/api/test_ut_run.pkb
Original file line number Diff line number Diff line change
Expand Up @@ -1244,6 +1244,31 @@ procedure tag_exclude_run_fun_pth_lst_lg is
ut.expect( ut3_tester_helper.main_helper.table_to_clob(l_results) ).not_to_be_like( '%test_package_2.test3%executed%' );
ut.expect( ut3_tester_helper.main_helper.table_to_clob(l_results) ).not_to_be_like( '%test_package_2.test4%executed%' );
ut.expect( ut3_tester_helper.main_helper.table_to_clob(l_results) ).not_to_be_like( '%test_package_3.test6%executed%' );

l_results := ut3_tester_helper.run_helper.run(a_tags => 'any');
ut.expect( ut3_tester_helper.main_helper.table_to_clob(l_results) ).to_be_like( '%suite2_level1_pkg.test1_level1 executed%' );
ut.expect( ut3_tester_helper.main_helper.table_to_clob(l_results) ).to_be_like( '%suite2_level1_pkg.test2_level1 executed%' );
ut.expect( ut3_tester_helper.main_helper.table_to_clob(l_results) ).to_be_like( '%suite1_level1_pkg.test1_level1 executed%' );
ut.expect( ut3_tester_helper.main_helper.table_to_clob(l_results) ).to_be_like( '%suite2_2_level2_pkg.suite2_2_test1_level2 executed%' );
ut.expect( ut3_tester_helper.main_helper.table_to_clob(l_results) ).to_be_like( '%suite2_2_level2_pkg.suite2_2_test2_level2 executed%' );
ut.expect( ut3_tester_helper.main_helper.table_to_clob(l_results) ).to_be_like( '%suite1_2_level2_pkg.suite1_2_test1_level2 executed%' );
ut.expect( ut3_tester_helper.main_helper.table_to_clob(l_results) ).to_be_like( '%suite1_2_level2_pkg.suite1_2_test2_level1 executed%' );
ut.expect( ut3_tester_helper.main_helper.table_to_clob(l_results) ).to_be_like( '%suite1_1_level2_pkg.suite1_1_test1_level2 executed%' );
ut.expect( ut3_tester_helper.main_helper.table_to_clob(l_results) ).not_to_be_like( '%suite1_level1_pkg.test2_level1 executed%' );
ut.expect( ut3_tester_helper.main_helper.table_to_clob(l_results) ).not_to_be_like( '%suite1_1_level2_pkg.suite1_1_test2_level2 executed%' );

l_results := ut3_tester_helper.run_helper.run(a_tags => 'none');
ut.expect( ut3_tester_helper.main_helper.table_to_clob(l_results) ).to_be_like( '%suite1_level1_pkg.test2_level1 executed%' );
ut.expect( ut3_tester_helper.main_helper.table_to_clob(l_results) ).to_be_like( '%suite1_1_level2_pkg.suite1_1_test2_level2 executed%' );
ut.expect( ut3_tester_helper.main_helper.table_to_clob(l_results) ).not_to_be_like( '%suite2_level1_pkg.test1_level1 executed%' );
ut.expect( ut3_tester_helper.main_helper.table_to_clob(l_results) ).not_to_be_like( '%suite2_level1_pkg.test2_level1 executed%' );
ut.expect( ut3_tester_helper.main_helper.table_to_clob(l_results) ).not_to_be_like( '%suite1_level1_pkg.test1_level1 executed%' );
ut.expect( ut3_tester_helper.main_helper.table_to_clob(l_results) ).not_to_be_like( '%suite2_2_level2_pkg.suite2_2_test1_level2 executed%' );
ut.expect( ut3_tester_helper.main_helper.table_to_clob(l_results) ).not_to_be_like( '%suite2_2_level2_pkg.suite2_2_test2_level2 executed%' );
ut.expect( ut3_tester_helper.main_helper.table_to_clob(l_results) ).not_to_be_like( '%suite1_2_level2_pkg.suite1_2_test1_level2 executed%' );
ut.expect( ut3_tester_helper.main_helper.table_to_clob(l_results) ).not_to_be_like( '%suite1_2_level2_pkg.suite1_2_test2_level1 executed%' );
ut.expect( ut3_tester_helper.main_helper.table_to_clob(l_results) ).not_to_be_like( '%suite1_1_level2_pkg.suite1_1_test1_level2 executed%' );


end;

Expand Down