github.com/code-reading/golang@v0.0.0-20220303082512-ba5bc0e589a3/go/src/os/user/lookup_unix_test.go (about) 1 // Copyright 2016 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 5 //go:build (aix || darwin || dragonfly || freebsd || (!android && linux) || netbsd || openbsd || solaris) && !cgo 6 // +build aix darwin dragonfly freebsd !android,linux netbsd openbsd solaris 7 // +build !cgo 8 9 package user 10 11 import ( 12 "fmt" 13 "reflect" 14 "strings" 15 "testing" 16 ) 17 18 var testGroupFile = `# See the opendirectoryd(8) man page for additional 19 # information about Open Directory. 20 ## 21 nobody:*:-2: 22 nogroup:*:-1: 23 wheel:*:0:root 24 emptyid:*::root 25 invalidgid:*:notanumber:root 26 +plussign:*:20:root 27 -minussign:*:21:root 28 29 daemon:*:1:root 30 indented:*:7: 31 # comment:*:4:found 32 # comment:*:4:found 33 kmem:*:2:root 34 ` + largeGroup() 35 36 var groupTests = []struct { 37 in string 38 name string 39 gid string 40 }{ 41 {testGroupFile, "nobody", "-2"}, 42 {testGroupFile, "kmem", "2"}, 43 {testGroupFile, "notinthefile", ""}, 44 {testGroupFile, "comment", ""}, 45 {testGroupFile, "plussign", ""}, 46 {testGroupFile, "+plussign", ""}, 47 {testGroupFile, "-minussign", ""}, 48 {testGroupFile, "minussign", ""}, 49 {testGroupFile, "emptyid", ""}, 50 {testGroupFile, "invalidgid", ""}, 51 {testGroupFile, "indented", "7"}, 52 {testGroupFile, "# comment", ""}, 53 {testGroupFile, "largegroup", "1000"}, 54 {"", "emptyfile", ""}, 55 } 56 57 // Generate a proper "largegroup" entry for testGroupFile string 58 func largeGroup() (res string) { 59 var b strings.Builder 60 b.WriteString("largegroup:x:1000:user1") 61 for i := 2; i <= 7500; i++ { 62 fmt.Fprintf(&b, ",user%d", i) 63 } 64 return b.String() 65 } 66 67 func TestFindGroupName(t *testing.T) { 68 for _, tt := range groupTests { 69 got, err := findGroupName(tt.name, strings.NewReader(tt.in)) 70 if tt.gid == "" { 71 if err == nil { 72 t.Errorf("findGroupName(%s): got nil error, expected err", tt.name) 73 continue 74 } 75 switch terr := err.(type) { 76 case UnknownGroupError: 77 if terr.Error() != "group: unknown group "+tt.name { 78 t.Errorf("findGroupName(%s): got %v, want %v", tt.name, terr, tt.name) 79 } 80 default: 81 t.Errorf("findGroupName(%s): got unexpected error %v", tt.name, terr) 82 } 83 } else { 84 if err != nil { 85 t.Fatalf("findGroupName(%s): got unexpected error %v", tt.name, err) 86 } 87 if got.Gid != tt.gid { 88 t.Errorf("findGroupName(%s): got gid %v, want %s", tt.name, got.Gid, tt.gid) 89 } 90 if got.Name != tt.name { 91 t.Errorf("findGroupName(%s): got name %s, want %s", tt.name, got.Name, tt.name) 92 } 93 } 94 } 95 } 96 97 var groupIdTests = []struct { 98 in string 99 gid string 100 name string 101 }{ 102 {testGroupFile, "-2", "nobody"}, 103 {testGroupFile, "2", "kmem"}, 104 {testGroupFile, "notinthefile", ""}, 105 {testGroupFile, "comment", ""}, 106 {testGroupFile, "7", "indented"}, 107 {testGroupFile, "4", ""}, 108 {testGroupFile, "20", ""}, // row starts with a plus 109 {testGroupFile, "21", ""}, // row starts with a minus 110 {"", "emptyfile", ""}, 111 } 112 113 func TestFindGroupId(t *testing.T) { 114 for _, tt := range groupIdTests { 115 got, err := findGroupId(tt.gid, strings.NewReader(tt.in)) 116 if tt.name == "" { 117 if err == nil { 118 t.Errorf("findGroupId(%s): got nil error, expected err", tt.gid) 119 continue 120 } 121 switch terr := err.(type) { 122 case UnknownGroupIdError: 123 if terr.Error() != "group: unknown groupid "+tt.gid { 124 t.Errorf("findGroupId(%s): got %v, want %v", tt.name, terr, tt.name) 125 } 126 default: 127 t.Errorf("findGroupId(%s): got unexpected error %v", tt.name, terr) 128 } 129 } else { 130 if err != nil { 131 t.Fatalf("findGroupId(%s): got unexpected error %v", tt.name, err) 132 } 133 if got.Gid != tt.gid { 134 t.Errorf("findGroupId(%s): got gid %v, want %s", tt.name, got.Gid, tt.gid) 135 } 136 if got.Name != tt.name { 137 t.Errorf("findGroupId(%s): got name %s, want %s", tt.name, got.Name, tt.name) 138 } 139 } 140 } 141 } 142 143 const testUserFile = ` # Example user file 144 root:x:0:0:root:/root:/bin/bash 145 daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin 146 bin:x:2:3:bin:/bin:/usr/sbin/nologin 147 indented:x:3:3:indented:/dev:/usr/sbin/nologin 148 sync:x:4:65534:sync:/bin:/bin/sync 149 negative:x:-5:60:games:/usr/games:/usr/sbin/nologin 150 man:x:6:12:man:/var/cache/man:/usr/sbin/nologin 151 allfields:x:6:12:mansplit,man2,man3,man4:/home/allfields:/usr/sbin/nologin 152 +plussign:x:8:10:man:/var/cache/man:/usr/sbin/nologin 153 -minussign:x:9:10:man:/var/cache/man:/usr/sbin/nologin 154 155 malformed:x:27:12 # more:colons:after:comment 156 157 struid:x:notanumber:12 # more:colons:after:comment 158 159 # commented:x:28:12:commented:/var/cache/man:/usr/sbin/nologin 160 # commentindented:x:29:12:commentindented:/var/cache/man:/usr/sbin/nologin 161 162 struid2:x:30:badgid:struid2name:/home/struid:/usr/sbin/nologin 163 ` 164 165 var userIdTests = []struct { 166 in string 167 uid string 168 name string 169 }{ 170 {testUserFile, "-5", "negative"}, 171 {testUserFile, "2", "bin"}, 172 {testUserFile, "100", ""}, // not in the file 173 {testUserFile, "8", ""}, // plus sign, glibc doesn't find it 174 {testUserFile, "9", ""}, // minus sign, glibc doesn't find it 175 {testUserFile, "27", ""}, // malformed 176 {testUserFile, "28", ""}, // commented out 177 {testUserFile, "29", ""}, // commented out, indented 178 {testUserFile, "3", "indented"}, 179 {testUserFile, "30", ""}, // the Gid is not valid, shouldn't match 180 {"", "1", ""}, 181 } 182 183 func TestInvalidUserId(t *testing.T) { 184 _, err := findUserId("notanumber", strings.NewReader("")) 185 if err == nil { 186 t.Fatalf("findUserId('notanumber'): got nil error") 187 } 188 if want := "user: invalid userid notanumber"; err.Error() != want { 189 t.Errorf("findUserId('notanumber'): got %v, want %s", err, want) 190 } 191 } 192 193 func TestLookupUserId(t *testing.T) { 194 for _, tt := range userIdTests { 195 got, err := findUserId(tt.uid, strings.NewReader(tt.in)) 196 if tt.name == "" { 197 if err == nil { 198 t.Errorf("findUserId(%s): got nil error, expected err", tt.uid) 199 continue 200 } 201 switch terr := err.(type) { 202 case UnknownUserIdError: 203 if want := "user: unknown userid " + tt.uid; terr.Error() != want { 204 t.Errorf("findUserId(%s): got %v, want %v", tt.name, terr, want) 205 } 206 default: 207 t.Errorf("findUserId(%s): got unexpected error %v", tt.name, terr) 208 } 209 } else { 210 if err != nil { 211 t.Fatalf("findUserId(%s): got unexpected error %v", tt.name, err) 212 } 213 if got.Uid != tt.uid { 214 t.Errorf("findUserId(%s): got uid %v, want %s", tt.name, got.Uid, tt.uid) 215 } 216 if got.Username != tt.name { 217 t.Errorf("findUserId(%s): got name %s, want %s", tt.name, got.Username, tt.name) 218 } 219 } 220 } 221 } 222 223 func TestLookupUserPopulatesAllFields(t *testing.T) { 224 u, err := findUsername("allfields", strings.NewReader(testUserFile)) 225 if err != nil { 226 t.Fatal(err) 227 } 228 want := &User{ 229 Username: "allfields", 230 Uid: "6", 231 Gid: "12", 232 Name: "mansplit", 233 HomeDir: "/home/allfields", 234 } 235 if !reflect.DeepEqual(u, want) { 236 t.Errorf("findUsername: got %#v, want %#v", u, want) 237 } 238 } 239 240 var userTests = []struct { 241 in string 242 name string 243 uid string 244 }{ 245 {testUserFile, "negative", "-5"}, 246 {testUserFile, "bin", "2"}, 247 {testUserFile, "notinthefile", ""}, 248 {testUserFile, "indented", "3"}, 249 {testUserFile, "plussign", ""}, 250 {testUserFile, "+plussign", ""}, 251 {testUserFile, "minussign", ""}, 252 {testUserFile, "-minussign", ""}, 253 {testUserFile, " indented", ""}, 254 {testUserFile, "commented", ""}, 255 {testUserFile, "commentindented", ""}, 256 {testUserFile, "malformed", ""}, 257 {testUserFile, "# commented", ""}, 258 {"", "emptyfile", ""}, 259 } 260 261 func TestLookupUser(t *testing.T) { 262 for _, tt := range userTests { 263 got, err := findUsername(tt.name, strings.NewReader(tt.in)) 264 if tt.uid == "" { 265 if err == nil { 266 t.Errorf("lookupUser(%s): got nil error, expected err", tt.uid) 267 continue 268 } 269 switch terr := err.(type) { 270 case UnknownUserError: 271 if want := "user: unknown user " + tt.name; terr.Error() != want { 272 t.Errorf("lookupUser(%s): got %v, want %v", tt.name, terr, want) 273 } 274 default: 275 t.Errorf("lookupUser(%s): got unexpected error %v", tt.name, terr) 276 } 277 } else { 278 if err != nil { 279 t.Fatalf("lookupUser(%s): got unexpected error %v", tt.name, err) 280 } 281 if got.Uid != tt.uid { 282 t.Errorf("lookupUser(%s): got uid %v, want %s", tt.name, got.Uid, tt.uid) 283 } 284 if got.Username != tt.name { 285 t.Errorf("lookupUser(%s): got name %s, want %s", tt.name, got.Username, tt.name) 286 } 287 } 288 } 289 }