Message ID | 1638864483-2446-1-git-send-email-xuyang2018.jy@fujitsu.com |
---|---|
State | Changes Requested |
Headers | show |
Series | [v2,1/2] library: add cmd check handler in needs_cmds | expand |
Hi! > diff --git a/lib/tst_test.c b/lib/tst_test.c > index a79275722..7cca209ab 100644 > --- a/lib/tst_test.c > +++ b/lib/tst_test.c I would rather put the version parsing code to a different source file than tst_test.c just because the tst_test.c is long enough already. What I did suggest for v1 is that the entry point function i.e. tst_check_cmd() now wouldn't get exported as a prototype to the tests by being defined in a header included in the tst_test.h header. We already have include/tst_private.h that is expected to be used for function prototypes that are not supposed to be available to the test code. Other than this the code looks good.
Hi Cyril > Hi! >> diff --git a/lib/tst_test.c b/lib/tst_test.c >> index a79275722..7cca209ab 100644 >> --- a/lib/tst_test.c >> +++ b/lib/tst_test.c > > I would rather put the version parsing code to a different source file > than tst_test.c just because the tst_test.c is long enough already. What > I did suggest for v1 is that the entry point function i.e. > tst_check_cmd() now wouldn't get exported as a prototype to the tests by > being defined in a header included in the tst_test.h header. > > We already have include/tst_private.h that is expected to be used for > function prototypes that are not supposed to be available to the test > code. > Now, I understand. so I can just move tst_check_cmd declaration into tst_private.h and then tst_test.c included it. But the source code should move into where, it has two choices: 1) like v1, move a new lib source file ie tst_version_parser.c 2) since it is related to cmd, we can move it into lib/tst_cmd.c I prefer to use 2nd way. What do you think about this? Best Regards Yang Xu > Other than this the code looks good. >
Hi! > Now, I understand. so I can just move tst_check_cmd declaration into > tst_private.h and then tst_test.c included it. > > But the source code should move into where, it has two choices: > 1) like v1, move a new lib source file ie tst_version_parser.c > 2) since it is related to cmd, we can move it into lib/tst_cmd.c > > > I prefer to use 2nd way. What do you think about this? I would probably put it into a separate file, but tst_cmd.c would work as well.
Hi Xu, Cyril, > Testcase ie statx05 needs mkfs.ext4 >= 1.43.0 because of encrypt feature. > As Cyril suggested, add cmd check handler in needs_cmd. Great idea, I have something like this in my TODO list as well, glad I can delete it :). > We don't use tst_ prefix ie tst_check_cmd since we don't export this api to user. > This check_cmd not only check cmd whether existed but also check the cmd version whether > meet test's requirement. > In check_cmd function, use strtok_r to split cmd_token,op_token,version_token. > It only supports six operations '>=' '<=' '>' '<' '==' '!='. > Currently, for the command version check, it only supports mkfs.ext4 command. If you > want to support more commands, just add your own .parser and .table_get methond in > version_parsers structure. > Suggested-by: Cyril Hrubis <chrubis@suse.cz> > Signed-off-by: Yang Xu <xuyang2018.jy@fujitsu.com> > --- > v1->v2 > 1. rename tst_version_parser to check_cmd Why not tst_cmd_check(), i.e. using tst_ prefix? +1 for moving it into tst_cmd.c. > 2. For mkfs_ext4_version_table_get method, use sscanf instead of strtok_r > 3. use enum for cmd op > 4. fix description > 5. add more newlib test for this > doc/c-test-api.txt | 14 +++ > lib/newlib_tests/.gitignore | 8 ++ > lib/newlib_tests/test_needs_cmds01.c | 25 ++++ > lib/newlib_tests/test_needs_cmds02.c | 24 ++++ > lib/newlib_tests/test_needs_cmds03.c | 24 ++++ > lib/newlib_tests/test_needs_cmds04.c | 24 ++++ > lib/newlib_tests/test_needs_cmds05.c | 24 ++++ > lib/newlib_tests/test_needs_cmds06.c | 24 ++++ > lib/newlib_tests/test_needs_cmds07.c | 24 ++++ > lib/newlib_tests/test_needs_cmds08.c | 27 +++++ Also, could you please put tests which expect TPASS or TCONF into lib/newlib_tests/runtest.sh? > diff --git a/lib/tst_test.c b/lib/tst_test.c > index a79275722..7cca209ab 100644 > --- a/lib/tst_test.c > +++ b/lib/tst_test.c > @@ -65,6 +65,15 @@ struct results { > unsigned int timeout; > }; > +enum cmd_op { > + OP_GE, /* >= */ > + OP_GT, /* > */ > + OP_LE, /* <= */ > + OP_LT, /* < */ > + OP_EQ, /* == */ > + OP_NE, /* != */ > +}; > + > static struct results *results; > static int ipc_fd; > @@ -950,6 +959,162 @@ static void prepare_device(void) > } > } > +static int mkfs_ext4_version_parser(void) > +{ > + FILE *f; > + int rc, major, minor, patch; > + > + f = popen("mkfs.ext4 -V 2>&1", "r"); > + if (!f) { > + tst_res(TWARN, "Could not run mkfs.ext4 -V 2>&1 cmd"); > + return -1; > + } > + rc = fscanf(f, "mke2fs %d.%d.%d", &major, &minor, &patch); I guess many functions will have X.Y.Z format. Maybe later we could have generic functions similar to kernel SYSCALL_DEFINEn() macros, passing them just necessary format string. At least that was what I had in my mind when thinking about this. > + pclose(f); > + if (rc != 3) { > + tst_res(TWARN, "Unable to parse mkfs.ext4 version"); > + return -1; > + } > + > + return major * 10000 + minor * 100 + patch; > +} > + > +static int mkfs_ext4_version_table_get(char *version) > +{ > + int major, minor, patch; > + int len; > + > + if (sscanf(version, "%u.%u.%u %n", &major, &minor, &patch, &len) != 3) { > + tst_res(TWARN, "Illega version(%s), " typo s/Illega/Illegal/ > + "should use format like 1.43.0", version); nit: I'd keep string on single line (easier to grep and it's not too long being on single line like the others below). Kind regards, Petr
Hi Petr > Hi Xu, Cyril, > >> Testcase ie statx05 needs mkfs.ext4>= 1.43.0 because of encrypt feature. > >> As Cyril suggested, add cmd check handler in needs_cmd. > > Great idea, I have something like this in my TODO list as well, glad I can > delete it :). That' great. So We can have time to do other thing in ltp. > >> We don't use tst_ prefix ie tst_check_cmd since we don't export this api to user. >> This check_cmd not only check cmd whether existed but also check the cmd version whether >> meet test's requirement. > >> In check_cmd function, use strtok_r to split cmd_token,op_token,version_token. >> It only supports six operations '>=' '<=' '>''<' '==' '!='. > >> Currently, for the command version check, it only supports mkfs.ext4 command. If you >> want to support more commands, just add your own .parser and .table_get methond in >> version_parsers structure. > >> Suggested-by: Cyril Hrubis<chrubis@suse.cz> >> Signed-off-by: Yang Xu<xuyang2018.jy@fujitsu.com> >> --- >> v1->v2 >> 1. rename tst_version_parser to check_cmd > Why not tst_cmd_check(), i.e. using tst_ prefix? I may misunderstand ltp-003 rule. It seems a public library function must have tst_ prefix, but a private library function still can have tst_ prefix ie tst_kconfig_get. Is it right? I also think using tst_cmd_check is better. > > +1 for moving it into tst_cmd.c. Will do. > > >> 2. For mkfs_ext4_version_table_get method, use sscanf instead of strtok_r >> 3. use enum for cmd op >> 4. fix description >> 5. add more newlib test for this >> doc/c-test-api.txt | 14 +++ >> lib/newlib_tests/.gitignore | 8 ++ >> lib/newlib_tests/test_needs_cmds01.c | 25 ++++ >> lib/newlib_tests/test_needs_cmds02.c | 24 ++++ >> lib/newlib_tests/test_needs_cmds03.c | 24 ++++ >> lib/newlib_tests/test_needs_cmds04.c | 24 ++++ >> lib/newlib_tests/test_needs_cmds05.c | 24 ++++ >> lib/newlib_tests/test_needs_cmds06.c | 24 ++++ >> lib/newlib_tests/test_needs_cmds07.c | 24 ++++ >> lib/newlib_tests/test_needs_cmds08.c | 27 +++++ > Also, could you please put tests which expect TPASS or TCONF into > lib/newlib_tests/runtest.sh? OK. Will do. > > >> diff --git a/lib/tst_test.c b/lib/tst_test.c >> index a79275722..7cca209ab 100644 >> --- a/lib/tst_test.c >> +++ b/lib/tst_test.c >> @@ -65,6 +65,15 @@ struct results { >> unsigned int timeout; >> }; > >> +enum cmd_op { >> + OP_GE, /*>= */ >> + OP_GT, /*> */ >> + OP_LE, /*<= */ >> + OP_LT, /*< */ >> + OP_EQ, /* == */ >> + OP_NE, /* != */ >> +}; >> + >> static struct results *results; > >> static int ipc_fd; >> @@ -950,6 +959,162 @@ static void prepare_device(void) >> } >> } > >> +static int mkfs_ext4_version_parser(void) >> +{ >> + FILE *f; >> + int rc, major, minor, patch; >> + >> + f = popen("mkfs.ext4 -V 2>&1", "r"); >> + if (!f) { >> + tst_res(TWARN, "Could not run mkfs.ext4 -V 2>&1 cmd"); >> + return -1; >> + } >> + rc = fscanf(f, "mke2fs %d.%d.%d",&major,&minor,&patch); > > I guess many functions will have X.Y.Z format. Maybe later we could have generic > functions similar to kernel SYSCALL_DEFINEn() macros, passing them just > necessary format string. At least that was what I had in my mind when thinking > about this. Yes, we can have a generic function in the feature if cases have this requirement. > >> + pclose(f); >> + if (rc != 3) { >> + tst_res(TWARN, "Unable to parse mkfs.ext4 version"); >> + return -1; >> + } >> + >> + return major * 10000 + minor * 100 + patch; >> +} >> + >> +static int mkfs_ext4_version_table_get(char *version) >> +{ >> + int major, minor, patch; >> + int len; >> + >> + if (sscanf(version, "%u.%u.%u %n",&major,&minor,&patch,&len) != 3) { >> + tst_res(TWARN, "Illega version(%s), " > typo s/Illega/Illegal/ > >> + "should use format like 1.43.0", version); > nit: I'd keep string on single line (easier to grep and it's not too long being > on single line like the others below). OK. Will do. Best Regards Yang Xu > > Kind regards, > Petr
diff --git a/doc/c-test-api.txt b/doc/c-test-api.txt index 64d0630ce..d35708516 100644 --- a/doc/c-test-api.txt +++ b/doc/c-test-api.txt @@ -2013,6 +2013,20 @@ terminated array of strings such as: }, ------------------------------------------------------------------------------- +Also can check required commands version whether is satisfied by using 'needs_cmds', + +[source,c] +------------------------------------------------------------------------------- +.needs_cmds = (const char *const []) { + "mkfs.ext4 >= 1.43.0", + NULL +}, ++------------------------------------------------------------------------------- + +Currently, we only support mkfs.ext4 command. If you want to support more commands, +please fill your own .parser and .table_get method in the version_parsers structure +of lib/tst_test.c. + 1.36 Assert sys or proc file value ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Using TST_ASSERT_INT/STR(path, val) to assert that integer value or string stored in diff --git a/lib/newlib_tests/.gitignore b/lib/newlib_tests/.gitignore index cf467b5a0..a19fa22e8 100644 --- a/lib/newlib_tests/.gitignore +++ b/lib/newlib_tests/.gitignore @@ -46,4 +46,12 @@ test_macros06 tst_fuzzy_sync01 tst_fuzzy_sync02 tst_fuzzy_sync03 +test_needs_cmds01 +test_needs_cmds02 +test_needs_cmds03 +test_needs_cmds04 +test_needs_cmds05 +test_needs_cmds06 +test_needs_cmds07 +test_needs_cmds08 test_zero_hugepage diff --git a/lib/newlib_tests/test_needs_cmds01.c b/lib/newlib_tests/test_needs_cmds01.c new file mode 100644 index 000000000..0ce69d61e --- /dev/null +++ b/lib/newlib_tests/test_needs_cmds01.c @@ -0,0 +1,25 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2021 Yang Xu <xuyang2018.jy@fujitsu.com> + */ + +#include <stdio.h> +#include "tst_test.h" + +static void do_test(void) +{ + tst_res(TPASS, "Tesing check_cmd() functionality OK."); +} + +static struct tst_test test = { + .test_all = do_test, + .needs_cmds = (const char *[]) { + "mkfs.ext4", + "mkfs.ext4 >= 1.43.0", + "mkfs.ext4 <= 2.0.0", + "mkfs.ext4 != 2.0.0", + "mkfs.ext4 > 1.43.0", + "mkfs.ext4 < 2.0.0", + NULL + } +}; diff --git a/lib/newlib_tests/test_needs_cmds02.c b/lib/newlib_tests/test_needs_cmds02.c new file mode 100644 index 000000000..1eeaf6351 --- /dev/null +++ b/lib/newlib_tests/test_needs_cmds02.c @@ -0,0 +1,24 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2021 Yang Xu <xuyang2018.jy@fujitsu.com> + */ + +/* + * Test Illegal format by using non-existing cmd. + */ + +#include <stdio.h> +#include "tst_test.h" + +static void do_test(void) +{ + tst_res(TFAIL, "Nonexisting command is present!"); +} + +static struct tst_test test = { + .test_all = do_test, + .needs_cmds = (const char *[]) { + "mkfs.ext45 >= 1.43.0", + NULL + } +}; diff --git a/lib/newlib_tests/test_needs_cmds03.c b/lib/newlib_tests/test_needs_cmds03.c new file mode 100644 index 000000000..c50077f4e --- /dev/null +++ b/lib/newlib_tests/test_needs_cmds03.c @@ -0,0 +1,24 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2021 Yang Xu <xuyang2018.jy@fujitsu.com> + */ + +/* + * Test Illegal format by using Illegal operation. + */ + +#include <stdio.h> +#include "tst_test.h" + +static void do_test(void) +{ + tst_res(TFAIL, "Wrong operator was evaluated!"); +} + +static struct tst_test test = { + .test_all = do_test, + .needs_cmds = (const char *[]) { + "mkfs.ext4 ! 1.43.0", + NULL + } +}; diff --git a/lib/newlib_tests/test_needs_cmds04.c b/lib/newlib_tests/test_needs_cmds04.c new file mode 100644 index 000000000..5d05ed46d --- /dev/null +++ b/lib/newlib_tests/test_needs_cmds04.c @@ -0,0 +1,24 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2021 Yang Xu <xuyang2018.jy@fujitsu.com> + */ + +/* + * Test Illegal format by using incomplete version. + */ + +#include <stdio.h> +#include "tst_test.h" + +static void do_test(void) +{ + tst_res(TFAIL, "Incomplete version was parsed!"); +} + +static struct tst_test test = { + .test_all = do_test, + .needs_cmds = (const char *[]) { + "mkfs.ext4 > 1.43", + NULL + } +}; diff --git a/lib/newlib_tests/test_needs_cmds05.c b/lib/newlib_tests/test_needs_cmds05.c new file mode 100644 index 000000000..f4b509b68 --- /dev/null +++ b/lib/newlib_tests/test_needs_cmds05.c @@ -0,0 +1,24 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2021 Yang Xu <xuyang2018.jy@fujitsu.com> + */ + +/* + * Test Illegal format by using version that has garbage. + */ + +#include <stdio.h> +#include "tst_test.h" + +static void do_test(void) +{ + tst_res(TFAIL, "Garbage version was parsed!"); +} + +static struct tst_test test = { + .test_all = do_test, + .needs_cmds = (const char *[]) { + "mkfs.ext4 > 1.43.0-1", + NULL + } +}; diff --git a/lib/newlib_tests/test_needs_cmds06.c b/lib/newlib_tests/test_needs_cmds06.c new file mode 100644 index 000000000..f1234820e --- /dev/null +++ b/lib/newlib_tests/test_needs_cmds06.c @@ -0,0 +1,24 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2021 Yang Xu <xuyang2018.jy@fujitsu.com> + */ + +/* + * Test Illegal format with garbage. + */ + +#include <stdio.h> +#include "tst_test.h" + +static void do_test(void) +{ + tst_res(TFAIL, "Garbage format was parsed!"); +} + +static struct tst_test test = { + .test_all = do_test, + .needs_cmds = (const char *[]) { + "mkfs.ext4 > 1.43.0 2", + NULL + } +}; diff --git a/lib/newlib_tests/test_needs_cmds07.c b/lib/newlib_tests/test_needs_cmds07.c new file mode 100644 index 000000000..e2d2643f4 --- /dev/null +++ b/lib/newlib_tests/test_needs_cmds07.c @@ -0,0 +1,24 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2021 Yang Xu <xuyang2018.jy@fujitsu.com> + */ + +/* + * Test non-existed cmd whether still can be detected. + */ + +#include <stdio.h> +#include "tst_test.h" + +static void do_test(void) +{ + tst_res(TFAIL, "Nonexisting command is present!"); +} + +static struct tst_test test = { + .test_all = do_test, + .needs_cmds = (const char *[]) { + "mkfs.ext45", + NULL + } +}; diff --git a/lib/newlib_tests/test_needs_cmds08.c b/lib/newlib_tests/test_needs_cmds08.c new file mode 100644 index 000000000..342c3716c --- /dev/null +++ b/lib/newlib_tests/test_needs_cmds08.c @@ -0,0 +1,27 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2021 Yang Xu <xuyang2018.jy@fujitsu.com> + */ + +/* + * Test mkfs.xfs that it doesn't have own parser and table_get function + * at the version_parsers structure in lib/tst_test.c. + * So it should report parser function for this cmd is not implemented. + */ + +#include <stdio.h> +#include "tst_test.h" + +static void do_test(void) +{ + tst_res(TFAIL, "Nonexisting parser function for mkfs.xfs is present!"); +} + +static struct tst_test test = { + .test_all = do_test, + .needs_cmds = (const char *[]) { + "mkfs.xfs", + "mkfs.xfs >= 4.20.0", + NULL + } +}; diff --git a/lib/tst_test.c b/lib/tst_test.c index a79275722..7cca209ab 100644 --- a/lib/tst_test.c +++ b/lib/tst_test.c @@ -65,6 +65,15 @@ struct results { unsigned int timeout; }; +enum cmd_op { + OP_GE, /* >= */ + OP_GT, /* > */ + OP_LE, /* <= */ + OP_LT, /* < */ + OP_EQ, /* == */ + OP_NE, /* != */ +}; + static struct results *results; static int ipc_fd; @@ -950,6 +959,162 @@ static void prepare_device(void) } } +static int mkfs_ext4_version_parser(void) +{ + FILE *f; + int rc, major, minor, patch; + + f = popen("mkfs.ext4 -V 2>&1", "r"); + if (!f) { + tst_res(TWARN, "Could not run mkfs.ext4 -V 2>&1 cmd"); + return -1; + } + rc = fscanf(f, "mke2fs %d.%d.%d", &major, &minor, &patch); + pclose(f); + if (rc != 3) { + tst_res(TWARN, "Unable to parse mkfs.ext4 version"); + return -1; + } + + return major * 10000 + minor * 100 + patch; +} + +static int mkfs_ext4_version_table_get(char *version) +{ + int major, minor, patch; + int len; + + if (sscanf(version, "%u.%u.%u %n", &major, &minor, &patch, &len) != 3) { + tst_res(TWARN, "Illega version(%s), " + "should use format like 1.43.0", version); + return -1; + } + + if (len != (int)strlen(version)) { + tst_res(TWARN, "Grabage after version"); + return -1; + } + + return major * 10000 + minor * 100 + patch; +} + +static struct version_parser { + const char *cmd; + int (*parser)(void); + int (*table_get)(char *version); +} version_parsers[] = { + {"mkfs.ext4", mkfs_ext4_version_parser, mkfs_ext4_version_table_get}, + {}, +}; + +static void check_cmd(const char *cmd) +{ + struct version_parser *p; + char *cmd_token, *op_token, *version_token, *next, *str; + char path[PATH_MAX]; + char parser_cmd[100]; + int ver_parser, ver_get; + int op_flag = 0; + + strcpy(parser_cmd, cmd); + + cmd_token = strtok_r(parser_cmd, " ", &next); + op_token = strtok_r(NULL, " ", &next); + version_token = strtok_r(NULL, " ", &next); + str = strtok_r(NULL, " ", &next); + + if (tst_get_path(cmd_token, path, sizeof(path))) + tst_brk(TCONF, "Couldn't find '%s' in $PATH", cmd_token); + + if (!op_token) + return; + + if (!strcmp(op_token, ">=")) + op_flag = OP_GE; + else if (!strcmp(op_token, ">")) + op_flag = OP_GT; + else if (!strcmp(op_token, "<=")) + op_flag = OP_LE; + else if (!strcmp(op_token, "<")) + op_flag = OP_LT; + else if (!strcmp(op_token, "==")) + op_flag = OP_EQ; + else if (!strcmp(op_token, "!=")) + op_flag = OP_NE; + else + tst_brk(TCONF, "Invalid op(%s)", op_token); + + if (!version_token || str) { + tst_brk(TCONF, "Illegal format(%s), should use format like " + "mkfs.ext4 >= 1.43.0", cmd); + } + + for (p = &version_parsers[0]; p->cmd; p++) { + if (!strcmp(p->cmd, cmd_token)) { + tst_res(TINFO, "Parsing %s version", p->cmd); + break; + } + } + + if (!p->cmd) { + tst_brk(TBROK, "No version parser for %s implemented!", + cmd_token); + } + + ver_parser = p->parser(); + if (ver_parser < 0) + tst_brk(TBROK, "Failed to parse %s version", p->cmd); + + ver_get = p->table_get(version_token); + if (ver_get < 0) + tst_brk(TBROK, "Failed to get %s version", p->cmd); + + switch (op_flag) { + case OP_GE: + if (ver_parser < ver_get) { + tst_brk(TCONF, "%s required >= %d, but got %d, " + "the version is required in order run the test.", + cmd, ver_get, ver_parser); + } + break; + case OP_GT: + if (ver_parser <= ver_get) { + tst_brk(TCONF, "%s required > %d, but got %d, " + "the version is required in order run the test.", + cmd, ver_get, ver_parser); + } + break; + case OP_LE: + if (ver_parser > ver_get) { + tst_brk(TCONF, "%s required <= %d, but got %d, " + "the version is required in order run the test.", + cmd, ver_get, ver_parser); + } + break; + case OP_LT: + if (ver_parser >= ver_get) { + tst_brk(TCONF, "%s required < %d, but got %d, " + "the version is required in order run the test.", + cmd, ver_get, ver_parser); + } + break; + case OP_EQ: + if (ver_parser != ver_get) { + tst_brk(TCONF, "%s required == %d, but got %d, " + "the version is required in order run the test.", + cmd, ver_get, ver_parser); + } + break; + case OP_NE: + if (ver_parser == ver_get) { + tst_brk(TCONF, "%s required != %d, but got %d, " + "the version is required in order run the test.", + cmd, ver_get, ver_parser); + } + break; + } +} + static void do_setup(int argc, char *argv[]) { if (!tst_test) @@ -987,12 +1152,10 @@ static void do_setup(int argc, char *argv[]) if (tst_test->needs_cmds) { const char *cmd; - char path[PATH_MAX]; int i; for (i = 0; (cmd = tst_test->needs_cmds[i]); ++i) - if (tst_get_path(cmd, path, sizeof(path))) - tst_brk(TCONF, "Couldn't find '%s' in $PATH", cmd); + check_cmd(cmd); } if (tst_test->needs_drivers) {
Testcase ie statx05 needs mkfs.ext4 >= 1.43.0 because of encrypt feature. As Cyril suggested, add cmd check handler in needs_cmd. We don't use tst_ prefix ie tst_check_cmd since we don't export this api to user. This check_cmd not only check cmd whether existed but also check the cmd version whether meet test's requirement. In check_cmd function, use strtok_r to split cmd_token,op_token,version_token. It only supports six operations '>=' '<=' '>' '<' '==' '!='. Currently, for the command version check, it only supports mkfs.ext4 command. If you want to support more commands, just add your own .parser and .table_get methond in version_parsers structure. Suggested-by: Cyril Hrubis <chrubis@suse.cz> Signed-off-by: Yang Xu <xuyang2018.jy@fujitsu.com> --- v1->v2 1. rename tst_version_parser to check_cmd 2. For mkfs_ext4_version_table_get method, use sscanf instead of strtok_r 3. use enum for cmd op 4. fix description 5. add more newlib test for this doc/c-test-api.txt | 14 +++ lib/newlib_tests/.gitignore | 8 ++ lib/newlib_tests/test_needs_cmds01.c | 25 ++++ lib/newlib_tests/test_needs_cmds02.c | 24 ++++ lib/newlib_tests/test_needs_cmds03.c | 24 ++++ lib/newlib_tests/test_needs_cmds04.c | 24 ++++ lib/newlib_tests/test_needs_cmds05.c | 24 ++++ lib/newlib_tests/test_needs_cmds06.c | 24 ++++ lib/newlib_tests/test_needs_cmds07.c | 24 ++++ lib/newlib_tests/test_needs_cmds08.c | 27 +++++ lib/tst_test.c | 169 ++++++++++++++++++++++++++- 11 files changed, 384 insertions(+), 3 deletions(-) create mode 100644 lib/newlib_tests/test_needs_cmds01.c create mode 100644 lib/newlib_tests/test_needs_cmds02.c create mode 100644 lib/newlib_tests/test_needs_cmds03.c create mode 100644 lib/newlib_tests/test_needs_cmds04.c create mode 100644 lib/newlib_tests/test_needs_cmds05.c create mode 100644 lib/newlib_tests/test_needs_cmds06.c create mode 100644 lib/newlib_tests/test_needs_cmds07.c create mode 100644 lib/newlib_tests/test_needs_cmds08.c