feat: add minimal path manipulation C module for internal VM use
Introduce a new `Path` struct and associated functions in `src/cli/path.c` and `src/cli/path.h` for resolving relative imports within the VM. The module provides operations such as normalization, directory extraction, extension removal, joining, and absolute path detection. Additionally, add a lightweight unit test framework under `test/unit/` with a `test.h`/`test.c` harness and `path_test.c` covering normalization cases. Update the build system (`Makefile`, `util/wren.mk`) to separate API tests from unit tests, rename the test executables to `api_wren` and `unit_wren`, and adjust CI targets and Python test scripts accordingly.
This commit is contained in:
@@ -0,0 +1,9 @@
|
||||
#include "path_test.h"
|
||||
#include "test.h"
|
||||
|
||||
int main()
|
||||
{
|
||||
testPath();
|
||||
|
||||
return showTestResults();
|
||||
}
|
||||
@@ -0,0 +1,105 @@
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "path.h"
|
||||
#include "test.h"
|
||||
|
||||
static void expectNormalize(const char* input, const char* expected)
|
||||
{
|
||||
Path* path = pathNew(input);
|
||||
Path* result = pathNormalize(path);
|
||||
|
||||
if (strcmp(result->chars, expected) != 0)
|
||||
{
|
||||
printf("FAIL %-30s Want %s\n", input, expected);
|
||||
printf(" Got %s\n\n", result->chars);
|
||||
fail();
|
||||
}
|
||||
else
|
||||
{
|
||||
#if SHOW_PASSES
|
||||
printf("PASS %-30s -> %s\n", input, result->chars);
|
||||
#endif
|
||||
pass();
|
||||
}
|
||||
|
||||
pathFree(path);
|
||||
pathFree(result);
|
||||
}
|
||||
|
||||
static void testNormalize()
|
||||
{
|
||||
// simple cases
|
||||
expectNormalize("", ".");
|
||||
expectNormalize(".", ".");
|
||||
expectNormalize("..", "..");
|
||||
expectNormalize("a", "a");
|
||||
expectNormalize("/", "/");
|
||||
|
||||
// collapses redundant separators
|
||||
expectNormalize("a/b/c", "a/b/c");
|
||||
expectNormalize("a//b///c////d", "a/b/c/d");
|
||||
|
||||
// eliminates "." parts
|
||||
expectNormalize("./", ".");
|
||||
expectNormalize("/.", "/");
|
||||
expectNormalize("/./", "/");
|
||||
expectNormalize("./.", ".");
|
||||
expectNormalize("a/./b", "a/b");
|
||||
expectNormalize("a/.b/c", "a/.b/c");
|
||||
expectNormalize("a/././b/./c", "a/b/c");
|
||||
expectNormalize("././a", "a");
|
||||
expectNormalize("a/./.", "a");
|
||||
|
||||
// eliminates ".." parts
|
||||
expectNormalize("..", "..");
|
||||
expectNormalize("../", "..");
|
||||
expectNormalize("../../..", "../../..");
|
||||
expectNormalize("../../../", "../../..");
|
||||
expectNormalize("/..", "/");
|
||||
expectNormalize("/../../..", "/");
|
||||
expectNormalize("/../../../a", "/a");
|
||||
expectNormalize("a/..", ".");
|
||||
expectNormalize("a/b/..", "a");
|
||||
expectNormalize("a/../b", "b");
|
||||
expectNormalize("a/./../b", "b");
|
||||
expectNormalize("a/b/c/../../d/e/..", "a/d");
|
||||
expectNormalize("a/b/../../../../c", "../../c");
|
||||
|
||||
// does not walk before root on absolute paths
|
||||
expectNormalize("..", "..");
|
||||
expectNormalize("../", "..");
|
||||
expectNormalize("/..", "/");
|
||||
expectNormalize("a/..", ".");
|
||||
expectNormalize("../a", "../a");
|
||||
expectNormalize("/../a", "/a");
|
||||
expectNormalize("/../a", "/a");
|
||||
expectNormalize("a/b/..", "a");
|
||||
expectNormalize("../a/b/..", "../a");
|
||||
expectNormalize("a/../b", "b");
|
||||
expectNormalize("a/./../b", "b");
|
||||
expectNormalize("a/b/c/../../d/e/..", "a/d");
|
||||
expectNormalize("a/b/../../../../c", "../../c");
|
||||
expectNormalize("a/b/c/../../..d/./.e/f././", "a/..d/.e/f.");
|
||||
|
||||
// removes trailing separators
|
||||
expectNormalize("./", ".");
|
||||
expectNormalize(".//", ".");
|
||||
expectNormalize("a/", "a");
|
||||
expectNormalize("a/b/", "a/b");
|
||||
expectNormalize("a/b///", "a/b");
|
||||
|
||||
expectNormalize("foo/bar/baz", "foo/bar/baz");
|
||||
expectNormalize("foo", "foo");
|
||||
expectNormalize("foo/bar/", "foo/bar");
|
||||
expectNormalize("./foo/././bar/././", "foo/bar");
|
||||
}
|
||||
|
||||
void testPath()
|
||||
{
|
||||
// TODO: Test other functions.
|
||||
testNormalize();
|
||||
}
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
void testPath();
|
||||
@@ -0,0 +1,29 @@
|
||||
#include <stdio.h>
|
||||
|
||||
#include "test.h"
|
||||
|
||||
int passes = 0;
|
||||
int failures = 0;
|
||||
|
||||
void pass()
|
||||
{
|
||||
passes++;
|
||||
}
|
||||
|
||||
void fail()
|
||||
{
|
||||
failures++;
|
||||
}
|
||||
|
||||
int showTestResults()
|
||||
{
|
||||
if (failures > 0)
|
||||
{
|
||||
printf("%d out of %d tests failed. :(\n", failures, passes + failures);
|
||||
return 1;
|
||||
}
|
||||
|
||||
printf("All %d tests passed!\n", passes + failures);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
// Set this to 1 to output passing tests.
|
||||
#define SHOW_PASSES 0
|
||||
|
||||
void pass();
|
||||
void fail();
|
||||
|
||||
int showTestResults();
|
||||
Reference in New Issue
Block a user