Skip to content

Commit d1bbcb2

Browse files
committed
checks for comments, exclusion constraints, array set_eq, and rls
1 parent 56c591f commit d1bbcb2

File tree

3 files changed

+289
-4
lines changed

3 files changed

+289
-4
lines changed

doc/pgtap.mmd

Lines changed: 117 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1378,10 +1378,12 @@ same!
13781378

13791379
### `set_eq()` ###
13801380

1381-
SELECT set_eq( :sql, :sql, :description );
1382-
SELECT set_eq( :sql, :sql );
1383-
SELECT set_eq( :sql, :array, :description );
1384-
SELECT set_eq( :sql, :array );
1381+
SELECT set_eq( :sql, :sql, :description );
1382+
SELECT set_eq( :sql, :sql );
1383+
SELECT set_eq( :sql, :array, :description );
1384+
SELECT set_eq( :sql, :array );
1385+
SELECT set_eq( :array, :array, :description );
1386+
SELECT set_eq( :array, :array );
13851387

13861388
**Parameters**
13871389

@@ -5068,6 +5070,30 @@ that do have check constraints, if any:
50685070
Just like `col_is_pk()`, except that it test that the column or array of
50695071
columns have a check constraint on them.
50705072

5073+
### `col_has_exclusion()` ###
5074+
5075+
SELECT col_has_check( :schema, :table, :columns, :description );
5076+
5077+
**Parameters**
5078+
5079+
`:schema`
5080+
: Schema in which to find the table.
5081+
5082+
`:table`
5083+
: Name of a table containing the exclusion constraint.
5084+
5085+
`:columns`
5086+
: Array of the names of the exclusion constraint columns.
5087+
5088+
`:column`
5089+
: Name of the exclusion constraint column.
5090+
5091+
`:description`
5092+
: A short description of the test.
5093+
5094+
Just like `col_is_check()`, except that it test that the column array has
5095+
an exclusion constraint on them.
5096+
50715097
### `index_is_unique()` ###
50725098

50735099
SELECT index_is_unique( :schema, :table, :index, :description );
@@ -7960,6 +7986,93 @@ missing policy command, like so:
79607986
# have: INSERT
79617987
# want: ALL
79627988

