feat: bux test command + Std::Test module
- Add 'bux test' CLI command: discovers .bux files in tests/, compiles each into a temp package, runs them, reports pass/fail - Add Std::Test module with Assert, AssertEqInt, AssertTrue, AssertFalse, Fail - Add bux_exit and bux_assert C runtime primitives - Update README.md and docs/BuildAndTest.md
This commit is contained in:
@@ -198,7 +198,7 @@ func Main() -> int {
|
||||
| **CTFE** | `const func` — compile-time function execution |
|
||||
| **Trait Bounds** | `func Max<T: Comparable>(a: T, b: T) -> T` |
|
||||
| **Package Manager** | `bux add`, `bux install`, `bux.lock`, path + git deps |
|
||||
| **Tooling** | `bux new`, `bux build`, `bux run`, `bux check` |
|
||||
| **Tooling** | `bux new`, `bux build`, `bux run`, `bux test`, `bux check` |
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -24,6 +24,7 @@ Commands:
|
||||
install Resolve and install dependencies
|
||||
build Build the current package
|
||||
run Build and run the current package
|
||||
test Run tests in tests/ directory
|
||||
check Type-check the current package
|
||||
clean Remove build artifacts
|
||||
help Show this help message
|
||||
@@ -574,6 +575,46 @@ proc cmdClean*(args: seq[string], opts: GlobalOptions): int =
|
||||
printInfo("clean: build directory removed", useColor)
|
||||
return 0
|
||||
|
||||
proc cmdTest*(args: seq[string], opts: GlobalOptions): int =
|
||||
let useColor = shouldUseColor(opts)
|
||||
let root = getCurrentDir()
|
||||
let testsDir = root / "tests"
|
||||
var testFiles: seq[string] = @[]
|
||||
if dirExists(testsDir):
|
||||
for kind, path in walkDir(testsDir):
|
||||
if kind == pcFile and path.endsWith(".bux"):
|
||||
testFiles.add(path)
|
||||
if testFiles.len == 0:
|
||||
printError("no tests found in tests/ directory", useColor)
|
||||
return 1
|
||||
var passed = 0
|
||||
var failed = 0
|
||||
for testFile in testFiles:
|
||||
let testName = splitFile(testFile).name
|
||||
let tmpDir = getTempDir() / "bux_test_" & testName
|
||||
removeDir(tmpDir)
|
||||
createDir(tmpDir / "src")
|
||||
copyFile(testFile, tmpDir / "src" / "Main.bux")
|
||||
writeFile(tmpDir / "bux.toml", "[package]\nname = \"" & testName & "\"\nversion = \"0.1.0\"\n")
|
||||
let buildRes = cmdBuild(@[tmpDir], opts)
|
||||
if buildRes != 0:
|
||||
printError(&" FAIL {testName} (build)", useColor)
|
||||
failed += 1
|
||||
continue
|
||||
var execFile = tmpDir / "build" / testName
|
||||
if not fileExists(execFile):
|
||||
execFile = tmpDir / "build" / "bux_out"
|
||||
let exitCode = execCmd(execFile)
|
||||
if exitCode == 0:
|
||||
printInfo(&" PASS {testName}", useColor)
|
||||
passed += 1
|
||||
else:
|
||||
printError(&" FAIL {testName} (exit {exitCode})", useColor)
|
||||
failed += 1
|
||||
removeDir(tmpDir)
|
||||
echo &"\nResults: {passed} passed, {failed} failed"
|
||||
return if failed > 0: 1 else: 0
|
||||
|
||||
proc cmdVersion*(args: seq[string], opts: GlobalOptions): int =
|
||||
echo "bux 0.1.0 (bootstrap)"
|
||||
return 0
|
||||
@@ -597,6 +638,7 @@ proc runCli*(args: seq[string]): int =
|
||||
of "build": return cmdBuild(cmdArgs, opts)
|
||||
of "run": return cmdRun(cmdArgs, opts)
|
||||
of "check": return cmdCheck(cmdArgs, opts)
|
||||
of "test": return cmdTest(cmdArgs, opts)
|
||||
of "clean": return cmdClean(cmdArgs, opts)
|
||||
of "version", "--version", "-v": return cmdVersion(cmdArgs, opts)
|
||||
of "help", "--help", "-h":
|
||||
|
||||
@@ -89,6 +89,9 @@ Output = "Bin"
|
||||
./buxc run
|
||||
./buxc run ./myproject
|
||||
|
||||
# Run tests
|
||||
./buxc test
|
||||
|
||||
# Clean build artifacts
|
||||
./buxc clean
|
||||
```
|
||||
|
||||
@@ -1324,6 +1324,20 @@ const char* bux_socket_error(void) {
|
||||
return strerror(errno);
|
||||
}
|
||||
|
||||
/* ============================================================================
|
||||
* Test / Assert primitives
|
||||
* ============================================================================ */
|
||||
|
||||
void bux_exit(int code) {
|
||||
exit(code);
|
||||
}
|
||||
|
||||
void bux_assert(int cond, const char* file, int line, const char* expr) {
|
||||
if (!cond) {
|
||||
fprintf(stderr, "ASSERT FAILED: %s at %s:%d\n", expr, file, line);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
/* ============================================================================
|
||||
* Cryptography primitives (OpenSSL)
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
module Std::Test {
|
||||
|
||||
extern func bux_exit(code: int);
|
||||
extern func bux_assert(cond: int, file: String, line: int, expr: String);
|
||||
|
||||
func Test_Exit(code: int) {
|
||||
bux_exit(code);
|
||||
}
|
||||
|
||||
func Test_Assert(cond: bool) {
|
||||
bux_assert(cond as int, "", 0, "");
|
||||
}
|
||||
|
||||
func Test_AssertEqInt(a: int, b: int) {
|
||||
if a != b {
|
||||
PrintLine("ASSERT_EQ FAILED:");
|
||||
PrintInt(a);
|
||||
PrintLine(" != ");
|
||||
PrintInt(b);
|
||||
bux_exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
func Test_AssertTrue(cond: bool) {
|
||||
if !cond {
|
||||
PrintLine("ASSERT_TRUE FAILED");
|
||||
bux_exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
func Test_AssertFalse(cond: bool) {
|
||||
if cond {
|
||||
PrintLine("ASSERT_FALSE FAILED");
|
||||
bux_exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
func Test_Fail(msg: String) {
|
||||
PrintLine("FAIL:");
|
||||
PrintLine(msg);
|
||||
bux_exit(1);
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user