From: Brendan Hansen Date: Thu, 2 Dec 2021 20:06:12 +0000 (-0600) Subject: started working on a self-hosted testing script X-Git-Url: https://git.brendanfh.com/?a=commitdiff_plain;h=4dd0a415fdd3096b67a9377872130ceb1ffd5e9c;p=onyx.git started working on a self-hosted testing script --- diff --git a/core/io/process.onyx b/core/io/process.onyx index bfa055e5..e1e7dfda 100644 --- a/core/io/process.onyx +++ b/core/io/process.onyx @@ -37,6 +37,10 @@ process_wait :: (use p: ^Process) => { return runtime.__process_wait(process_handle); } +process_destroy :: (use p: ^Process) => { + runtime.__process_destroy(process_handle); +} + #local process_stream_vtable := Stream_Vtable.{ read = (use p: ^Process, buffer: [] u8) -> (Error, u32) { // Read from the process stdout diff --git a/core/io/reader.onyx b/core/io/reader.onyx index 7d38953d..3eccde39 100644 --- a/core/io/reader.onyx +++ b/core/io/reader.onyx @@ -23,6 +23,7 @@ reader_make :: (s: ^Stream, buffer_size := 4096, allocator := context.allocator) reader: Reader; reader.stream = s; + reader.error = .None; memory.alloc_slice(^reader.buffer, buffer_size, allocator); reader.buffer_allocator = allocator; @@ -60,6 +61,29 @@ reader_empty :: (use reader: ^Reader) -> bool { return done && reader_get_buffered(reader) == 0; } +read_all :: (use reader: ^Reader, allocator := context.allocator) -> [] u8 { + array :: package core.array + output := array.make(u8, 128, allocator=allocator); + + while !reader_empty(reader) { + if err := reader_read_next_chunk(reader); err != .None do break; + if error != .None { + reader_consume_error(reader); + break; + } + + buffered := reader_get_buffered(reader); + if buffered > 0 { + array.ensure_capacity(^output, output.count + buffered); + memory.copy(output.data + output.count, buffer.data, buffered); + output.count += buffered; + start = end; + } + } + + return output; +} + read_byte :: (use reader: ^Reader) -> u8 { while start == end { if error != .None { diff --git a/core/runtime/onyx_run.onyx b/core/runtime/onyx_run.onyx index f18a3847..48ab62fb 100644 --- a/core/runtime/onyx_run.onyx +++ b/core/runtime/onyx_run.onyx @@ -25,8 +25,9 @@ use package wasi Error :: 0x02; } -__process_spawn :: (path: str, args: [] str, non_blocking_io: bool) -> io.Process.Handle #foreign "env" "process_spawn" --- -__process_read :: (handle: io.Process.Handle, buffer: [] u8) -> u32 #foreign "env" "process_read" --- -__process_write :: (handle: io.Process.Handle, buffer: [] u8) -> u32 #foreign "env" "process_write" --- -__process_kill :: (handle: io.Process.Handle) -> bool #foreign "env" "process_kill" --- -__process_wait :: (handle: io.Process.Handle) -> ProcessResult #foreign "env" "process_wait" --- \ No newline at end of file +__process_spawn :: (path: str, args: [] str, non_blocking_io: bool) -> io.Process.Handle #foreign "env" "process_spawn" --- +__process_read :: (handle: io.Process.Handle, buffer: [] u8) -> u32 #foreign "env" "process_read" --- +__process_write :: (handle: io.Process.Handle, buffer: [] u8) -> u32 #foreign "env" "process_write" --- +__process_kill :: (handle: io.Process.Handle) -> bool #foreign "env" "process_kill" --- +__process_wait :: (handle: io.Process.Handle) -> ProcessResult #foreign "env" "process_wait" --- +__process_destroy :: (handle: io.Process.Handle) -> void #foreign "env" "process_destroy" --- \ No newline at end of file diff --git a/core/string.onyx b/core/string.onyx index e7d907e3..1673b601 100644 --- a/core/string.onyx +++ b/core/string.onyx @@ -72,6 +72,20 @@ concat :: #match { return str.{ data, total_length }; }, + (buffer: [] u8, strings: ..str) -> str { + total_copied := 0; + for s: strings { + // Should never greater than, but better safe than sorry. + if total_copied >= buffer.count do break; + + bytes_to_copy := math.min(s.count, buffer.count - total_copied); + memory.copy(buffer.data + total_copied, s.data, bytes_to_copy); + total_copied += bytes_to_copy; + } + + return buffer[0 .. total_copied]; + }, + (into: ^[..] u8, s: str) -> str { array.ensure_capacity(into, into.count + s.count); memory.copy(into.data, s.data, into.count); diff --git a/core/wasi/wasi.onyx b/core/wasi/wasi.onyx index 4a873baa..e0ecea6f 100644 --- a/core/wasi/wasi.onyx +++ b/core/wasi/wasi.onyx @@ -54,7 +54,7 @@ Errno :: enum (u16) { NetReset :: 0x27; NetUnreach :: 0x28; NFile :: 0x29; - NoBufs :: 0x2a; + NoBufs :: 0x2a; NoDev :: 0x2b; NoEntry :: 0x2c; NoExec :: 0x2d; @@ -152,7 +152,7 @@ Filetype :: enum (u8) { Directory :: 0x03; RegularFile :: 0x04; SocketDgram :: 0x05; - SocketStream :: 0x06; + SocketStream :: 0x06; SymLink :: 0x07; } @@ -164,7 +164,7 @@ DirEnt :: struct { } Advice :: enum (u8) { - Normal :: 0x00; + Normal :: 0x00; Sequential :: 0x01; Random :: 0x02; WillNeed :: 0x03; diff --git a/misc/onyx.sublime-syntax b/misc/onyx.sublime-syntax index 9f0233b2..735c96e1 100644 --- a/misc/onyx.sublime-syntax +++ b/misc/onyx.sublime-syntax @@ -38,7 +38,7 @@ contexts: - match: '\b(i8x16|i16x8|i32x4|i64x2|f32x4|f64x2|v128)\b' scope: storage.type - - match: '\b(true|false|null|null_proc|context)\b' + - match: '\b(true|false|null|null_proc|context|it)\b' scope: constant.numeric.onyx # Numbers diff --git a/scripts/run_tests.onyx b/scripts/run_tests.onyx new file mode 100644 index 00000000..077c3dc5 --- /dev/null +++ b/scripts/run_tests.onyx @@ -0,0 +1,112 @@ +#load "core/std" + +use package core +#local wasi :: package wasi + +Directory_Entry :: struct { + dirent : wasi.DirEnt; + name : str; +} + +list_directory :: (path: str) -> Iterator(Directory_Entry) { + Context :: struct { + dir_fd: wasi.FileDescriptor; + opened := false; + reached_end := false; + + entry_walker: ^u8; + + buffer_used: u32 = 0; + buffer: [1024] u8; + + last_cookie: wasi.DirCookie = 0; + } + + next :: (use c: ^Context) -> (Directory_Entry, bool) { + use package core.intrinsics.onyx {__zero_value} + if !opened do return __zero_value(Directory_Entry), false; + + read_more :: macro () { + if !reached_end { + err := wasi.fd_readdir(dir_fd, ~~buffer, sizeof typeof buffer, last_cookie, ^buffer_used); + reached_end = buffer_used != sizeof typeof buffer; + + entry_walker = ~~buffer; + } else { + return __zero_value(Directory_Entry), false; + } + } + + if buffer_used < sizeof(wasi.DirEnt) do read_more(); + + dirent := cast(^wasi.DirEnt) entry_walker; + if buffer_used < sizeof(wasi.DirEnt) + dirent.d_namlen { + read_more(); + dirent = ~~entry_walker; + } + + name := str.{~~(dirent + 1), dirent.d_namlen}; + + entry_size := sizeof(wasi.DirEnt) + dirent.d_namlen; + entry_walker += entry_size; + buffer_used -= entry_size; + last_cookie = dirent.d_next; + + return .{*dirent, name}, true; + } + + close :: (use c: ^Context) { + wasi.fd_close(dir_fd); + cfree(c); + } + + c := new(Context); + if err := wasi.path_open(4, 0, path, .Directory, ~~0xffffffff, ~~0xffffffff, .Sync, ^c.dir_fd); err == .Success { + c.opened = true; + } + + return .{ c, next, close }; +} + +@Temporary +find_onyx_files :: (root: str, cases: ^[..] str) { + for list_directory(root) { + path_buffer: [512] u8; + if string.ends_with(it.name, ".onyx") { + test_case := string.concat(path_buffer, root, "/", it.name) |> string.alloc_copy(); + array.push(cases, test_case); + } + + if it.dirent.d_type == .Directory { + find_onyx_files(string.concat(path_buffer, root, "/", it.name), cases); + } + } + + return; +} + +main :: (args) => { + test_folder := "./tests"; + + cases := array.make(str); + find_onyx_files(test_folder, ^cases); + for cases { + printf("Running test {}...\n", it); + + proc := io.process_spawn("./bin/onyx", .["run", it]); + defer io.process_destroy(^proc); + + proc_reader := io.reader_make(^proc); + output := io.read_all(^proc_reader); + defer memory.free_slice(^output); + + if exit := io.process_wait(^proc); exit != .Success { + // Error running the test case + println(exit); + println(output); + } + } + + // Ensure the corresponding correct output file present + // Run tests, checking their output +} \ No newline at end of file diff --git a/src/wasm_runtime.c b/src/wasm_runtime.c index 9ca74257..3b327837 100644 --- a/src/wasm_runtime.c +++ b/src/wasm_runtime.c @@ -206,6 +206,7 @@ WASM_INTEROP(onyx_process_spawn_impl) { process_path[process_len] = '\0'; OnyxProcess *process = bh_alloc_item(global_heap_allocator, OnyxProcess); + memset(process, 0, sizeof(*process)); process->magic_number = ONYX_PROCESS_MAGIC_NUMBER; #ifdef _BH_LINUX @@ -231,13 +232,19 @@ WASM_INTEROP(onyx_process_spawn_impl) { switch (pid = fork()) { case -1: // Bad fork wasm_val_init_ptr(&results->data[0], NULL); // Failed to run + + close(process->proc_to_host[0]); + close(process->proc_to_host[1]); + close(process->host_to_proc[0]); + close(process->host_to_proc[1]); break; case 0: // Child process close(process->proc_to_host[0]); close(process->host_to_proc[1]); - dup2(process->proc_to_host[1], 1); // Map the output to the pipe dup2(process->host_to_proc[0], 0); // Map the output to the pipe + dup2(process->proc_to_host[1], 1); // Map the output to the pipe + dup2(process->proc_to_host[1], 2); // Stderr to stdout if (!blocking_io) { fcntl(0, F_SETFL, O_NONBLOCK); @@ -245,9 +252,9 @@ WASM_INTEROP(onyx_process_spawn_impl) { } execv(process_path, process_args); - wasm_val_init_ptr(&results->data[0], NULL); + exit(-1); break; - + default: { process->pid = pid; close(process->host_to_proc[0]); @@ -265,7 +272,7 @@ WASM_INTEROP(onyx_process_spawn_impl) { char cmdLine[2048]; memset(cmdLine, 0, 2048); strncat(cmdLine, process_path, 2047); - + byte_t* data = wasm_memory_data(wasm_memory); byte_t* array_loc = data + args_ptr; fori (i, 0, args_len) { @@ -363,6 +370,8 @@ WASM_INTEROP(onyx_process_wait_impl) { #ifdef _BH_LINUX i32 status; waitpid(process->pid, &status, 0); + close(process->proc_to_host[0]); + close(process->host_to_proc[1]); i32 exit_code = WEXITSTATUS(status); results->data[0] = WASM_I32_VAL(exit_code != 0 ? 2 : 0); @@ -371,6 +380,22 @@ WASM_INTEROP(onyx_process_wait_impl) { return NULL; } +WASM_INTEROP(onyx_process_destroy_impl) { + OnyxProcess *process = (OnyxProcess *) params->data[0].of.i64; + if (process == NULL || process->magic_number != ONYX_PROCESS_MAGIC_NUMBER) { + return NULL; + } + + #ifdef _BH_LINUX + kill(process->pid, SIGKILL); + close(process->proc_to_host[0]); + close(process->host_to_proc[1]); + bh_free(global_heap_allocator, process); + #endif + + return NULL; +} + void onyx_run_wasm(bh_buffer wasm_bytes) { wasm_instance_t* instance = NULL; wasmer_features_t* features = NULL; @@ -523,6 +548,14 @@ void onyx_run_wasm(bh_buffer wasm_bytes) { import = wasm_func_as_extern(wasm_func); goto import_found; } + + if (wasm_name_equals_string(import_name, "process_destroy")) { + wasm_functype_t* func_type = wasm_functype_new_1_0(wasm_valtype_new_i64()); + + wasm_func_t* wasm_func = wasm_func_new(wasm_store, func_type, onyx_process_destroy_impl); + import = wasm_func_as_extern(wasm_func); + goto import_found; + } } goto bad_import;