commit 6d072d9771a5fddf197a78091d12bca3fb398240
Author: David E. Wheeler <david@justatheory.com>
Date:   Sat Oct 9 22:45:13 2021 -0400

    Fix test failures on Postgres 14
    
    Due to the following changes:
    
    *   Support for right unary (postfix) operators was dropped, so has_rightop()
        does not work (and has no operators to test against) on Postgres 14. So
        mock the test output for that function on Postgres 14.
    
    *   The types for functions work on changed from anyelement/anyarray to
        anycompatible/anycompatiblearray. So use the appropriate types depending
        on the versin of Postgres.
    
    *   A primary key was added to pg_catalog.pg_class, breaking tests that did
        not expect it. So create primary key-less and unique key-less tables in
        the tests that we can depend on, instead.

diff --git a/Makefile b/Makefile
index fedaf7c..88280e2 100644
--- a/Makefile
+++ b/Makefile
@@ -134,7 +134,7 @@ EXCLUDE_TEST_FILES += test/sql/policy.sql
 endif
 
 # Partition tests tests not supported by 9.x and earlier.
-ifeq ($(shell echo $(VERSION) | grep -qE "[89][.]" && echo yes || echo no),yes)
+ifeq ($(shell echo $(VERSION) | grep -qE "^[89][.]" && echo yes || echo no),yes)
 EXCLUDE_TEST_FILES += test/sql/partitions.sql
 endif
 
diff --git a/doc/pgtap.mmd b/doc/pgtap.mmd
index 090f4de..bfc7da4 100644
--- a/doc/pgtap.mmd
+++ b/doc/pgtap.mmd
@@ -3875,8 +3875,9 @@ fail. If the operator does not exist, the test will fail. Example:
 
 If you omit the schema name, then the operator must be visible in the search
 path. If you omit the test description, pgTAP will generate a reasonable one
-for you. The return value is also optional. If you need to test for a left or
-right unary operator, use `has_leftop()` or `has_rightop()` instead.
+for you. The return value is also optional. If you need to test for a left
+(prefix) or right (postfix) unary operator, use `has_leftop()` or
+`has_rightop()` instead.
 
 ### `has_leftop()` ###
 
@@ -3904,9 +3905,9 @@ right unary operator, use `has_leftop()` or `has_rightop()` instead.
 `:description`
 : A short description of the test.
 
-Tests for the presence of a left-unary operator. If the operator exists with
-the given schema, name, right argument, and return value, the test will fail.
-If the operator does not exist, the test will fail. Example:
+Tests for the presence of a left-unary (prefix) operator. If the operator
+exists with the given schema, name, right argument, and return value, the
+test will fail. If the operator does not exist, the test will fail. Example:
 
     SELECT has_leftop( 'pg_catalog', '!!', 'bigint', 'numeric' );
 
@@ -3940,9 +3941,10 @@ for you. The return type is also optional.
 `:description`
 : A short description of the test.
 
-Tests for the presence of a right-unary operator. If the operator exists with
-the given left argument, schema, name, and return value, the test will fail.
-If the operator does not exist, the test will fail. Example:
+Tests for the presence of a right-unary (postfix) operator, supported through
+PostgreSQL 13. If the operator exists with the given left argument, schema,
+name, and return value, the test will fail. If the operator does not exist,
+the test will fail. Example:
 
     SELECT has_rightop( 'bigint', 'pg_catalog', '!', 'numeric' );
 
diff --git a/test/sql/functap.sql b/test/sql/functap.sql
index 45f23fc..b62e4ac 100644
--- a/test/sql/functap.sql
+++ b/test/sql/functap.sql
@@ -15,12 +15,37 @@ AS 'BEGIN RETURN TRUE; END;' LANGUAGE plpgsql IMMUTABLE;
 CREATE FUNCTION public.pet () RETURNS SETOF BOOL
 AS 'BEGIN RETURN NEXT TRUE; RETURN; END;' LANGUAGE plpgsql STABLE;
 
