Merge branch '3956_file_version_sort_fixes'

* 3956_file_version_sort_fixes:
  Fix file version sort.
  Ticket #3905, 3956: fix file version sort.
This commit is contained in:
Andrew Borodin 2019-03-02 12:18:14 +03:00
commit e7249a88de
8 changed files with 750 additions and 32 deletions

View File

@ -538,6 +538,28 @@ const char *str_detect_termencoding (void);
int str_verscmp (const char *s1, const char *s2);
/* Compare version strings:
This function compares strings s1 and s2:
1) By PREFIX in the same way as strcmp.
2) Then by VERSION (most similarly to version compare of Debian's dpkg).
Leading zeros in version numbers are ignored.
3) If both (PREFIX and VERSION) are equal, strcmp function is used for
comparison. So this function can return 0 if (and only if) strings s1
and s2 are identical.
It returns number > 0 for s1 > s2, 0 for s1 == s2 and number < 0 for s1 < s2.
This function compares strings, in a way that if VER1 and VER2 are version
numbers and PREFIX and SUFFIX (SUFFIX defined as (\.[A-Za-z~][A-Za-z0-9~]*)*)
are strings then VER1 < VER2 implies filevercmp (PREFIX VER1 SUFFIX,
PREFIX VER2 SUFFIX) < 0.
This function is intended to be a replacement for strverscmp.
*/
int filevercmp (const char *s1, const char *s2);
/* return how many lines and columns will text occupy on terminal
*/
void str_msg_term_size (const char *text, int *lines, int *columns);

View File

@ -1,6 +1,7 @@
noinst_LTLIBRARIES = libmcstrutil.la
libmcstrutil_la_SOURCES = \
filevercmp.c \
replace.c \
strescape.c \
strutil8bit.c \

232
lib/strutil/filevercmp.c Normal file
View File

