aboutsummaryrefslogtreecommitdiff
path: root/internal/mmap/mmap_test.go
blob: 814c23a303ebde6865d59c3852d37d12520e4813 (about) (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
//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)
	}
}