Skip to content

Commit 077fdb1

Browse files
committed
Various PR fixe
1 parent b8b66ee commit 077fdb1

File tree

6 files changed

+145
-102
lines changed

6 files changed

+145
-102
lines changed

docs/userguide/annotations.md

Lines changed: 1 addition & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -1616,7 +1616,7 @@ or
16161616

16171617
Tags are defined as a comma separated list within the `--%tags` annotation.
16181618

1619-
When a suite/context is tagged, all of its children will automatically inherit the tag and get executed along with the parent, unless they are excluded by tag expression.
1619+
When a suite/context is tagged, all of its children will automatically inherit the tag and get executed along with the parent, unless they are excluded explicitly at runtime with a negated tag expression.
16201620
Parent suite tests are not executed, but a suitepath hierarchy is kept.
16211621

16221622
Sample test suite package with tags.
@@ -1657,52 +1657,6 @@ create or replace package body ut_sample_test is
16571657
end ut_sample_test;
16581658
/
16591659
```
1660-
1661-
#### Tag Expressions
1662-
1663-
Tag expressions are boolean expressions with the operators !, & and |. In addition, ( and ) can be used to adjust for operator precedence.
1664-
1665-
| Operator | Meaning |
1666-
| -------- | --------|
1667-
| ! | not |
1668-
| & | and |
1669-
| \| | or |
1670-
1671-
If you are tagging your tests across multiple dimensions, tag expressions help you to select which tests to execute. When tagging by test type (e.g., micro, integration, end-to-end) and feature (e.g., product, catalog, shipping), the following tag expressions can be useful.
1672-
1673-
1674-
| Tag Expression | Selection |
1675-
| -------- | --------|
1676-
| product | all tests for product |
1677-
| catalog \| shipping | all tests for catalog plus all tests for shipping |
1678-
| catalog & shipping | all tests for the intersection between catalog and shipping |
1679-
| product & !end-to-end | all tests for product, but not the end-to-end tests |
1680-
| (micro \| integration) & (product \| shipping) | all micro or integration tests for product or shipping |
1681-
1682-
1683-
Execution of the test is done by using the parameter `a_tags` with tag expressions
1684-
1685-
1686-
```sql linenums="1"
1687-
select * from table(ut.run(a_tags => 'fast|!complex'));
1688-
```
1689-
The above call will execute all tests from `ut_sample_test` package as the whole suite is tagged with `api` because a suite meet expression condition.
1690-
1691-
```sql linenums="1"
1692-
select * from table(ut.run(a_path => 'ut_sample_test',a_tags => 'api'));
1693-
```
1694-
The above call will execute all tests from `ut_sample_test` package as the whole suite is tagged with `api`
1695-
1696-
```sql linenums="1"
1697-
select * from table(ut.run(a_tags => 'complex'));
1698-
```
1699-
The above call will execute only the `ut_sample_test.ut_refcursors1` test, as only the test `ut_refcursors1` is tagged with `complex`
1700-
1701-
```sql linenums="1"
1702-
select * from table(ut.run(a_tags => 'fast'));
1703-
```
1704-
The above call will execute both `ut_sample_test.ut_refcursors1` and `ut_sample_test.ut_test` tests, as both tests are tagged with `fast`
1705-
17061660
#### Tag naming convention
17071661

17081662
Tags must follow the below naming convention:
@@ -1715,45 +1669,11 @@ Tags must follow the below naming convention:
17151669
- vertical bar (|)
17161670
- exclamation point (!)
17171671
- tag cannot be null or blank
1718-
- tag cannot contain whitespace
17191672
- tag cannot start with a dash, e.g. `-some-stuff` is **not** a valid tag
17201673
- 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`
17211674
- leading and trailing spaces are ignored in tag name, e.g. `--%tags( tag1 , tag2 )` becomes `tag1` and `tag2` tag names
17221675

17231676

