mirror of
https://github.com/MidnightCommander/mc
synced 2024-12-22 12:32:40 +03:00
Ticket #3905, 3956: fix file version sort.
* Update str_verscmp implementation: sync with Gnulib. * Add tests. Testcases are taken from Gnulib. Signed-off-by: Andrew Borodin <aborodin@vmail.ru>
This commit is contained in:
parent
e2b8a50cea
commit
2163009270
@ -5,7 +5,21 @@
|
||||
Free Software Foundation, Inc.
|
||||
|
||||
This file is part of the GNU C Library.
|
||||
Contributed by Jean-Fran<EFBFBD>ois Bignolles <bignolle ecoledoc ibp fr>, 1997.
|
||||
Contributed by Jean-François Bignolles <bignolle@ecoledoc.ibp.fr>, 1997.
|
||||
|
||||
The GNU C Library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
The GNU C Library 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
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with the GNU C Library; if not, see
|
||||
<https://www.gnu.org/licenses/>.
|
||||
|
||||
This file is part of the Midnight Commander.
|
||||
|
||||
@ -39,11 +53,11 @@
|
||||
#ifndef HAVE_STRVERSCMP
|
||||
|
||||
/* states: S_N: normal, S_I: comparing integral part, S_F: comparing
|
||||
fractionnal parts, S_Z: idem but with leading Zeroes only */
|
||||
fractional parts, S_Z: idem but with leading Zeroes only */
|
||||
#define S_N 0x0
|
||||
#define S_I 0x4
|
||||
#define S_F 0x8
|
||||
#define S_Z 0xC
|
||||
#define S_I 0x3
|
||||
#define S_F 0x6
|
||||
#define S_Z 0x9
|
||||
|
||||
/* result_type: CMP: return diff; LEN: compare using len_diff/diff */
|
||||
#define CMP 2
|
||||
@ -73,35 +87,34 @@ str_verscmp (const char *s1, const char *s2)
|
||||
return strverscmp (s1, s2);
|
||||
|
||||
#else /* HAVE_STRVERSCMP */
|
||||
unsigned char *p1 = (unsigned char *) s1;
|
||||
unsigned char *p2 = (unsigned char *) s2;
|
||||
const unsigned char *p1 = (const unsigned char *) s1;
|
||||
const unsigned char *p2 = (const unsigned char *) s2;
|
||||
unsigned char c1, c2;
|
||||
int state;
|
||||
int diff;
|
||||
|
||||
/* Symbol(s) 0 [1-9] others (padding)
|
||||
Transition (10) 0 (01) d (00) x (11) - */
|
||||
static const unsigned int next_state[] = {
|
||||
/* state x d 0 - */
|
||||
/* S_N */ S_N, S_I, S_Z, S_N,
|
||||
/* S_I */ S_N, S_I, S_I, S_I,
|
||||
/* S_F */ S_N, S_F, S_F, S_F,
|
||||
/* S_Z */ S_N, S_F, S_Z, S_Z
|
||||
/* *INDENT-OFF* */
|
||||
/* Symbol(s) 0 [1-9] others
|
||||
Transition (10) 0 (01) d (00) x */
|
||||
static const unsigned char next_state[] =
|
||||
{
|
||||
/* state x d 0 */
|
||||
/* S_N */ S_N, S_I, S_Z,
|
||||
/* S_I */ S_N, S_I, S_I,
|
||||
/* S_F */ S_N, S_F, S_F,
|
||||
/* S_Z */ S_N, S_F, S_Z
|
||||
};
|
||||
|
||||
static const int result_type[] = {
|
||||
/* state x/x x/d x/0 x/- d/x d/d d/0 d/-
|
||||
0/x 0/d 0/0 0/- -/x -/d -/0 -/- */
|
||||
static const signed char result_type[] =
|
||||
{
|
||||
/* state x/x x/d x/0 d/x d/d d/0 0/x 0/d 0/0 */
|
||||
|
||||
/* S_N */ CMP, CMP, CMP, CMP, CMP, LEN, CMP, CMP,
|
||||
CMP, CMP, CMP, CMP, CMP, CMP, CMP, CMP,
|
||||
/* S_I */ CMP, -1, -1, CMP, +1, LEN, LEN, CMP,
|
||||
+1, LEN, LEN, CMP, CMP, CMP, CMP, CMP,
|
||||
/* S_F */ CMP, CMP, CMP, CMP, CMP, LEN, CMP, CMP,
|
||||
CMP, CMP, CMP, CMP, CMP, CMP, CMP, CMP,
|
||||
/* S_Z */ CMP, +1, +1, CMP, -1, CMP, CMP, CMP,
|
||||
-1, CMP, CMP, CMP
|
||||
/* S_N */ CMP, CMP, CMP, CMP, LEN, CMP, CMP, CMP, CMP,
|
||||
/* S_I */ CMP, -1, -1, +1, LEN, LEN, +1, LEN, LEN,
|
||||
/* S_F */ CMP, CMP, CMP, CMP, CMP, CMP, CMP, CMP, CMP,
|
||||
/* S_Z */ CMP, +1, +1, -1, CMP, CMP, -1, CMP, CMP
|
||||
};
|
||||
/* *INDENT-ON* */
|
||||
|
||||
if (p1 == p2)
|
||||
return 0;
|
||||
@ -109,17 +122,20 @@ str_verscmp (const char *s1, const char *s2)
|
||||
c1 = *p1++;
|
||||
c2 = *p2++;
|
||||
/* Hint: '0' is a digit too. */
|
||||
state = S_N | ((c1 == '0') + (isdigit (c1) != 0));
|
||||
state = S_N + ((c1 == '0') + (isdigit (c1) != 0));
|
||||
|
||||
while ((diff = c1 - c2) == 0 && c1 != '\0')
|
||||
while ((diff = c1 - c2) == 0)
|
||||
{
|
||||
if (c1 == '\0')
|
||||
return diff;
|
||||
|
||||
state = next_state[state];
|
||||
c1 = *p1++;
|
||||
c2 = *p2++;
|
||||
state |= (c1 == '0') + (isdigit (c1) != 0);
|
||||
state += (c1 == '0') + (isdigit (c1) != 0);
|
||||
}
|
||||
|
||||
state = result_type[state << 2 | (((c2 == '0') + (isdigit (c2) != 0)))];
|
||||
state = result_type[state * 3 + (((c2 == '0') + (isdigit (c2) != 0)))];
|
||||
|
||||
switch (state)
|
||||
{
|
||||
|
@ -15,7 +15,8 @@ endif
|
||||
|
||||
TESTS = \
|
||||
replace__str_replace_all \
|
||||
parse_integer
|
||||
parse_integer \
|
||||
str_verscmp
|
||||
|
||||
check_PROGRAMS = $(TESTS)
|
||||
|
||||
@ -24,3 +25,6 @@ replace__str_replace_all_SOURCES = \
|
||||
|
||||
parse_integer_SOURCES = \
|
||||
parse_integer.c
|
||||
|
||||
str_verscmp_SOURCES = \
|
||||
str_verscmp.c
|
||||
|
143
tests/lib/strutil/str_verscmp.c
Normal file
143
tests/lib/strutil/str_verscmp.c
Normal file
@ -0,0 +1,143 @@
|
||||
/*
|
||||
lib/strutil - tests for lib/strutil/str_verscmp function.
|
||||
Testcases are taken from Gnulib.
|
||||
|
||||
Copyright (C) 2019
|
||||
Free Software Foundation, Inc.
|
||||
|
||||
Written by:
|
||||
Andrew Borodin <aborodin@vmail.ru>, 2019
|
||||
|
||||
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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#define TEST_SUITE_NAME "/lib/strutil"
|
||||
|
||||
#include "tests/mctest.h"
|
||||
|
||||
#include "lib/strutil.h"
|
||||
|
||||
/* --------------------------------------------------------------------------------------------- */
|
||||
|
||||
/* From glibc bug 9913 */
|
||||
static char const a[] = "B0075022800016.gbp.corp.com";
|
||||
static char const b[] = "B007502280067.gbp.corp.com";
|
||||
static char const c[] = "B007502357019.GBP.CORP.COM";
|
||||
|
||||
/* --------------------------------------------------------------------------------------------- */
|
||||
|
||||
/* @Before */
|
||||
static void
|
||||
setup (void)
|
||||
{
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------- */
|
||||
|
||||
/* @After */
|
||||
static void
|
||||
teardown (void)
|
||||
{
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------- */
|
||||
|
||||
static int
|
||||
sign (int n)
|
||||
{
|
||||
return ((n < 0) ? -1 : (n == 0) ? 0 : 1);
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------- */
|
||||
|
||||
/* @DataSource("str_verscmp_test_ds") */
|
||||
/* *INDENT-OFF* */
|
||||
static const struct str_verscmp_test_struct
|
||||
{
|
||||
const char *s1;
|
||||
const char *s2;
|
||||
int expected_result;
|
||||
} str_verscmp_test_ds[] =
|
||||
{
|
||||
{ "", "", 0 },
|
||||
{ "a", "a", 0 },
|
||||
{ "a", "b", -1 },
|
||||
{ "b", "a", 1 },
|
||||
{ "000", "00", -1 },
|
||||
{ "00", "000", 1 },
|
||||
{ "a0", "a", 1 },
|
||||
{ "00", "01", -1 },
|
||||
{ "01", "010", -1 },
|
||||
{ "010", "09", -1 },
|
||||
{ "09", "0", -1 },
|
||||
{ "9", "10", -1 },
|
||||
{ "0a", "0", 1 },
|
||||
/* From glibc bug 9913 */
|
||||
{ a, b, -1 },
|
||||
{ b, c, -1 },
|
||||
{ a, c, -1 },
|
||||
{ b, a, 1 },
|
||||
{ c, b, 1 },
|
||||
{ c, a, 1 }
|
||||
};
|
||||
/* *INDENT-ON* */
|
||||
|
||||
/* @Test(dataSource = "str_verscmp_test_ds") */
|
||||
/* *INDENT-OFF* */
|
||||
START_TEST (str_verscmp_test)
|
||||
/* *INDENT-ON* */
|
||||
{
|
||||
/* given */
|
||||
int actual_result;
|
||||
const struct str_verscmp_test_struct *data = &str_verscmp_test_ds[_i];
|
||||
|
||||
/* when */
|
||||
actual_result = str_verscmp (data->s1, data->s2);
|
||||
|
||||
/* then */
|
||||
mctest_assert_int_eq (sign (actual_result), sign (data->expected_result));
|
||||
}
|
||||
/* *INDENT-OFF* */
|
||||
END_TEST
|
||||
/* *INDENT-ON* */
|
||||
|
||||
/* --------------------------------------------------------------------------------------------- */
|
||||
|
||||
int
|
||||
main (void)
|
||||
{
|
||||
int number_failed;
|
||||
|
||||
Suite *s = suite_create (TEST_SUITE_NAME);
|
||||
TCase *tc_core = tcase_create ("Core");
|
||||
SRunner *sr;
|
||||
|
||||
tcase_add_checked_fixture (tc_core, setup, teardown);
|
||||
|
||||
/* Add new tests here: *************** */
|
||||
mctest_add_parameterized_test (tc_core, str_verscmp_test, str_verscmp_test_ds);
|
||||
/* *********************************** */
|
||||
|
||||
suite_add_tcase (s, tc_core);
|
||||
sr = srunner_create (s);
|
||||
srunner_set_log (sr, "str_verscmp.log");
|
||||
srunner_run_all (sr, CK_ENV);
|
||||
number_failed = srunner_ntests_failed (sr);
|
||||
srunner_free (sr);
|
||||
return (number_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------- */
|
Loading…
Reference in New Issue
Block a user