123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383 |
- /*
- lib - Read string from mc_pipe_stream
- Copyright (C) 2021-2025
- Free Software Foundation, Inc.
- Written by:
- Andrew Borodin <aborodin@vmail.ru>, 2021
- This file is part of the Midnight Commander.
- The Midnight Commander is free software: you can redistribute it
- and/or modify it under the terms of the GNU General Public License as
- published by the Free Software Foundation, either version 3 of the License,
- or (at your option) any later version.
- The Midnight Commander is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
- You should have received a copy of the GNU General Public License
- along with this program. If not, see <https://www.gnu.org/licenses/>.
- */
- #define TEST_SUITE_NAME "/lib/util"
- #include "tests/mctest.h"
- #include "lib/util.h"
- /* --------------------------------------------------------------------------------------------- */
- #define MAX_CHUNKS 8
- /* --------------------------------------------------------------------------------------------- */
- static mc_pipe_stream_t stream;
- static char etalon_long_file_list[BUF_1K];
- static size_t etalon_long_file_list_pos;
- /* --------------------------------------------------------------------------------------------- */
- /* @Before */
- static void
- setup (void)
- {
- }
- /* @After */
- static void
- teardown (void)
- {
- }
- /* --------------------------------------------------------------------------------------------- */
- /* @DataSource("data_source") */
- static const struct data_source
- {
- // input
- const char *buf; // string to read
- // output
- int pos[MAX_CHUNKS]; // ps.pos values
- const char *str[MAX_CHUNKS]; // chunks
- size_t len[MAX_CHUNKS]; // chunk lengths
- } data_source[] = {
- {
- // 0
- .buf = "",
- .pos = { 0 },
- .str = { "" },
- .len = { 0 },
- },
- {
- // 1
- .buf = "\n",
- .pos = { 0, 1 },
- .str = { "\n" },
- .len = { 1, 0 },
- },
- {
- // 2
- .buf = "\\\n",
- .pos = { 0, 2 },
- .str = { "\\\n" },
- .len = { 2, 0 },
- },
- {
- // 3
- .buf = "\\\\\n",
- .pos = { 0, 3 },
- .str = { "\\\\\n" },
- .len = { 3, 0 },
- },
- {
- // 4
- .buf = "\\\\\\\n",
- .pos = { 0, 4 },
- .str = { "\\\\\\\n" },
- .len = { 4, 0 },
- },
- {
- // 5
- .buf = "\\\\\\\\\n",
- .pos = { 0, 5 },
- .str = { "\\\\\\\\\n" },
- .len = { 5, 0 },
- },
- {
- // 6
- .buf = "12345",
- .pos = { 0, 5 },
- .str = { "12345" },
- .len = { 5, 0 },
- },
- {
- // 7
- .buf = "12345\n",
- .pos = { 0, 6 },
- .str = { "12345\n" },
- .len = { 6, 0 },
- },
- {
- // 8
- .buf = "12345\\\n",
- .pos = { 0, 7 },
- .str = { "12345\\\n" },
- .len = { 7, 0 },
- },
- {
- // 9
- .buf = "12345\\\\\n",
- .pos = { 0, 8 },
- .str = { "12345\\\\\n" },
- .len = { 8, 0 },
- },
- {
- // 10
- .buf = "12345\nabcd",
- .pos = { 0, 6, 10 },
- .str = { "12345\n", "abcd" },
- .len = { 6, 4, 0 },
- },
- {
- // 11
- .buf = "12345\\\nabcd",
- .pos = { 0, 11 },
- .str = { "12345\\\nabcd" },
- .len = { 11, 0 },
- },
- {
- // 12
- .buf = "12345\\\\\nabcd",
- .pos = { 0, 8, 12 },
- .str = { "12345\\\\\n", "abcd" },
- .len = { 8, 4, 0 },
- },
- {
- // 13
- .buf = "12345\\\\\\\nabcd",
- .pos = { 0, 13 },
- .str = { "12345\\\\\\\nabcd" },
- .len = { 13, 0 },
- },
- {
- // 14
- .buf = "12345\\\\\\\\\nabcd",
- .pos = { 0, 10, 14 },
- .str = { "12345\\\\\\\\\n", "abcd" },
- .len = { 10, 4, 0 },
- },
- {
- // 15
- .buf = "12345\nabcd\n",
- .pos = { 0, 6, 11 },
- .str = { "12345\n", "abcd\n" },
- .len = { 6, 5, 0 },
- },
- {
- // 16
- .buf = "12345\nabcd\n~!@#$%^",
- .pos = { 0, 6, 11, 18 },
- .str = { "12345\n", "abcd\n", "~!@#$%^" },
- .len = { 6, 5, 7, 0 },
- },
- {
- // 17
- .buf = "12345\nabcd\n~!@#$%^\n",
- .pos = { 0, 6, 11, 19 },
- .str = { "12345\n", "abcd\n", "~!@#$%^\n" },
- .len = { 6, 5, 8, 0 },
- },
- };
- /* @Test(dataSource = "data_source") */
- START_PARAMETRIZED_TEST (mc_pstream_get_string_test, data_source)
- {
- // given
- int j = 0;
- // when
- memset (&stream, 0, sizeof (stream));
- stream.len = strlen (data->buf);
- memmove (&stream.buf, data->buf, stream.len);
- // then
- do
- {
- GString *ret;
- ck_assert_int_eq (stream.pos, data->pos[j]);
- ret = mc_pstream_get_string (&stream);
- if (ret == NULL)
- break;
- ck_assert_int_eq (ret->len, data->len[j]);
- mctest_assert_str_eq (ret->str, data->str[j]);
- g_string_free (ret, TRUE);
- j++;
- }
- while (TRUE);
- }
- END_PARAMETRIZED_TEST
- /* --------------------------------------------------------------------------------------------- */
- static mc_pipe_t *
- test_mc_popen (void)
- {
- mc_pipe_t *p;
- p = g_try_new0 (mc_pipe_t, 1);
- // make less than sizeof (etalon_long_file_list)
- p->out.len = 128;
- etalon_long_file_list_pos = 0;
- return p;
- }
- static void
- test_mc_pread (mc_pipe_t *p)
- {
- size_t len;
- p->out.pos = 0;
- if (etalon_long_file_list_pos >= sizeof (etalon_long_file_list))
- {
- etalon_long_file_list_pos = sizeof (etalon_long_file_list);
- p->out.len = MC_PIPE_STREAM_EOF;
- return;
- }
- len = sizeof (etalon_long_file_list) - etalon_long_file_list_pos;
- len = MIN (len, (size_t) p->out.len);
- memmove (p->out.buf, etalon_long_file_list + etalon_long_file_list_pos, len);
- p->out.len = (ssize_t) len;
- etalon_long_file_list_pos += len;
- }
- START_TEST (mc_pstream_get_long_file_list_test)
- {
- // given
- GString *result_long_file_list = NULL;
- mc_pipe_t *pip;
- GString *remain_file_name = NULL;
- // when
- // fill the list
- memset (etalon_long_file_list, 'a', sizeof (etalon_long_file_list) - 1);
- // create an \n-separated list
- etalon_long_file_list[5] = '\n';
- etalon_long_file_list[25] = '\n';
- etalon_long_file_list[50] = '\n';
- etalon_long_file_list[75] = '\n';
- etalon_long_file_list[127] = '\n';
- etalon_long_file_list[200] = '\n';
- etalon_long_file_list[310] = '\n';
- etalon_long_file_list[325] = '\n';
- etalon_long_file_list[360] = '\n';
- etalon_long_file_list[512] = '\n';
- etalon_long_file_list[701] = '\n';
- etalon_long_file_list[725] = '\n';
- etalon_long_file_list[800] = '\n';
- etalon_long_file_list[sizeof (etalon_long_file_list) - 2] = '\n';
- etalon_long_file_list[sizeof (etalon_long_file_list) - 1] = '\0';
- // then
- // read file list
- pip = test_mc_popen ();
- while (TRUE)
- {
- GString *line;
- test_mc_pread (pip);
- if (pip->out.len == MC_PIPE_STREAM_EOF)
- break;
- while ((line = mc_pstream_get_string (&pip->out)) != NULL)
- {
- // handle an \n-separated file list
- if (line->str[line->len - 1] == '\n')
- {
- // entire file name or last chunk
- g_string_truncate (line, line->len - 1);
- // join filename chunks
- if (remain_file_name != NULL)
- {
- g_string_append_len (remain_file_name, line->str, line->len);
- g_string_free (line, TRUE);
- line = remain_file_name;
- remain_file_name = NULL;
- }
- }
- else
- {
- // first or middle chunk of file name
- if (remain_file_name == NULL)
- remain_file_name = line;
- else
- {
- g_string_append_len (remain_file_name, line->str, line->len);
- g_string_free (line, TRUE);
- }
- line = NULL;
- }
- // collect file names to assemble the result string
- if (line == NULL)
- continue;
- if (result_long_file_list == NULL)
- result_long_file_list = line;
- else
- {
- g_string_append_len (result_long_file_list, line->str, line->len);
- g_string_free (line, TRUE);
- }
- g_string_append_c (result_long_file_list, '\n');
- }
- }
- mctest_assert_str_eq (etalon_long_file_list, result_long_file_list->str);
- g_string_free (result_long_file_list, TRUE);
- }
- END_TEST
- /* --------------------------------------------------------------------------------------------- */
- int
- main (void)
- {
- TCase *tc_core;
- tc_core = tcase_create ("Core");
- tcase_add_checked_fixture (tc_core, setup, teardown);
- // Add new tests here: ***************
- mctest_add_parameterized_test (tc_core, mc_pstream_get_string_test, data_source);
- tcase_add_test (tc_core, mc_pstream_get_long_file_list_test);
- // ***********************************
- return mctest_run_all (tc_core);
- }
- /* --------------------------------------------------------------------------------------------- */
|