summaryrefslogtreecommitdiffhomepage
path: root/util/winutil/winutil_windows_test.go
blob: 955006789bc43ef50db8a27171769dc69cc3ea1d (plain)
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
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
// Copyright (c) Tailscale Inc & contributors
// SPDX-License-Identifier: BSD-3-Clause

package winutil

import (
	"reflect"
	"testing"
	"unsafe"
)

//lint:file-ignore U1000 Fields are unused but necessary for tests.

const (
	localSystemSID = "S-1-5-18"
	networkSID     = "S-1-5-2"
)

func TestLookupPseudoUser(t *testing.T) {
	localSystem, err := LookupPseudoUser(localSystemSID)
	if err != nil {
		t.Errorf("LookupPseudoUser(%q) error: %v", localSystemSID, err)
	}
	if localSystem.Gid != localSystemSID {
		t.Errorf("incorrect Gid, got %q, want %q", localSystem.Gid, localSystemSID)
	}
	t.Logf("localSystem: %v", localSystem)

	// networkSID is a built-in known group but not a pseudo-user.
	_, err = LookupPseudoUser(networkSID)
	if err == nil {
		t.Errorf("LookupPseudoUser(%q) unexpectedly succeeded", networkSID)
	}
}

type testType interface {
	byte | uint16 | uint32 | uint64
}

type noPointers[T testType] struct {
	foo byte
	bar T
	baz bool
}

type hasPointer struct {
	foo byte
	bar uint32
	s1  *struct{}
	baz byte
}

func checkContiguousBuffer[T any, BU BufUnit](t *testing.T, extra []BU, pt *T, ptLen uint32, slcs [][]BU) {
	szBU := int(unsafe.Sizeof(BU(0)))
	expectedAlign := max(reflect.TypeFor[T]().Align(), szBU)
	// Check that pointer is aligned
	if rem := uintptr(unsafe.Pointer(pt)) % uintptr(expectedAlign); rem != 0 {
		t.Errorf("pointer alignment got %d, want 0", rem)
	}
	// Check that alloc length is aligned
	if rem := int(ptLen) % expectedAlign; rem != 0 {
		t.Errorf("allocation length alignment got %d, want 0", rem)
	}
	expectedLen := int(unsafe.Sizeof(*pt))
	expectedLen = alignUp(expectedLen, szBU)
	expectedLen += len(extra) * szBU
	expectedLen = alignUp(expectedLen, expectedAlign)
	if gotLen := int(ptLen); gotLen != expectedLen {
		t.Errorf("allocation length got %d, want %d", gotLen, expectedLen)
	}
	if ln := len(slcs); ln != 1 {
		t.Errorf("len(slcs) got %d, want 1", ln)
	}
	if len(extra) == 0 && slcs[0] != nil {
		t.Error("slcs[0] got non-nil, want nil")
	}
	if len(extra) != len(slcs[0]) {
		t.Errorf("len(slcs[0]) got %d, want %d", len(slcs[0]), len(extra))
	} else if rem := uintptr(unsafe.Pointer(unsafe.SliceData(slcs[0]))) % uintptr(szBU); rem != 0 {
		t.Errorf("additional data alignment got %d, want 0", rem)
	}
}

func TestAllocateContiguousBuffer(t *testing.T) {
	t.Run("NoValues", testNoValues)
	t.Run("NoPointers", testNoPointers)
	t.Run("HasPointer", testHasPointer)
}

func testNoValues(t *testing.T) {
	defer func() {
		if r := recover(); r == nil {
			t.Error("expected panic but didn't get one")
		}
	}()

	AllocateContiguousBuffer[hasPointer, byte]()
}

const maxTestBufLen = 8

func testNoPointers(t *testing.T) {
	buf8 := make([]byte, maxTestBufLen)
	buf16 := make([]uint16, maxTestBufLen)
	for i := range maxTestBufLen {
		s8, sl, slcs8 := AllocateContiguousBuffer[noPointers[byte]](buf8[:i])
		checkContiguousBuffer(t, buf8[:i], s8, sl, slcs8)
		s16, sl, slcs8 := AllocateContiguousBuffer[noPointers[uint16]](buf8[:i])
		checkContiguousBuffer(t, buf8[:i], s16, sl, slcs8)
		s32, sl, slcs8 := AllocateContiguousBuffer[noPointers[uint32]](buf8[:i])
		checkContiguousBuffer(t, buf8[:i], s32, sl, slcs8)
		s64, sl, slcs8 := AllocateContiguousBuffer[noPointers[uint64]](buf8[:i])
		checkContiguousBuffer(t, buf8[:i], s64, sl, slcs8)
		s8, sl, slcs16 := AllocateContiguousBuffer[noPointers[byte]](buf16[:i])
		checkContiguousBuffer(t, buf16[:i], s8, sl, slcs16)
		s16, sl, slcs16 = AllocateContiguousBuffer[noPointers[uint16]](buf16[:i])
		checkContiguousBuffer(t, buf16[:i], s16, sl, slcs16)
		s32, sl, slcs16 = AllocateContiguousBuffer[noPointers[uint32]](buf16[:i])
		checkContiguousBuffer(t, buf16[:i], s32, sl, slcs16)
		s64, sl, slcs16 = AllocateContiguousBuffer[noPointers[uint64]](buf16[:i])
		checkContiguousBuffer(t, buf16[:i], s64, sl, slcs16)
	}
}

func testHasPointer(t *testing.T) {
	buf8 := make([]byte, maxTestBufLen)
	buf16 := make([]uint16, maxTestBufLen)
	for i := range maxTestBufLen {
		s, sl, slcs8 := AllocateContiguousBuffer[hasPointer](buf8[:i])
		checkContiguousBuffer(t, buf8[:i], s, sl, slcs8)
		s, sl, slcs16 := AllocateContiguousBuffer[hasPointer](buf16[:i])
		checkContiguousBuffer(t, buf16[:i], s, sl, slcs16)
	}
}