7989+
### `rls_is_enabled()` ###
7990+
7991+
SELECT rls_is_enabled( :schema, :table, :desired_value );
7992+
7993+
Test whether [row-level security](https://www.postgresql.org/docs/current/ddl-rowsecurity.html)
7994+
is enabled (`:desired_value` true) or disabled (`:desired_value` false).
7995+
7996+
**Parameters**
7997+
7998+
`:schema`
7999+
: Name of a schema in which to find the `:table`.
8000+
8001+
`:table`
8002+
: Name of a table which has RLS enabled or not.
8003+
8004+
`:desired_value`
8005+
: `true` to assert that the table has RLS enabled, `false` to assert it's disabled.
8006+
8007+
Commentary
8008+
----------
8009+
8010+
### `table_comment_has()` ###
8011+
8012+
SELECT table_comment_has( :schema, :table, :comment );
8013+
SELECT table_comment_has( :schema, :table, :comment, :description );
8014+
8015+
Assert that a table comment contains a full line of text (delimited by `\n`).
8016+
8017+
**Parameters**
8018+
8019+
`:schema`
8020+
: Name of a schema in which to find the `:table`.
8021+
8022+
`:table`
8023+
: Name of a table which has a comment set.
8024+
8025+
`:comment`
8026+
: The line the table comment should include.
8027+
8028+
`:description`
8029+
: A short description of the test.
8030+
8031+
### `column_comment_has()` ###
8032+
8033+
SELECT column_comment_has( :schema, :table, :column, :comment );
8034+
SELECT column_comment_has( :schema, :table, :column, :comment, :description );
8035+
8036+
Assert that a comment comment contains a full line of text (delimited by `\n`).
8037+
8038+
**Parameters**
8039+
8040+
`:schema`
8041+
: Name of a schema in which to find the `:table`.
8042+
8043+
`:table`
8044+
: Name of a table including `:column`.
8045+
8046+
`:column`
8047+
: Name of a column which has a comment set.
8048+
8049+
`:comment`
8050+
: The line the column comment should include.
8051+
8052+
`:description`
8053+
: A short description of the test.
8054+
8055+
### `function_comment_has()` ###
8056+
8057+
SELECT function_comment_has( :schema, :function, :comment );
8058+
SELECT function_comment_has( :schema, :function, :comment, :description );
8059+
8060+
Assert that a function comment contains a full line of text (delimited by `\n`).
8061+
8062+
**Parameters**
8063+
8064+
`:schema`
8065+
: Name of a schema in which to find the `:function`.
8066+
8067+
`:function`
8068+
: Name of a function which has RLS enabled or not.
8069+
8070+
`:comment`
8071+
: The line the function comment should include.
8072+
8073+
`:description`
8074+
: A short description of the test.
8075+
79638076
No Test for the Wicked
79648077
======================
79658078

sql/pgtap--1.2.0--1.2.1.sql

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -155,3 +155,89 @@ CREATE OR REPLACE FUNCTION col_is_pk ( NAME, NAME, NAME )
155155
RETURNS TEXT AS $$
156156
SELECT col_is_pk( $1, $2, $3, 'Column ' || quote_ident($1) || '.' || quote_ident($2) || '(' || quote_ident($3) || ') should be a primary key' );
157157
$$ LANGUAGE sql;
158+
159+
-- col_has_exclusion(schema, table, columns, description)
160+
CREATE OR REPLACE FUNCTION col_has_exclusion(TEXT, TEXT, TEXT[], TEXT)
161+
RETURNS TEXT AS $$
162+
SELECT ok(array_agg(attr.attname)::TEXT[] @> $3 AND $3 @> array_agg(attr.attname)::TEXT[])
163+
FROM pg_constraint AS con
164+
JOIN LATERAL unnest(con.conkey) AS attnums (num) ON TRUE
165+
JOIN pg_attribute AS attr ON attr.attrelid = con.conrelid
166+
AND attr.attnum = attnums.num
167+
WHERE conrelid = format('%1$I.%2$I', $1, $2)::regclass
168+
AND contype = 'x';
169+
$$ LANGUAGE sql;
170+
171+
-- set_eq( array, array, description )
172+
CREATE OR REPLACE FUNCTION set_eq(anyarray, anyarray, TEXT)
173+
RETURNS TEXT AS $$
174+
SELECT ok($1 @> $2 AND $2 @> $1, $3);
175+
$$ LANGUAGE sql;
176+
177+
-- set_eq( array, array )
178+
CREATE OR REPLACE FUNCTION set_eq(anyarray, anyarray)
179+
RETURNS TEXT AS $$
180+
SELECT set_eq($1, $2, 'arrays have identical contents')
181+
$$ LANGUAGE sql;
182+
183+
-- table_comment_has(schema, table, comment, description)
184+
CREATE OR REPLACE FUNCTION table_comment_has(TEXT, TEXT, TEXT, TEXT)
185+
RETURNS TEXT AS $$
186+
SELECT ok(COUNT(*) >= 1, $4)
187+
FROM pg_description
188+
JOIN LATERAL regexp_split_to_table(description, '\n') AS lines (line) ON TRUE
189+
WHERE objoid = format('%1$I.%2$I', $1, $2)::regclass
190+
AND objsubid = 0
191+
AND trim(line) ILIKE $3
192+
$$ LANGUAGE sql;
193+
194+
-- table_comment_has(schema, table, comment)
195+
CREATE OR REPLACE FUNCTION table_comment_has(TEXT, TEXT, TEXT)
196+
RETURNS TEXT AS $$
197+
SELECT table_comment_has($1, $2, $3, 'table comment contains expected line');
198+
$$ LANGUAGE sql;
199+
200+
-- column_comment_has(schema, table, column, comment, description)
201+
CREATE OR REPLACE FUNCTION column_comment_has(TEXT, TEXT, TEXT, TEXT, TEXT)
202+
RETURNS TEXT AS $$
203+
SELECT ok(COUNT(*) >= 1, $5)
204+
FROM pg_description
205+
JOIN pg_attribute AS attr
206+
ON attr.attrelid = pg_description.objoid
207+
AND attr.attnum = pg_description.objsubid
208+
JOIN LATERAL regexp_split_to_table(description, '\n') AS lines (line) ON TRUE
209+
WHERE objoid = format('%1$I.%2$I', $1, $2)::regclass
210+
AND attr.attname = $3::name
211+
AND trim(line) ILIKE $4
212+
$$ LANGUAGE sql;
213+
214+
-- column_comment_has(schema, table, column, comment)
215+
CREATE OR REPLACE FUNCTION column_comment_has(TEXT, TEXT, TEXT, TEXT)
216+
RETURNS TEXT AS $$
217+
SELECT column_comment_has($1, $2, $3, $4, 'column comment contains expected line');
218+
$$ LANGUAGE sql;
219+
220+
-- function_comment_has(schema, function, comment, description)
221+
CREATE OR REPLACE FUNCTION function_comment_has(TEXT, TEXT, TEXT, TEXT)
222+
RETURNS TEXT AS $$
223+
SELECT ok(COUNT(*) >= 1, $4)
224+
FROM pg_description
225+
JOIN LATERAL regexp_split_to_table(description, '\n') AS lines (line) ON TRUE
226+
WHERE objoid = format('%1$I.%2$I', $1, $2)::regproc
227+
AND objsubid = 0
228+
AND trim(line) ILIKE $3
229+
$$ LANGUAGE sql;
230+
231+
-- function_comment_has(schema, function, comment)
232+
CREATE OR REPLACE FUNCTION function_comment_has(TEXT, TEXT, TEXT)
233+
RETURNS TEXT AS $$
234+
SELECT function_comment_has($1, $2, $3, 'function comment contains expected line');
235+
$$ LANGUAGE sql;
236+
237+
-- rls_is_enabled(schema, table, desired_value)
238+
CREATE OR REPLACE FUNCTION rls_is_enabled(TEXT, TEXT, BOOLEAN)
239+
RETURNS TEXT AS $$
240+
SELECT ok(relrowsecurity IS NOT DISTINCT FROM $3)
241+
FROM pg_class
242+
WHERE oid = format('%1$I.%2$I', $1, $2)::regclass
243+
$$ LANGUAGE sql;

sql/pgtap.sql.in

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2418,6 +2418,18 @@ RETURNS TEXT AS $$
24182418
SELECT col_has_check( $1, $2, 'Column ' || quote_ident($1) || '(' || quote_ident($2) || ') should have a check constraint' );
24192419
$$ LANGUAGE sql;
24202420

2421+
-- col_has_exclusion(schema, table, columns, description)
2422+
CREATE OR REPLACE FUNCTION col_has_exclusion(TEXT, TEXT, TEXT[], TEXT)
2423+
RETURNS TEXT AS $$
2424+
SELECT ok(array_agg(attr.attname)::TEXT[] @> $3 AND $3 @> array_agg(attr.attname)::TEXT[])
2425+
FROM pg_constraint AS con
2426+
JOIN LATERAL unnest(con.conkey) AS attnums (num) ON TRUE
2427+
JOIN pg_attribute AS attr ON attr.attrelid = con.conrelid
2428+
AND attr.attnum = attnums.num
2429+
WHERE conrelid = format('%1$I.%2$I', $1, $2)::regclass
2430+
AND contype = 'x';
2431+
$$ LANGUAGE sql;
2432+
24212433
-- fk_ok( fk_schema, fk_table, fk_column[], pk_schema, pk_table, pk_column[], description )
24222434
CREATE OR REPLACE FUNCTION fk_ok ( NAME, NAME, NAME[], NAME, NAME, NAME[], TEXT )
24232435
RETURNS TEXT AS $$
@@ -6864,6 +6876,18 @@ RETURNS TEXT AS $$
68646876
SELECT _relcomp( $1, $2, NULL::text, '' );
68656877
$$ LANGUAGE sql;
68666878

6879+
-- set_eq( array, array, description )
6880+
CREATE OR REPLACE FUNCTION set_eq(anyarray, anyarray, TEXT)
6881+
RETURNS TEXT AS $$
6882+
SELECT ok($1 @> $2 AND $2 @> $1, $3);
6883+
$$ LANGUAGE sql;
6884+
6885+
-- set_eq( array, array )
6886+
CREATE OR REPLACE FUNCTION set_eq(anyarray, anyarray)
6887+
RETURNS TEXT AS $$
6888+
SELECT set_eq($1, $2, 'arrays have identical contents')
6889+
$$ LANGUAGE sql;
6890+
68676891
-- bag_eq( sql, sql, description )
68686892
CREATE OR REPLACE FUNCTION bag_eq( TEXT, TEXT, TEXT )
68696893
RETURNS TEXT AS $$
@@ -11366,3 +11390,65 @@ RETURNS TEXT AS $$
1136611390
'Function ' || quote_ident($1) || '() should not be a procedure'
1136711391
);
1136811392
$$ LANGUAGE sql;
11393+
11394+
-- table_comment_has(schema, table, comment, description)
11395+
CREATE OR REPLACE FUNCTION table_comment_has(TEXT, TEXT, TEXT, TEXT)
11396+
RETURNS TEXT AS $$
11397+
SELECT ok(COUNT(*) >= 1, $4)
11398+
FROM pg_description
11399+
JOIN LATERAL regexp_split_to_table(description, '\n') AS lines (line) ON TRUE
11400+
WHERE objoid = format('%1$I.%2$I', $1, $2)::regclass
11401+
AND objsubid = 0
11402+
AND trim(line) ILIKE $3
11403+
$$ LANGUAGE sql;
11404+
11405+
-- table_comment_has(schema, table, comment)
11406+
CREATE OR REPLACE FUNCTION table_comment_has(TEXT, TEXT, TEXT)
11407+
RETURNS TEXT AS $$
11408+
SELECT table_comment_has($1, $2, $3, 'table comment contains expected line');
11409+
$$ LANGUAGE sql;
11410+
11411+
-- column_comment_has(schema, table, column, comment, description)
11412+
CREATE OR REPLACE FUNCTION column_comment_has(TEXT, TEXT, TEXT, TEXT, TEXT)
11413+
RETURNS TEXT AS $$
11414+
SELECT ok(COUNT(*) >= 1, $5)
11415+
FROM pg_description
11416+
JOIN pg_attribute AS attr
11417+
ON attr.attrelid = pg_description.objoid
11418+
AND attr.attnum = pg_description.objsubid
11419+
JOIN LATERAL regexp_split_to_table(description, '\n') AS lines (line) ON TRUE
11420+
WHERE objoid = format('%1$I.%2$I', $1, $2)::regclass
11421+
AND attr.attname = $3::name
11422+
AND trim(line) ILIKE $4
11423+
$$ LANGUAGE sql;
11424+
11425+
-- column_comment_has(schema, table, column, comment)
11426+
CREATE OR REPLACE FUNCTION column_comment_has(TEXT, TEXT, TEXT, TEXT)
11427+
RETURNS TEXT AS $$
11428+
SELECT column_comment_has($1, $2, $3, $4, 'column comment contains expected line');
11429+
$$ LANGUAGE sql;
11430+
11431+
-- function_comment_has(schema, function, comment, description)
11432+
CREATE OR REPLACE FUNCTION function_comment_has(TEXT, TEXT, TEXT, TEXT)
11433+
RETURNS TEXT AS $$
11434+
SELECT ok(COUNT(*) >= 1, $4)
11435+
FROM pg_description
11436+
JOIN LATERAL regexp_split_to_table(description, '\n') AS lines (line) ON TRUE
11437+
WHERE objoid = format('%1$I.%2$I', $1, $2)::regproc
11438+
AND objsubid = 0
11439+
AND trim(line) ILIKE $3
11440+
$$ LANGUAGE sql;
11441+
11442+
-- function_comment_has(schema, function, comment)
11443+
CREATE OR REPLACE FUNCTION function_comment_has(TEXT, TEXT, TEXT)
11444+
RETURNS TEXT AS $$
11445+
SELECT function_comment_has($1, $2, $3, 'function comment contains expected line');
11446+
$$ LANGUAGE sql;
11447+
11448+
-- rls_is_enabled(schema, table, desired_value)
11449+
CREATE OR REPLACE FUNCTION rls_is_enabled(TEXT, TEXT, BOOLEAN)
11450+
RETURNS TEXT AS $$
11451+
SELECT ok(relrowsecurity IS NOT DISTINCT FROM $3)
11452+
FROM pg_class
11453+
WHERE oid = format('%1$I.%2$I', $1, $2)::regclass
11454+
$$ LANGUAGE sql;

0 commit comments

Comments
 (0)