@ -0,0 +1,232 @@
/*
Copyright (C) 1995 Ian Jackson <iwj10@cus.cam.ac.uk>
Copyright (C) 2001 Anthony Towns <aj@azure.humbug.org.au>
Copyright (C) 2008-2018 Free Software Foundation, Inc.
This program 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.
This program 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/>.
*/
#include <config.h>
#include <sys/types.h>
#include <stdlib.h>
#include <string.h>
#include <limits.h>
#include "lib/strutil.h"
/*** global variables ****************************************************************************/
/*** file scope macro definitions ****************************************************************/
/*** file scope type declarations ****************************************************************/
/*** file scope variables ************************************************************************/
/* --------------------------------------------------------------------------------------------- */
/*** file scope functions ************************************************************************/
/* --------------------------------------------------------------------------------------------- */
/* Match a file suffix defined by this regular expression: /(\.[A-Za-z~][A-Za-z0-9~]*)*$/
*
* @str pointer to string to scan.
*
* @return pointer to the matching suffix, or NULL if not found.
* Upon return, @str points to terminating NUL.
*/
static const char *
match_suffix (const char **str)
{
const char *match = NULL;
gboolean read_alpha = FALSE;
while (**str != '\0')
{
if (read_alpha)
{
read_alpha = FALSE;
if (!g_ascii_isalpha (**str) && **str != '~')
match = NULL;
}
else if (**str == '.')
{
read_alpha = TRUE;
if (match == NULL)
match = *str;
}
else if (!g_ascii_isalnum (**str) && **str != '~')
match = NULL;
(*str)++;
}
return match;
}
/* --------------------------------------------------------------------------------------------- */
/* verrevcmp helper function */
static int
order (unsigned char c)
{
if (g_ascii_isdigit (c))
return 0;
if (g_ascii_isalpha (c))
return c;
if (c == '~')
return -1;
return (int) c + UCHAR_MAX + 1;
}
/* --------------------------------------------------------------------------------------------- */
/* Slightly modified verrevcmp function from dpkg
*
* This implements the algorithm for comparison of version strings
* specified by Debian and now widely adopted. The detailed
* specification can be found in the Debian Policy Manual in the
* section on the 'Version' control field. This version of the code
* implements that from s5.6.12 of Debian Policy v3.8.0.1
* https://www.debian.org/doc/debian-policy/ch-controlfields.html#s-f-Version
*
* @s1 first string to compare
* @s1_len length of @s1
* @s2 second string to compare
* @s2_len length of @s2
*
* @return an integer less than, equal to, or greater than zero, if @s1 is <, == or > than @s2.
*/
static int
verrevcmp (const char *s1, size_t s1_len, const char *s2, size_t s2_len)
{
size_t s1_pos = 0;
size_t s2_pos = 0;
while (s1_pos < s1_len || s2_pos < s2_len)
{
int first_diff = 0;
while ((s1_pos < s1_len && !g_ascii_isdigit (s1[s1_pos]))
|| (s2_pos < s2_len && !g_ascii_isdigit (s2[s2_pos])))
{
int s1_c = 0;
int s2_c = 0;
if (s1_pos != s1_len)
s1_c = order (s1[s1_pos]);
if (s2_pos != s2_len)
s2_c = order (s2[s2_pos]);
if (s1_c != s2_c)
return (s1_c - s2_c);
s1_pos++;
s2_pos++;
}
while (s1[s1_pos] == '0')
s1_pos++;
while (s2[s2_pos] == '0')
s2_pos++;
while (g_ascii_isdigit (s1[s1_pos]) && g_ascii_isdigit (s2[s2_pos]))
{
if (first_diff == 0)
first_diff = s1[s1_pos] - s2[s2_pos];
s1_pos++;
s2_pos++;
}
if (g_ascii_isdigit (s1[s1_pos]))
return 1;
if (g_ascii_isdigit (s2[s2_pos]))
return -1;
if (first_diff != 0)
return first_diff;
}
return 0;
}
/* --------------------------------------------------------------------------------------------- */
/*** public functions ****************************************************************************/
/* --------------------------------------------------------------------------------------------- */
/* Compare version strings.
*
* @s1 first string to compare
* @s2 second string to compare
*
* @return an integer less than, equal to, or greater than zero, if @s1 is <, == or > than @s2.
*/
int
filevercmp (const char *s1, const char *s2)
{
const char *s1_pos, *s2_pos;
const char *s1_suffix, *s2_suffix;
size_t s1_len, s2_len;
int simple_cmp, result;
/* easy comparison to see if strings are identical */
simple_cmp = strcmp (s1, s2);
if (simple_cmp == 0)
return 0;
/* special handle for "", "." and ".." */
if (*s1 == '\0')
return -1;
if (*s2 == '\0')
return 1;
if (DIR_IS_DOT (s1))
return -1;
if (DIR_IS_DOT (s2))
return 1;
if (DIR_IS_DOTDOT (s1))
return -1;
if (DIR_IS_DOTDOT (s2))
return 1;
/* special handle for other hidden files */
if (*s1 == '.' && *s2 != '.')
return -1;
if (*s1 != '.' && *s2 == '.')
return 1;
if (*s1 == '.' && *s2 == '.')
{
s1++;
s2++;
}
/* "cut" file suffixes */
s1_pos = s1;
s2_pos = s2;
s1_suffix = match_suffix (&s1_pos);
s2_suffix = match_suffix (&s2_pos);
s1_len = (s1_suffix != NULL ? s1_suffix : s1_pos) - s1;
s2_len = (s2_suffix != NULL ? s2_suffix : s2_pos) - s2;
/* restore file suffixes if strings are identical after "cut" */
if ((s1_suffix != NULL || s2_suffix != NULL) && (s1_len == s2_len)
&& strncmp (s1, s2, s1_len) == 0)
{
s1_len = s1_pos - s1;
s2_len = s2_pos - s2;
}
result = verrevcmp (s1, s1_len, s2, s2_len);
return result == 0 ? simple_cmp : result;
}
/* --------------------------------------------------------------------------------------------- */

View File

