//go:build unix
package mmap_test
import (
"bytes"
"os"
"path/filepath"
"testing"
"lindenii.org/go/furgit/internal/mmap"
)
// makeTempFileWithContents creates one file with content and opens it for reading.
func makeTempFileWithContents(t *testing.T, content []byte) *os.File {
t.Helper()
path := filepath.Join(t.TempDir(), "data")
err := os.WriteFile(path, content, 0o600)
if err != nil {
t.Fatalf("WriteFile: %v", err)
}
file, err := os.Open(path) //nolint:gosec
if err != nil {
t.Fatalf("Open: %v", err)
}
t.Cleanup(func() { _ = file.Close() })
return file
}
// makeLargeTempFileLongerThanPage creates and opens one file
// whose content repeats seed
// until it spans more than one OS page.
func makeLargeTempFileLongerThanPage(t *testing.T, seed []byte) (*os.File, []byte) {
t.Helper()
content := bytes.Repeat(seed, os.Getpagesize()/len(seed)+2)
return makeTempFileWithContents(t, content), content
}
func TestOpenData(t *testing.T) {
t.Parallel()
file, content := makeLargeTempFileLongerThanPage(t, []byte("mapped bytes\n"))
mapping, err := mmap.Open(file)
if err != nil {
t.Fatalf("Open: %v", err)
}
// The mapping must survive closing the originating file.
err = file.Close()
if err != nil {
t.Fatalf("file Close: %v", err)
}
if !bytes.Equal(mapping.Data(), content) {
t.Fatalf("Data mismatch")
}
err = mapping.Close()
if err != nil {
t.Fatalf("Close: %v", err)
}
}
func TestOpenEmpty(t *testing.T) {
t.Parallel()
file := makeTempFileWithContents(t, nil)
mapping, err := mmap.Open(file)
if err != nil {
t.Fatalf("Open: %v", err)
}
if len(mapping.Data()) != 0 {
t.Fatalf("Data = %d bytes, want empty", len(mapping.Data()))
}
err = mapping.Close()
if err != nil {
t.Fatalf("Close: %v", err)
}
}
func TestCloseIdempotent(t *testing.T) {
t.Parallel()
file, _ := makeLargeTempFileLongerThanPage(t, []byte("once"))
mapping, err := mmap.Open(file)
if err != nil {
t.Fatalf("Open: %v", err)
}
err = mapping.Close()
if err != nil {
t.Fatalf("first Close: %v", err)
}
err = mapping.Close()
if err != nil {
t.Fatalf("second Close: %v", err)
}
}