(root)/
glibc-2.38/
stdio-common/
tst-vfprintf-mbs-prec.c
       1  /* Test for wchar_t/multi-byte conversion and precision in vfprintf.
       2     Copyright (C) 2017-2023 Free Software Foundation, Inc.
       3     This file is part of the GNU C Library.
       4  
       5     The GNU C Library is free software; you can redistribute it and/or
       6     modify it under the terms of the GNU Lesser General Public
       7     License as published by the Free Software Foundation; either
       8     version 2.1 of the License, or (at your option) any later version.
       9  
      10     The GNU C Library is distributed in the hope that it will be useful,
      11     but WITHOUT ANY WARRANTY; without even the implied warranty of
      12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      13     Lesser General Public License for more details.
      14  
      15     You should have received a copy of the GNU Lesser General Public
      16     License along with the GNU C Library; if not, see
      17     <https://www.gnu.org/licenses/>.  */
      18  
      19  #include <locale.h>
      20  #include <stdbool.h>
      21  #include <stdint.h>
      22  #include <stdio.h>
      23  #include <string.h>
      24  #include <support/check.h>
      25  #include <support/test-driver.h>
      26  #include <wchar.h>
      27  
      28  #define DYNARRAY_STRUCT str
      29  #define DYNARRAY_ELEMENT char
      30  #define DYNARRAY_PREFIX str_
      31  #include <malloc/dynarray-skeleton.c>
      32  
      33  #define DYNARRAY_STRUCT wstr
      34  #define DYNARRAY_ELEMENT wchar_t
      35  #define DYNARRAY_PREFIX wstr_
      36  #include <malloc/dynarray-skeleton.c>
      37  
      38  #define DYNARRAY_STRUCT len
      39  #define DYNARRAY_ELEMENT size_t
      40  #define DYNARRAY_PREFIX len_
      41  #include <malloc/dynarray-skeleton.c>
      42  
      43  /* This should be larger than the internal buffer in vfprintf.  The
      44     constant needs to be kept in sync with the format strings in
      45     test_mbs_long and test_wide_long.  */
      46  enum { WIDE_STRING_LENGTH = 1000 };
      47  
      48  /* Creates two large, random strings used for truncation testing.
      49     After the call, *MBS will be encoded in UTF-8, and *WIDE will
      50     contain the same string in the internal UCS-32 encoding.  Both
      51     strings are null-terminated.  The array *LENGTH counts the number
      52     of multi-byte characters for each prefix string of *WIDE: The first
      53     N wide characters of *WIDE correspond the first (*LENGTH)[N] bytes
      54     of *MBS.  The caller should deallocate all three arrays using
      55     free.  */
      56  static void
      57  make_random_string (char **mbs, wchar_t **wide, size_t **length)
      58  {
      59    struct str str;
      60    str_init (&str);
      61    struct wstr wstr;
      62    wstr_init (&wstr);
      63    struct len len;
      64    len_init (&len);
      65  
      66    for (int i = 0; i < WIDE_STRING_LENGTH; ++i)
      67      {
      68        len_add (&len, str_size (&str));
      69        /* Cover some multi-byte UTF-8 sequences.  Avoid the null
      70           character.  */
      71        uint32_t ch = 1 + (rand () % 521);
      72        wstr_add (&wstr, ch);
      73  
      74        /* Limited UTF-8 conversion.  */
      75        if (ch <= 127)
      76          str_add (&str, ch);
      77        else
      78          {
      79            /* We only implement two-byte sequences.  */
      80            uint32_t first = ch >> 6;
      81            TEST_VERIFY (first < 32);
      82            str_add (&str, 0xC0 | first);
      83            str_add (&str, 0x80 | (ch & 0x3f));
      84          }
      85      }
      86    len_add (&len, str_size (&str));
      87    wstr_add (&wstr, L'\0');
      88    str_add (&str, '\0');
      89  
      90    *mbs = str_finalize (&str, NULL);
      91    TEST_VERIFY_EXIT (*mbs != NULL);
      92    *wide = wstr_finalize (&wstr, NULL);
      93    TEST_VERIFY_EXIT (*wide != NULL);
      94    *length = len_finalize (&len, NULL);
      95    TEST_VERIFY_EXIT (*length != NULL);
      96  }
      97  
      98  /* snprintf tests (multi-byte result).  */
      99  static void
     100  test_mbs_result (void)
     101  {
     102    char buf[200];
     103  
     104    /* ASCII wide string.  */
     105    memset (buf, '@', sizeof (buf));
     106    TEST_VERIFY (snprintf (buf, sizeof (buf), "%ls", L"xyz") == 3);
     107    TEST_VERIFY (strcmp (buf, "xyz") == 0);
     108  
     109    /* Unicode wide string.  */
     110    memset (buf, '@', sizeof (buf));
     111    TEST_VERIFY (snprintf (buf, sizeof (buf), "%ls", L"x\u00DFz") == 4);
     112    TEST_VERIFY (strcmp (buf, "x\xC3\x9Fz") == 0);
     113  
     114    /* Varying precisions.  */
     115    memset (buf, '@', sizeof (buf));
     116    TEST_VERIFY (snprintf (buf, sizeof (buf), "%.1ls", L"x\u00DFz") == 1);
     117    TEST_VERIFY (strcmp (buf, "x") == 0);
     118    memset (buf, '@', sizeof (buf));
     119    TEST_VERIFY (snprintf (buf, sizeof (buf), "%.2ls", L"x\u00DFz") == 1);
     120    TEST_VERIFY (strcmp (buf, "x") == 0);
     121    memset (buf, '@', sizeof (buf));
     122    TEST_VERIFY (snprintf (buf, sizeof (buf), "%.3ls", L"x\u00DFz") == 3);
     123    TEST_VERIFY (strcmp (buf, "x\xC3\x9F") == 0);
     124    memset (buf, '@', sizeof (buf));
     125    TEST_VERIFY (snprintf (buf, sizeof (buf), "%.4ls", L"x\u00DFz") == 4);
     126    TEST_VERIFY (strcmp (buf, "x\xC3\x9Fz") == 0);
     127    memset (buf, '@', sizeof (buf));
     128    TEST_VERIFY (snprintf (buf, sizeof (buf), "%.5ls", L"x\u00DFz") == 4);
     129    TEST_VERIFY (strcmp (buf, "x\xC3\x9Fz") == 0);
     130  
     131    /* Varying precisions with width 2, right-justified.  */
     132    memset (buf, '@', sizeof (buf));
     133    TEST_VERIFY (snprintf (buf, sizeof (buf), "%2.1ls", L"x\u00DFz") == 2);
     134    TEST_VERIFY (strcmp (buf, " x") == 0);
     135    memset (buf, '@', sizeof (buf));
     136    TEST_VERIFY (snprintf (buf, sizeof (buf), "%2.2ls", L"x\u00DFz") == 2);
     137    TEST_VERIFY (strcmp (buf, " x") == 0);
     138    memset (buf, '@', sizeof (buf));
     139    TEST_VERIFY (snprintf (buf, sizeof (buf), "%2.3ls", L"x\u00DFz") == 3);
     140    TEST_VERIFY (strcmp (buf, "x\xC3\x9F") == 0);
     141    memset (buf, '@', sizeof (buf));
     142    TEST_VERIFY (snprintf (buf, sizeof (buf), "%2.4ls", L"x\u00DFz") == 4);
     143    TEST_VERIFY (strcmp (buf, "x\xC3\x9Fz") == 0);
     144    memset (buf, '@', sizeof (buf));
     145    TEST_VERIFY (snprintf (buf, sizeof (buf), "%2.5ls", L"x\u00DFz") == 4);
     146    TEST_VERIFY (strcmp (buf, "x\xC3\x9Fz") == 0);
     147  
     148    /* Varying precisions with width 2, left-justified.  */
     149    memset (buf, '@', sizeof (buf));
     150    TEST_VERIFY (snprintf (buf, sizeof (buf), "%-2.1ls", L"x\u00DFz") == 2);
     151    TEST_VERIFY (strcmp (buf, "x ") == 0);
     152    memset (buf, '@', sizeof (buf));
     153    TEST_VERIFY (snprintf (buf, sizeof (buf), "%-2.2ls", L"x\u00DFz") == 2);
     154    TEST_VERIFY (strcmp (buf, "x ") == 0);
     155    memset (buf, '@', sizeof (buf));
     156    TEST_VERIFY (snprintf (buf, sizeof (buf), "%-2.3ls", L"x\u00DFz") == 3);
     157    TEST_VERIFY (strcmp (buf, "x\xC3\x9F") == 0);
     158    memset (buf, '@', sizeof (buf));
     159    TEST_VERIFY (snprintf (buf, sizeof (buf), "%-2.4ls", L"x\u00DFz") == 4);
     160    TEST_VERIFY (strcmp (buf, "x\xC3\x9Fz") == 0);
     161    memset (buf, '@', sizeof (buf));
     162    TEST_VERIFY (snprintf (buf, sizeof (buf), "%-2.5ls", L"x\u00DFz") == 4);
     163    TEST_VERIFY (strcmp (buf, "x\xC3\x9Fz") == 0);
     164  
     165    /* Varying precisions with width 3, right-justified.  */
     166    memset (buf, '@', sizeof (buf));
     167    TEST_VERIFY (snprintf (buf, sizeof (buf), "%3.1ls", L"x\u00DFz") == 3);
     168    TEST_VERIFY (strcmp (buf, "  x") == 0);
     169    memset (buf, '@', sizeof (buf));
     170    TEST_VERIFY (snprintf (buf, sizeof (buf), "%3.2ls", L"x\u00DFz") == 3);
     171    TEST_VERIFY (strcmp (buf, "  x") == 0);
     172    memset (buf, '@', sizeof (buf));
     173    TEST_VERIFY (snprintf (buf, sizeof (buf), "%3.3ls", L"x\u00DFz") == 3);
     174    TEST_VERIFY (strcmp (buf, "x\xC3\x9F") == 0);
     175    memset (buf, '@', sizeof (buf));
     176    TEST_VERIFY (snprintf (buf, sizeof (buf), "%3.4ls", L"x\u00DFz") == 4);
     177    TEST_VERIFY (strcmp (buf, "x\xC3\x9Fz") == 0);
     178    memset (buf, '@', sizeof (buf));
     179    TEST_VERIFY (snprintf (buf, sizeof (buf), "%3.5ls", L"x\u00DFz") == 4);
     180    TEST_VERIFY (strcmp (buf, "x\xC3\x9Fz") == 0);
     181  
     182    /* Varying precisions with width 3, left-justified.  */
     183    memset (buf, '@', sizeof (buf));
     184    TEST_VERIFY (snprintf (buf, sizeof (buf), "%-3.1ls", L"x\u00DFz") == 3);
     185    TEST_VERIFY (strcmp (buf, "x  ") == 0);
     186    memset (buf, '@', sizeof (buf));
     187    TEST_VERIFY (snprintf (buf, sizeof (buf), "%-3.2ls", L"x\u00DFz") == 3);
     188    TEST_VERIFY (strcmp (buf, "x  ") == 0);
     189    memset (buf, '@', sizeof (buf));
     190    TEST_VERIFY (snprintf (buf, sizeof (buf), "%-3.3ls", L"x\u00DFz") == 3);
     191    TEST_VERIFY (strcmp (buf, "x\xC3\x9F") == 0);
     192    memset (buf, '@', sizeof (buf));
     193    TEST_VERIFY (snprintf (buf, sizeof (buf), "%-3.4ls", L"x\u00DFz") == 4);
     194    TEST_VERIFY (strcmp (buf, "x\xC3\x9Fz") == 0);
     195    memset (buf, '@', sizeof (buf));
     196    TEST_VERIFY (snprintf (buf, sizeof (buf), "%-3.5ls", L"x\u00DFz") == 4);
     197    TEST_VERIFY (strcmp (buf, "x\xC3\x9Fz") == 0);
     198  
     199    /* Varying precisions with width 4, right-justified.  */
     200    memset (buf, '@', sizeof (buf));
     201    TEST_VERIFY (snprintf (buf, sizeof (buf), "%4.1ls", L"x\u00DFz") == 4);
     202    TEST_VERIFY (strcmp (buf, "   x") == 0);
     203    memset (buf, '@', sizeof (buf));
     204    TEST_VERIFY (snprintf (buf, sizeof (buf), "%4.2ls", L"x\u00DFz") == 4);
     205    TEST_VERIFY (strcmp (buf, "   x") == 0);
     206    memset (buf, '@', sizeof (buf));
     207    TEST_VERIFY (snprintf (buf, sizeof (buf), "%4.3ls", L"x\u00DFz") == 4);
     208    TEST_VERIFY (strcmp (buf, " x\xC3\x9F") == 0);
     209    memset (buf, '@', sizeof (buf));
     210    TEST_VERIFY (snprintf (buf, sizeof (buf), "%4.4ls", L"x\u00DFz") == 4);
     211    TEST_VERIFY (strcmp (buf, "x\xC3\x9Fz") == 0);
     212    memset (buf, '@', sizeof (buf));
     213    TEST_VERIFY (snprintf (buf, sizeof (buf), "%4.5ls", L"x\u00DFz") == 4);
     214    TEST_VERIFY (strcmp (buf, "x\xC3\x9Fz") == 0);
     215  
     216    /* Varying precisions with width 4, left-justified.  */
     217    memset (buf, '@', sizeof (buf));
     218    TEST_VERIFY (snprintf (buf, sizeof (buf), "%-4.1ls", L"x\u00DFz") == 4);
     219    TEST_VERIFY (strcmp (buf, "x   ") == 0);
     220    memset (buf, '@', sizeof (buf));
     221    TEST_VERIFY (snprintf (buf, sizeof (buf), "%-4.2ls", L"x\u00DFz") == 4);
     222    TEST_VERIFY (strcmp (buf, "x   ") == 0);
     223    memset (buf, '@', sizeof (buf));
     224    TEST_VERIFY (snprintf (buf, sizeof (buf), "%-4.3ls", L"x\u00DFz") == 4);
     225    TEST_VERIFY (strcmp (buf, "x\xC3\x9F ") == 0);
     226    memset (buf, '@', sizeof (buf));
     227    TEST_VERIFY (snprintf (buf, sizeof (buf), "%-4.4ls", L"x\u00DFz") == 4);
     228    TEST_VERIFY (strcmp (buf, "x\xC3\x9Fz") == 0);
     229    memset (buf, '@', sizeof (buf));
     230    TEST_VERIFY (snprintf (buf, sizeof (buf), "%-4.5ls", L"x\u00DFz") == 4);
     231    TEST_VERIFY (strcmp (buf, "x\xC3\x9Fz") == 0);
     232  }
     233  
     234  /* swprintf tests (wide string result).  */
     235  static void
     236  test_wide_result (void)
     237  {
     238    enum { size = 20 };
     239    wchar_t buf[20];
     240  
     241    /* ASCII wide string.  */
     242    wmemset (buf, '@', size);
     243    TEST_VERIFY (swprintf (buf, size, L"%s", "xyz") == 3);
     244    TEST_VERIFY (wcscmp (buf, L"xyz") == 0);
     245  
     246    /* Unicode wide string.  */
     247    wmemset (buf, '@', size);
     248    TEST_VERIFY (swprintf (buf, size, L"%s", "x\xC3\x9Fz") == 3);
     249    TEST_VERIFY (wcscmp (buf, L"x\u00DFz") == 0);
     250  
     251    /* Varying precisions.  */
     252    wmemset (buf, '@', size);
     253    TEST_VERIFY (swprintf (buf, size, L"%.1s", "x\xC3\x9Fz") == 1);
     254    TEST_VERIFY (wcscmp (buf, L"x") == 0);
     255    wmemset (buf, '@', size);
     256    TEST_VERIFY (swprintf (buf, size, L"%.2s", "x\xC3\x9Fz") == 2);
     257    TEST_VERIFY (wcscmp (buf, L"x\u00DF") == 0);
     258    wmemset (buf, '@', size);
     259    TEST_VERIFY (swprintf (buf, size, L"%.3s", "x\xC3\x9Fz") == 3);
     260    TEST_VERIFY (wcscmp (buf, L"x\u00DFz") == 0);
     261    wmemset (buf, '@', size);
     262    TEST_VERIFY (swprintf (buf, size, L"%.4s", "x\xC3\x9Fz") == 3);
     263    TEST_VERIFY (wcscmp (buf, L"x\u00DFz") == 0);
     264  
     265    /* Varying precisions with width 2, right-justified.  */
     266    wmemset (buf, '@', size);
     267    TEST_VERIFY (swprintf (buf, size, L"%2.1s", "x\xC3\x9Fz") == 2);
     268    TEST_VERIFY (wcscmp (buf, L" x") == 0);
     269    wmemset (buf, '@', size);
     270    TEST_VERIFY (swprintf (buf, size, L"%2.2s", "x\xC3\x9Fz") == 2);
     271    TEST_VERIFY (wcscmp (buf, L"x\u00DF") == 0);
     272    wmemset (buf, '@', size);
     273    TEST_VERIFY (swprintf (buf, size, L"%2.3s", "x\xC3\x9Fz") == 3);
     274    TEST_VERIFY (wcscmp (buf, L"x\u00DFz") == 0);
     275    wmemset (buf, '@', size);
     276    TEST_VERIFY (swprintf (buf, size, L"%2.4s", "x\xC3\x9Fz") == 3);
     277    TEST_VERIFY (wcscmp (buf, L"x\u00DFz") == 0);
     278  
     279    /* Varying precisions with width 2, left-justified.  */
     280    wmemset (buf, '@', size);
     281    TEST_VERIFY (swprintf (buf, size, L"%-2.1s", "x\xC3\x9Fz") == 2);
     282    TEST_VERIFY (wcscmp (buf, L"x ") == 0);
     283    wmemset (buf, '@', size);
     284    TEST_VERIFY (swprintf (buf, size, L"%-2.2s", "x\xC3\x9Fz") == 2);
     285    TEST_VERIFY (wcscmp (buf, L"x\u00DF") == 0);
     286    wmemset (buf, '@', size);
     287    TEST_VERIFY (swprintf (buf, size, L"%-2.3s", "x\xC3\x9Fz") == 3);
     288    TEST_VERIFY (wcscmp (buf, L"x\u00DFz") == 0);
     289    wmemset (buf, '@', size);
     290    TEST_VERIFY (swprintf (buf, size, L"%-2.4s", "x\xC3\x9Fz") == 3);
     291    TEST_VERIFY (wcscmp (buf, L"x\u00DFz") == 0);
     292  
     293    /* Varying precisions with width 3, right-justified.  */
     294    wmemset (buf, '@', size);
     295    TEST_VERIFY (swprintf (buf, size, L"%3.1s", "x\xC3\x9Fz") == 3);
     296    TEST_VERIFY (wcscmp (buf, L"  x") == 0);
     297    wmemset (buf, '@', size);
     298    TEST_VERIFY (swprintf (buf, size, L"%3.2s", "x\xC3\x9Fz") == 3);
     299    TEST_VERIFY (wcscmp (buf, L" x\u00DF") == 0);
     300    wmemset (buf, '@', size);
     301    TEST_VERIFY (swprintf (buf, size, L"%3.3s", "x\xC3\x9Fz") == 3);
     302    TEST_VERIFY (wcscmp (buf, L"x\u00DFz") == 0);
     303    wmemset (buf, '@', size);
     304    TEST_VERIFY (swprintf (buf, size, L"%3.4s", "x\xC3\x9Fz") == 3);
     305    TEST_VERIFY (wcscmp (buf, L"x\u00DFz") == 0);
     306  
     307    /* Varying precisions with width 3, left-justified.  */
     308    wmemset (buf, '@', size);
     309    TEST_VERIFY (swprintf (buf, size, L"%-3.1s", "x\xC3\x9Fz") == 3);
     310    TEST_VERIFY (wcscmp (buf, L"x  ") == 0);
     311    wmemset (buf, '@', size);
     312    TEST_VERIFY (swprintf (buf, size, L"%-3.2s", "x\xC3\x9Fz") == 3);
     313    TEST_VERIFY (wcscmp (buf, L"x\u00DF ") == 0);
     314    wmemset (buf, '@', size);
     315    TEST_VERIFY (swprintf (buf, size, L"%-3.3s", "x\xC3\x9Fz") == 3);
     316    TEST_VERIFY (wcscmp (buf, L"x\u00DFz") == 0);
     317    wmemset (buf, '@', size);
     318    TEST_VERIFY (swprintf (buf, size, L"%-3.4s", "x\xC3\x9Fz") == 3);
     319    TEST_VERIFY (wcscmp (buf, L"x\u00DFz") == 0);
     320  
     321    /* Varying precisions with width 4, right-justified.  */
     322    wmemset (buf, '@', size);
     323    TEST_VERIFY (swprintf (buf, size, L"%4.1s", "x\xC3\x9Fz") == 4);
     324    TEST_VERIFY (wcscmp (buf, L"   x") == 0);
     325    wmemset (buf, '@', size);
     326    TEST_VERIFY (swprintf (buf, size, L"%4.2s", "x\xC3\x9Fz") == 4);
     327    TEST_VERIFY (wcscmp (buf, L"  x\u00DF") == 0);
     328    wmemset (buf, '@', size);
     329    TEST_VERIFY (swprintf (buf, size, L"%4.3s", "x\xC3\x9Fz") == 4);
     330    TEST_VERIFY (wcscmp (buf, L" x\u00DFz") == 0);
     331    wmemset (buf, '@', size);
     332    TEST_VERIFY (swprintf (buf, size, L"%4.4s", "x\xC3\x9Fz") == 4);
     333    TEST_VERIFY (wcscmp (buf, L" x\u00DFz") == 0);
     334    wmemset (buf, '@', size);
     335    TEST_VERIFY (swprintf (buf, size, L"%4.5s", "x\xC3\x9Fz") == 4);
     336    TEST_VERIFY (wcscmp (buf, L" x\u00DFz") == 0);
     337  
     338    /* Varying precisions with width 4, left-justified.  */
     339    wmemset (buf, '@', size);
     340    TEST_VERIFY (swprintf (buf, size, L"%-4.1s", "x\xC3\x9Fz") == 4);
     341    TEST_VERIFY (wcscmp (buf, L"x   ") == 0);
     342    wmemset (buf, '@', size);
     343    TEST_VERIFY (swprintf (buf, size, L"%-4.2s", "x\xC3\x9Fz") == 4);
     344    TEST_VERIFY (wcscmp (buf, L"x\u00DF  ") == 0);
     345    wmemset (buf, '@', size);
     346    TEST_VERIFY (swprintf (buf, size, L"%-4.3s", "x\xC3\x9Fz") == 4);
     347    TEST_VERIFY (wcscmp (buf, L"x\u00DFz ") == 0);
     348    wmemset (buf, '@', size);
     349    TEST_VERIFY (swprintf (buf, size, L"%-4.4s", "x\xC3\x9Fz") == 4);
     350    TEST_VERIFY (wcscmp (buf, L"x\u00DFz ") == 0);
     351    wmemset (buf, '@', size);
     352    TEST_VERIFY (swprintf (buf, size, L"%-4.5s", "x\xC3\x9Fz") == 4);
     353    TEST_VERIFY (wcscmp (buf, L"x\u00DFz ") == 0);
     354  }
     355  
     356  /* Test with long strings and multi-byte result.  */
     357  static void
     358  test_mbs_long (const char *mbs, const wchar_t *wide, const size_t *length)
     359  {
     360    char buf[4000];
     361    _Static_assert (sizeof (buf) > 3 * WIDE_STRING_LENGTH,
     362                    "buffer size consistent with string length");
     363    const char *suffix = "||TERM";
     364    TEST_VERIFY_EXIT (sizeof (buf)
     365                      > length[WIDE_STRING_LENGTH] + strlen (suffix));
     366  
     367    /* Test formatting of the entire string.  */
     368    {
     369      int ret = snprintf (buf, sizeof (buf), "%ls%s", wide, suffix);
     370      TEST_VERIFY (ret == length[WIDE_STRING_LENGTH] + strlen (suffix));
     371      TEST_VERIFY (memcmp (buf, mbs, length[WIDE_STRING_LENGTH]) == 0);
     372      TEST_VERIFY (strcmp (buf + length[WIDE_STRING_LENGTH], suffix) == 0);
     373  
     374      /* Left-justified string, printed in full.  */
     375      ret = snprintf (buf, sizeof (buf), "%-3500ls%s", wide, suffix);
     376      TEST_VERIFY (ret == 3500 + strlen (suffix));
     377      TEST_VERIFY (memcmp (buf, mbs, length[WIDE_STRING_LENGTH]) == 0);
     378      for (size_t i = length[WIDE_STRING_LENGTH]; i < 3500; ++i)
     379        TEST_VERIFY (buf[i] == ' ');
     380      TEST_VERIFY (strcmp (buf + 3500, suffix) == 0);
     381  
     382      /* Right-justified string, printed in full.   */
     383      ret = snprintf (buf, sizeof (buf), "%3500ls%s", wide, suffix);
     384      TEST_VERIFY (ret == 3500 + strlen (suffix));
     385      size_t padding = 3500 - length[WIDE_STRING_LENGTH];
     386      for (size_t i = 0; i < padding; ++i)
     387        TEST_VERIFY (buf[i] == ' ');
     388      TEST_VERIFY (memcmp (buf + padding, mbs, length[WIDE_STRING_LENGTH]) == 0);
     389      TEST_VERIFY (strcmp (buf + 3500, suffix) == 0);
     390    }
     391  
     392    size_t wide_characters_converted = 0;
     393    for (int mbs_len = 0; mbs_len <= length[WIDE_STRING_LENGTH] + 1;
     394         ++mbs_len)
     395      {
     396        if (wide_characters_converted < WIDE_STRING_LENGTH
     397            && mbs_len >= length[wide_characters_converted + 1])
     398          /* The requested prefix length contains room for another wide
     399             character.  */
     400          ++wide_characters_converted;
     401        if (test_verbose > 0)
     402          printf ("info: %s: mbs_len=%d wide_chars_converted=%zu length=%zu\n",
     403                  __func__, mbs_len, wide_characters_converted,
     404                  length[wide_characters_converted]);
     405        TEST_VERIFY (length[wide_characters_converted] <= mbs_len);
     406        TEST_VERIFY (wide_characters_converted == 0
     407                     || length[wide_characters_converted - 1] < mbs_len);
     408  
     409        int ret = snprintf (buf, sizeof (buf), "%.*ls%s", mbs_len, wide, suffix);
     410        TEST_VERIFY (ret == length[wide_characters_converted] + strlen (suffix));
     411        TEST_VERIFY (memcmp (buf, mbs, length[wide_characters_converted]) == 0);
     412        TEST_VERIFY (strcmp (buf + length[wide_characters_converted],
     413                             suffix) == 0);
     414  
     415        /* Left-justified string, printed in full.  */
     416        if (test_verbose)
     417          printf ("info: %s: left-justified\n", __func__);
     418        ret = snprintf (buf, sizeof (buf), "%-3500.*ls%s",
     419                        mbs_len, wide, suffix);
     420        TEST_VERIFY (ret == 3500 + strlen (suffix));
     421        TEST_VERIFY (memcmp (buf, mbs, length[wide_characters_converted]) == 0);
     422        for (size_t i = length[wide_characters_converted]; i < 3500; ++i)
     423          TEST_VERIFY (buf[i] == ' ');
     424        TEST_VERIFY (strcmp (buf + 3500, suffix) == 0);
     425  
     426        /* Right-justified string, printed in full.   */
     427        if (test_verbose)
     428          printf ("info: %s: right-justified\n", __func__);
     429        ret = snprintf (buf, sizeof (buf), "%3500.*ls%s", mbs_len, wide, suffix);
     430        TEST_VERIFY (ret == 3500 + strlen (suffix));
     431        size_t padding = 3500 - length[wide_characters_converted];
     432        for (size_t i = 0; i < padding; ++i)
     433          TEST_VERIFY (buf[i] == ' ');
     434        TEST_VERIFY (memcmp (buf + padding, mbs,
     435                             length[wide_characters_converted]) == 0);
     436        TEST_VERIFY (strcmp (buf + 3500, suffix) == 0);
     437      }
     438  }
     439  
     440  /* Test with long strings and wide string result.  */
     441  static void
     442  test_wide_long (const char *mbs, const wchar_t *wide, const size_t *length)
     443  {
     444  #define BUF_SIZE 2000
     445    wchar_t buf[BUF_SIZE];
     446    _Static_assert (sizeof (buf) > sizeof (wchar_t) * WIDE_STRING_LENGTH,
     447                    "buffer size consistent with string length");
     448    const wchar_t *suffix = L"||TERM";
     449    TEST_VERIFY_EXIT (sizeof (buf)
     450                      > length[WIDE_STRING_LENGTH] + wcslen (suffix));
     451  
     452    /* Test formatting of the entire string.  */
     453    {
     454      int ret = swprintf (buf, BUF_SIZE, L"%s%ls", mbs, suffix);
     455      TEST_VERIFY (ret == WIDE_STRING_LENGTH + wcslen (suffix));
     456      TEST_VERIFY (wmemcmp (buf, wide, WIDE_STRING_LENGTH) == 0);
     457      TEST_VERIFY (wcscmp (buf + WIDE_STRING_LENGTH, suffix) == 0);
     458  
     459      /* Left-justified string, printed in full.  */
     460      ret = swprintf (buf, BUF_SIZE, L"%-1500s%ls", mbs, suffix);
     461      TEST_VERIFY (ret == 1500 + wcslen (suffix));
     462      TEST_VERIFY (wmemcmp (buf, wide, WIDE_STRING_LENGTH) == 0);
     463      for (size_t i = WIDE_STRING_LENGTH; i < 1500; ++i)
     464        TEST_VERIFY (buf[i] == L' ');
     465      TEST_VERIFY (wcscmp (buf + 1500, suffix) == 0);
     466  
     467      /* Right-justified string, printed in full.   */
     468      ret = swprintf (buf, BUF_SIZE, L"%1500s%ls", mbs, suffix);
     469      TEST_VERIFY (ret == 1500 + wcslen (suffix));
     470      size_t padding = 1500 - WIDE_STRING_LENGTH;
     471      for (size_t i = 0; i < padding; ++i)
     472        TEST_VERIFY (buf[i] == ' ');
     473      TEST_VERIFY (wmemcmp (buf + padding, wide, WIDE_STRING_LENGTH) == 0);
     474      TEST_VERIFY (wcscmp (buf + 1500, suffix) == 0);
     475    }
     476  
     477    for (int wide_len = 0; wide_len <= WIDE_STRING_LENGTH + 1; ++wide_len)
     478      {
     479        size_t actual_wide_len;
     480        if (wide_len < WIDE_STRING_LENGTH)
     481          actual_wide_len = wide_len;
     482        else
     483          actual_wide_len = WIDE_STRING_LENGTH;
     484        if (test_verbose > 0)
     485          printf ("info: %s: wide_len=%d actual_wide_len=%zu\n",
     486                  __func__, wide_len, actual_wide_len);
     487  
     488        int ret = swprintf (buf, BUF_SIZE, L"%.*s%ls",
     489                            wide_len, mbs, suffix);
     490        TEST_VERIFY (ret == actual_wide_len + wcslen (suffix));
     491        TEST_VERIFY (wmemcmp (buf, wide, actual_wide_len) == 0);
     492        TEST_VERIFY (wcscmp (buf + actual_wide_len, suffix) == 0);
     493  
     494        /* Left-justified string, printed in full.  */
     495        ret = swprintf (buf, BUF_SIZE, L"%-1500.*s%ls",
     496                        wide_len, mbs, suffix);
     497        TEST_VERIFY (ret == 1500 + wcslen (suffix));
     498        TEST_VERIFY (wmemcmp (buf, wide, actual_wide_len) == 0);
     499        for (size_t i = actual_wide_len; i < 1500; ++i)
     500          TEST_VERIFY (buf[i] == L' ');
     501        TEST_VERIFY (wcscmp (buf + 1500, suffix) == 0);
     502  
     503        /* Right-justified string, printed in full.   */
     504        ret = swprintf (buf, BUF_SIZE, L"%1500.*s%ls",
     505                        wide_len, mbs, suffix);
     506        TEST_VERIFY (ret == 1500 + wcslen (suffix));
     507        size_t padding = 1500 - actual_wide_len;
     508        for (size_t i = 0; i < padding; ++i)
     509          TEST_VERIFY (buf[i] == L' ');
     510        TEST_VERIFY (wmemcmp (buf + padding, wide, actual_wide_len) == 0);
     511        TEST_VERIFY (wcscmp (buf + 1500, suffix) == 0);
     512      }
     513  }
     514  
     515  static int
     516  do_test (void)
     517  {
     518    /* This test only covers UTF-8 as a multi-byte character set.  A
     519       locale with a multi-byte character set with shift state would be
     520       a relevant test target as well, but glibc currently does not ship
     521       such a locale.  */
     522    TEST_VERIFY (setlocale (LC_CTYPE, "de_DE.UTF-8") != NULL);
     523  
     524    test_mbs_result ();
     525    test_wide_result ();
     526  
     527    char *mbs;
     528    wchar_t *wide;
     529    size_t *length;
     530    make_random_string (&mbs, &wide, &length);
     531    TEST_VERIFY (strlen (mbs) == length[WIDE_STRING_LENGTH]);
     532    if (test_verbose > 0)
     533      printf ("info: long multi-byte string contains %zu characters\n",
     534              length[WIDE_STRING_LENGTH]);
     535    test_mbs_long (mbs, wide, length);
     536    test_wide_long (mbs, wide, length);
     537    free (mbs);
     538    free (wide);
     539    free (length);
     540  
     541    return 0;
     542  }
     543  
     544  #include <support/test-driver.c>