@ -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)
{

View File

@ -354,7 +354,7 @@ sort_vers (file_entry_t * a, file_entry_t * b)
if (ad == bd || panels_options.mix_all_files)
{
return str_verscmp (a->fname, b->fname) * reverse;
return filevercmp (a->fname, b->fname) * reverse;
}
else
{

View File

@ -15,7 +15,9 @@ endif
TESTS = \
replace__str_replace_all \
parse_integer
parse_integer \
str_verscmp \
filevercmp
check_PROGRAMS = $(TESTS)
@ -24,3 +26,9 @@ replace__str_replace_all_SOURCES = \
parse_integer_SOURCES = \
parse_integer.c
str_verscmp_SOURCES = \
str_verscmp.c
filevercmp_SOURCES = \
filevercmp.c

View File

@ -0,0 +1,296 @@
/*
lib/strutil - tests for lib/strutil/fileverscmp function.
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"
/* --------------------------------------------------------------------------------------------- */
/* @Before */
static void
setup (void)
{
}
/* --------------------------------------------------------------------------------------------- */
/* @After */
static void
teardown (void)
{
}
/* --------------------------------------------------------------------------------------------- */
static int
sign (int n)
{
return ((n < 0) ? -1 : (n == 0) ? 0 : 1);
}
/* --------------------------------------------------------------------------------------------- */
/* @DataSource("filevercmp_test_ds1") */
/* Testcases are taken from Gnulib */
/* *INDENT-OFF* */
static const struct filevercmp_test_struct
{
const char *s1;
const char *s2;
int expected_result;
} filevercmp_test_ds1[] =
{
{ "", "", 0 },
{ "a", "a", 0 },
{ "a", "b", -1 },
{ "b", "a", 1 },
{ "a0", "a", 1 },
{ "00", "01", -1 },
{ "01", "010", -1 },
{ "9", "10", -1 },
{ "0a", "0", 1 }
};
/* *INDENT-ON* */
/* @Test(dataSource = "filevercmp_test_ds1") */
/* *INDENT-OFF* */
START_TEST (filevercmp_test1)
/* *INDENT-ON* */
{
/* given */
int actual_result;
const struct filevercmp_test_struct *data = &filevercmp_test_ds1[_i];
/* when */
actual_result = filevercmp (data->s1, data->s2);
/* then */
mctest_assert_int_eq (sign (actual_result), sign (data->expected_result));
}
/* *INDENT-OFF* */
END_TEST
/* *INDENT-ON* */
/* --------------------------------------------------------------------------------------------- */
/* @DataSource("filevercmp_test_ds2") */
/* Testcases are taken from Gnulib */
static const char *filevercmp_test_ds2[] = {
"",
".",
"..",
".0",
".9",
".A",
".Z",
".a~",
".a",
".b~",
".b",
".z",
".zz~",
".zz",
".zz.~1~",
".zz.0",
"0",
"9",
"A",
"Z",
"a~",
"a",
"a.b~",
"a.b",
"a.bc~",
"a.bc",
"b~",
"b",
"gcc-c++-10.fc9.tar.gz",
"gcc-c++-10.fc9.tar.gz.~1~",
"gcc-c++-10.fc9.tar.gz.~2~",
"gcc-c++-10.8.12-0.7rc2.fc9.tar.bz2",
"gcc-c++-10.8.12-0.7rc2.fc9.tar.bz2.~1~",
"glibc-2-0.1.beta1.fc10.rpm",
"glibc-common-5-0.2.beta2.fc9.ebuild",
"glibc-common-5-0.2b.deb",
"glibc-common-11b.ebuild",
"glibc-common-11-0.6rc2.ebuild",
"libstdc++-0.5.8.11-0.7rc2.fc10.tar.gz",
"libstdc++-4a.fc8.tar.gz",
"libstdc++-4.10.4.20040204svn.rpm",
"libstdc++-devel-3.fc8.ebuild",
"libstdc++-devel-3a.fc9.tar.gz",
"libstdc++-devel-8.fc8.deb",
"libstdc++-devel-8.6.2-0.4b.fc8",
"nss_ldap-1-0.2b.fc9.tar.bz2",
"nss_ldap-1-0.6rc2.fc8.tar.gz",
"nss_ldap-1.0-0.1a.tar.gz",
"nss_ldap-10beta1.fc8.tar.gz",
"nss_ldap-10.11.8.6.20040204cvs.fc10.ebuild",
"z",
"zz~",
"zz",
"zz.~1~",
"zz.0",
"#.b#"
};
const size_t filevercmp_test_ds2_len = G_N_ELEMENTS (filevercmp_test_ds2);
/* @Test(dataSource = "filevercmp_test_ds2") */
/* *INDENT-OFF* */
START_TEST (filevercmp_test2)
/* *INDENT-ON* */
{
const char *i = filevercmp_test_ds2[_i];
size_t _j;
for (_j = 0; _j < filevercmp_test_ds2_len; _j++)
{
const char *j = filevercmp_test_ds2[_j];
int result;
result = filevercmp (i, j);
if (result < 0)
ck_assert_int_eq (!!((size_t) _i < _j), 1);
else if (0 < result)
ck_assert_int_eq (!!(_j < (size_t) _i), 1);
else
ck_assert_int_eq (!!(_j == (size_t) _i), 1);
}
}
/* *INDENT-OFF* */
END_TEST
/* *INDENT-ON* */
/* @DataSource("filevercmp_test_ds3") */
/* Ticket #3959 */
static const char *filevercmp_test_ds3[] = {
"application-1.10.tar.gz",
"application-1.10.1.tar.gz"
};
const size_t filevercmp_test_ds3_len = G_N_ELEMENTS (filevercmp_test_ds3);
/* @Test(dataSource = "filevercmp_test_ds3") */
/* *INDENT-OFF* */
START_TEST (filevercmp_test3)
/* *INDENT-ON* */
{
const char *i = filevercmp_test_ds3[_i];
size_t _j;
for (_j = 0; _j < filevercmp_test_ds3_len; _j++)
{
const char *j = filevercmp_test_ds3[_j];
int result;
result = filevercmp (i, j);
if (result < 0)
ck_assert_int_eq (!!((size_t) _i < _j), 1);
else if (0 < result)
ck_assert_int_eq (!!(_j < (size_t) _i), 1);
else
ck_assert_int_eq (!!(_j == (size_t) _i), 1);
}
}
/* *INDENT-OFF* */
END_TEST
/* *INDENT-ON* */
/* @DataSource("filevercmp_test_ds4") */
/* Ticket #3905 */
static const char *filevercmp_test_ds4[] = {
"firefox-58.0.1+build1.tar.gz",
"firefox-59.0~b14+build1.tar.gz",
"firefox-59.0.1+build1.tar.gz"
};
const size_t filevercmp_test_ds4_len = G_N_ELEMENTS (filevercmp_test_ds4);
/* @Test(dataSource = "filevercmp_test_ds4") */
/* *INDENT-OFF* */
START_TEST (filevercmp_test4)
/* *INDENT-ON* */
{
const char *i = filevercmp_test_ds4[_i];
size_t _j;
for (_j = 0; _j < filevercmp_test_ds4_len; _j++)
{
const char *j = filevercmp_test_ds4[_j];
int result;
result = filevercmp (i, j);
if (result < 0)
ck_assert_int_eq (!!((size_t) _i < _j), 1);
else if (0 < result)
ck_assert_int_eq (!!(_j < (size_t) _i), 1);
else
ck_assert_int_eq (!!(_j == (size_t) _i), 1);
}
}
/* *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, filevercmp_test1, filevercmp_test_ds1);
tcase_add_loop_test (tc_core, filevercmp_test2, 0, filevercmp_test_ds2_len);
tcase_add_loop_test (tc_core, filevercmp_test3, 0, filevercmp_test_ds3_len);
tcase_add_loop_test (tc_core, filevercmp_test4, 0, filevercmp_test_ds4_len);
/* *********************************** */
suite_add_tcase (s, tc_core);
sr = srunner_create (s);
srunner_set_log (sr, "filevercmp.log");
srunner_run_all (sr, CK_ENV);
number_failed = srunner_ntests_failed (sr);
srunner_free (sr);
return (number_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
}
/* --------------------------------------------------------------------------------------------- */

View 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;
}
/* --------------------------------------------------------------------------------------------- */