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:
2026-06-05 22:58:02 +03:00
parent 2a19734c72
commit f02b354e9a
5 changed files with 104 additions and 1 deletions
+1 -1
View File
@@ -198,7 +198,7 @@ func Main() -> int {
| **CTFE** | `const func` — compile-time function execution | | **CTFE** | `const func` — compile-time function execution |
| **Trait Bounds** | `func Max<T: Comparable>(a: T, b: T) -> T` | | **Trait Bounds** | `func Max<T: Comparable>(a: T, b: T) -> T` |
| **Package Manager** | `bux add`, `bux install`, `bux.lock`, path + git deps | | **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` |
--- ---
+42
View File
@@ -24,6 +24,7 @@ Commands:
install Resolve and install dependencies install Resolve and install dependencies
build Build the current package build Build the current package
run Build and run the current package run Build and run the current package
test Run tests in tests/ directory
check Type-check the current package check Type-check the current package
clean Remove build artifacts clean Remove build artifacts
help Show this help message help Show this help message
@@ -574,6 +575,46 @@ proc cmdClean*(args: seq[string], opts: GlobalOptions): int =
printInfo("clean: build directory removed", useColor) printInfo("clean: build directory removed", useColor)
return 0 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 = proc cmdVersion*(args: seq[string], opts: GlobalOptions): int =
echo "bux 0.1.0 (bootstrap)" echo "bux 0.1.0 (bootstrap)"
return 0 return 0
@@ -597,6 +638,7 @@ proc runCli*(args: seq[string]): int =
of "build": return cmdBuild(cmdArgs, opts) of "build": return cmdBuild(cmdArgs, opts)
of "run": return cmdRun(cmdArgs, opts) of "run": return cmdRun(cmdArgs, opts)
of "check": return cmdCheck(cmdArgs, opts) of "check": return cmdCheck(cmdArgs, opts)
of "test": return cmdTest(cmdArgs, opts)
of "clean": return cmdClean(cmdArgs, opts) of "clean": return cmdClean(cmdArgs, opts)
of "version", "--version", "-v": return cmdVersion(cmdArgs, opts) of "version", "--version", "-v": return cmdVersion(cmdArgs, opts)
of "help", "--help", "-h": of "help", "--help", "-h":
+3
View File
@@ -89,6 +89,9 @@ Output = "Bin"
./buxc run ./buxc run
./buxc run ./myproject ./buxc run ./myproject
# Run tests
./buxc test
# Clean build artifacts # Clean build artifacts
./buxc clean ./buxc clean
``` ```
+14
View File
@@ -1324,6 +1324,20 @@ const char* bux_socket_error(void) {
return strerror(errno); 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) * Cryptography primitives (OpenSSL)
+44
View File
@@ -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);
}
}