]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
Added str_find_get_match_end_pos(). Added unit testing.
authorTimo Sirainen <tss@iki.fi>
Tue, 31 Mar 2009 21:34:28 +0000 (17:34 -0400)
committerTimo Sirainen <tss@iki.fi>
Tue, 31 Mar 2009 21:34:28 +0000 (17:34 -0400)
--HG--
branch : HEAD

src/lib/str-find.c
src/lib/str-find.h
src/tests/test-lib.c

index effd88ecc688011eb27e1f1aa8b107bbbc99d39b..66b8cd33b083201d2f944d1627e257679d9c10ac 100644 (file)
@@ -13,6 +13,8 @@ struct str_find_context {
        unsigned int *matches;
        unsigned int match_count;
 
+       size_t match_end_pos;
+
        int badtab[UCHAR_MAX+1];
        int goodtab[FLEXIBLE_ARRAY_MEMBER];
 };
@@ -79,6 +81,8 @@ struct str_find_context *str_find_init(pool_t pool, const char *key)
        struct str_find_context *ctx;
        unsigned int key_len = strlen(key);
 
+       i_assert(key_len > 0);
+
        ctx = p_malloc(pool, sizeof(struct str_find_context) +
                       sizeof(ctx->goodtab[0]) * key_len);
        ctx->pool = pool;
@@ -118,8 +122,10 @@ bool str_find_more(struct str_find_context *ctx,
                                        break;
                        }
 
-                       if (a == key_len)
+                       if (a == key_len) {
+                               ctx->match_end_pos = key_len - ctx->matches[i];
                                return TRUE;
+                       }
                } else {
                        for (b = 0; b < size; b++) {
                                if (ctx->key[a+b] != data[b])
@@ -140,8 +146,10 @@ bool str_find_more(struct str_find_context *ctx,
                while (j + key_len <= size) {
                        i = key_len - 1;
                        while (ctx->key[i] == data[i + j]) {
-                               if (i == 0)
+                               if (i == 0) {
+                                       ctx->match_end_pos = j + key_len;
                                        return TRUE;
+                               }
                                i--;
                        }
 
@@ -163,6 +171,11 @@ bool str_find_more(struct str_find_context *ctx,
        return FALSE;
 }
 
+size_t str_find_get_match_end_pos(struct str_find_context *ctx)
+{
+       return ctx->match_end_pos;
+}
+
 void str_find_reset(struct str_find_context *ctx)
 {
        ctx->match_count = 0;
index 2c9bf0ce374b5c0c7ff3180c942f57b23ab958f3..9ab8f37830d7ac7a9fbeb3a6b067c006a0817a14 100644 (file)
@@ -10,6 +10,9 @@ void str_find_deinit(struct str_find_context **ctx);
    blocks and have the key still match. */
 bool str_find_more(struct str_find_context *ctx,
                   const unsigned char *data, size_t size);
+/* After str_find_more() has returned TRUE, this function returns the end
+   position in the previous data block where the key had matched. */
+size_t str_find_get_match_end_pos(struct str_find_context *ctx);
 /* Reset input data. The next str_find_more() call won't try to match the key
    to earlier data. */
 void str_find_reset(struct str_find_context *ctx);
index ad35496f6872f572c611227b23a83f15715d6a92..f937fc7623105c4c9b5434087e07b2030dd9ff68 100644 (file)
@@ -10,6 +10,7 @@
 #include "primes.h"
 #include "priorityq.h"
 #include "seq-range-array.h"
+#include "str-find.h"
 #include "str-sanitize.h"
 #include "utc-mktime.h"
 
@@ -725,6 +726,86 @@ static void test_seq_range_array(void)
        test_seq_range_array_random();
 }
 
+static const char *str_find_text = "xababcd";
+
+static bool test_str_find_substring(const char *key, int expected_pos)
+{
+       const unsigned char *text = (const unsigned char *)str_find_text;
+       const unsigned int text_len = strlen(str_find_text);
+       struct str_find_context *ctx;
+       unsigned int i, j, pos, max, offset;
+       bool ret;
+
+       ctx = str_find_init(pool_datastack_create(), key);
+       /* divide text into every possible block combination and test that
+          it matches */
+       max = 1 << (text_len-1);
+       for (i = 0; i < max; i++) {
+               str_find_reset(ctx);
+               pos = 0; offset = 0; ret = FALSE;
+               for (j = 0; j < text_len; j++) {
+                       if ((i & (1 << j)) != 0) {
+                               if (str_find_more(ctx, text+pos, j-pos+1)) {
+                                       ret = TRUE;
+                                       break;
+                               }
+                               offset += j-pos + 1;
+                               pos = j + 1;
+                       }
+               }
+               if (pos != text_len && !ret) {
+                       if (str_find_more(ctx, text+pos, j-pos))
+                               ret = TRUE;
+               }
+               if (expected_pos < 0) {
+                       if (ret)
+                               return FALSE;
+               } else {
+                       if (!ret)
+                               return FALSE;
+
+                       pos = str_find_get_match_end_pos(ctx) +
+                               offset - strlen(key);
+                       if ((int)pos != expected_pos)
+                               return FALSE;
+               }
+       }
+       return TRUE;
+}
+
+struct str_find_input {
+       const char *str;
+       int pos;
+};
+static void test_str_find(void)
+{
+       static const char *fail_input[] = {
+               "xabc",
+               "xabd",
+               "abd"
+       };
+       unsigned int idx, len;
+       const char *key, *p;
+       unsigned int i;
+       bool success = TRUE;
+
+       for (idx = 0; idx < strlen(str_find_text); idx++) {
+               for (len = strlen(str_find_text)-idx; len > 0; len--) {
+                       /* we'll get a search key for all substrings of text */
+                       T_BEGIN {
+                               key = t_strndup(str_find_text + idx, len);
+                               p = strstr(str_find_text, key);
+                               success = test_str_find_substring(key, p - str_find_text);
+                       } T_END;
+                       if (!success)
+                               break;
+               }
+       }
+       for (i = 0; i < N_ELEMENTS(fail_input) && success; i++)
+               success = test_str_find_substring(fail_input[i], -1);
+       test_out("str_find()", success);
+}
+
 struct str_sanitize_input {
        const char *str;
        unsigned int max_len;
@@ -832,6 +913,7 @@ int main(void)
                test_primes,
                test_priorityq,
                test_seq_range_array,
+               test_str_find,
                test_str_sanitize,
                test_utc_mktime,