1// Copyright 2011 The Go Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style
3// license that can be found in the LICENSE file.
4
5package user
6
7import (
8	"os"
9	"testing"
10)
11
12var (
13	hasCgo  = false
14	hasUSER = os.Getenv("USER") != ""
15	hasHOME = os.Getenv("HOME") != ""
16)
17
18func checkUser(t *testing.T) {
19	t.Helper()
20	if !userImplemented {
21		t.Skip("user: not implemented; skipping tests")
22	}
23}
24
25func TestCurrent(t *testing.T) {
26	old := userBuffer
27	defer func() {
28		userBuffer = old
29	}()
30	userBuffer = 1 // force use of retry code
31	u, err := Current()
32	if err != nil {
33		if hasCgo || (hasUSER && hasHOME) {
34			t.Fatalf("Current: %v (got %#v)", err, u)
35		} else {
36			t.Skipf("skipping: %v", err)
37		}
38	}
39	if u.HomeDir == "" {
40		t.Errorf("didn't get a HomeDir")
41	}
42	if u.Username == "" {
43		t.Errorf("didn't get a username")
44	}
45}
46
47func BenchmarkCurrent(b *testing.B) {
48	for i := 0; i < b.N; i++ {
49		Current()
50	}
51}
52
53func compare(t *testing.T, want, got *User) {
54	if want.Uid != got.Uid {
55		t.Errorf("got Uid=%q; want %q", got.Uid, want.Uid)
56	}
57	if want.Username != got.Username {
58		t.Errorf("got Username=%q; want %q", got.Username, want.Username)
59	}
60	if want.Name != got.Name {
61		t.Errorf("got Name=%q; want %q", got.Name, want.Name)
62	}
63	if want.HomeDir != got.HomeDir {
64		t.Errorf("got HomeDir=%q; want %q", got.HomeDir, want.HomeDir)
65	}
66	if want.Gid != got.Gid {
67		t.Errorf("got Gid=%q; want %q", got.Gid, want.Gid)
68	}
69}
70
71func TestLookup(t *testing.T) {
72	checkUser(t)
73
74	want, err := Current()
75	if err != nil {
76		if hasCgo || (hasUSER && hasHOME) {
77			t.Fatalf("Current: %v", err)
78		} else {
79			t.Skipf("skipping: %v", err)
80		}
81	}
82
83	// TODO: Lookup() has a fast path that calls Current() and returns if the
84	// usernames match, so this test does not exercise very much. It would be
85	// good to try and test finding a different user than the current user.
86	got, err := Lookup(want.Username)
87	if err != nil {
88		t.Fatalf("Lookup: %v", err)
89	}
90	compare(t, want, got)
91}
92
93func TestLookupId(t *testing.T) {
94	checkUser(t)
95
96	want, err := Current()
97	if err != nil {
98		if hasCgo || (hasUSER && hasHOME) {
99			t.Fatalf("Current: %v", err)
100		} else {
101			t.Skipf("skipping: %v", err)
102		}
103	}
104
105	got, err := LookupId(want.Uid)
106	if err != nil {
107		t.Fatalf("LookupId: %v", err)
108	}
109	compare(t, want, got)
110}
111
112func checkGroup(t *testing.T) {
113	t.Helper()
114	if !groupImplemented {
115		t.Skip("user: group not implemented; skipping test")
116	}
117}
118
119func TestLookupGroup(t *testing.T) {
120	old := groupBuffer
121	defer func() {
122		groupBuffer = old
123	}()
124	groupBuffer = 1 // force use of retry code
125	checkGroup(t)
126
127	user, err := Current()
128	if err != nil {
129		if hasCgo || (hasUSER && hasHOME) {
130			t.Fatalf("Current: %v", err)
131		} else {
132			t.Skipf("skipping: %v", err)
133		}
134	}
135
136	g1, err := LookupGroupId(user.Gid)
137	if err != nil {
138		// NOTE(rsc): Maybe the group isn't defined. That's fine.
139		// On my OS X laptop, rsc logs in with group 5000 even
140		// though there's no name for group 5000. Such is Unix.
141		t.Logf("LookupGroupId(%q): %v", user.Gid, err)
142		return
143	}
144	if g1.Gid != user.Gid {
145		t.Errorf("LookupGroupId(%q).Gid = %s; want %s", user.Gid, g1.Gid, user.Gid)
146	}
147
148	g2, err := LookupGroup(g1.Name)
149	if err != nil {
150		t.Fatalf("LookupGroup(%q): %v", g1.Name, err)
151	}
152	if g1.Gid != g2.Gid || g1.Name != g2.Name {
153		t.Errorf("LookupGroup(%q) = %+v; want %+v", g1.Name, g2, g1)
154	}
155}
156
157func checkGroupList(t *testing.T) {
158	t.Helper()
159	if !groupListImplemented {
160		t.Skip("user: group list not implemented; skipping test")
161	}
162}
163
164func TestGroupIds(t *testing.T) {
165	checkGroupList(t)
166
167	user, err := Current()
168	if err != nil {
169		if hasCgo || (hasUSER && hasHOME) {
170			t.Fatalf("Current: %v", err)
171		} else {
172			t.Skipf("skipping: %v", err)
173		}
174	}
175
176	gids, err := user.GroupIds()
177	if err != nil {
178		t.Fatalf("%+v.GroupIds(): %v", user, err)
179	}
180	if !containsID(gids, user.Gid) {
181		t.Errorf("%+v.GroupIds() = %v; does not contain user GID %s", user, gids, user.Gid)
182	}
183}
184
185func containsID(ids []string, id string) bool {
186	for _, x := range ids {
187		if x == id {
188			return true
189		}
190	}
191	return false
192}
193