#include <assert.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include "idl/string.h"
#include "file.h"
#include "CUnit/Theory.h"
#define ok (IDL_RETCODE_OK)
#define bad_param (IDL_RETCODE_BAD_PARAMETER)
#if _WIN32
# define ROOT "C:\\"
# define SEP "\\"
#else
# define ROOT "/"
# define SEP "/"
#endif
static char *prefix = NULL;
CU_Init(idl_file)
{
idl_current_path(&prefix);
return 0;
}
CU_Clean(idl_file)
{
if (prefix)
free(prefix);
return 0;
}
struct scrub_test {
const char *input;
const char *output;
const int8_t length;
};
const struct scrub_test tests[] = {
{ ROOT "..", "", -1 },
{ ROOT "/..", "", -1 },
{ ROOT "//..", "", -1 },
{ ROOT "a/../..", "", -1 },
{ ROOT "/a//..//..", "", -1 },
{ ROOT "//a///..///..", "", -1 },
{ "", "", 0 },
{ ".", "", 0 },
{ "./", "", 0 },
{ ".//", "", 0 },
{ ".///", "", 0 },
{ "././", "", 0 },
{ ".//.//", "", 0 },
{ ".///.///", "", 0 },
{ "..", "..", 2 },
{ "../", "..", 2 },
{ "..//", "..", 2 },
{ "..///", "..", 2 },
{ "./..", "..", 2 },
{ ".//..", "..", 2 },
{ ".///..", "..", 2 },
{ ".///..///", "..", 2 },
{ "../..", ".." SEP "..", 5 },
{ "..//..", ".." SEP "..", 5 },
{ "..///..", ".." SEP "..", 5 },
{ "../../../", ".." SEP ".." SEP "..", 8 },
{ ROOT , ROOT, 1 },
{ ROOT "/", ROOT, 1 },
{ ROOT "//", ROOT, 1 },
{ ROOT ".", ROOT, 1 },
{ ROOT "/.", ROOT, 1 },
{ ROOT "//.", ROOT, 1 },
{ ROOT "./", ROOT, 1 },
{ ROOT "/.//", ROOT, 1 },
{ ROOT "//.///", ROOT, 1 },
{ "a/..", "", 0 },
{ "a//..", "", 0 },
{ "a///..", "", 0 },
{ "a/b/../..", "", 0 },
{ "a//b//..//..", "", 0 },
{ "a///b///..///..", "", 0 },
{ "a/../b/..", "", 0 },
{ "a//..//b//..", "", 0 },
{ "a///..///b///..", "", 0 },
{ "a/./.././b", "b", 1 },
{ "a//.//..//.//b", "b", 1 },
{ "a///.///..///.///b", "b", 1 },
{ "ab/./.././cd", "cd", 2 },
{ "ab//.//..//.//cd", "cd", 2 },
{ "ab///.///..///.///cd", "cd", 2 },
{ "abc/./.././def", "def", 3 },
{ "abc//.//..//.//def", "def", 3 },
{ "abc///.///..///.///def", "def", 3 },
{ ROOT "a/..", ROOT, 1 },
{ ROOT "/a//..", ROOT, 1 },
{ ROOT "//a///..", ROOT, 1 },
{ ROOT "a/b/../..", ROOT, 1 },
{ ROOT "/a//b//..//..", ROOT, 1 },
{ ROOT "//a///b///..///..", ROOT, 1 },
{ ROOT "a/../b/..", ROOT, 1 },
{ ROOT "/a//..//b//..", ROOT, 1 },
{ ROOT "//a///..///b///..", ROOT, 1 },
{ ROOT "ab/./.././cd", ROOT "cd", 3 },
{ ROOT "/ab//.//..//.//cd", ROOT "cd", 3 },
{ ROOT "//ab///.///..///.///cd", ROOT "cd", 3 },
{ ROOT "abc/./.././def", ROOT "def", 4 },
{ ROOT "/abc//.//..//.//def", ROOT "def", 4 },
{ ROOT "//abc///.///..///.///def", ROOT "def", 4 }
};
CU_Test(idl_file, untaint)
{
const size_t n = sizeof(tests) / sizeof(tests[0]);
for (size_t i=0; i < n; i++) {
char *str;
size_t len;
idl_retcode_t rc;
str = idl_strdup(tests[i].input);
CU_ASSERT_NEQ_FATAL (str, NULL);
fprintf(stderr, "input: '%s'\n", str);
rc = idl_untaint_path(str, &len);
if (tests[i].length == -1) {
CU_ASSERT_EQ (rc, IDL_RETCODE_BAD_PARAMETER);
} else {
CU_ASSERT_EQ (len, strlen(tests[i].output));
}
if (rc == IDL_RETCODE_OK) {
fprintf(stderr, "output: '%s'\n", str);
CU_ASSERT_STREQ (str, tests[i].output);
}
free(str);
}
}
CU_Test(idl_file, normalize_empty)
{
idl_retcode_t ret;
char *norm = NULL;
ret = idl_normalize_path("", &norm);
CU_ASSERT_GEQ_FATAL (ret, 0);
CU_ASSERT_NEQ_FATAL (norm, NULL);
assert(prefix);
fprintf(stderr, "path: %s\nexpect: %s\nnormalized: %s\n", prefix, prefix, norm);
CU_ASSERT_STREQ (norm, prefix);
free(norm);
}
CU_Test(idl_file, normalize_revert)
{
idl_retcode_t ret;
char *norm = NULL, *path = NULL;
(void) idl_asprintf(&path, "%s/..", prefix);
CU_ASSERT_NEQ_FATAL (path, NULL);
ret = idl_normalize_path(path, &norm);
CU_ASSERT_GEQ_FATAL (ret, 0);
CU_ASSERT_NEQ_FATAL (norm, NULL);
fprintf(stderr, "path: %s\n", path);
{ size_t sep = 0;
for (size_t i=0,n=strlen(prefix); i < n; i++) {
if (idl_isseparator(path[i]))
sep = i;
}
CU_ASSERT_NEQ_FATAL (sep, 0);
path[sep] = '\0';
}
fprintf(stderr, "expect: %s\nnormalized: %s\n", path, norm);
CU_ASSERT_STREQ (path, norm);
free(path);
free(norm);
}
CU_Test(idl_file, normalize_revert_too_many)
{
idl_retcode_t ret;
size_t size, step, steps = 1;
char *revert = NULL, *path = NULL, *norm = NULL;
fprintf(stderr, "prefix: %s\n", prefix);
for (size_t i=0; prefix[i]; i++)
steps += idl_isseparator(prefix[i]);
step = sizeof("/..") - 1;
size = steps * step;
revert = malloc(size + 1);
CU_ASSERT_NEQ_FATAL (revert, NULL);
for (size_t i=0; i < steps; i++)
memcpy(revert + (i*step), "/..", step);
revert[size] = '\0';
fprintf(stderr, "revert: %s\n", revert);
path = NULL;
(void) idl_asprintf(&path, "%s%s", prefix, revert);
CU_ASSERT_NEQ_FATAL (path, NULL);
fprintf(stderr, "path: %s\n", path);
norm = NULL;
ret = idl_normalize_path(path, &norm);
CU_ASSERT_EQ (ret, IDL_RETCODE_BAD_PARAMETER);
CU_ASSERT_EQ (norm, NULL);
free(revert);
free(path);
if (norm)
free(norm);
}
struct relative_test {
const char *base;
const char *path;
const char *relpath;
idl_retcode_t retcode;
};
static struct relative_test relative_bad_params_tests[] = {
{ "", ROOT "foo", NULL, bad_param },
{ ".", ROOT "foo", NULL, bad_param },
{ "./", ROOT "foo", NULL, bad_param },
{ ROOT ".", ROOT "foo", NULL, bad_param },
{ ROOT "./", ROOT "foo", NULL, bad_param },
{ "./foo/bar", ROOT "foo", NULL, bad_param },
{ ROOT "foo/./bar", ROOT "foo", NULL, bad_param },
{ ROOT "foo/bar/.", ROOT "foo", NULL, bad_param },
{ "..", ROOT "foo", NULL, bad_param },
{ "../", ROOT "foo", NULL, bad_param },
{ ROOT "..", ROOT "foo", NULL, bad_param },
{ "../foo/bar", ROOT "foo", NULL, bad_param },
{ ROOT "foo/../bar", ROOT "foo", NULL, bad_param },
{ ROOT "foo/bar/..", ROOT "foo", NULL, bad_param }
};
CU_Test(idl_file, relative_bad_params)
{
idl_retcode_t ret;
char *rel;
struct relative_test *t = relative_bad_params_tests;
size_t n = sizeof(relative_bad_params_tests)/sizeof(relative_bad_params_tests[0]);
for (size_t i=0; i < n; i++) {
const char *base, *path;
for (size_t j=0; j < 2; j++) {
rel = NULL;
base = j ? t[i].path : t[i].base;
path = j ? t[i].base : t[i].path;
fprintf(stderr, "base: %s\n", base);
fprintf(stderr, "path: %s\n", path);
ret = idl_relative_path(base, path, &rel);
fprintf(stderr, "relative: %s\n", rel ? rel : "-");
CU_ASSERT_EQ_FATAL (ret, bad_param);
CU_ASSERT_EQ (rel, NULL);
if (rel)
free(rel);
}
}
}
static struct relative_test relative_tests[] = {
{ ROOT "", ROOT "", "", ok },
{ ROOT "f/o/o", ROOT "", ".." SEP ".." SEP "..", ok },
{ ROOT "", ROOT "f/o/o", "f" SEP "o" SEP "o", ok },
{ ROOT "f/o/o", ROOT "b/a/r", ".." SEP ".." SEP ".." SEP "b" SEP "a" SEP "r", ok },
{ ROOT "f/o/o", ROOT "f/o", "..", ok },
{ ROOT "f/oo", ROOT "f/o", ".." SEP "o", ok },
{ ROOT "f/o", ROOT "f/o", "", ok },
{ ROOT "f/o", ROOT "f/oo", ".." SEP "oo", ok },
{ ROOT "f/o", ROOT "f/o/o", "o", ok },
{ ROOT "foo/bar", ROOT "foo/baz", ".." SEP "baz", ok },
{ ROOT "f//o///o////", ROOT "f////o///o//", "", ok },
{ ROOT "f/o//o///", ROOT "f///o//o/", "", ok },
{ ROOT "b/a//r///", ROOT "b/a/r", "", ok },
{ ROOT "b//a//r", ROOT "b/a/r", "", ok },
{ ROOT "b/a//r///", ROOT "b/a/z", ".." SEP "z", ok }
};
CU_Test(idl_file, relative)
{
idl_retcode_t ret;
char *rel;
struct relative_test *t = relative_tests;
size_t n = sizeof(relative_tests)/sizeof(relative_tests[0]);
for (size_t i=0; i < n; i++) {
rel = NULL;
fprintf(stderr, "base: '%s'\n", t[i].base);
fprintf(stderr, "path: '%s'\n", t[i].path);
ret = idl_relative_path(t[i].base, t[i].path, &rel);
CU_ASSERT_EQ (ret, t[i].retcode);
if (rel)
fprintf(stderr, "relative: '%s'\n", rel);
if (t[i].relpath) {
CU_ASSERT_NEQ_FATAL (rel, NULL);
CU_ASSERT_STREQ (t[i].relpath, rel);
} else {
CU_ASSERT_EQ (rel, NULL);
}
if (rel)
free(rel);
}
}
typedef struct out_file_test{
const char *path;
const char *output_dir;
const char *base_dir;
const char *out_ext;
idl_retcode_t ret;
const char *expected_out;
} out_file_test_t;
static void test_out_file(const out_file_test_t test)
{
char *out = NULL;
idl_retcode_t ret = idl_generate_out_file(test.path, test.output_dir, test.base_dir, test.out_ext, &out, true);
CU_ASSERT_EQ (ret, test.ret);
if(ret != IDL_RETCODE_BAD_PARAMETER){
CU_ASSERT_STREQ (out, test.expected_out);
}
if (out)
free(out);
}
CU_Test(idl_file, out_file_generation)
{
const out_file_test_t out_tests[] = {
{"a/b.idl", NULL, NULL, NULL, IDL_RETCODE_OK, "a/b"},
{"a/b.idl", NULL, NULL, "c", IDL_RETCODE_OK, "a/b.c"},
{"a/b.idl", "c", NULL, NULL, IDL_RETCODE_OK, "c/a/b"},
{ROOT"a/b.idl", NULL, ROOT"a", "c", IDL_RETCODE_OK, "b.c"},
{ROOT"a/b.idl", "f", ROOT"a", "c", IDL_RETCODE_OK, "f/b.c"},
{ROOT"a/b.idl", NULL, NULL, NULL, IDL_RETCODE_OK, "b"},
{ROOT"a/b.idl", NULL, NULL, "c", IDL_RETCODE_OK, "b.c"},
{"a/b.idl", "c", NULL, NULL, IDL_RETCODE_OK, "c/a/b"},
{ROOT"a/b.idl", "c", NULL, NULL, IDL_RETCODE_OK, "c/b"},
{"a/b.idl", ROOT"c", NULL, NULL, IDL_RETCODE_OK, ROOT"c/a/b"},
{"a/b/c.idl", "..", NULL, NULL, IDL_RETCODE_OK, "../a/b/c"},
{"a/b/c.idl", "../d", NULL, NULL, IDL_RETCODE_OK, "../d/a/b/c"},
{"a/b/c.idl", ".", NULL, NULL, IDL_RETCODE_OK, "./a/b/c"},
{ROOT"a/b/c/file.idl", ".", ROOT"a/b/", NULL, IDL_RETCODE_OK, "./c/file"},
{ROOT"a/b/c/file.idl", "..", ROOT"a/b/", "h", IDL_RETCODE_OK, "../c/file.h"},
{ROOT"a/b/c/file.idl", ".", ROOT"a/b/", NULL, IDL_RETCODE_OK, "./c/file"},
{ROOT"a/b/c/file.idl", NULL, ROOT"a/b/", NULL, IDL_RETCODE_OK, "c/file"},
{ROOT"a/b/c/file.idl", ".", ROOT"a/b/d/", NULL, IDL_RETCODE_BAD_PARAMETER, "./c/file"},
{ROOT"a/b/c/file.idl", NULL, ROOT"a/b/d/", NULL, IDL_RETCODE_BAD_PARAMETER, "c/file"}
};
for (size_t i = 0; i < sizeof(out_tests)/sizeof(out_tests[0]); i++)
test_out_file(out_tests[i]);
}