terom@15: terom@15: #include terom@15: #include terom@15: #include terom@15: terom@15: #include "lib/url.h" terom@15: terom@16: #define FAIL(...) do { printf("FAIL: "); printf(__VA_ARGS__); printf("\n"); return -1; } while (0) terom@15: terom@17: struct url_schema terom@17: basic_http = { 1, { "http" } }, terom@18: svn_ssh = { 2, { "svn", "ssh" } }, terom@18: schema_unix = { 1, { "unix" } } terom@18: ; terom@18: terom@18: struct url_opts terom@18: opts_single = { 1, { { "key0", "val0" } } }, terom@18: opts_multi = { 2, { { "key0", "val0" }, { "key1", "val1" } } }, terom@18: opts_nullval = { 1, { { "keyN", NULL } } } terom@18: ; terom@15: terom@15: struct url_test { terom@15: const char *url; terom@15: const struct url expected; terom@15: } url_tests[] = { terom@15: { "localhost:http", { terom@15: NULL, NULL, NULL, "localhost", "http", NULL, NULL terom@15: } }, terom@15: terom@16: { "http://example.com/path", { terom@16: &basic_http, NULL, NULL, "example.com", NULL, "path", NULL terom@16: } }, terom@17: terom@17: { "svn+ssh://user:passwd@someplace:someport/something", { terom@17: &svn_ssh, "user", "passwd", "someplace", "someport", "something" terom@17: } }, terom@17: terom@17: { "user@:service/", { terom@17: NULL, "user", NULL, NULL, "service", NULL terom@17: } }, terom@18: terom@18: { "unix:////tmp/foo.sock", { terom@18: &schema_unix, NULL, NULL, NULL, NULL, "/tmp/foo.sock" terom@18: } }, terom@18: terom@18: { "unix:///tmp/foo.sock", { terom@18: &schema_unix, NULL, NULL, NULL, NULL, "tmp/foo.sock" terom@18: } }, terom@18: terom@18: { "/tmp/foo.sock", { terom@18: NULL, NULL, NULL, NULL, NULL, "tmp/foo.sock" terom@18: } }, terom@18: terom@18: { "?key0=val0", { terom@18: NULL, NULL, NULL, NULL, NULL, NULL, &opts_single terom@18: } }, terom@18: terom@18: { "http://foo.com/index.php?key0=val0&key1=val1", { terom@18: &basic_http, NULL, NULL, "foo.com", NULL, "index.php", &opts_multi terom@18: } }, terom@18: terom@18: { "example.org:81/?keyN", { terom@18: NULL, NULL, NULL, "example.org", "81", NULL, &opts_nullval terom@18: } }, terom@18: terom@15: { NULL, { } }, terom@15: }; terom@15: terom@15: int cmp_url_str (const char *field, const char *test, const char *real) { terom@15: if (!test) { terom@15: if (real) terom@16: FAIL("%s shouldn't be present", field); terom@15: terom@15: } else if (!real) { terom@16: FAIL("%s is missing", field); terom@15: terom@15: } else { terom@15: if (strcmp(test, real) != 0) terom@16: FAIL("%s differs: %s -> %s", field, test, real); terom@15: } terom@15: terom@15: // ok terom@15: return 0; terom@15: } terom@15: terom@15: int cmp_url (const struct url *test, const struct url *real) { terom@15: int i; terom@15: terom@15: // test schema terom@15: if (!test->schema) { terom@15: if (real->schema) terom@15: FAIL("test has no schema, but real does"); terom@15: terom@15: } else if (!real->schema) { terom@15: FAIL("test has a schema, but real doesn't"); terom@15: terom@15: } else { terom@15: if (test->schema->count != test->schema->count) terom@15: FAIL("inconsistent scheme count"); terom@15: terom@15: for (i = 0; i < test->schema->count; i++) { terom@15: if (strcmp(test->schema->list[i], real->schema->list[i]) != 0) terom@15: FAIL("differing scheme #%d", i); terom@15: } terom@15: } terom@15: terom@15: // test username terom@15: if (cmp_url_str("username", test->username, real->username)) terom@15: goto error; terom@15: terom@15: // test password terom@15: if (cmp_url_str("password", test->password, real->password)) terom@15: goto error; terom@15: terom@15: // test hostname terom@15: if (cmp_url_str("hostname", test->hostname, real->hostname)) terom@15: goto error; terom@15: terom@15: // test service terom@15: if (cmp_url_str("service", test->service, real->service)) terom@15: goto error; terom@15: terom@15: // test path terom@15: if (cmp_url_str("path", test->path, real->path)) terom@15: goto error; terom@15: terom@15: // test query terom@15: if (!test->opts) { terom@15: if (real->opts) terom@15: FAIL("test has no opts, but real does"); terom@15: terom@15: } else if (!real->opts) { terom@15: FAIL("test has opts, but real doesn't"); terom@15: terom@15: } else { terom@15: if (test->opts->count != test->opts->count) terom@15: FAIL("inconsistent opts count"); terom@15: terom@15: for (i = 0; i < test->opts->count; i++) { terom@18: if (cmp_url_str("opt key", test->opts->list[i].key, real->opts->list[i].key)) terom@18: FAIL("differing opt key #%d", i); terom@15: terom@18: if (cmp_url_str("opt value", test->opts->list[i].value, real->opts->list[i].value)) terom@18: FAIL("differing opt value #%d", i); terom@15: } terom@15: } terom@15: terom@15: // ok terom@15: return 0; terom@15: terom@15: error: terom@15: return -1; terom@15: } terom@15: terom@15: void usage (const char *exec_name) { terom@15: printf("Usage: %s\n\n\tNo arguments are accepted\n", exec_name); terom@15: terom@15: exit(EXIT_FAILURE); terom@15: } terom@15: terom@15: int main (int argc, char **argv) { terom@15: const struct url_test *test; terom@15: struct url url; terom@15: terom@15: if (argc > 1) terom@15: usage(argv[0]); terom@15: terom@15: // run the tests terom@15: for (test = url_tests; test->url; test++) { terom@15: // first output the URL we are handling... terom@16: printf("%-80s - ", test->url); terom@15: fflush(stdout); terom@15: terom@15: // parse the URL terom@15: memset(&url, 0, sizeof(url)); terom@15: terom@15: if (url_parse(&url, test->url)) { terom@15: printf("FATAL: url_parse failed\n"); terom@15: return EXIT_FAILURE; terom@15: } terom@15: terom@15: // compare it terom@15: if (cmp_url(&test->expected, &url)) { terom@15: printf("\texpected: "); terom@16: url_dump(&test->expected, stdout); terom@15: terom@15: printf("\tresult: "); terom@16: url_dump(&url, stdout); terom@15: terom@15: } else { terom@15: printf("OK\n\t"); terom@16: url_dump(&url, stdout); terom@15: } terom@18: terom@18: printf("\n"); terom@15: } terom@15: } terom@15: