native test framework
This commit is contained in:
+69
-24
@@ -43,26 +43,7 @@ destroy_build_config :: proc(cfg: ^BuildConfig) {
|
||||
delete(cfg.c_options.defines)
|
||||
}
|
||||
|
||||
// run_build implements `brolang build [root]`: it loads and type-checks
|
||||
// `root/build.bro`, reads its `config` constant, and compiles the program
|
||||
// package the config names. build.bro is only checked (never lowered/emitted),
|
||||
// so the config is read straight from the HIR.
|
||||
run_build :: proc(root: string) -> int {
|
||||
project_root := root
|
||||
owns_project_root := false
|
||||
if len(project_root) == 0 {
|
||||
found_root, found := find_build_root()
|
||||
if !found {
|
||||
fmt.eprintln("brolang build: could not find build.bro in the current directory or any parent")
|
||||
return 2
|
||||
}
|
||||
project_root = found_root
|
||||
owns_project_root = true
|
||||
}
|
||||
defer if owns_project_root {
|
||||
delete(project_root)
|
||||
}
|
||||
|
||||
load_build_config :: proc(project_root: string) -> (BuildConfig, bool) {
|
||||
sources := source.init_store()
|
||||
defer source.destroy_store(&sources)
|
||||
diagnostics := source.init_store_diagnostics(&sources)
|
||||
@@ -73,7 +54,7 @@ run_build :: proc(root: string) -> int {
|
||||
arena: vmem.Arena
|
||||
if err := vmem.arena_init_growing(&arena); err != nil {
|
||||
fmt.eprintln("failed to initialize build arena:", err)
|
||||
return 2
|
||||
return {}, false
|
||||
}
|
||||
defer vmem.arena_destroy(&arena)
|
||||
a := vmem.arena_allocator(&arena)
|
||||
@@ -82,7 +63,7 @@ run_build :: proc(root: string) -> int {
|
||||
if !loaded {
|
||||
source.print_all(&diagnostics)
|
||||
fmt.eprintln("failed to load build root:", project_root)
|
||||
return 2
|
||||
return {}, false
|
||||
}
|
||||
// check needs no `main`: it synthesizes a trap main and emits one benign
|
||||
// "missing main" diagnostic, which is expected for build.bro. Suppress that
|
||||
@@ -90,10 +71,32 @@ run_build :: proc(root: string) -> int {
|
||||
hir_module := checker.check(&ast_module, &diagnostics, &symbols, target.DEFAULT, a)
|
||||
if build_bro_has_errors(&diagnostics) {
|
||||
source.print_all(&diagnostics)
|
||||
return {}, false
|
||||
}
|
||||
return extract_build_config(&hir_module, &symbols)
|
||||
}
|
||||
|
||||
project_root_for_command :: proc(root, command: string) -> (string, bool, bool) {
|
||||
if len(root) > 0 {
|
||||
return root, false, true
|
||||
}
|
||||
project_root, found := find_build_root()
|
||||
if !found {
|
||||
fmt.eprintfln("brolang %s: could not find build.bro in the current directory or any parent", command)
|
||||
return "", false, false
|
||||
}
|
||||
return project_root, true, true
|
||||
}
|
||||
|
||||
// run_build implements `brolang build [root]`: it reads build.bro and compiles
|
||||
// the configured program package.
|
||||
run_build :: proc(root: string) -> int {
|
||||
project_root, owned, found := project_root_for_command(root, "build")
|
||||
if !found {
|
||||
return 2
|
||||
}
|
||||
|
||||
cfg, ok := extract_build_config(&hir_module, &symbols)
|
||||
defer if owned {delete(project_root)}
|
||||
cfg, ok := load_build_config(project_root)
|
||||
if !ok {
|
||||
return 2
|
||||
}
|
||||
@@ -109,6 +112,48 @@ run_build :: proc(root: string) -> int {
|
||||
return compile_package(program, output, cfg.link_arguments, target.DEFAULT, cfg.c_options, project_root)
|
||||
}
|
||||
|
||||
run_tests :: proc(root: string) -> int {
|
||||
project_root, owned, found := project_root_for_command(root, "test")
|
||||
if !found {
|
||||
return 2
|
||||
}
|
||||
defer if owned {delete(project_root)}
|
||||
cfg, ok := load_build_config(project_root)
|
||||
if !ok {
|
||||
return 2
|
||||
}
|
||||
defer destroy_build_config(&cfg)
|
||||
|
||||
program := filepath.join({project_root, cfg.source_dir})
|
||||
defer delete(program)
|
||||
test_name := fmt.aprintf("%s-test", cfg.output_name)
|
||||
defer delete(test_name)
|
||||
output, output_ok := build_output_path(project_root, test_name)
|
||||
if !output_ok {
|
||||
return 2
|
||||
}
|
||||
defer delete(output)
|
||||
status := compile_package(
|
||||
program, output, cfg.link_arguments, target.DEFAULT, cfg.c_options, project_root, .Test,
|
||||
)
|
||||
if status != 0 {
|
||||
return status
|
||||
}
|
||||
state, stdout, stderr, err := os2.process_exec(
|
||||
os2.Process_Desc{command=[]string{output}},
|
||||
context.allocator,
|
||||
)
|
||||
defer delete(stdout)
|
||||
defer delete(stderr)
|
||||
if len(stdout) > 0 {fmt.print(string(stdout))}
|
||||
if len(stderr) > 0 {fmt.eprint(string(stderr))}
|
||||
if err != nil {
|
||||
fmt.eprintln("failed to run test executable:", err)
|
||||
return 2
|
||||
}
|
||||
return 0 if state.exit_code == 0 else 1
|
||||
}
|
||||
|
||||
valid_output_name :: proc(name: string) -> bool {
|
||||
return len(name) > 0 && name != "." && name != ".." &&
|
||||
!strings.contains(name, "/") && !strings.contains(name, "\\")
|
||||
|
||||
Reference in New Issue
Block a user