In the middle of porting core:testing

This commit is contained in:
Jeroen van Rijn
2025-10-28 19:01:25 +01:00
parent 39eba452bf
commit 46489a1cd5
25 changed files with 288 additions and 75 deletions

View File

@@ -1,9 +1,9 @@
#+build js
package fmt
import "core:bufio"
import "core:io"
import "core:os"
import "core:bufio"
import "core:io"
import os "core:os/os2"
foreign import "odin_env"
@@ -34,52 +34,52 @@ stderr := io.Writer{
}
@(private="file")
fd_to_writer :: proc(fd: os.Handle, loc := #caller_location) -> io.Writer {
switch fd {
case 1: return stdout
case 2: return stderr
fd_to_writer :: proc(f: ^os.File, loc := #caller_location) -> io.Writer {
switch {
case f == os.stdout: return stdout
case f == os.stderr: return stderr
case: panic("`fmt.fprint` variant called with invalid file descriptor for JS, only 1 (stdout) and 2 (stderr) are supported", loc)
}
}
// fprint formats using the default print settings and writes to fd
fprint :: proc(fd: os.Handle, args: ..any, sep := " ", flush := true, loc := #caller_location) -> int {
fprint :: proc(f: ^os.File, args: ..any, sep := " ", flush := true, loc := #caller_location) -> int {
buf: [1024]byte
b: bufio.Writer
defer bufio.writer_flush(&b)
bufio.writer_init_with_buf(&b, fd_to_writer(fd, loc), buf[:])
bufio.writer_init_with_buf(&b, fd_to_writer(f, loc), buf[:])
w := bufio.writer_to_writer(&b)
return wprint(w, ..args, sep=sep, flush=flush)
}
// fprintln formats using the default print settings and writes to fd
fprintln :: proc(fd: os.Handle, args: ..any, sep := " ", flush := true, loc := #caller_location) -> int {
fprintln :: proc(f: ^os.File, args: ..any, sep := " ", flush := true, loc := #caller_location) -> int {
buf: [1024]byte
b: bufio.Writer
defer bufio.writer_flush(&b)
bufio.writer_init_with_buf(&b, fd_to_writer(fd, loc), buf[:])
bufio.writer_init_with_buf(&b, fd_to_writer(f, loc), buf[:])
w := bufio.writer_to_writer(&b)
return wprintln(w, ..args, sep=sep, flush=flush)
}
// fprintf formats according to the specified format string and writes to fd
fprintf :: proc(fd: os.Handle, fmt: string, args: ..any, flush := true, newline := false, loc := #caller_location) -> int {
fprintf :: proc(f: ^os.File, fmt: string, args: ..any, flush := true, newline := false, loc := #caller_location) -> int {
buf: [1024]byte
b: bufio.Writer
defer bufio.writer_flush(&b)
bufio.writer_init_with_buf(&b, fd_to_writer(fd, loc), buf[:])
bufio.writer_init_with_buf(&b, fd_to_writer(f, loc), buf[:])
w := bufio.writer_to_writer(&b)
return wprintf(w, fmt, ..args, flush=flush, newline=newline)
}
// fprintfln formats according to the specified format string and writes to fd, followed by a newline.
fprintfln :: proc(fd: os.Handle, fmt: string, args: ..any, flush := true, loc := #caller_location) -> int {
return fprintf(fd, fmt, ..args, flush=flush, newline=true, loc=loc)
fprintfln :: proc(f: ^os.File, fmt: string, args: ..any, flush := true, loc := #caller_location) -> int {
return fprintf(f, fmt, ..args, flush=flush, newline=true, loc=loc)
}
// print formats using the default print settings and writes to stdout

View File

@@ -3,64 +3,66 @@
#+build !orca
package fmt
import "base:runtime"
import "core:os"
import "core:io"
import "core:bufio"
import "base:runtime"
import os "core:os/os2"
import "core:io"
import "core:bufio"
// NOTE(Jeroen): The other option is to deprecate `fprint*` and make it an alias for `wprint*`, using File.stream directly.
// fprint formats using the default print settings and writes to fd
fprint :: proc(fd: os.Handle, args: ..any, sep := " ", flush := true) -> int {
fprint :: proc(f: ^os.File, args: ..any, sep := " ", flush := true) -> int {
buf: [1024]byte
b: bufio.Writer
defer bufio.writer_flush(&b)
bufio.writer_init_with_buf(&b, os.stream_from_handle(fd), buf[:])
bufio.writer_init_with_buf(&b, f.stream, buf[:])
w := bufio.writer_to_writer(&b)
return wprint(w, ..args, sep=sep, flush=flush)
}
// fprintln formats using the default print settings and writes to fd
fprintln :: proc(fd: os.Handle, args: ..any, sep := " ", flush := true) -> int {
fprintln :: proc(f: ^os.File, args: ..any, sep := " ", flush := true) -> int {
buf: [1024]byte
b: bufio.Writer
defer bufio.writer_flush(&b)
bufio.writer_init_with_buf(&b, os.stream_from_handle(fd), buf[:])
bufio.writer_init_with_buf(&b, f.stream, buf[:])
w := bufio.writer_to_writer(&b)
return wprintln(w, ..args, sep=sep, flush=flush)
}
// fprintf formats according to the specified format string and writes to fd
fprintf :: proc(fd: os.Handle, fmt: string, args: ..any, flush := true, newline := false) -> int {
fprintf :: proc(f: ^os.File, fmt: string, args: ..any, flush := true, newline := false) -> int {
buf: [1024]byte
b: bufio.Writer
defer bufio.writer_flush(&b)
bufio.writer_init_with_buf(&b, os.stream_from_handle(fd), buf[:])
bufio.writer_init_with_buf(&b, f.stream, buf[:])
w := bufio.writer_to_writer(&b)
return wprintf(w, fmt, ..args, flush=flush, newline=newline)
}
// fprintfln formats according to the specified format string and writes to fd, followed by a newline.
fprintfln :: proc(fd: os.Handle, fmt: string, args: ..any, flush := true) -> int {
return fprintf(fd, fmt, ..args, flush=flush, newline=true)
fprintfln :: proc(f: ^os.File, fmt: string, args: ..any, flush := true) -> int {
return fprintf(f, fmt, ..args, flush=flush, newline=true)
}
fprint_type :: proc(fd: os.Handle, info: ^runtime.Type_Info, flush := true) -> (n: int, err: io.Error) {
fprint_type :: proc(f: ^os.File, info: ^runtime.Type_Info, flush := true) -> (n: int, err: io.Error) {
buf: [1024]byte
b: bufio.Writer
defer bufio.writer_flush(&b)
bufio.writer_init_with_buf(&b, os.stream_from_handle(fd), buf[:])
bufio.writer_init_with_buf(&b, f.stream, buf[:])
w := bufio.writer_to_writer(&b)
return wprint_type(w, info, flush=flush)
}
fprint_typeid :: proc(fd: os.Handle, id: typeid, flush := true) -> (n: int, err: io.Error) {
fprint_typeid :: proc(f: ^os.File, id: typeid, flush := true) -> (n: int, err: io.Error) {
buf: [1024]byte
b: bufio.Writer
defer bufio.writer_flush(&b)
bufio.writer_init_with_buf(&b, os.stream_from_handle(fd), buf[:])
bufio.writer_init_with_buf(&b, f.stream, buf[:])
w := bufio.writer_to_writer(&b)
return wprint_typeid(w, id, flush=flush)

View File

@@ -2,13 +2,13 @@
#+build !orca
package log
import "base:runtime"
import "core:fmt"
import "core:strings"
import "core:os"
import "core:terminal"
import "core:terminal/ansi"
import "core:time"
import "base:runtime"
import "core:fmt"
import "core:strings"
import os "core:os/os2"
import "core:terminal"
import "core:terminal/ansi"
import "core:time"
Level_Headers := [?]string{
0..<10 = "[DEBUG] --- ",
@@ -35,7 +35,7 @@ Default_File_Logger_Opts :: Options{
File_Console_Logger_Data :: struct {
file_handle: os.Handle,
file_handle: ^os.File,
ident: string,
}
@@ -66,16 +66,16 @@ init_standard_stream_status :: proc "contextless" () {
}
}
create_file_logger :: proc(h: os.Handle, lowest := Level.Debug, opt := Default_File_Logger_Opts, ident := "", allocator := context.allocator) -> Logger {
create_file_logger :: proc(f: ^os.File, lowest := Level.Debug, opt := Default_File_Logger_Opts, ident := "", allocator := context.allocator) -> Logger {
data := new(File_Console_Logger_Data, allocator)
data.file_handle = h
data.file_handle = f
data.ident = ident
return Logger{file_logger_proc, data, lowest, opt}
}
destroy_file_logger :: proc(log: Logger, allocator := context.allocator) {
data := cast(^File_Console_Logger_Data)log.data
if data.file_handle != os.INVALID_HANDLE {
if data.file_handle != nil {
os.close(data.file_handle)
}
free(data, allocator)
@@ -83,7 +83,7 @@ destroy_file_logger :: proc(log: Logger, allocator := context.allocator) {
create_console_logger :: proc(lowest := Level.Debug, opt := Default_Console_Logger_Opts, ident := "", allocator := context.allocator) -> Logger {
data := new(File_Console_Logger_Data, allocator)
data.file_handle = os.INVALID_HANDLE
data.file_handle = nil
data.ident = ident
return Logger{console_logger_proc, data, lowest, opt}
}
@@ -93,7 +93,7 @@ destroy_console_logger :: proc(log: Logger, allocator := context.allocator) {
}
@(private)
_file_console_logger_proc :: proc(h: os.Handle, ident: string, level: Level, text: string, options: Options, location: runtime.Source_Code_Location) {
_file_console_logger_proc :: proc(h: ^os.File, ident: string, level: Level, text: string, options: Options, location: runtime.Source_Code_Location) {
backing: [1024]byte //NOTE(Hoej): 1024 might be too much for a header backing, unless somebody has really long paths.
buf := strings.builder_from_bytes(backing[:])
@@ -106,9 +106,7 @@ _file_console_logger_proc :: proc(h: os.Handle, ident: string, level: Level, tex
do_location_header(options, &buf, location)
if .Thread_Id in options {
// NOTE(Oskar): not using context.thread_id here since that could be
// incorrect when replacing context for a thread.
fmt.sbprintf(&buf, "[{}] ", os.current_thread_id())
fmt.sbprintf(&buf, "[{}] ", os.get_current_thread_id())
}
if ident != "" {
@@ -126,7 +124,7 @@ file_logger_proc :: proc(logger_data: rawptr, level: Level, text: string, option
console_logger_proc :: proc(logger_data: rawptr, level: Level, text: string, options: Options, location := #caller_location) {
options := options
data := cast(^File_Console_Logger_Data)logger_data
h: os.Handle = ---
h: ^os.File = nil
if level < Level.Error {
h = os.stdout
options -= global_subtract_stdout_options
@@ -216,4 +214,4 @@ do_location_header :: proc(opts: Options, buf: ^strings.Builder, location := #ca
}
fmt.sbprint(buf, "] ")
}
}

View File

@@ -311,6 +311,11 @@ is_directory :: proc(path: string) -> bool {
return fi.type == .Directory
}
@(require_results)
is_tty :: proc "contextless" (f: ^File) -> bool {
return _is_tty(f)
}
copy_file :: proc(dst_path, src_path: string) -> Error {
when #defined(_copy_file_native) {

View File

@@ -29,6 +29,9 @@ _fd :: proc(f: ^File) -> uintptr {
return 0
}
_is_tty :: proc "contextless" (f: ^File) -> bool {
return true
}
_name :: proc(f: ^File) -> string {
return ""

View File

@@ -6,6 +6,7 @@ import "core:io"
import "core:time"
import "core:sync"
import "core:sys/linux"
import "core:sys/posix"
// Most implementations will EINVAL at some point when doing big writes.
// In practice a read/write call would probably never read/write these big buffers all at once,
@@ -178,6 +179,17 @@ _fd :: proc(f: ^File) -> uintptr {
return uintptr(impl.fd)
}
_is_tty :: proc "contextless" (f: ^File) -> bool {
if f == nil || f.impl == nil {
return false
}
impl := (^File_Impl)(f.impl)
// TODO: Replace `posix.isatty` with `tcgetattr(fd, &termios) == 0`
is_tty := posix.isatty(posix.FD(impl.fd))
return bool(is_tty)
}
_name :: proc(f: ^File) -> string {
return (^File_Impl)(f.impl).name if f != nil && f.impl != nil else ""
}

View File

@@ -162,6 +162,12 @@ __fd :: proc(f: ^File) -> posix.FD {
return -1
}
is_tty :: proc "contextless" (f: ^File) -> bool {
fd := _fd(f)
is_tty := posix.isatty(posix.FD(fd))
return bool(is_tty)
}
_name :: proc(f: ^File) -> string {
if f != nil && f.impl != nil {
return (^File_Impl)(f.impl).name

View File

@@ -43,4 +43,4 @@ _copy_file_native :: proc(dst_path, src_path: string) -> (err: Error) {
}
return
}
}

View File

@@ -271,6 +271,10 @@ __fd :: proc(f: ^File) -> wasi.fd_t {
return -1
}
_is_tty :: proc "contextless" (f: ^File) -> bool {
return false
}
_name :: proc(f: ^File) -> string {
if f != nil && f.impl != nil {
return (^File_Impl)(f.impl).name

View File

@@ -241,6 +241,11 @@ _fd :: proc "contextless" (f: ^File) -> uintptr {
return uintptr((^File_Impl)(f.impl).fd)
}
_is_tty :: proc "contextless" (f: ^File) -> bool {
fd := _fd(f)
return win32.GetFileType(win32.HANDLE(fd)) == win32.FILE_TYPE_CHAR
}
_destroy :: proc(f: ^File_Impl) -> Error {
if f == nil {
return nil

View File

@@ -114,6 +114,21 @@ get_ppid :: proc() -> int {
return _get_ppid()
}
/*
Obtain the current thread id
*/
@(require_results)
get_current_thread_id :: proc "contextless" () -> int {
return _get_current_thread_id()
}
/*
Return the number of cores
*/
get_processor_core_count :: proc() -> int {
return _get_processor_core_count()
}
/*
Obtain ID's of all processes running in the system.
*/

View File

@@ -0,0 +1,33 @@
#+private
#+build freebsd
foreign import libc "system:c"
foreign import dl "system:dl"
foreign libc {
@(link_name="sysctlbyname")
_sysctlbyname :: proc(path: cstring, oldp: rawptr, oldlenp: rawptr, newp: rawptr, newlen: int) -> c.int ---
}
foreign dl {
@(link_name="pthread_getthreadid_np")
pthread_getthreadid_np :: proc() -> c.int ---
}
@(require_results)
_get_current_thread_id :: proc "contextless" () -> int {
return int(pthread_getthreadid_np())
}
@(require_results)
_get_processor_core_count :: proc() -> int {
count : int = 0
count_size := size_of(count)
if _sysctlbyname("hw.ncpu", &count, &count_size, nil, 0) == 0 {
if count > 0 {
return count
}
}
return 1
}
}

View File

@@ -34,6 +34,14 @@ _get_ppid :: proc() -> int {
return 0
}
_get_current_thread_id :: proc "contextless" () -> int {
return 0
}
_get_processor_core_count :: proc() -> int {
return 1
}
_process_info_by_handle :: proc(process: Process, selection: Process_Info_Fields, allocator: runtime.Allocator) -> (info: Process_Info, err: Error) {
err = .Unsupported
return

View File

@@ -5,12 +5,20 @@ package os2
import "base:runtime"
import "base:intrinsics"
import "core:c"
import "core:time"
import "core:slice"
import "core:strings"
import "core:strconv"
import "core:sys/unix"
import "core:sys/linux"
foreign import libc "system:c"
foreign libc {
@(link_name="get_nprocs") _unix_get_nprocs :: proc() -> c.int ---
}
PIDFD_UNASSIGNED :: ~uintptr(0)
@(private="package")
@@ -48,6 +56,16 @@ _get_ppid :: proc() -> int {
return int(linux.getppid())
}
@(private="package")
_get_current_thread_id :: proc "contextless" () -> int {
return unix.sys_gettid()
}
@(private="package")
_get_processor_core_count :: proc() -> int {
return int(_unix_get_nprocs())
}
@(private="package")
_process_list :: proc(allocator: runtime.Allocator) -> (list: []int, err: Error) {
temp_allocator := TEMP_ALLOCATOR_GUARD({ allocator })

View File

@@ -0,0 +1,28 @@
#+private
#+build netbsd
@(private)
foreign libc {
@(link_name="lwp_self")
_lwp_self :: proc() -> i32 ---
@(link_name="sysctlbyname")
_sysctlbyname :: proc(path: cstring, oldp: rawptr, oldlenp: rawptr, newp: rawptr, newlen: int) -> c.int ---
}
@(require_results)
_get_current_thread_id :: proc "contextless" () -> int {
return int(lwp_self())
}
_get_processor_core_count :: proc() -> int {
count : int = 0
count_size := size_of(count)
if _sysctlbyname("hw.ncpu", &count, &count_size, nil, 0) == 0 {
if count > 0 {
return count
}
}
return 1
}
}

View File

@@ -0,0 +1,20 @@
#+private
#+build openbsd
@(default_calling_convention="c")
foreign libc {
@(link_name="getthrid") _unix_getthrid :: proc() -> int ---
@(link_name="sysconf") _sysconf :: proc(name: c.int) -> c.long ---
}
@(require_results)
_get_current_thread_id :: proc "contextless" () -> int {
return _unix_getthrid()
}
_SC_NPROCESSORS_ONLN :: 503
@(private, require_results)
_get_processor_core_count :: proc() -> int {
return int(_sysconf(_SC_NPROCESSORS_ONLN))
}
}

View File

@@ -10,14 +10,39 @@ import "core:sys/posix"
import "core:sys/unix"
import "core:time"
foreign import lib "system:System"
foreign import libc "system:System"
foreign lib {
foreign libc {
sysctl :: proc "c" (
name: [^]i32, namelen: u32,
oldp: rawptr, oldlenp: ^uint,
newp: rawptr, newlen: uint,
) -> posix.result ---
@(link_name="sysctlbyname")
_sysctlbyname :: proc(path: cstring, oldp: rawptr, oldlenp: rawptr, newp: rawptr, newlen: int) -> c.int ---
}
_get_current_thread_id :: proc "contextless" () -> int {
tid: u64
// NOTE(Oskar): available from OSX 10.6 and iOS 3.2.
// For older versions there is `syscall(SYS_thread_selfid)`, but not really
// the same thing apparently.
foreign pthread { pthread_threadid_np :: proc "c" (rawptr, ^u64) -> c.int --- }
pthread_threadid_np(nil, &tid)
return int(tid)
}
_processor_core_count :: proc() -> int {
count : int = 0
count_size := size_of(count)
if _sysctlbyname("hw.logicalcpu", &count, &count_size, nil, 0) == 0 {
if count > 0 {
return count
}
}
return 1
}
_process_info_by_pid :: proc(pid: int, selection: Process_Info_Fields, allocator: runtime.Allocator) -> (info: Process_Info, err: Error) {

View File

@@ -34,6 +34,14 @@ _get_ppid :: proc() -> int {
return 0
}
_get_current_thread_id :: proc "contextless" () -> int {
return 0
}
_get_processor_core_count :: proc() -> int {
return 1
}
_process_info_by_handle :: proc(process: Process, selection: Process_Info_Fields, allocator: runtime.Allocator) -> (info: Process_Info, err: Error) {
err = .Unsupported
return

View File

@@ -1,6 +1,7 @@
#+private file
package os2
import "base:intrinsics"
import "base:runtime"
import "core:strings"
@@ -55,6 +56,35 @@ _get_ppid :: proc() -> int {
return -1
}
@(private="package")
_get_current_thread_id :: proc "contextless" () -> int {
return int(win32.GetCurrentThreadId())
}
@(private="package")
_get_processor_core_count :: proc() -> int {
length : win32.DWORD = 0
result := win32.GetLogicalProcessorInformation(nil, &length)
thread_count := 0
if !result && win32.GetLastError() == 122 && length > 0 {
runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD()
processors := make([]win32.SYSTEM_LOGICAL_PROCESSOR_INFORMATION, length, context.temp_allocator)
result = win32.GetLogicalProcessorInformation(&processors[0], &length)
if result {
for processor in processors {
if processor.Relationship == .RelationProcessorCore {
thread := intrinsics.count_ones(processor.ProcessorMask)
thread_count += int(thread)
}
}
}
}
return thread_count
}
@(private="package")
_process_list :: proc(allocator: runtime.Allocator) -> (list: []int, err: Error) {
snap := win32.CreateToolhelp32Snapshot(win32.TH32CS_SNAPPROCESS, 0)

View File

@@ -598,7 +598,7 @@ foreign libc {
@(link_name="fstat64") _unix_fstat :: proc(fd: Handle, stat: ^OS_Stat) -> c.int ---
@(link_name="readlink") _unix_readlink :: proc(path: cstring, buf: ^byte, bufsiz: c.size_t) -> c.ssize_t ---
@(link_name="access") _unix_access :: proc(path: cstring, mask: c.int) -> c.int ---
@(link_name="fsync") _unix_fsync :: proc(handle: Handle) -> c.int ---
@(link_name="fsync") _unix_fsync :: proc(handle: Handle) -> c.int ---
@(link_name="dup") _unix_dup :: proc(handle: Handle) -> Handle ---
@(link_name="fdopendir$INODE64") _unix_fdopendir_amd64 :: proc(fd: Handle) -> Dir ---

View File

@@ -1,9 +1,9 @@
#+private
package terminal
import "base:runtime"
import "core:os"
import "core:strings"
import "base:runtime"
import os "core:os/os2"
import "core:strings"
// Reference documentation:
//
@@ -86,4 +86,4 @@ init_terminal :: proc "contextless" () {
@(fini)
fini_terminal :: proc "contextless" () {
_fini_terminal()
}
}

View File

@@ -4,13 +4,9 @@ package terminal
import "base:runtime"
import os "core:os/os2"
import "core:sys/posix"
_is_terminal :: proc "contextless" (f: ^os.File) -> bool {
context = runtime.default_context()
fd := os.fd(f)
is_tty := posix.isatty(posix.FD(fd))
return bool(is_tty)
return os.is_tty(f)
}
_init_terminal :: proc "contextless" () {

View File

@@ -6,10 +6,7 @@ import os "core:os/os2"
import "core:sys/windows"
_is_terminal :: proc "contextless" (f: ^os.File) -> bool {
context = runtime.default_context()
fd := os.fd(f)
is_tty := windows.GetFileType(windows.HANDLE(fd)) == windows.FILE_TYPE_CHAR
return is_tty
return os.is_tty(f)
}
old_modes: [2]struct{

View File

@@ -20,7 +20,7 @@ import "core:io"
@require import "core:log"
import "core:math/rand"
import "core:mem"
import "core:os"
import os "core:os/os2"
import "core:slice"
@require import "core:strings"
import "core:sync/chan"
@@ -216,8 +216,8 @@ runner :: proc(internal_tests: []Internal_Test) -> bool {
}
}
stdout := io.to_writer(os.stream_from_handle(os.stdout))
stderr := io.to_writer(os.stream_from_handle(os.stderr))
stdout := os.stdout.stream
stderr := os.stderr.stream
// The animations are only ever shown through STDOUT;
// STDERR is used exclusively for logging regardless of error level.
@@ -314,7 +314,7 @@ runner :: proc(internal_tests: []Internal_Test) -> bool {
// -- Set thread count.
when TEST_THREADS == 0 {
thread_count := os.processor_core_count()
thread_count := os.get_processor_core_count()
} else {
thread_count := max(1, TEST_THREADS)
}

View File

@@ -10,11 +10,11 @@ package testing
Feoramund: Total rewrite.
*/
import "base:intrinsics"
import "core:c/libc"
import "core:os"
import "core:sync"
import "core:terminal/ansi"
import "base:intrinsics"
import "core:c/libc"
import os "core:os/os2"
import "core:sync"
import "core:terminal/ansi"
@(private="file") stop_runner_flag: libc.sig_atomic_t