// Copyright 2026 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. //go:build darwin || openbsd package unix_test import ( "os" "path/filepath" "testing" "golang.org/x/sys/unix" ) func TestWritevReadv(t *testing.T) { r, w, err := os.Pipe() if err != nil { t.Fatal(err) } defer r.Close() defer w.Close() data := [][]byte{[]byte("hello"), []byte(", "), []byte("world")} wn, err := unix.Writev(int(w.Fd()), data) if err != nil { t.Fatal(err) } if wn != 12 { t.Fatalf("Writev wrote %d bytes, want 12", wn) } w.Close() buf1 := make([]byte, 5) buf2 := make([]byte, 2) buf3 := make([]byte, 5) rn, err := unix.Readv(int(r.Fd()), [][]byte{buf1, buf2, buf3}) if err != nil { t.Fatal(err) } if rn != 12 { t.Fatalf("Readv read %d bytes, want 12", rn) } if string(buf1) != "hello" || string(buf2) != ", " || string(buf3[:5]) != "world" { t.Fatalf("Readv got %q %q %q, want %q %q %q", buf1, buf2, buf3, "hello", ", ", "world") } } func TestPwritevPreadv(t *testing.T) { path := filepath.Join(t.TempDir(), "preadv_test") f, err := os.Create(path) if err != nil { t.Fatal(err) } t.Cleanup(func() { f.Close() }) const off = 16 data := [][]byte{[]byte("foo"), []byte("bar")} wn, err := unix.Pwritev(int(f.Fd()), data, off) if err != nil { t.Fatal(err) } if wn != 6 { t.Fatalf("Pwritev wrote %d bytes, want 6", wn) } got1 := make([]byte, 3) got2 := make([]byte, 3) rn, err := unix.Preadv(int(f.Fd()), [][]byte{got1, got2}, off) if err != nil { t.Fatal(err) } if rn != 6 { t.Fatalf("Preadv read %d bytes, want 6", rn) } if string(got1) != "foo" || string(got2) != "bar" { t.Fatalf("Preadv got %q %q, want %q %q", got1, got2, "foo", "bar") } } func TestPwritevOffset(t *testing.T) { // Regression guard: off_t encoding must not overflow on large offsets. // Mirrors the Linux test for golang.org/issues/57291. path := filepath.Join(t.TempDir(), "offset_test") f, err := os.Create(path) if err != nil { t.Fatal(err) } t.Cleanup(func() { f.Close() }) const off = 20 b := [][]byte{{byte(0)}} n, err := unix.Pwritev(int(f.Fd()), b, off) if err != nil { t.Fatal(err) } if n != 1 { t.Fatalf("Pwritev wrote %d bytes, want 1", n) } info, err := f.Stat() if err != nil { t.Fatal(err) } if want := int64(off + 1); info.Size() != want { t.Fatalf("file size %d, want %d", info.Size(), want) } } func TestWritevReadvAllocations(t *testing.T) { // Verify no heap allocations when iovec count <= minIovec (8). // Allocations in this path indicate a regression in the fast path. f, err := os.Create(filepath.Join(t.TempDir(), "alloc_test")) if err != nil { t.Fatal(err) } t.Cleanup(func() { f.Close() }) iovs := make([][]byte, 8) for i := range iovs { iovs[i] = []byte{'A'} } check := func(name string, fn func()) { t.Helper() n := int(testing.AllocsPerRun(100, fn)) if n != 0 { t.Errorf("%s: got %d allocations, want 0", name, n) } } check("Writev", func() { unix.Writev(int(f.Fd()), iovs) }) check("Pwritev", func() { unix.Pwritev(int(f.Fd()), iovs, 0) }) check("Readv", func() { unix.Readv(int(f.Fd()), iovs) }) check("Preadv", func() { unix.Preadv(int(f.Fd()), iovs, 0) }) }