-CREATE AGGREGATE public.tap_accum (
-    sfunc    = array_append,
-    basetype = anyelement,
-    stype    = anyarray,
-    initcond = '{}'
-);
+DO $$
+BEGIN
+    IF pg_version_num() >= 140000 THEN
+        CREATE AGGREGATE public.tap_accum (
+            sfunc    = array_append,
+            basetype = anycompatible,
+            stype    = anycompatiblearray,
+            initcond = '{}'
+        );
+        CREATE FUNCTION atype()
+        RETURNS text AS 'SELECT ''anycompatiblearray''::text'
+        LANGUAGE SQL IMMUTABLE;
+        CREATE FUNCTION etype()
+        RETURNS text AS 'SELECT ''anycompatible''::text'
+        LANGUAGE SQL IMMUTABLE;
+    ELSE
+        CREATE AGGREGATE public.tap_accum (
+            sfunc    = array_append,
+            basetype = anyelement,
+            stype    = anyarray,
+            initcond = '{}'
+        );
+        CREATE FUNCTION atype()
+        RETURNS text AS 'SELECT ''anyarray''::text'
+        LANGUAGE SQL IMMUTABLE;
+        CREATE FUNCTION etype()
+        RETURNS text AS 'SELECT ''anyelement''::text'
+        LANGUAGE SQL IMMUTABLE;
+    END IF;
+END;
+$$;
 
 /****************************************************************************/
 -- Test has_function().
@@ -105,10 +130,10 @@ SELECT * FROM check_test(
 );
 
 SELECT * FROM check_test(
-    has_function( 'array_cat', ARRAY['anyarray','anyarray'] ),
+    has_function( 'array_cat', ARRAY[atype(), atype()] ),
     true,
     'simple array function',
-    'Function array_cat(anyarray, anyarray) should exist',
+    'Function array_cat(' || atype() || ', ' || atype() || ') should exist',
     ''
 );
 
@@ -265,10 +290,10 @@ SELECT * FROM check_test(
 );
 
 SELECT * FROM check_test(
-    hasnt_function( 'array_cat', ARRAY['anyarray','anyarray'] ),
+    hasnt_function( 'array_cat', ARRAY[atype(), atype()] ),
     false,
     'simple array function',
-    'Function array_cat(anyarray, anyarray) should not exist',
+    'Function array_cat(' || atype() || ', ' || atype() || ') should not exist',
     ''
 );
 