1724-
#### Excluding tests/suites by tags
1725-
1726-
It is possible to exclude parts of test suites with tags.
1727-
In order to do so, prefix the tag name to exclude with a `!` (exclamation) sign when invoking the test run which is equivalent of `-` (dash) in legacy notation.
1728-
Examples (based on above sample test suite)
1729-
1730-
```sql linenums="1"
1731-
select * from table(ut.run(a_tags => '(api|fast)&!complex'));
1732-
```
1733-
1734-
which is equivalent of legacy calling:
1735-
1736-
```sql linenums="1"
1737-
select * from table(ut.run(a_tags => 'api,fast,-complex'));
1738-
```
1739-
1740-
or
1741-
1742-
```sql linenums="1"
1743-
select * from table(ut.run(a_tags => '(api|fast)&(!complex&!test1)'));
1744-
```
1745-
1746-
which is equivalent of legacy calling:
1747-
1748-
```sql linenums="1"
1749-
select * from table(ut.run(a_tags => 'api,fast,-complex,-test1'));
1750-
```
1751-
1752-
The above call will execute all suites/contexts/tests that are marked with any of tags `api` or `fast` except those suites/contexts/tests that are marked as `complex`.
1753-
Given the above example package `ut_sample_test`, only `ut_sample_test.ut_test` will be executed.
1754-
1755-
1756-
17571677
### Suitepath
17581678

17591679
It is very likely that the application for which you are going to introduce tests consists of many different packages, procedures and functions.

docs/userguide/running-unit-tests.md

