#include #include #include #include #include #include "kmp.h" #include "c-tap-test.h" /* Consistently initialise a content type. */ #define FC(x,s) fc_t x = { \ .contents = (unsigned char *) s, \ .len = strlen (s), \ } /* Test it doesn't blow up on one-byte search strings. */ static void short_test () { kmp_result_t * results; kmp_result_t * r; kmp_t sho = { .needle = (unsigned char *) "a", .length = 1, }; FC(fc, "I wandered lonely as a cloud"); printf ("# Test with one-byte search.\n"); TAP_TEST_EQUAL (kmp_make_table (& sho), kmp_status_ok); TAP_TEST_EQUAL (kmp_search (& fc, & sho, & results), kmp_status_ok); r = results; TAP_TEST_EQUAL (r->line, 1); TAP_TEST_EQUAL (r->offset, 3); r = r->next; TAP_TEST_EQUAL (r->line, 1); TAP_TEST_EQUAL (r->offset, 18); r = r->next; TAP_TEST_EQUAL (r->line, 1); TAP_TEST_EQUAL (r->offset, 21); TAP_TEST_EQUAL (r->next, 0); TAP_TEST_EQUAL (kmp_free (& sho), kmp_status_ok); TAP_TEST_EQUAL (kmp_result_free (results), kmp_status_ok); } /* Test that it can match subsequent identical strings with no gap. */ static void close_test () { kmp_result_t * results; kmp_result_t * r; kmp_t sho = { .needle = (unsigned char *) "ill", .length = 3, }; FC(fc, "illillillbillfillill"); printf ("# Test with repetitive text.\n"); TAP_TEST_EQUAL (kmp_make_table (& sho), kmp_status_ok); TAP_TEST_EQUAL (kmp_search (& fc, & sho, & results), kmp_status_ok); r = results; TAP_TEST_EQUAL (r->line, 1); TAP_TEST_EQUAL (r->offset, 0); r = r->next; TAP_TEST_EQUAL (r->line, 1); TAP_TEST_EQUAL (r->offset, 3); r = r->next; TAP_TEST_EQUAL (r->line, 1); TAP_TEST_EQUAL (r->offset, 6); r = r->next; TAP_TEST_EQUAL (r->line, 1); TAP_TEST_EQUAL (r->offset, 10); r = r->next; TAP_TEST_EQUAL (r->line, 1); TAP_TEST_EQUAL (r->offset, 14); r = r->next; TAP_TEST_EQUAL (r->line, 1); TAP_TEST_EQUAL (r->offset, 17); TAP_TEST_EQUAL (r->next, 0); TAP_TEST_EQUAL (kmp_free (& sho), kmp_status_ok); TAP_TEST_EQUAL (kmp_result_free (results), kmp_status_ok); } /* Test the generation of line numbers. */ static void line_test () { kmp_result_t * results; kmp_result_t * r; kmp_t sho = { .needle = (unsigned char *) "il", .length = 2, }; FC(fc, "I wandered lonely as a cloud\n" "That floats on high o'er vales and hills,\n" "When all at once I saw a crowd,\n" "A host, of golden daffodils;\n" "Beside the lake, beneath the trees,\n" "Fluttering and dancing in the breeze.\n"); printf ("# Test line number counting.\n"); TAP_TEST_EQUAL (kmp_make_table (& sho), kmp_status_ok); TAP_TEST_EQUAL (kmp_search (& fc, & sho, & results), kmp_status_ok); r = results; TAP_TEST_EQUAL (r->line, 2); TAP_TEST_EQUAL (r->offset, 65); r = r->next; TAP_TEST_EQUAL (r->line, 4); TAP_TEST_EQUAL (r->offset, 127); TAP_TEST_EQUAL (r->next, 0); TAP_TEST_EQUAL (kmp_free (& sho), kmp_status_ok); TAP_TEST_EQUAL (kmp_result_free (results), kmp_status_ok); } /* Test what happens when the search string does not match. */ static void no_match_test () { kmp_result_t * results; kmp_t sho = { .needle = (unsigned char *) "monkey", .length = strlen ("monkey"), }; FC(fc, "I wandered lonely as a cloud\n"); printf ("# Test matching failure.\n"); TAP_TEST_EQUAL (kmp_make_table (& sho), kmp_status_ok); TAP_TEST_EQUAL (kmp_search (& fc, & sho, & results), kmp_status_ok); TAP_TEST_EQUAL (results, 0); TAP_TEST_EQUAL (kmp_free (& sho), kmp_status_ok); TAP_TEST_EQUAL (kmp_result_free (results), kmp_status_ok); } /* Test what happens when the search string is longer than the thing to search. */ static void too_short_test () { kmp_result_t * results; kmp_t sho = { .needle = (unsigned char *) "monkey", .length = strlen ("monkey"), }; FC(fc, "monke"); printf ("# Test mismatched string lengths.\n"); TAP_TEST_EQUAL (kmp_make_table (& sho), kmp_status_ok); TAP_TEST_EQUAL (kmp_search (& fc, & sho, & results), kmp_status_too_short); TAP_TEST_EQUAL (results, 0); TAP_TEST_EQUAL (kmp_free (& sho), kmp_status_ok); } /* Test the table comes out the same as in the Wikipedia example. */ static void table_test () { int i; kmp_t x = { .needle = (unsigned char *) "PARTICIPATE IN PARACHUTE", .length = strlen ("PARTICIPATE IN PARACHUTE"), }; int table[] = { -1, 0, 0, 0, 0, 0, 0, 0, 1, 2, 0, 0, 0, 0, 0, 0, 1, 2, 3, 0, 0, 0, 0, 0 }; printf ("# Test table construction from KMP's paper.\n"); TAP_TEST_EQUAL (kmp_make_table (& x), kmp_status_ok); for (i = 0; i < sizeof (table) / sizeof (int); i++) { TAP_TEST_EQUAL (x.table[i], table[i]); } TAP_TEST_EQUAL (kmp_free (& x), kmp_status_ok); } /* Run the tests then print a plan. */ int main () { short_test (); close_test (); line_test (); no_match_test (); too_short_test (); table_test (); TAP_PLAN; return 0; }