@@ -1018,7 +1043,7 @@ SELECT * FROM check_test(
 /****************************************************************************/
 -- Test is_aggregate() and isnt_aggregate().
 SELECT * FROM check_test(
-    is_aggregate( 'public', 'tap_accum', ARRAY['anyelement'], 'whatever' ),
+    is_aggregate( 'public', 'tap_accum', ARRAY[etype()], 'whatever' ),
     true,
     'is_aggregate(schema, func, arg, desc)',
     'whatever',
@@ -1026,7 +1051,7 @@ SELECT * FROM check_test(
 );
 
 SELECT * FROM check_test(
-    isnt_aggregate( 'public', 'tap_accum', ARRAY['anyelement'], 'whatever' ),
+    isnt_aggregate( 'public', 'tap_accum', ARRAY[etype()], 'whatever' ),
     false,
     'isnt_aggregate(schema, func, arg, desc)',
     'whatever',
@@ -1034,18 +1059,18 @@ SELECT * FROM check_test(
 );
 
 SELECT * FROM check_test(
-    is_aggregate( 'public', 'tap_accum', ARRAY['anyelement'] ),
+    is_aggregate( 'public', 'tap_accum', ARRAY[etype()] ),
     true,
     'is_aggregate(schema, func, arg)',
-    'Function public.tap_accum(anyelement) should be an aggregate function',
+    'Function public.tap_accum(' || etype() || ') should be an aggregate function',
     ''
 );
 
 SELECT * FROM check_test(
-    isnt_aggregate( 'public', 'tap_accum', ARRAY['anyelement'] ),
+    isnt_aggregate( 'public', 'tap_accum', ARRAY[etype()] ),
     false,
     'isnt_aggregate(schema, func, arg)',
-    'Function public.tap_accum(anyelement) should not be an aggregate function',
+    'Function public.tap_accum(' || etype() || ') should not be an aggregate function',
     ''
 );
 
@@ -1114,7 +1139,7 @@ SELECT * FROM check_test(
 );
 
 SELECT * FROM check_test(
-    is_aggregate( 'public', 'tap_accum', ARRAY['anyelement'], 'whatever' ),
+    is_aggregate( 'public', 'tap_accum', ARRAY[etype()], 'whatever' ),
     true,
     'is_aggregate(schema, func, arg, desc)',
     'whatever',
@@ -1122,7 +1147,7 @@ SELECT * FROM check_test(
 );
 
 SELECT * FROM check_test(
-    isnt_aggregate( 'public', 'tap_accum', ARRAY['anyelement'], 'whatever' ),
+    isnt_aggregate( 'public', 'tap_accum', ARRAY[etype()], 'whatever' ),
     false,
     'isnt_aggregate(schema, func, arg, desc)',
     'whatever',
@@ -1130,18 +1155,18 @@ SELECT * FROM check_test(
 );
 
 SELECT * FROM check_test(
-    is_aggregate( 'public', 'tap_accum', ARRAY['anyelement'] ),
+    is_aggregate( 'public', 'tap_accum', ARRAY[etype()] ),
     true,
     'is_aggregate(schema, func, arg)',
-    'Function public.tap_accum(anyelement) should be an aggregate function',
+    'Function public.tap_accum(' || etype() || ') should be an aggregate function',
     ''
 );
 
 SELECT * FROM check_test(
-    isnt_aggregate( 'public', 'tap_accum', ARRAY['anyelement'] ),
+    isnt_aggregate( 'public', 'tap_accum', ARRAY[etype()] ),
     false,
     'isnt_aggregate(schema, func, arg)',
-    'Function public.tap_accum(anyelement) should not be an aggregate function',
+    'Function public.tap_accum(' || etype() || ') should not be an aggregate function',
     ''
 );
 
@@ -1210,7 +1235,7 @@ SELECT * FROM check_test(
 );
 
 SELECT * FROM check_test(
-    is_aggregate( 'tap_accum', ARRAY['anyelement'], 'whatever' ),
+    is_aggregate( 'tap_accum', ARRAY[etype()], 'whatever' ),
     true,
     'is_aggregate(func, arg, desc)',
     'whatever',
@@ -1218,7 +1243,7 @@ SELECT * FROM check_test(
 );
 
 SELECT * FROM check_test(
-    isnt_aggregate( 'tap_accum', ARRAY['anyelement'], 'whatever' ),
+    isnt_aggregate( 'tap_accum', ARRAY[etype()], 'whatever' ),
     false,
     'isnt_aggregate(func, arg, desc)',
     'whatever',
@@ -1226,18 +1251,18 @@ SELECT * FROM check_test(
 );
 
 SELECT * FROM check_test(
-    is_aggregate( 'tap_accum', ARRAY['anyelement'] ),
+    is_aggregate( 'tap_accum', ARRAY[etype()] ),
     true,
     'is_aggregate(func, arg)',
-    'Function tap_accum(anyelement) should be an aggregate function',
+    'Function tap_accum(' || etype() || ') should be an aggregate function',
     ''
 );
 
 SELECT * FROM check_test(
-    isnt_aggregate( 'tap_accum', ARRAY['anyelement'] ),
+    isnt_aggregate( 'tap_accum', ARRAY[etype()] ),
     false,
     'isnt_aggregate(func, arg)',
-    'Function tap_accum(anyelement) should not be an aggregate function',
+    'Function tap_accum(' || etype() || ') should not be an aggregate function',
     ''
 );
 
diff --git a/test/sql/hastap.sql b/test/sql/hastap.sql
index 3448190..e63c6db 100644
--- a/test/sql/hastap.sql
+++ b/test/sql/hastap.sql
@@ -1459,7 +1459,7 @@ SELECT * FROM check_test(
 -- Test has_leftop().
 
 SELECT * FROM check_test(
-  has_leftop( 'pg_catalog', '!!', 'bigint', 'numeric', 'desc' ),
+  has_leftop( 'pg_catalog', '+', 'bigint', 'bigint', 'desc' ),
   true,
   'has_leftop( schema, name, right, result, desc )',
   'desc',
@@ -1467,15 +1467,15 @@ SELECT * FROM check_test(
 );
 
 SELECT * FROM check_test(
-  has_leftop( 'pg_catalog', '!!', 'bigint', 'numeric'::name ),
+  has_leftop( 'pg_catalog', '+', 'bigint', 'bigint'::name ),
   true,
   'has_leftop( schema, name, right, result )',
-  'Left operator pg_catalog.!!(NONE,bigint) RETURNS numeric should exist',
+  'Left operator pg_catalog.+(NONE,bigint) RETURNS bigint should exist',
   ''
 );
 
 SELECT * FROM check_test(
-  has_leftop( '!!', 'bigint', 'numeric', 'desc' ),
+  has_leftop( '+', 'bigint', 'bigint', 'desc' ),
   true,
   'has_leftop( name, right, result, desc )',
   'desc',
@@ -1483,15 +1483,15 @@ SELECT * FROM check_test(
 );
 
 SELECT * FROM check_test(
-  has_leftop( '!!', 'bigint', 'numeric'::name ),
+  has_leftop( '+', 'bigint', 'bigint'::name ),
   true,
   'has_leftop( name, right, result )',
-  'Left operator !!(NONE,bigint) RETURNS numeric should exist',
+  'Left operator +(NONE,bigint) RETURNS bigint should exist',
   ''
 );
 
 SELECT * FROM check_test(
-  has_leftop( '!!', 'bigint', 'desc' ),
+  has_leftop( '+', 'bigint', 'desc' ),
   true,
   'has_leftop( name, right, desc )',
   'desc',
@@ -1499,15 +1499,15 @@ SELECT * FROM check_test(
 );
 
 SELECT * FROM check_test(
-  has_leftop( '!!', 'bigint' ),
+  has_leftop( '+', 'bigint' ),
   true,
   'has_leftop( name, right )',
-  'Left operator !!(NONE,bigint) should exist',
+  'Left operator +(NONE,bigint) should exist',
   ''
 );
 
 SELECT * FROM check_test(
-  has_leftop( 'pg_catalog', '!!', 'text', 'numeric', 'desc' ),
+  has_leftop( 'pg_catalog', '+', 'text', 'numeric', 'desc' ),
   false,
   'has_leftop( schema, name, right, result, desc ) fail',
   'desc',
@@ -1515,15 +1515,15 @@ SELECT * FROM check_test(
 );
 
 SELECT * FROM check_test(
-  has_leftop( 'pg_catalog', '!!', 'text', 'numeric'::name ),
+  has_leftop( 'pg_catalog', '+', 'text', 'numeric'::name ),
   false,
   'has_leftop( schema, name, right, result ) fail',
-  'Left operator pg_catalog.!!(NONE,text) RETURNS numeric should exist',
+  'Left operator pg_catalog.+(NONE,text) RETURNS numeric should exist',
   ''
 );
 
 SELECT * FROM check_test(
-  has_leftop( '!!', 'text', 'numeric', 'desc' ),
+  has_leftop( '+', 'text', 'integer', 'desc' ),
   false,
   'has_leftop( name, right, result, desc ) fail',
   'desc',
@@ -1531,15 +1531,15 @@ SELECT * FROM check_test(
 );
 
 SELECT * FROM check_test(
-  has_leftop( '!!', 'text', 'numeric'::name ),
+  has_leftop( '+', 'text', 'integer'::name ),
   false,
   'has_leftop( name, right, result ) fail',
-  'Left operator !!(NONE,text) RETURNS numeric should exist',
+  'Left operator +(NONE,text) RETURNS integer should exist',
   ''
 );
 
 SELECT * FROM check_test(
-  has_leftop( '!!', 'text', 'desc' ),
+  has_leftop( '+', 'text', 'desc' ),
   false,
   'has_leftop( name, right, desc ) fail',
   'desc',
@@ -1547,111 +1547,162 @@ SELECT * FROM check_test(
 );
 
 SELECT * FROM check_test(
-  has_leftop( '!!', 'text' ),
+  has_leftop( '+', 'text' ),
   false,
   'has_leftop( name, right ) fail',
-  'Left operator !!(NONE,text) should exist',
+  'Left operator +(NONE,text) should exist',
   ''
 );
 
 /****************************************************************************/
 -- Test has_rightop().
 
-SELECT * FROM check_test(
-  has_rightop( 'bigint', 'pg_catalog', '!', 'numeric', 'desc' ),
-  true,
-  'has_rightop( left, schema, name, result, desc )',
-  'desc',
-  ''
-);
+CREATE FUNCTION test_rightop() RETURNS SETOF TEXT LANGUAGE plpgsql AS $$
+DECLARE
+    tap record;
+BEGIN
+    IF pg_version_num() < 140000 THEN
+        FOR tap IN SELECT * FROM check_test(
+            has_rightop( 'bigint', 'pg_catalog', '!', 'numeric', 'desc' ),
+            true,
+            'has_rightop( left, schema, name, result, desc )',
+            'desc',
+            ''
+        ) AS b LOOP RETURN NEXT tap.b; END LOOP;
 
-SELECT * FROM check_test(
-  has_rightop( 'bigint', 'pg_catalog', '!', 'numeric'::name ),
-  true,
-  'has_rightop( left, schema, name, result )',
-  'Right operator pg_catalog.!(bigint,NONE) RETURNS numeric should exist',
-  ''
-);
+        FOR tap IN SELECT * FROM check_test(
+            has_rightop( 'bigint', 'pg_catalog', '!', 'numeric'::name ),
+            true,
+            'has_rightop( left, schema, name, result )',
+            'Right operator pg_catalog.!(bigint,NONE) RETURNS numeric should exist',
+            ''
+        ) AS b LOOP RETURN NEXT tap.b; END LOOP;
 
-SELECT * FROM check_test(
-  has_rightop( 'bigint', '!', 'numeric', 'desc' ),
-  true,
-  'has_rightop( left, name, result, desc )',
-  'desc',
-  ''
-);
+        FOR tap IN SELECT * FROM check_test(
+            has_rightop( 'bigint', '!', 'numeric', 'desc' ),
+            true,
+            'has_rightop( left, name, result, desc )',
+            'desc',
+            ''
+        ) AS b LOOP RETURN NEXT tap.b; END LOOP;
 
-SELECT * FROM check_test(
-  has_rightop( 'bigint', '!', 'numeric'::name ),
-  true,
-  'has_rightop( left, name, result )',
-  'Right operator !(bigint,NONE) RETURNS numeric should exist',
-  ''
-);
+        FOR tap IN SELECT * FROM check_test(
+            has_rightop( 'bigint', '!', 'numeric'::name ),
+            true,
+            'has_rightop( left, name, result )',
+            'Right operator !(bigint,NONE) RETURNS numeric should exist',
+            ''
+        ) AS b LOOP RETURN NEXT tap.b; END LOOP;
 
-SELECT * FROM check_test(
-  has_rightop( 'bigint', '!', 'desc' ),
-  true,
-  'has_rightop( left, name, desc )',
-  'desc',
-  ''
-);
+        FOR tap IN SELECT * FROM check_test(
+            has_rightop( 'bigint', '!', 'desc' ),
+            true,
+            'has_rightop( left, name, desc )',
+            'desc',
+            ''
+        ) AS b LOOP RETURN NEXT tap.b; END LOOP;
 
-SELECT * FROM check_test(
-  has_rightop( 'bigint', '!' ),
-  true,
-  'has_rightop( left, name )',
-  'Right operator !(bigint,NONE) should exist',
-  ''
-);
+        FOR tap IN SELECT * FROM check_test(
+            has_rightop( 'bigint', '!' ),
+            true,
+            'has_rightop( left, name )',
+            'Right operator !(bigint,NONE) should exist',
+            ''
+        ) AS b LOOP RETURN NEXT tap.b; END LOOP;
 
-SELECT * FROM check_test(
-  has_rightop( 'text', 'pg_catalog', '!', 'numeric', 'desc' ),
-  false,
-  'has_rightop( left, schema, name, result, desc ) fail',
-  'desc',
-  ''
-);
+        FOR tap IN SELECT * FROM check_test(
+            has_rightop( 'text', 'pg_catalog', '!', 'numeric', 'desc' ),
+            false,
+            'has_rightop( left, schema, name, result, desc ) fail',
+            'desc',
+            ''
+        ) AS b LOOP RETURN NEXT tap.b; END LOOP;
 
-SELECT * FROM check_test(
-  has_rightop( 'text', 'pg_catalog', '!', 'numeric'::name ),
-  false,
-  'has_rightop( left, schema, name, result ) fail',
-  'Right operator pg_catalog.!(text,NONE) RETURNS numeric should exist',
-  ''
-);
+        FOR tap IN SELECT * FROM check_test(
+            has_rightop( 'text', 'pg_catalog', '!', 'numeric'::name ),
+            false,
+            'has_rightop( left, schema, name, result ) fail',
+            'Right operator pg_catalog.!(text,NONE) RETURNS numeric should exist',
+            ''
+        ) AS b LOOP RETURN NEXT tap.b; END LOOP;
 
-SELECT * FROM check_test(
-  has_rightop( 'text', '!', 'numeric', 'desc' ),
-  false,
-  'has_rightop( left, name, result, desc ) fail',
-  'desc',
-  ''
-);
+        FOR tap IN SELECT * FROM check_test(
+            has_rightop( 'text', '!', 'numeric', 'desc' ),
+            false,
+            'has_rightop( left, name, result, desc ) fail',
+            'desc',
+            ''
+        ) AS b LOOP RETURN NEXT tap.b; END LOOP;
 
-SELECT * FROM check_test(
-  has_rightop( 'text', '!', 'numeric'::name ),
-  false,
-  'has_rightop( left, name, result ) fail',
-  'Right operator !(text,NONE) RETURNS numeric should exist',
-  ''
-);
+        FOR tap IN SELECT * FROM check_test(
+            has_rightop( 'text', '!', 'numeric'::name ),
+            false,
+            'has_rightop( left, name, result ) fail',
+            'Right operator !(text,NONE) RETURNS numeric should exist',
+            ''
+        ) AS b LOOP RETURN NEXT tap.b; END LOOP;
 
-SELECT * FROM check_test(
-  has_rightop( 'text', '!', 'desc' ),
-  false,
-  'has_rightop( left, name, desc ) fail',
-  'desc',
-  ''
-);
+        FOR tap IN SELECT * FROM check_test(
+            has_rightop( 'text', '!', 'desc' ),
+            false,
+            'has_rightop( left, name, desc ) fail',
+            'desc',
+            ''
+        ) AS b LOOP RETURN NEXT tap.b; END LOOP;
+
+        FOR tap IN SELECT * FROM check_test(
+            has_rightop( 'text', '!' ),
+            false,
+            'has_rightop( left, name ) fail',
+            'Right operator !(text,NONE) should exist',
+            ''
+        ) AS b LOOP RETURN NEXT tap.b; END LOOP;
+    ELSE
+        -- PostgreSQL 14 dropped support for postfix operators, so mock the
+        -- output for the test to pass.
+        FOR tap IN SELECT * FROM (VALUES
+            ('has_rightop( left, schema, name, result, desc ) should pass'),
+            ('has_rightop( left, schema, name, result, desc ) should have the proper description'),
+            ('has_rightop( left, schema, name, result, desc ) should have the proper diagnostics'),
+            ('has_rightop( left, schema, name, result ) should pass'),
+            ('has_rightop( left, schema, name, result ) should have the proper description'),
+            ('has_rightop( left, schema, name, result ) should have the proper diagnostics'),
+            ('has_rightop( left, name, result, desc ) should pass'),
+            ('has_rightop( left, name, result, desc ) should have the proper description'),
+            ('has_rightop( left, name, result, desc ) should have the proper diagnostics'),
+            ('has_rightop( left, name, result ) should pass'),
+            ('has_rightop( left, name, result ) should have the proper description'),
+            ('has_rightop( left, name, result ) should have the proper diagnostics'),
+            ('has_rightop( left, name, desc ) should pass'),
+            ('has_rightop( left, name, desc ) should have the proper description'),
+            ('has_rightop( left, name, desc ) should have the proper diagnostics'),
+            ('has_rightop( left, name ) should pass'),
+            ('has_rightop( left, name ) should have the proper description'),
+            ('has_rightop( left, name ) should have the proper diagnostics'),
+            ('has_rightop( left, schema, name, result, desc ) fail should fail'),
+            ('has_rightop( left, schema, name, result, desc ) fail should have the proper description'),
+            ('has_rightop( left, schema, name, result, desc ) fail should have the proper diagnostics'),
+            ('has_rightop( left, schema, name, result ) fail should fail'),
+            ('has_rightop( left, schema, name, result ) fail should have the proper description'),
+            ('has_rightop( left, schema, name, result ) fail should have the proper diagnostics'),
+            ('has_rightop( left, name, result, desc ) fail should fail'),
+            ('has_rightop( left, name, result, desc ) fail should have the proper description'),
+            ('has_rightop( left, name, result, desc ) fail should have the proper diagnostics'),
+            ('has_rightop( left, name, result ) fail should fail'),
+            ('has_rightop( left, name, result ) fail should have the proper description'),
+            ('has_rightop( left, name, result ) fail should have the proper diagnostics'),
+            ('has_rightop( left, name, desc ) fail should fail'),
+            ('has_rightop( left, name, desc ) fail should have the proper description'),
+            ('has_rightop( left, name, desc ) fail should have the proper diagnostics'),
+            ('has_rightop( left, name ) fail should fail'),
+            ('has_rightop( left, name ) fail should have the proper description'),
+            ('has_rightop( left, name ) fail should have the proper diagnostics')
+        ) AS A(b) LOOP RETURN NEXT pass(tap.b); END LOOP;
+    END IF;
+END;
+$$;
+SELECT * FROM test_rightop();
 
-SELECT * FROM check_test(
-  has_rightop( 'text', '!' ),
-  false,
-  'has_rightop( left, name ) fail',
-  'Right operator !(text,NONE) should exist',
-  ''
-);
 
 /****************************************************************************/
 -- Test has_language() and hasnt_language().
diff --git a/test/sql/pktap.sql b/test/sql/pktap.sql
index f7577c3..b814277 100644
--- a/test/sql/pktap.sql
+++ b/test/sql/pktap.sql
@@ -12,6 +12,10 @@ CREATE TABLE public.sometab(
     numb  NUMERIC(10, 2),
     myint NUMERIC(8)
 );
+-- This table has no pk
+CREATE TABLE public.pkless(
+    id INT NOT NULL UNIQUE
+);
 CREATE SCHEMA hide;
 CREATE TABLE hide.hidesometab(
     id    INT NOT NULL PRIMARY KEY,
@@ -66,18 +70,18 @@ SELECT * FROM check_test(
 );
 
 SELECT * FROM check_test(
-    has_pk( 'pg_catalog', 'pg_class', 'pg_catalog.pg_class should have a pk' ),
+    has_pk( 'public', 'pkless', 'public.pkless should have a pk' ),
     false,
     'has_pk( schema, table, description ) fail',
-    'pg_catalog.pg_class should have a pk',
+    'public.pkless should have a pk',
     ''
 );
 
 SELECT * FROM check_test(
-    has_pk( 'pg_class', 'pg_class should have a pk' ),
+    has_pk( 'pkless', 'pkless should have a pk' ),
     false,
     'has_pk( table, description ) fail',
-    'pg_class should have a pk',
+    'pkless should have a pk',
     ''
 );
 
@@ -109,18 +113,18 @@ SELECT * FROM check_test(
 );
 
 SELECT * FROM check_test(
-    hasnt_pk( 'pg_catalog', 'pg_class', 'pg_catalog.pg_class should not have a pk' ),
+    hasnt_pk( 'public', 'pkless', 'public.pkless should not have a pk' ),
     true,
     'hasnt_pk( schema, table, description ) pass',
-    'pg_catalog.pg_class should not have a pk',
+    'public.pkless should not have a pk',
     ''
 );
 
 SELECT * FROM check_test(
-    hasnt_pk( 'pg_class', 'pg_class should not have a pk' ),
+    hasnt_pk( 'pkless', 'pkless should not have a pk' ),
     true,
     'hasnt_pk( table, description ) pass',
-    'pg_class should not have a pk',
+    'pkless should not have a pk',
     ''
 );
 
diff --git a/test/sql/unique.sql b/test/sql/unique.sql
index cd6ec32..1019beb 100644
--- a/test/sql/unique.sql
+++ b/test/sql/unique.sql
@@ -12,6 +12,10 @@ CREATE TABLE public.sometab(
     myint NUMERIC(8),
     UNIQUE (numb, myint)
 );
+-- This table has no unique index
+CREATE TABLE public.uniqueless(
+    id INT PRIMARY KEY
+);
 RESET client_min_messages;
 
 /****************************************************************************/
@@ -42,18 +46,18 @@ SELECT * FROM check_test(
 );
 
 SELECT * FROM check_test(
-    has_unique( 'pg_catalog', 'pg_class', 'pg_catalog.pg_class should have a unique constraint' ),
+    has_unique( 'public', 'uniqueless', 'public.uniqueless should have a unique constraint' ),
     false,
     'has_unique( schema, table, description ) fail',
-    'pg_catalog.pg_class should have a unique constraint',
+    'public.uniqueless should have a unique constraint',
     ''
 );
 
 SELECT * FROM check_test(
-    has_unique( 'pg_class', 'pg_class should have a unique constraint' ),
+    has_unique( 'uniqueless', 'uniqueless should have a unique constraint' ),
     false,
     'has_unique( table, description ) fail',
-    'pg_class should have a unique constraint',
+    'uniqueless should have a unique constraint',
     ''
 );
 
