Manual pages: mcmcdiffmceditmcview

root/tests/lib/utilunix__mc_pstream_get_string.c

/* [previous][next][first][last][top][bottom][index][help]  */

DEFINITIONS

This source file includes following definitions.
  1. START_PARAMETRIZED_TEST
  2. test_mc_popen
  3. test_mc_pread
  4. START_TEST
  5. main

   1 /*
   2    lib - Read string from mc_pipe_stream
   3 
   4    Copyright (C) 2021-2025
   5    Free Software Foundation, Inc.
   6 
   7    Written by:
   8    Andrew Borodin <aborodin@vmail.ru>, 2021
   9 
  10    This file is part of the Midnight Commander.
  11 
  12    The Midnight Commander is free software: you can redistribute it
  13    and/or modify it under the terms of the GNU General Public License as
  14    published by the Free Software Foundation, either version 3 of the License,
  15    or (at your option) any later version.
  16 
  17    The Midnight Commander is distributed in the hope that it will be useful,
  18    but WITHOUT ANY WARRANTY; without even the implied warranty of
  19    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  20    GNU General Public License for more details.
  21 
  22    You should have received a copy of the GNU General Public License
  23    along with this program.  If not, see <https://www.gnu.org/licenses/>.
  24  */
  25 
  26 #define TEST_SUITE_NAME "/lib/util"
  27 
  28 #include "tests/mctest.h"
  29 
  30 #include "lib/util.h"
  31 
  32 /* --------------------------------------------------------------------------------------------- */
  33 
  34 #define MAX_CHUNKS 8
  35 
  36 /* --------------------------------------------------------------------------------------------- */
  37 
  38 static mc_pipe_stream_t stream;
  39 
  40 static char etalon_long_file_list[BUF_1K];
  41 static size_t etalon_long_file_list_pos;
  42 
  43 /* --------------------------------------------------------------------------------------------- */
  44 
  45 /* @DataSource("data_source") */
  46 static const struct data_source
  47 {
  48     // input
  49     const char *buf;  // string to read
  50 
  51     // output
  52     int pos[MAX_CHUNKS];          // ps.pos values
  53     const char *str[MAX_CHUNKS];  // chunks
  54     size_t len[MAX_CHUNKS];       // chunk lengths
  55 } data_source[] = {
  56     {
  57         // 0
  58         .buf = "",
  59         .pos = { 0 },
  60         .str = { "" },
  61         .len = { 0 },
  62     },
  63     {
  64         // 1
  65         .buf = "\n",
  66         .pos = { 0, 1 },
  67         .str = { "\n" },
  68         .len = { 1, 0 },
  69     },
  70     {
  71         // 2
  72         .buf = "\\\n",
  73         .pos = { 0, 2 },
  74         .str = { "\\\n" },
  75         .len = { 2, 0 },
  76     },
  77     {
  78         // 3
  79         .buf = "\\\\\n",
  80         .pos = { 0, 3 },
  81         .str = { "\\\\\n" },
  82         .len = { 3, 0 },
  83     },
  84     {
  85         // 4
  86         .buf = "\\\\\\\n",
  87         .pos = { 0, 4 },
  88         .str = { "\\\\\\\n" },
  89         .len = { 4, 0 },
  90     },
  91     {
  92         // 5
  93         .buf = "\\\\\\\\\n",
  94         .pos = { 0, 5 },
  95         .str = { "\\\\\\\\\n" },
  96         .len = { 5, 0 },
  97     },
  98     {
  99         // 6
 100         .buf = "12345",
 101         .pos = { 0, 5 },
 102         .str = { "12345" },
 103         .len = { 5, 0 },
 104     },
 105     {
 106         // 7
 107         .buf = "12345\n",
 108         .pos = { 0, 6 },
 109         .str = { "12345\n" },
 110         .len = { 6, 0 },
 111     },
 112     {
 113         // 8
 114         .buf = "12345\\\n",
 115         .pos = { 0, 7 },
 116         .str = { "12345\\\n" },
 117         .len = { 7, 0 },
 118     },
 119     {
 120         // 9
 121         .buf = "12345\\\\\n",
 122         .pos = { 0, 8 },
 123         .str = { "12345\\\\\n" },
 124         .len = { 8, 0 },
 125     },
 126     {
 127         // 10
 128         .buf = "12345\nabcd",
 129         .pos = { 0, 6, 10 },
 130         .str = { "12345\n", "abcd" },
 131         .len = { 6, 4, 0 },
 132     },
 133     {
 134         // 11
 135         .buf = "12345\\\nabcd",
 136         .pos = { 0, 11 },
 137         .str = { "12345\\\nabcd" },
 138         .len = { 11, 0 },
 139     },
 140     {
 141         // 12
 142         .buf = "12345\\\\\nabcd",
 143         .pos = { 0, 8, 12 },
 144         .str = { "12345\\\\\n", "abcd" },
 145         .len = { 8, 4, 0 },
 146     },
 147     {
 148         // 13
 149         .buf = "12345\\\\\\\nabcd",
 150         .pos = { 0, 13 },
 151         .str = { "12345\\\\\\\nabcd" },
 152         .len = { 13, 0 },
 153     },
 154     {
 155         // 14
 156         .buf = "12345\\\\\\\\\nabcd",
 157         .pos = { 0, 10, 14 },
 158         .str = { "12345\\\\\\\\\n", "abcd" },
 159         .len = { 10, 4, 0 },
 160     },
 161     {
 162         // 15
 163         .buf = "12345\nabcd\n",
 164         .pos = { 0, 6, 11 },
 165         .str = { "12345\n", "abcd\n" },
 166         .len = { 6, 5, 0 },
 167     },
 168     {
 169         // 16
 170         .buf = "12345\nabcd\n~!@#$%^",
 171         .pos = { 0, 6, 11, 18 },
 172         .str = { "12345\n", "abcd\n", "~!@#$%^" },
 173         .len = { 6, 5, 7, 0 },
 174     },
 175     {
 176         // 17
 177         .buf = "12345\nabcd\n~!@#$%^\n",
 178         .pos = { 0, 6, 11, 19 },
 179         .str = { "12345\n", "abcd\n", "~!@#$%^\n" },
 180         .len = { 6, 5, 8, 0 },
 181     },
 182 };
 183 
 184 /* @Test(dataSource = "data_source") */
 185 START_PARAMETRIZED_TEST (mc_pstream_get_string_test, data_source)
     /* [previous][next][first][last][top][bottom][index][help]  */
 186 {
 187     // given
 188     int j = 0;
 189 
 190     // when
 191     memset (&stream, 0, sizeof (stream));
 192     stream.len = strlen (data->buf);
 193     memmove (&stream.buf, data->buf, stream.len);
 194 
 195     // then
 196     do
 197     {
 198         GString *ret;
 199 
 200         ck_assert_int_eq (stream.pos, data->pos[j]);
 201 
 202         ret = mc_pstream_get_string (&stream);
 203         if (ret == NULL)
 204             break;
 205 
 206         ck_assert_int_eq (ret->len, data->len[j]);
 207         mctest_assert_str_eq (ret->str, data->str[j]);
 208 
 209         g_string_free (ret, TRUE);
 210 
 211         j++;
 212     }
 213     while (TRUE);
 214 }
 215 END_PARAMETRIZED_TEST
 216 
 217 /* --------------------------------------------------------------------------------------------- */
 218 
 219 static mc_pipe_t *
 220 test_mc_popen (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
 221 {
 222     mc_pipe_t *p;
 223 
 224     p = g_try_new0 (mc_pipe_t, 1);
 225     // make less than sizeof (etalon_long_file_list)
 226     p->out.len = 128;
 227 
 228     etalon_long_file_list_pos = 0;
 229 
 230     return p;
 231 }
 232 
 233 static void
 234 test_mc_pread (mc_pipe_t *p)
     /* [previous][next][first][last][top][bottom][index][help]  */
 235 {
 236     size_t len;
 237 
 238     p->out.pos = 0;
 239 
 240     if (etalon_long_file_list_pos >= sizeof (etalon_long_file_list))
 241     {
 242         etalon_long_file_list_pos = sizeof (etalon_long_file_list);
 243         p->out.len = MC_PIPE_STREAM_EOF;
 244         return;
 245     }
 246 
 247     len = sizeof (etalon_long_file_list) - etalon_long_file_list_pos;
 248     len = MIN (len, (size_t) p->out.len);
 249     memmove (p->out.buf, etalon_long_file_list + etalon_long_file_list_pos, len);
 250     p->out.len = (ssize_t) len;
 251 
 252     etalon_long_file_list_pos += len;
 253 }
 254 
 255 START_TEST (mc_pstream_get_long_file_list_test)
     /* [previous][next][first][last][top][bottom][index][help]  */
 256 
 257 {
 258     // given
 259     GString *result_long_file_list = NULL;
 260     mc_pipe_t *pip;
 261     GString *remain_file_name = NULL;
 262 
 263     // when
 264     // fill the list
 265     memset (etalon_long_file_list, 'a', sizeof (etalon_long_file_list) - 1);
 266     // create an \n-separated list
 267     etalon_long_file_list[5] = '\n';
 268     etalon_long_file_list[25] = '\n';
 269     etalon_long_file_list[50] = '\n';
 270     etalon_long_file_list[75] = '\n';
 271     etalon_long_file_list[127] = '\n';
 272     etalon_long_file_list[200] = '\n';
 273     etalon_long_file_list[310] = '\n';
 274     etalon_long_file_list[325] = '\n';
 275     etalon_long_file_list[360] = '\n';
 276     etalon_long_file_list[512] = '\n';
 277     etalon_long_file_list[701] = '\n';
 278     etalon_long_file_list[725] = '\n';
 279     etalon_long_file_list[800] = '\n';
 280     etalon_long_file_list[sizeof (etalon_long_file_list) - 2] = '\n';
 281     etalon_long_file_list[sizeof (etalon_long_file_list) - 1] = '\0';
 282 
 283     // then
 284     // read file list
 285     pip = test_mc_popen ();
 286 
 287     while (TRUE)
 288     {
 289         GString *line;
 290 
 291         test_mc_pread (pip);
 292 
 293         if (pip->out.len == MC_PIPE_STREAM_EOF)
 294             break;
 295 
 296         while ((line = mc_pstream_get_string (&pip->out)) != NULL)
 297         {
 298             // handle an \n-separated file list
 299 
 300             if (line->str[line->len - 1] == '\n')
 301             {
 302                 // entire file name or last chunk
 303 
 304                 g_string_truncate (line, line->len - 1);
 305 
 306                 // join filename chunks
 307                 if (remain_file_name != NULL)
 308                 {
 309                     g_string_append_len (remain_file_name, line->str, line->len);
 310                     g_string_free (line, TRUE);
 311                     line = remain_file_name;
 312                     remain_file_name = NULL;
 313                 }
 314             }
 315             else
 316             {
 317                 // first or middle chunk of file name
 318                 if (remain_file_name == NULL)
 319                     remain_file_name = line;
 320                 else
 321                 {
 322                     g_string_append_len (remain_file_name, line->str, line->len);
 323                     g_string_free (line, TRUE);
 324                 }
 325 
 326                 line = NULL;
 327             }
 328 
 329             // collect file names to assemble the result string
 330             if (line == NULL)
 331                 continue;
 332 
 333             if (result_long_file_list == NULL)
 334                 result_long_file_list = line;
 335             else
 336             {
 337                 g_string_append_len (result_long_file_list, line->str, line->len);
 338                 g_string_free (line, TRUE);
 339             }
 340 
 341             g_string_append_c (result_long_file_list, '\n');
 342         }
 343     }
 344 
 345     mctest_assert_str_eq (etalon_long_file_list, result_long_file_list->str);
 346     g_string_free (result_long_file_list, TRUE);
 347 }
 348 END_TEST
 349 
 350 /* --------------------------------------------------------------------------------------------- */
 351 
 352 int
 353 main (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
 354 {
 355     TCase *tc_core;
 356 
 357     tc_core = tcase_create ("Core");
 358 
 359     // Add new tests here: ***************
 360     mctest_add_parameterized_test (tc_core, mc_pstream_get_string_test, data_source);
 361     tcase_add_test (tc_core, mc_pstream_get_long_file_list_test);
 362     // ***********************************
 363 
 364     return mctest_run_all (tc_core);
 365 }
 366 
 367 /* --------------------------------------------------------------------------------------------- */

/* [previous][next][first][last][top][bottom][index][help]  */