test: fix mishandling of 'test ! arg1 op arg2 more args'; add testsuite
authorDenis Vlasenko <vda.linux@googlemail.com>
Sat, 9 Feb 2008 05:48:42 +0000 (05:48 -0000)
committerDenis Vlasenko <vda.linux@googlemail.com>
Sat, 9 Feb 2008 05:48:42 +0000 (05:48 -0000)
coreutils/test.c
testsuite/test.tests [new file with mode: 0755]

index a30a5087dcbba67733a117e4877d04d815409a42..22dadac0e84ff2065f22a82fba0f2d307011efb4 100644 (file)
@@ -555,7 +555,7 @@ int test_main(int argc, char **argv)
 {
        int res;
        const char *arg0;
-       bool _off;
+       bool negate = 0;
 
        arg0 = bb_basename(argv[0]);
        if (arg0[0] == '[') {
@@ -578,9 +578,8 @@ int test_main(int argc, char **argv)
        INIT_S();
 
        res = setjmp(leaving);
-       if (res) {
+       if (res)
                goto ret;
-       }
 
        /* resetting ngroups is probably unnecessary.  it will
         * force a new call to getgroups(), which prevents using
@@ -592,34 +591,40 @@ int test_main(int argc, char **argv)
         */
        ngroups = 0;
 
+       //argc--;
+       argv++;
+
        /* Implement special cases from POSIX.2, section 4.62.4 */
-       if (argc == 1) {
+       if (!argv[0]) { /* "test" */
                res = 1;
                goto ret;
        }
-       if (argc == 2) {
-               res = (*argv[1] == '\0');
+       if (LONE_CHAR(argv[0], '!') && argv[1]) {
+               negate = 1;
+               //argc--;
+               argv++;
+       }
+       if (!argv[1]) { /* "test [!] arg" */
+               res = (*argv[0] == '\0');
                goto ret;
        }
-
-       /* remember if we saw argc==4 which wants *no* '!' test */
-       _off = argc - 4;
-       if (_off ? (LONE_CHAR(argv[1], '!'))
-                : (argv[1][0] != '!' || argv[1][1] != '\0')
-       ) {
-               if (argc == 3) {
-                       res = (*argv[2] != '\0');
-                       goto ret;
-               }
-
-               t_lex(argv[2 + _off]);
+       if (argv[2] && !argv[3]) {
+               t_lex(argv[1]);
                if (t_wp_op && t_wp_op->op_type == BINOP) {
-                       t_wp = &argv[1 + _off];
-                       res = (binop() == _off);
+                       /* "test [!] arg1 <binary_op> arg2" */
+                       t_wp = &argv[0];
+                       res = (binop() == 0);
                        goto ret;
                }
        }
-       t_wp = &argv[1];
+
+       /* Some complex expression. Undo '!' removal */
+       if (negate) {
+               negate = 0;
+               //argc++;
+               argv--;
+       }
+       t_wp = &argv[0];
        res = !oexpr(t_lex(*t_wp));
 
        if (*t_wp != NULL && *++t_wp != NULL) {
@@ -628,5 +633,5 @@ int test_main(int argc, char **argv)
        }
  ret:
        DEINIT_S();
-       return res;
+       return negate ? !res : res;
 }
diff --git a/testsuite/test.tests b/testsuite/test.tests
new file mode 100755 (executable)
index 0000000..351d355
--- /dev/null
@@ -0,0 +1,26 @@
+#!/bin/sh
+
+# Copyright 2007 by Denys Vlasenko <vda.linux@googlemail.com>
+# Licensed under GPL v2, see file LICENSE for details.
+
+. testing.sh
+
+# testing "test name" "options" "expected result" "file input" "stdin"
+#   file input will be file called "input"
+#   test can create a file "actual" instead of writing to stdout
+
+# Need to call 'busybox test', otherwise shell builtin is used
+
+testing "test ! a = b -a ! c = c: should be false" \
+       "busybox test ! a = b -a ! c = c; echo \$?" \
+       "1\n" \
+       "" \
+       "" \
+
+testing "test ! a = b -a ! c = d: should be true" \
+       "busybox test ! a = b -a ! c = d; echo \$?" \
+       "0\n" \
+       "" \
+       "" \
+
+exit $FAILCOUNT