util/tests: add rfc1738 cmocka tests
authorDouglas Bagnall <douglas.bagnall@catalyst.net.nz>
Sat, 17 Feb 2018 20:53:32 +0000 (09:53 +1300)
committerDouglas Bagnall <dbagnall@samba.org>
Thu, 22 Feb 2018 00:04:18 +0000 (01:04 +0100)
These don't pass yet.

Signed-off-by: Douglas Bagnall <douglas.bagnall@catalyst.net.nz>
Reviewed-by: Andrew Bartlett <abartlet@samba.org>
lib/util/tests/rfc1738.c [new file with mode: 0644]
lib/util/wscript_build
selftest/knownfail.d/rfc1738 [new file with mode: 0644]
selftest/tests.py

diff --git a/lib/util/tests/rfc1738.c b/lib/util/tests/rfc1738.c
new file mode 100644 (file)
index 0000000..6e96037
--- /dev/null
@@ -0,0 +1,411 @@
+#include <stdarg.h>
+#include <stddef.h>
+#include <setjmp.h>
+#include <stdint.h>
+#include <cmocka.h>
+#include "lib/replace/replace.h"
+
+#include <errno.h>
+#include <unistd.h>
+#include <talloc.h>
+#include <ctype.h>
+#include <string.h>
+#include "lib/util/samba_util.h"
+
+/* These flags say what can be asserted about a relationship between a string
+   and its supposedly escaped equivalent.
+
+   The first part of the flag name indicates the direction of transformation;
+   tyhe second part is the expected result. For example, ESCAPE_EQ means the
+   escape is expected to succeed and result is expected to be equal to the
+   given answer. ESCAPE_EQ_CASECMP is only equal when compared
+   case-insensitively. UNESCAPE_ERR means unescaping the escaped string should
+   result in an error.
+*/
+#define UNESCAPE_ERR 1
+#define ESCAPE_ERR 2
+#define ESCAPE_EQ 4
+#define UNESCAPE_EQ 8
+#define ESCAPE_NE 16
+#define UNESCAPE_NE 32
+#define ESCAPE_EQ_CASECMP 64
+
+struct rfc1738_test {
+       const char *escaped;   /* original for unescape; result for escape  */
+       const char *unescaped; /* result in unescape; original for escape */
+       uint32_t flags;   /* see above */
+       int unesc_len;    /* end - start will be this */
+       int unesc_strlen; /* strlen() will say this */
+       int esc_len;      /* escaped string length */
+};
+
+/* unreserved = ALPHA DIGIT - . _ ~       */
+
+char spectrum[255 + 1];
+char spectrum_escaped[255 * 3 + 1];
+
+struct rfc1738_test examples[] = {
+
+#define SIMPLE1 "this_is_a_simple-string._With_no_escapes~" /* maps to self */
+       {
+               SIMPLE1,
+               SIMPLE1,
+               ESCAPE_EQ | UNESCAPE_EQ, /* round trip should work */
+               sizeof(SIMPLE1) - 1,
+               sizeof(SIMPLE1) - 1,
+               sizeof(SIMPLE1) - 1,
+       },
+#define SIMPLE2 "no escapes, but\n non-printables \xc5\x8d\x99"
+#define SIMPLE2_ESC "no%20escapes%2C%20but%0A%20non-printables%20%C5%8D%99"
+       {
+               SIMPLE2_ESC,
+               SIMPLE2,
+               ESCAPE_EQ | UNESCAPE_EQ,
+               sizeof(SIMPLE2) - 1,
+               sizeof(SIMPLE2) - 1,
+               sizeof(SIMPLE2_ESC) - 1,
+       },
+#define SIMPLE3 "this @#$^&*()_+{}:;"
+#define SIMPLE3_ESC "this%20%40%23%24%5E%26%2A%28%29_%2B%7B%7D%3A%3B"
+       {
+               SIMPLE3_ESC,
+               SIMPLE3,
+               ESCAPE_EQ | UNESCAPE_EQ,
+               sizeof(SIMPLE3) - 1,
+               sizeof(SIMPLE3) - 1,
+               sizeof(SIMPLE3_ESC) - 1,
+       },
+
+#define ESCAPE1 "%/\x06this string has expected escapes"
+#define ESCAPE1_ESC "%25%2F%06this%20string%20has%20expected%20escapes"
+#define ESCAPE1_ESC_ESC "%2525%252F%2506this%2520string%2520has%2520expected"\
+       "%2520escapes"
+       {
+               ESCAPE1_ESC,
+               ESCAPE1,
+               ESCAPE_EQ | UNESCAPE_EQ,
+               sizeof(ESCAPE1) - 1,
+               sizeof(ESCAPE1) - 1,
+               sizeof(ESCAPE1_ESC) - 1,
+       },
+       {
+               ESCAPE1_ESC_ESC, /*re-escaping */
+               ESCAPE1_ESC,
+               ESCAPE_EQ | UNESCAPE_EQ,
+               sizeof(ESCAPE1_ESC) - 1,
+               sizeof(ESCAPE1_ESC) - 1,
+               sizeof(ESCAPE1_ESC_ESC) - 1,
+       },
+#define ESCAPE2 "%25%2f%06-this-string-has-expected-lowercase-escapes-%ab"
+#define ESCAPE2_UNESC "%/\x06-this-string-has-expected-lowercase-escapes-\xab"
+       {
+               ESCAPE2,
+               ESCAPE2_UNESC,
+               ESCAPE_EQ_CASECMP | UNESCAPE_EQ, /* escape won't match case */
+               sizeof(ESCAPE2_UNESC) - 1,
+               sizeof(ESCAPE2_UNESC) - 1,
+               sizeof(ESCAPE2) - 1,
+       },
+#define ESCAPE3 "%25%2f%06 %32 %44 %6a%AA THIS string h%61s random escapes %ab"
+#define ESCAPE3_UNESC "%/\x06 2 D j\xAA THIS string has random escapes \xab"
+       {
+               ESCAPE3,
+               ESCAPE3_UNESC,
+               ESCAPE_NE | UNESCAPE_EQ, /* escape will have escaped spaces */
+               sizeof(ESCAPE3_UNESC) - 1,
+               sizeof(ESCAPE3_UNESC) - 1,
+               sizeof(ESCAPE3) - 1,
+       },
+#define ESCAPE4 "%25%25%25" /*  */
+#define ESCAPE4_UNESC "%%%" /*  */
+#define ESCAPE4_ESC "%2525%2525%2525"
+       {
+               ESCAPE4,
+               ESCAPE4_UNESC,
+               ESCAPE_EQ | UNESCAPE_EQ,
+               sizeof(ESCAPE4_UNESC) - 1,
+               sizeof(ESCAPE4_UNESC) - 1,
+               sizeof(ESCAPE4) - 1,
+       },
+       {
+               ESCAPE4_ESC,
+               ESCAPE4,
+               ESCAPE_EQ | UNESCAPE_EQ,
+               sizeof(ESCAPE4) - 1,
+               sizeof(ESCAPE4) - 1,
+               sizeof(ESCAPE4_ESC) - 1,
+       },
+#define BAD1 "trailing percent is bad %"
+#define BAD1_ESC "trailing%20percent%20is%20bad%20%25"
+       {
+               BAD1_ESC,
+               BAD1,
+               UNESCAPE_EQ |ESCAPE_EQ,
+               sizeof(BAD1) - 1,
+               sizeof(BAD1) - 1,
+               sizeof(BAD1_ESC) - 1,
+       },
+       {
+               BAD1,
+               NULL,
+               UNESCAPE_ERR,
+               0,
+               0,
+               sizeof(BAD1) - 1,
+       },
+#define BAD2 "trailing percent is bad %1"
+#define BAD3 "bad characters %1 "
+       {
+               BAD2,
+               NULL,
+               UNESCAPE_ERR,
+               0,
+               0,
+               sizeof(BAD2) - 1,
+       },
+       {
+               BAD3,
+               NULL,
+               UNESCAPE_ERR,
+               0,
+               0,
+               sizeof(BAD3) - 1,
+       },
+#define BAD4 "bad characters %1 "
+       {
+               BAD4,
+               NULL,
+               UNESCAPE_ERR,
+               0,
+               0,
+               sizeof(BAD4) - 1,
+       },
+#define BAD5 "bad characters %1- "
+       {
+               BAD5,
+               NULL,
+               UNESCAPE_ERR,
+               0,
+               0,
+               sizeof(BAD5) - 1,
+       },
+#define BAD6 "bad characters %1G "
+       {
+               BAD6,
+               NULL,
+               UNESCAPE_ERR,
+               0,
+               0,
+               sizeof(BAD6) - 1,
+       },
+#define BAD7 "bad characters %%1 "
+       {
+               BAD7,
+               NULL,
+               UNESCAPE_ERR,
+               0,
+               0,
+               sizeof(BAD7) - 1,
+       },
+#define BAD8 "bad characters %sb "
+       {
+               BAD8,
+               NULL,
+               UNESCAPE_ERR,
+               0,
+               0,
+               sizeof(BAD8) - 1,
+       },
+#define BAD_SSCANF "sscanf would be happy with this\n"
+#define BAD_SSCANF_ESC "sscanf would be happy with this% a"
+       {
+               BAD_SSCANF_ESC,
+               BAD_SSCANF,
+               ESCAPE_NE | UNESCAPE_ERR,
+               sizeof(BAD_SSCANF) - 1,
+               sizeof(BAD_SSCANF) - 1,
+               sizeof(BAD_SSCANF_ESC) - 1,
+       },
+       /* now try some with zeros in. escaping can't see past zeros, and the result is truncated */
+#define ZERO "%00"
+#define ZERO_UNESC "\0"
+       {
+               ESCAPE4 ZERO ESCAPE4,
+               ESCAPE4_UNESC ZERO_UNESC ESCAPE4_UNESC,
+               ESCAPE_NE | UNESCAPE_EQ,
+               sizeof(ESCAPE4_UNESC ZERO_UNESC ESCAPE4_UNESC) - 1,
+               sizeof(ESCAPE4_UNESC) - 1,
+               sizeof(ESCAPE4 ZERO ESCAPE4) - 1,
+       },
+       {
+               ZERO ESCAPE4,
+               ZERO_UNESC ESCAPE4_UNESC,
+               ESCAPE_NE | UNESCAPE_EQ,
+               sizeof(ZERO_UNESC ESCAPE4_UNESC) - 1,
+               0,
+               sizeof(ZERO ESCAPE4) - 1,
+       },
+       {
+               ZERO,
+               ZERO_UNESC,
+               ESCAPE_NE | UNESCAPE_EQ,
+               sizeof(ZERO_UNESC) - 1,
+               0,
+               sizeof(ZERO) - 1,
+       },
+       {
+               spectrum_escaped,
+               spectrum,
+               ESCAPE_EQ | UNESCAPE_EQ,
+               255,
+               255,
+               255 * 3,
+       },
+};
+
+static struct rfc1738_test * dup_test(struct rfc1738_test *src)
+{
+       struct rfc1738_test *dest = malloc(sizeof(*dest));
+       char *esc = NULL, *unesc = NULL;
+       if (dest == NULL) {
+               return NULL;
+       }
+       *dest = *src;
+       if (src->esc_len) {
+               esc = malloc(src->esc_len + 1);
+               if (esc == NULL) {
+                       free(dest);
+                       return NULL;
+               }
+               memcpy(esc, src->escaped, src->esc_len + 1);
+               dest->escaped = esc;
+       }
+
+       if (src->unesc_len) {
+               unesc = malloc(src->unesc_len + 1);
+               if (unesc == NULL) {
+                       free(esc);
+                       free(dest);
+                       return NULL;
+               }
+               memcpy(unesc, src->unescaped, src->unesc_len + 1);
+               dest->unescaped = unesc;
+       }
+
+       return dest;
+}
+
+static void free_test(struct rfc1738_test *t)
+{
+       free(discard_const_p(char, t->escaped));
+       free(discard_const_p(char, t->unescaped));
+       free(t);
+}
+
+
+static void test_unescape(void **state)
+{
+       uint i;
+       char *s, *e;
+       struct rfc1738_test *test, *orig;
+       for (i = 0; i < ARRAY_SIZE(examples); i++) {
+               orig = &examples[i];
+               if ((orig->flags & (UNESCAPE_ERR |
+                                   UNESCAPE_EQ |
+                                   UNESCAPE_NE)) == 0) {
+                       continue;
+               }
+               test = dup_test(&examples[i]);
+               s = discard_const_p(char, test->escaped);
+               e = rfc1738_unescape(s);
+               if (test->flags & UNESCAPE_ERR) {
+                       assert_null(e);
+                       free_test(test);
+                       continue;
+               }
+               assert_non_null(e);
+               assert_int_equal(e - s, test->unesc_len);
+
+               if (test->flags & UNESCAPE_EQ) {
+                       assert_memory_equal(s,
+                                           orig->unescaped,
+                                           orig->unesc_len);
+                       assert_int_equal(strlen(s),
+                                        orig->unesc_strlen);
+               } else {
+                       assert_memory_not_equal(s,
+                                               orig->unescaped,
+                                               orig->unesc_len);
+                       assert_int_equal(strlen(s),
+                                        orig->unesc_strlen);
+               }
+               free_test(test);
+       }
+}
+
+static void test_escape(void **state)
+{
+       uint i;
+       char *s, *e;
+       struct rfc1738_test *test, *orig;
+       for (i = 0; i < ARRAY_SIZE(examples); i++) {
+               orig = &examples[i];
+               if ((orig->flags & (ESCAPE_EQ |
+                                   ESCAPE_EQ_CASECMP |
+                                   ESCAPE_NE)) == 0) {
+                       continue;
+               }
+               test = dup_test(&examples[i]);
+               s = discard_const_p(char, test->unescaped);
+               e = rfc1738_escape_part(NULL, s);
+               if (test->flags & ESCAPE_EQ) {
+                       assert_memory_equal(e, test->escaped,
+                                           test->esc_len + 1);
+               } else if (test->flags & ESCAPE_EQ_CASECMP) {
+                       int cmp = strcasecmp(e, test->escaped);
+                       assert_int_equal(cmp, 0);
+                       assert_string_not_equal(e, test->escaped);
+               } else {
+                       assert_string_not_equal(e, test->escaped);
+               }
+               free_test(test);
+       }
+}
+
+
+static void gen_spectrum(void)
+{
+       int i, j = 0;
+       const char *lut = "0123456789ABCDEF";
+       for (i = 1; i < 256; i++) {
+               spectrum[i - 1] = i;
+               if (isalnum(i) ||
+                   i == '-'   ||
+                   i == '.'   ||
+                   i == '_'   ||
+                   i == '-'   ||
+                   i == '~') {
+                       spectrum_escaped[j] = i;
+                       j++;
+               } else {
+                       spectrum_escaped[j] = '%';
+                       spectrum_escaped[j + 1] = lut[i >> 4];
+                       spectrum_escaped[j + 2] = lut[i & 15];
+                       j += 3;
+               }
+       }
+       spectrum[i - 1] = '\0';
+       spectrum_escaped[j] = '\0';
+}
+
+int main(int argc, const char **argv)
+{
+       const struct CMUnitTest tests[] = {
+               cmocka_unit_test(test_escape),
+               cmocka_unit_test(test_unescape),
+       };
+
+       gen_spectrum();
+       cmocka_set_message_output(CM_OUTPUT_SUBUNIT);
+       return cmocka_run_group_tests(tests, NULL, NULL);
+}
index 8dbe1636e3bfd1f0886c08148e59dea88ba44b85..d49d4a2fc68dcbe34bf8438cd88058de456faaf8 100644 (file)
@@ -216,3 +216,9 @@ else:
                         source='util_str_hex.c',
                         deps='talloc',
                         local_include=False)
+
+    bld.SAMBA_BINARY('test_rfc1738',
+                     source='tests/rfc1738.c',
+                     deps='cmocka replace samba-util',
+                     local_include=False,
+                     install=False)
diff --git a/selftest/knownfail.d/rfc1738 b/selftest/knownfail.d/rfc1738
new file mode 100644 (file)
index 0000000..6ff17bd
--- /dev/null
@@ -0,0 +1 @@
+^samba.unittests.rfc1738
index 4e6b8957c0363a5e3c95da44dba0c02f9fb23cd7..1c6921af0ca12dfd003dd53263b9f472c5fb34cc 100644 (file)
@@ -182,3 +182,5 @@ plantestsuite("samba.unittests.smb1cli_session", "none",
 
 plantestsuite("samba.unittests.tldap", "none",
               [os.path.join(bindir(), "default/source3/test_tldap")])
+plantestsuite("samba.unittests.rfc1738", "none",
+              [os.path.join(bindir(), "default/lib/util/test_rfc1738")])