Lines changed: 69 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -319,23 +319,85 @@ select * from table(ut.run('hr.test_apply_bonus', a_random_test_order_seed => 30
319319

320320
In addition to the path, you can filter the tests to be run by specifying tags. Tags are defined in the test / context / suite with the `--%tags`-annotation ([Read more](annotations.md#tags)).
321321
Multiple tags are separated by comma.
322-
The framework applies `OR` logic to all specified tags so any test / suite that matches at least one tag will be included in the test run.
322+
323+
324+
### Tag Expressions
325+
326+
Tag expressions are boolean expressions with the operators !, & and |. In addition, ( and ) can be used to adjust for operator precedence.
327+
328+
| Operator | Meaning |
329+
| -------- | --------|
330+
| ! | not |
331+
| & | and |
332+
| \| | or |
333+
334+
If you are tagging your tests across multiple dimensions, tag expressions help you to select which tests to execute. When tagging by test type (e.g., micro, integration, end-to-end) and feature (e.g., product, catalog, shipping), the following tag expressions can be useful.
335+
336+
337+
| Tag Expression | Selection |
338+
| -------- | --------|
339+
| product | all tests for product |
340+
| catalog \| shipping | all tests for catalog plus all tests for shipping |
341+
| catalog & shipping | all tests for the intersection between catalog and shipping |
342+
| product & !end-to-end | all tests for product, but not the end-to-end tests |
343+
| (micro \| integration) & (product \| shipping) | all micro or integration tests for product or shipping |
344+
345+
346+
Execution of the test is done by using the parameter `a_tags` with tag expressions
347+
323348

324349
```sql linenums="1"
325-
begin
326-
ut.run('hr.test_apply_bonus', a_tags => 'test1,test2');
327-
end;
350+
select * from table(ut.run(a_tags => 'fast|!complex'));
351+
```
352+
The above call will execute all tests from `ut_sample_test` package as the whole suite is tagged with `api` because a suite meet expression condition.
353+
354+
```sql linenums="1"
355+
select * from table(ut.run(a_path => 'ut_sample_test',a_tags => 'api'));
356+
```
357+
The above call will execute all tests from `ut_sample_test` package as the whole suite is tagged with `api`
358+
359+
```sql linenums="1"
360+
select * from table(ut.run(a_tags => 'complex'));
328361
```
362+
The above call will execute only the `ut_sample_test.ut_refcursors1` test, as only the test `ut_refcursors1` is tagged with `complex`
363+
329364
```sql linenums="1"
330-
select * from table(ut.run('hr.test_apply_bonus', a_tags => 'suite1'))
365+
select * from table(ut.run(a_tags => 'fast'));
331366
```
367+
The above call will execute both `ut_sample_test.ut_refcursors1` and `ut_sample_test.ut_test` tests, as both tests are tagged with `fast`
368+
369+
### Excluding tests/suites by tags
332370

333-
You can also exclude specific tags by adding a `-` (dash) in front of the tag
371+
It is possible to exclude parts of test suites with tags.
372+
In order to do so, prefix the tag name to exclude with a `!` (exclamation) sign when invoking the test run which is equivalent of `-` (dash) in legacy notation.
373+
Examples (based on above sample test suite)
334374

335375
```sql linenums="1"
336-
select * from table(ut.run('hr.test_apply_bonus', a_tags => '-suite1'))
376+
select * from table(ut.run(a_tags => '(api|fast)&!complex'));
337377
```
338378

379+
which is equivalent of legacy calling:
380+
381+
```sql linenums="1"
382+
select * from table(ut.run(a_tags => 'api,fast,-complex'));
383+
```
384+
385+
or
386+
387+
```sql linenums="1"
388+
select * from table(ut.run(a_tags => '(api|fast)&(!complex&!test1)'));
389+
```
390+
391+
which is equivalent of legacy calling:
392+
393+
```sql linenums="1"
394+
select * from table(ut.run(a_tags => 'api,fast,-complex,-test1'));
395+
```
396+
397+
The above call will execute all suites/contexts/tests that are marked with any of tags `api` or `fast` except those suites/contexts/tests that are marked as `complex`.
398+
Given the above example package `ut_sample_test`, only `ut_sample_test.ut_test` will be executed.
399+
400+
339401
## Keeping uncommitted data after test-run
340402

341403
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.

source/core/ut_suite_tag_filter.pkb

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -87,19 +87,18 @@ create or replace package body ut_suite_tag_filter is
8787
/*
8888
https://stackoverflow.com/questions/29634992/shunting-yard-validate-expression
8989
*/
90-
function shunt_logical_expression(a_tags in varchar2) return ut_varchar2_list is
90+
function shunt_logical_expression(a_tags in ut_varchar2_list) return ut_varchar2_list is
9191
l_operator_stack ut_stack := ut_stack();
92-
l_input_tokens ut_varchar2_list := tokenize_tags_string(a_tags);
9392
l_rnp_tokens ut_varchar2_list := ut_varchar2_list();
9493
l_token varchar2(32767);
9594
l_expect_operand boolean := true;
9695
l_expect_operator boolean := false;
9796
l_idx pls_integer;
9897
begin
99-
l_idx := l_input_tokens.first;
98+
l_idx := a_tags.first;
10099
--Exuecute modified shunting algorithm
101100
WHILE (l_idx is not null) loop
102-
l_token := l_input_tokens(l_idx);
101+
l_token := a_tags(l_idx);
103102
if (l_token member of gc_operators and l_token member of gc_binary_operators) then
104103
if not(l_expect_operator) then
105104
raise_application_error(ut_utils.gc_invalid_tag_expression, 'Invalid Tag expression');
@@ -108,21 +107,21 @@ create or replace package body ut_suite_tag_filter is
108107
l_rnp_tokens.extend;
109108
l_rnp_tokens(l_rnp_tokens.last) := l_operator_stack.pop;
110109
end loop;
111-
l_operator_stack.push(l_input_tokens(l_idx));
110+
l_operator_stack.push(a_tags(l_idx));
112111
l_expect_operand := true;
113112
l_expect_operator:= false;
114113
elsif (l_token member of gc_operators and l_token member of gc_unary_operators) then
115114
if not(l_expect_operand) then
116115
raise_application_error(ut_utils.gc_invalid_tag_expression, 'Invalid Tag expression');
117116
end if;
118-
l_operator_stack.push(l_input_tokens(l_idx));
117+
l_operator_stack.push(a_tags(l_idx));
119118
l_expect_operand := true;
120119
l_expect_operator:= false;
121120
elsif l_token = '(' then
122121
if not(l_expect_operand) then
123122
raise_application_error(ut_utils.gc_invalid_tag_expression, 'Invalid Tag expression');
124123
end if;
125-
l_operator_stack.push(l_input_tokens(l_idx));
124+
l_operator_stack.push(a_tags(l_idx));
126125
l_expect_operand := true;
127126
l_expect_operator:= false;
128127
elsif l_token = ')' then
@@ -146,7 +145,7 @@ create or replace package body ut_suite_tag_filter is
146145
l_expect_operand := false;
147146
end if;
148147

149-
l_idx := l_input_tokens.next(l_idx);
148+
l_idx := a_tags.next(l_idx);
150149
end loop;
151150

152151
while l_operator_stack.peek is not null loop
@@ -198,9 +197,10 @@ create or replace package body ut_suite_tag_filter is
198197
function create_where_filter(a_tags varchar2
199198
) return varchar2 is
200199
l_tags varchar2(4000);
200+
l_tokenized_tags ut_varchar2_list;
201201
begin
202202
l_tags := replace(replace_legacy_tag_notation(a_tags),' ');
203-
l_tags := conv_postfix_to_infix_sql(shunt_logical_expression(l_tags));
203+
l_tags := conv_postfix_to_infix_sql(shunt_logical_expression(tokenize_tags_string(l_tags)));
204204
l_tags := replace(l_tags, '|',' or ');
205205
l_tags := replace(l_tags ,'&',' and ');
206206
l_tags := replace(l_tags ,'!','not');

source/core/ut_suite_tag_filter.pks

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ create or replace package ut_suite_tag_filter authid definer is
3131
* and return a list of elements in Reverse Polish Notation ( postfix )
3232
* As part of execution it will validate expression.
3333
*/
34-
function shunt_logical_expression(a_tags in varchar2) return ut_varchar2_list;
34+
function shunt_logical_expression(a_tags in ut_varchar2_list) return ut_varchar2_list;
3535

3636
/*
3737
* Function that converts postfix notation into infix and creating a string of sql filter

test/ut3_tester/core/test_ut_suite_tag_filter.pkb

Lines changed: 45 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,24 +3,65 @@ create or replace package body test_ut_suite_tag_filter is
33
procedure test_conversion_to_rpn is
44
l_postfix ut3_develop.ut_varchar2_list;
55
l_postfix_string varchar2(4000);
6+
l_input_token ut3_develop.ut_varchar2_list;
67
begin
7-
l_postfix := ut3_develop.ut_suite_tag_filter.shunt_logical_expression('A');
8+
l_input_token := ut3_develop.ut_suite_tag_filter.tokenize_tags_string('A');
9+
l_postfix := ut3_develop.ut_suite_tag_filter.shunt_logical_expression(l_input_token);
810
l_postfix_string := ut3_develop.ut_utils.table_to_clob(l_postfix,'');
911
ut.expect(l_postfix_string).to_equal('A');
1012

11-
l_postfix := ut3_develop.ut_suite_tag_filter.shunt_logical_expression('A|B');
13+
l_input_token := ut3_develop.ut_suite_tag_filter.tokenize_tags_string('A|B');
14+
l_postfix := ut3_develop.ut_suite_tag_filter.shunt_logical_expression(l_input_token);
1215
l_postfix_string := ut3_develop.ut_utils.table_to_clob(l_postfix,'');
1316
ut.expect(l_postfix_string).to_equal('AB|');
1417

15-
l_postfix := ut3_develop.ut_suite_tag_filter.shunt_logical_expression('(a|b)|c&d');
18+
l_input_token := ut3_develop.ut_suite_tag_filter.tokenize_tags_string('(a|b)|c&d');
19+
l_postfix := ut3_develop.ut_suite_tag_filter.shunt_logical_expression(l_input_token);
1620
l_postfix_string := ut3_develop.ut_utils.table_to_clob(l_postfix,'');
1721
ut.expect(l_postfix_string).to_equal('ab|cd&|');
1822

19-
l_postfix := ut3_develop.ut_suite_tag_filter.shunt_logical_expression('!a|b');
23+
l_input_token := ut3_develop.ut_suite_tag_filter.tokenize_tags_string('!a|b');
24+
l_postfix := ut3_develop.ut_suite_tag_filter.shunt_logical_expression(l_input_token);
2025
l_postfix_string := ut3_develop.ut_utils.table_to_clob(l_postfix,'');
2126
ut.expect(l_postfix_string).to_equal('a!b|');
2227
end;
2328

29+
procedure test_conversion_opr_by_opr is
30+
l_postfix ut3_develop.ut_varchar2_list;
31+
l_input_token ut3_develop.ut_varchar2_list;
32+
begin
33+
l_input_token := ut3_develop.ut_varchar2_list('A','B');
34+
l_postfix := ut3_develop.ut_suite_tag_filter.shunt_logical_expression(l_input_token);
35+
ut.fail('Expected exception but nothing was raised');
36+
end;
37+
38+
procedure test_conversion_oprd_by_opd is
39+
l_postfix ut3_develop.ut_varchar2_list;
40+
l_input_token ut3_develop.ut_varchar2_list;
41+
begin
42+
l_input_token := ut3_develop.ut_varchar2_list('|','|');
43+
l_postfix := ut3_develop.ut_suite_tag_filter.shunt_logical_expression(l_input_token);
44+
ut.fail('Expected exception but nothing was raised');
45+
end;
46+
47+
procedure test_conversion_lb_by_oper is
48+
l_postfix ut3_develop.ut_varchar2_list;
49+
l_input_token ut3_develop.ut_varchar2_list;
50+
begin
51+
l_input_token := ut3_develop.ut_varchar2_list('(','A','|','B',')','(');
52+
l_postfix := ut3_develop.ut_suite_tag_filter.shunt_logical_expression(l_input_token);
53+
ut.fail('Expected exception but nothing was raised');
54+
end;
55+
56+
procedure test_conversion_rb_by_oprd is
57+
l_postfix ut3_develop.ut_varchar2_list;
58+
l_input_token ut3_develop.ut_varchar2_list;
59+
begin
60+
l_input_token := ut3_develop.ut_varchar2_list(')','A');
61+
l_postfix := ut3_develop.ut_suite_tag_filter.shunt_logical_expression(l_input_token);
62+
ut.fail('Expected exception but nothing was raised');
63+
end;
64+
2465
procedure conv_from_rpn_to_sql_filter is
2566
l_postfix_rpn ut3_develop.ut_varchar2_list;
2667
l_infix_string varchar2(4000);

test/ut3_tester/core/test_ut_suite_tag_filter.pks

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,29 @@ create or replace package test_ut_suite_tag_filter is
33
--%suite(ut_suite_tag_filter)
44
--%suitepath(utplsql.ut3_tester.core)
55

6+
--%context( Conversion to Reverse Polish Notation)
7+
68
--%test( Test conversion of expression into Reverse Polish Notation)
79
procedure test_conversion_to_rpn;
810

11+
--%test( Operator is followed by operator)
12+
--%throws(ut3_develop.ut_utils.gc_invalid_tag_expression)
13+
procedure test_conversion_opr_by_opr;
14+
15+
--%test( Operand is followed by operand)
16+
--%throws(ut3_develop.ut_utils.gc_invalid_tag_expression)
17+
procedure test_conversion_oprd_by_opd;
18+
19+
--%test( Left Bracket is followed by operator)
20+
--%throws(ut3_develop.ut_utils.gc_invalid_tag_expression)
21+
procedure test_conversion_lb_by_oper;
22+
23+
--%test( Right Bracket is followed by operand)
24+
--%throws(ut3_develop.ut_utils.gc_invalid_tag_expression)
25+
procedure test_conversion_rb_by_oprd;
26+
27+
--%endcontext
28+
929
--%test( Test conversion of expression from Reverse Polish Notation into custom where filter for SQL)
1030
procedure conv_from_rpn_to_sql_filter;
1131

0 commit comments

Comments
 (0)