LCOV - differential code coverage report
Current view: top level - src/test/modules/test_saslprep - test_saslprep.c (source / functions) Coverage Total Hit UNC GNC
Current: bed3ffbf9d952be6c7d739d068cdce44c046dfb7 vs 574581b50ac9c63dd9e4abebb731a3b67e5b50f6 Lines: 37.1 % 105 39 66 39
Current Date: 2026-05-05 10:23:31 +0900 Functions: 83.3 % 6 5 1 5
Baseline: lcov-20260505-025707-baseline Branches: 19.4 % 31 6 25 6
Baseline Date: 2026-05-05 10:27:06 +0900 Line coverage date bins:
Legend: Lines:     hit not hit
Branches: + taken - not taken # not executed
(7,30] days: 100.0 % 2 2 2
(30,360] days: 35.9 % 103 37 66 37
Function coverage date bins:
(30,360] days: 83.3 % 6 5 1 5
Branch coverage date bins:
(30,360] days: 19.4 % 31 6 25 6

 Age         Owner                    Branch data    TLA  Line data    Source code
                                  1                 :                : /*--------------------------------------------------------------------------
                                  2                 :                :  *
                                  3                 :                :  * test_saslprep.c
                                  4                 :                :  *      Test harness for the SASLprep implementation.
                                  5                 :                :  *
                                  6                 :                :  * Portions Copyright (c) 1996-2026, PostgreSQL Global Development Group
                                  7                 :                :  *
                                  8                 :                :  * IDENTIFICATION
                                  9                 :                :  *      src/test/modules/test_saslprep/test_saslprep.c
                                 10                 :                :  *
                                 11                 :                :  * -------------------------------------------------------------------------
                                 12                 :                :  */
                                 13                 :                : 
                                 14                 :                : #include "postgres.h"
                                 15                 :                : 
                                 16                 :                : #include "access/htup_details.h"
                                 17                 :                : #include "common/saslprep.h"
                                 18                 :                : #include "fmgr.h"
                                 19                 :                : #include "funcapi.h"
                                 20                 :                : #include "mb/pg_wchar.h"
                                 21                 :                : #include "miscadmin.h"
                                 22                 :                : #include "utils/builtins.h"
                                 23                 :                : 
   47 michael@paquier.xyz        24                 :GNC           1 : PG_MODULE_MAGIC;
                                 25                 :                : 
                                 26                 :                : static const char *
                                 27                 :            129 : saslprep_status_to_text(pg_saslprep_rc rc)
                                 28                 :                : {
                                 29                 :            129 :     const char *status = "???";
                                 30                 :                : 
                                 31   [ -  +  +  +  :            129 :     switch (rc)
                                                 - ]
                                 32                 :                :     {
   47 michael@paquier.xyz        33                 :UNC           0 :         case SASLPREP_OOM:
                                 34                 :              0 :             status = "OOM";
                                 35                 :              0 :             break;
   47 michael@paquier.xyz        36                 :GNC          95 :         case SASLPREP_SUCCESS:
                                 37                 :             95 :             status = "SUCCESS";
                                 38                 :             95 :             break;
                                 39                 :              1 :         case SASLPREP_INVALID_UTF8:
                                 40                 :              1 :             status = "INVALID_UTF8";
                                 41                 :              1 :             break;
                                 42                 :             33 :         case SASLPREP_PROHIBITED:
                                 43                 :             33 :             status = "PROHIBITED";
                                 44                 :             33 :             break;
                                 45                 :                :     }
                                 46                 :                : 
                                 47                 :            129 :     return status;
                                 48                 :                : }
                                 49                 :                : 
                                 50                 :                : /*
                                 51                 :                :  * Simple function to test SASLprep with arbitrary bytes as input.
                                 52                 :                :  *
                                 53                 :                :  * This takes a bytea in input, returning in output the generating data as
                                 54                 :                :  * bytea with the status returned by pg_saslprep().
                                 55                 :                :  */
                                 56                 :              2 : PG_FUNCTION_INFO_V1(test_saslprep);
                                 57                 :                : Datum
                                 58                 :            129 : test_saslprep(PG_FUNCTION_ARGS)
                                 59                 :                : {
                                 60                 :            129 :     bytea      *string = PG_GETARG_BYTEA_PP(0);
                                 61                 :                :     char       *src;
                                 62                 :                :     Size        src_len;
                                 63                 :                :     char       *input_data;
                                 64                 :                :     char       *result;
                                 65                 :                :     Size        result_len;
                                 66                 :            129 :     bytea      *result_bytea = NULL;
                                 67                 :            129 :     const char *status = NULL;
                                 68                 :                :     Datum      *values;
                                 69                 :                :     bool       *nulls;
                                 70                 :                :     TupleDesc   tupdesc;
                                 71                 :                :     pg_saslprep_rc rc;
                                 72                 :                : 
                                 73                 :                :     /* determine result type */
                                 74         [ -  + ]:            129 :     if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
   47 michael@paquier.xyz        75         [ #  # ]:UNC           0 :         elog(ERROR, "return type must be a row type");
                                 76                 :                : 
   47 michael@paquier.xyz        77                 :GNC         129 :     values = palloc0_array(Datum, tupdesc->natts);
                                 78                 :            129 :     nulls = palloc0_array(bool, tupdesc->natts);
                                 79                 :                : 
                                 80                 :            129 :     src_len = VARSIZE_ANY_EXHDR(string);
                                 81                 :            129 :     src = VARDATA_ANY(string);
                                 82                 :                : 
                                 83                 :                :     /*
                                 84                 :                :      * Copy the input given, to make SASLprep() act on a sanitized string.
                                 85                 :                :      */
                                 86                 :            129 :     input_data = palloc0(src_len + 1);
   22                            87                 :            129 :     memcpy(input_data, src, src_len);
                                 88                 :            129 :     input_data[src_len] = '\0';
                                 89                 :                : 
   47                            90                 :            129 :     rc = pg_saslprep(input_data, &result);
                                 91                 :            129 :     status = saslprep_status_to_text(rc);
                                 92                 :                : 
                                 93         [ +  + ]:            129 :     if (result)
                                 94                 :                :     {
                                 95                 :             95 :         result_len = strlen(result);
                                 96                 :             95 :         result_bytea = palloc(result_len + VARHDRSZ);
                                 97                 :             95 :         SET_VARSIZE(result_bytea, result_len + VARHDRSZ);
                                 98                 :             95 :         memcpy(VARDATA(result_bytea), result, result_len);
                                 99                 :             95 :         values[0] = PointerGetDatum(result_bytea);
                                100                 :                :     }
                                101                 :                :     else
                                102                 :             34 :         nulls[0] = true;
                                103                 :                : 
                                104                 :            129 :     values[1] = CStringGetTextDatum(status);
                                105                 :                : 
                                106                 :            129 :     PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
                                107                 :                : }
                                108                 :                : 
                                109                 :                : /* Context structure for set-returning function with ranges */
                                110                 :                : typedef struct
                                111                 :                : {
                                112                 :                :     int         current_range;
                                113                 :                :     char32_t    current_codepoint;
                                114                 :                : } pg_saslprep_test_context;
                                115                 :                : 
                                116                 :                : /*
                                117                 :                :  * UTF-8 code point ranges.
                                118                 :                :  */
                                119                 :                : typedef struct
                                120                 :                : {
                                121                 :                :     char32_t    start_codepoint;
                                122                 :                :     char32_t    end_codepoint;
                                123                 :                : } pg_utf8_codepoint_range;
                                124                 :                : 
                                125                 :                : static const pg_utf8_codepoint_range pg_utf8_test_ranges[] = {
                                126                 :                :     /* 1, 2, 3 bytes */
                                127                 :                :     {0x0000, 0xD7FF},           /* Basic Multilingual Plane, before surrogates */
                                128                 :                :     {0xE000, 0xFFFF},           /* Basic Multilingual Plane, after surrogates */
                                129                 :                :     /* 4 bytes */
                                130                 :                :     {0x10000, 0x1FFFF},         /* Supplementary Multilingual Plane */
                                131                 :                :     {0x20000, 0x2FFFF},         /* Supplementary Ideographic Plane */
                                132                 :                :     {0x30000, 0x3FFFF},         /* Tertiary Ideographic Plane */
                                133                 :                :     {0x40000, 0xDFFFF},         /* Unassigned planes */
                                134                 :                :     {0xE0000, 0xEFFFF},         /* Supplementary Special-purpose Plane */
                                135                 :                :     {0xF0000, 0xFFFFF},         /* Private Use Area A */
                                136                 :                :     {0x100000, 0x10FFFF},       /* Private Use Area B */
                                137                 :                : };
                                138                 :                : 
                                139                 :                : #define PG_UTF8_TEST_RANGES_LEN \
                                140                 :                :     (sizeof(pg_utf8_test_ranges) / sizeof(pg_utf8_test_ranges[0]))
                                141                 :                : 
                                142                 :                : 
                                143                 :                : /*
                                144                 :                :  * test_saslprep_ranges
                                145                 :                :  *
                                146                 :                :  * Test SASLprep across various UTF-8 ranges.
                                147                 :                :  */
                                148                 :              1 : PG_FUNCTION_INFO_V1(test_saslprep_ranges);
                                149                 :                : Datum
   47 michael@paquier.xyz       150                 :UNC           0 : test_saslprep_ranges(PG_FUNCTION_ARGS)
                                151                 :                : {
                                152                 :                :     FuncCallContext *funcctx;
                                153                 :                :     pg_saslprep_test_context *ctx;
                                154                 :                :     HeapTuple   tuple;
                                155                 :                :     Datum       result;
                                156                 :                : 
                                157                 :                :     /* First call setup */
                                158         [ #  # ]:              0 :     if (SRF_IS_FIRSTCALL())
                                159                 :                :     {
                                160                 :                :         MemoryContext oldcontext;
                                161                 :                :         TupleDesc   tupdesc;
                                162                 :                : 
                                163                 :              0 :         funcctx = SRF_FIRSTCALL_INIT();
                                164                 :              0 :         oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
                                165                 :                : 
                                166         [ #  # ]:              0 :         if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
                                167         [ #  # ]:              0 :             elog(ERROR, "return type must be a row type");
                                168                 :              0 :         funcctx->tuple_desc = tupdesc;
                                169                 :                : 
                                170                 :                :         /* Allocate context with range setup */
                                171                 :              0 :         ctx = (pg_saslprep_test_context *) palloc(sizeof(pg_saslprep_test_context));
                                172                 :              0 :         ctx->current_range = 0;
                                173                 :              0 :         ctx->current_codepoint = pg_utf8_test_ranges[0].start_codepoint;
                                174                 :              0 :         funcctx->user_fctx = ctx;
                                175                 :                : 
                                176                 :              0 :         MemoryContextSwitchTo(oldcontext);
                                177                 :                :     }
                                178                 :                : 
                                179                 :              0 :     funcctx = SRF_PERCALL_SETUP();
                                180                 :              0 :     ctx = (pg_saslprep_test_context *) funcctx->user_fctx;
                                181                 :                : 
                                182         [ #  # ]:              0 :     while (ctx->current_range < PG_UTF8_TEST_RANGES_LEN)
                                183                 :                :     {
                                184                 :              0 :         char32_t    codepoint = ctx->current_codepoint;
                                185                 :                :         unsigned char utf8_buf[5];
                                186                 :                :         char        input_str[6];
                                187                 :              0 :         char       *output = NULL;
                                188                 :                :         pg_saslprep_rc rc;
                                189                 :                :         int         utf8_len;
                                190                 :                :         const char *status;
                                191                 :                :         bytea      *input_bytea;
                                192                 :                :         bytea      *output_bytea;
                                193                 :                :         char        codepoint_str[16];
                                194                 :              0 :         Datum       values[4] = {0};
                                195                 :              0 :         bool        nulls[4] = {0};
                                196                 :              0 :         const pg_utf8_codepoint_range *range =
                                197                 :              0 :             &pg_utf8_test_ranges[ctx->current_range];
                                198                 :                : 
                                199         [ #  # ]:              0 :         CHECK_FOR_INTERRUPTS();
                                200                 :                : 
                                201                 :                :         /* Switch to next range if finished with the previous one */
                                202         [ #  # ]:              0 :         if (ctx->current_codepoint > range->end_codepoint)
                                203                 :                :         {
                                204                 :              0 :             ctx->current_range++;
                                205         [ #  # ]:              0 :             if (ctx->current_range < PG_UTF8_TEST_RANGES_LEN)
                                206                 :              0 :                 ctx->current_codepoint =
                                207                 :              0 :                     pg_utf8_test_ranges[ctx->current_range].start_codepoint;
                                208                 :              0 :             continue;
                                209                 :                :         }
                                210                 :                : 
                                211                 :              0 :         codepoint = ctx->current_codepoint;
                                212                 :                : 
                                213                 :                :         /* Convert code point to UTF-8 */
                                214                 :              0 :         utf8_len = unicode_utf8len(codepoint);
                                215         [ #  # ]:              0 :         if (utf8_len == 0)
                                216                 :                :         {
                                217                 :              0 :             ctx->current_codepoint++;
                                218                 :              0 :             continue;
                                219                 :                :         }
                                220                 :              0 :         unicode_to_utf8(codepoint, utf8_buf);
                                221                 :                : 
                                222                 :                :         /* Create null-terminated string */
                                223                 :              0 :         memcpy(input_str, utf8_buf, utf8_len);
                                224                 :              0 :         input_str[utf8_len] = '\0';
                                225                 :                : 
                                226                 :                :         /* Test with pg_saslprep */
                                227                 :              0 :         rc = pg_saslprep(input_str, &output);
                                228                 :                : 
                                229                 :                :         /* Prepare output values */
                                230                 :              0 :         memset(nulls, false, sizeof(nulls));
                                231                 :                : 
                                232                 :                :         /* codepoint as text U+XXXX format */
                                233         [ #  # ]:              0 :         if (codepoint <= 0xFFFF)
                                234                 :              0 :             snprintf(codepoint_str, sizeof(codepoint_str), "U+%04X", codepoint);
                                235                 :                :         else
                                236                 :              0 :             snprintf(codepoint_str, sizeof(codepoint_str), "U+%06X", codepoint);
                                237                 :              0 :         values[0] = CStringGetTextDatum(codepoint_str);
                                238                 :                : 
                                239                 :                :         /* status */
                                240                 :              0 :         status = saslprep_status_to_text(rc);
                                241                 :              0 :         values[1] = CStringGetTextDatum(status);
                                242                 :                : 
                                243                 :                :         /* input_bytes */
                                244                 :              0 :         input_bytea = (bytea *) palloc(VARHDRSZ + utf8_len);
                                245                 :              0 :         SET_VARSIZE(input_bytea, VARHDRSZ + utf8_len);
                                246                 :              0 :         memcpy(VARDATA(input_bytea), utf8_buf, utf8_len);
                                247                 :              0 :         values[2] = PointerGetDatum(input_bytea);
                                248                 :                : 
                                249                 :                :         /* output_bytes */
                                250         [ #  # ]:              0 :         if (output != NULL)
                                251                 :                :         {
                                252                 :              0 :             int         output_len = strlen(output);
                                253                 :                : 
                                254                 :              0 :             output_bytea = (bytea *) palloc(VARHDRSZ + output_len);
                                255                 :              0 :             SET_VARSIZE(output_bytea, VARHDRSZ + output_len);
                                256                 :              0 :             memcpy(VARDATA(output_bytea), output, output_len);
                                257                 :              0 :             values[3] = PointerGetDatum(output_bytea);
                                258                 :              0 :             pfree(output);
                                259                 :                :         }
                                260                 :                :         else
                                261                 :                :         {
                                262                 :              0 :             nulls[3] = true;
                                263                 :              0 :             values[3] = (Datum) 0;
                                264                 :                :         }
                                265                 :                : 
                                266                 :                :         /* Build and return tuple */
                                267                 :              0 :         tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
                                268                 :              0 :         result = HeapTupleGetDatum(tuple);
                                269                 :                : 
                                270                 :                :         /* Move to next code point */
                                271                 :              0 :         ctx->current_codepoint++;
                                272                 :                : 
                                273                 :              0 :         SRF_RETURN_NEXT(funcctx, result);
                                274                 :                :     }
                                275                 :                : 
                                276                 :                :     /* All done */
                                277                 :              0 :     SRF_RETURN_DONE(funcctx);
                                278                 :                : }
        

Generated by: LCOV version 2.5.0-beta