Programming Language

Nocter

A self-contained systems language built around simplicity, encapsulation, and foolproof design.

/development/std/process/command_io_tests_darwin.nct

command_io_tests_darwin.nct

//! Native qualification for three-direction readiness and bounded transfer facts.

see ./command_io_darwin.nct
see ./pipe_darwin.nct

use /internal/os/darwin.SyscallResult
use /internal/os/darwin
use /internal/ptr as internal_ptr
use /ptr

test command_io_classification_preserves_direction_and_broken_pipe {
    if !events_match_interest(POLL_INPUT, POLL_INPUT)
        || !events_match_interest(POLL_OUTPUT, POLL_OUTPUT)
        || events_match_interest(POLL_INPUT, POLL_OUTPUT)
        || events_match_interest(POLL_OUTPUT, POLL_INPUT) {
        return error.new("std.process.test", "poll direction validation changed")
    }

    match classify_command_io_read(SyscallResult { value: 1, errno: 0 }, 1) {
        CommandIoReadAttempt.bytes(count) {
            if count != 1 { return error.new("std.process.test", "read count changed") }
        }
        _ { return error.new("std.process.test", "read bytes changed classification") }
    }
    match classify_command_io_write(
        SyscallResult { value: 0, errno: darwin.ERRNO_BROKEN_PIPE },
        1,
    ) {
        CommandIoWriteAttempt.broken_pipe {}
        _ { return error.new("std.process.test", "broken pipe changed classification") }
    }
    match classify_command_io_write(SyscallResult { value: 2, errno: 0 }, 1) {
        CommandIoWriteAttempt.malformed {}
        _ { return error.new("std.process.test", "oversized write became progress") }
    }
    match classify_command_io_write(
        SyscallResult { value: 0, errno: darwin.ERRNO_WOULD_BLOCK },
        1,
    ) {
        CommandIoWriteAttempt.would_block {}
        _ { return error.new("std.process.test", "would-block write changed classification") }
    }
    return
}

test command_io_poll_observes_writer_and_reader_together {
    match create_cloexec_pipe() {
        PipeAttempt.failed(_) {
            return error.new("std.process.test", "input readiness pipe creation failed")
        }
        PipeAttempt.ready(input_pipe) {
            var input = move input_pipe
            match configure_pipe_writer_for_async_io(&input) {
                PipeConfigurationAttempt.failed(_) {
                    return error.new("std.process.test", "asynchronous writer configuration failed")
                }
                PipeConfigurationAttempt.ready {}
            }
            match create_cloexec_pipe() {
                PipeAttempt.failed(_) {
                    return error.new("std.process.test", "output readiness pipe creation failed")
                }
                PipeAttempt.ready(output_pipe) {
                    var output = move output_pipe
                    let sent: u8 = 71
                    let written = darwin.syscall3(
                        darwin.SYS_WRITE,
                        pipe_write_fd(&output),
                        ptr.addr(ptr.from_ref(&sent)),
                        1,
                    )
                    if written.errno != 0 || written.value != 1 {
                        return error.new("std.process.test", "readiness fixture write failed")
                    }
                    match poll_command_io_once(
                        pipe_write_fd(&input),
                        true,
                        pipe_read_fd(&output),
                        true,
                        0,
                        false,
                    ) {
                        CommandIoPollAttempt.ready(input_events, stdout_events, stderr_events) {
                            if !input_events.writable || input_events.readable
                                || !stdout_events.readable || stdout_events.writable
                                || stderr_events.readable || stderr_events.writable
                                || stderr_events.error || stderr_events.hangup
                                || stderr_events.invalid {
                                return error.new("std.process.test", "three-direction readiness changed")
                            }
                        }
                        _ { return error.new("std.process.test", "three-direction poll failed") }
                    }

                    close_pipe_read(&+input)
                    let byte: u8 = 1
                    match write_command_input_once(
                        pipe_write_fd(&input),
                        internal_input_byte(&byte),
                        0,
                    ) {
                        CommandIoWriteAttempt.broken_pipe {}
                        _ { return error.new("std.process.test", "owned writer raised SIGPIPE or lost EPIPE") }
                    }
                    drop output
                    drop input
                }
            }
        }
    }
    return
}

noalloc func internal_input_byte(value: &u8): &[u8] {
    return internal_ptr.slice_from_raw_parts_value(ptr.from_ref(value), 1)
}