| // Copyright 2016 The Go Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style |
| // license that can be found in the LICENSE file. |
| |
| //go:build unix && !android && !cgo |
| |
| package user |
| |
| import ( |
| "reflect" |
| "strings" |
| "testing" |
| ) |
| |
| var groupTests = []struct { |
| in string |
| name string |
| gid string |
| }{ |
| {testGroupFile, "nobody", "-2"}, |
| {testGroupFile, "kmem", "2"}, |
| {testGroupFile, "notinthefile", ""}, |
| {testGroupFile, "comment", ""}, |
| {testGroupFile, "plussign", ""}, |
| {testGroupFile, "+plussign", ""}, |
| {testGroupFile, "-minussign", ""}, |
| {testGroupFile, "minussign", ""}, |
| {testGroupFile, "emptyid", ""}, |
| {testGroupFile, "invalidgid", ""}, |
| {testGroupFile, "indented", "7"}, |
| {testGroupFile, "# comment", ""}, |
| {testGroupFile, "largegroup", "1000"}, |
| {testGroupFile, "manymembers", "777"}, |
| {"", "emptyfile", ""}, |
| } |
| |
| func TestFindGroupName(t *testing.T) { |
| for _, tt := range groupTests { |
| got, err := findGroupName(tt.name, strings.NewReader(tt.in)) |
| if tt.gid == "" { |
| if err == nil { |
| t.Errorf("findGroupName(%s): got nil error, expected err", tt.name) |
| continue |
| } |
| switch terr := err.(type) { |
| case UnknownGroupError: |
| if terr.Error() != "group: unknown group "+tt.name { |
| t.Errorf("findGroupName(%s): got %v, want %v", tt.name, terr, tt.name) |
| } |
| default: |
| t.Errorf("findGroupName(%s): got unexpected error %v", tt.name, terr) |
| } |
| } else { |
| if err != nil { |
| t.Fatalf("findGroupName(%s): got unexpected error %v", tt.name, err) |
| } |
| if got.Gid != tt.gid { |
| t.Errorf("findGroupName(%s): got gid %v, want %s", tt.name, got.Gid, tt.gid) |
| } |
| if got.Name != tt.name { |
| t.Errorf("findGroupName(%s): got name %s, want %s", tt.name, got.Name, tt.name) |
| } |
| } |
| } |
| } |
| |
| var groupIdTests = []struct { |
| in string |
| gid string |
| name string |
| }{ |
| {testGroupFile, "-2", "nobody"}, |
| {testGroupFile, "2", "kmem"}, |
| {testGroupFile, "notinthefile", ""}, |
| {testGroupFile, "comment", ""}, |
| {testGroupFile, "7", "indented"}, |
| {testGroupFile, "4", ""}, |
| {testGroupFile, "20", ""}, // row starts with a plus |
| {testGroupFile, "21", ""}, // row starts with a minus |
| {"", "emptyfile", ""}, |
| } |
| |
| func TestFindGroupId(t *testing.T) { |
| for _, tt := range groupIdTests { |
| got, err := findGroupId(tt.gid, strings.NewReader(tt.in)) |
| if tt.name == "" { |
| if err == nil { |
| t.Errorf("findGroupId(%s): got nil error, expected err", tt.gid) |
| continue |
| } |
| switch terr := err.(type) { |
| case UnknownGroupIdError: |
| if terr.Error() != "group: unknown groupid "+tt.gid { |
| t.Errorf("findGroupId(%s): got %v, want %v", tt.name, terr, tt.name) |
| } |
| default: |
| t.Errorf("findGroupId(%s): got unexpected error %v", tt.name, terr) |
| } |
| } else { |
| if err != nil { |
| t.Fatalf("findGroupId(%s): got unexpected error %v", tt.name, err) |
| } |
| if got.Gid != tt.gid { |
| t.Errorf("findGroupId(%s): got gid %v, want %s", tt.name, got.Gid, tt.gid) |
| } |
| if got.Name != tt.name { |
| t.Errorf("findGroupId(%s): got name %s, want %s", tt.name, got.Name, tt.name) |
| } |
| } |
| } |
| } |
| |
| const testUserFile = ` # Example user file |
| root:x:0:0:root:/root:/bin/bash |
| daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin |
| bin:x:2:3:bin:/bin:/usr/sbin/nologin |
| indented:x:3:3:indented:/dev:/usr/sbin/nologin |
| sync:x:4:65534:sync:/bin:/bin/sync |
| negative:x:-5:60:games:/usr/games:/usr/sbin/nologin |
| man:x:6:12:man:/var/cache/man:/usr/sbin/nologin |
| allfields:x:6:12:mansplit,man2,man3,man4:/home/allfields:/usr/sbin/nologin |
| +plussign:x:8:10:man:/var/cache/man:/usr/sbin/nologin |
| -minussign:x:9:10:man:/var/cache/man:/usr/sbin/nologin |
| |
| malformed:x:27:12 # more:colons:after:comment |
| |
| struid:x:notanumber:12 # more:colons:after:comment |
| |
| # commented:x:28:12:commented:/var/cache/man:/usr/sbin/nologin |
| # commentindented:x:29:12:commentindented:/var/cache/man:/usr/sbin/nologin |
| |
| struid2:x:30:badgid:struid2name:/home/struid:/usr/sbin/nologin |
| ` |
| |
| var userIdTests = []struct { |
| in string |
| uid string |
| name string |
| }{ |
| {testUserFile, "-5", "negative"}, |
| {testUserFile, "2", "bin"}, |
| {testUserFile, "100", ""}, // not in the file |
| {testUserFile, "8", ""}, // plus sign, glibc doesn't find it |
| {testUserFile, "9", ""}, // minus sign, glibc doesn't find it |
| {testUserFile, "27", ""}, // malformed |
| {testUserFile, "28", ""}, // commented out |
| {testUserFile, "29", ""}, // commented out, indented |
| {testUserFile, "3", "indented"}, |
| {testUserFile, "30", ""}, // the Gid is not valid, shouldn't match |
| {"", "1", ""}, |
| } |
| |
| func TestInvalidUserId(t *testing.T) { |
| _, err := findUserId("notanumber", strings.NewReader("")) |
| if err == nil { |
| t.Fatalf("findUserId('notanumber'): got nil error") |
| } |
| if want := "user: invalid userid notanumber"; err.Error() != want { |
| t.Errorf("findUserId('notanumber'): got %v, want %s", err, want) |
| } |
| } |
| |
| func TestLookupUserId(t *testing.T) { |
| for _, tt := range userIdTests { |
| got, err := findUserId(tt.uid, strings.NewReader(tt.in)) |
| if tt.name == "" { |
| if err == nil { |
| t.Errorf("findUserId(%s): got nil error, expected err", tt.uid) |
| continue |
| } |
| switch terr := err.(type) { |
| case UnknownUserIdError: |
| if want := "user: unknown userid " + tt.uid; terr.Error() != want { |
| t.Errorf("findUserId(%s): got %v, want %v", tt.name, terr, want) |
| } |
| default: |
| t.Errorf("findUserId(%s): got unexpected error %v", tt.name, terr) |
| } |
| } else { |
| if err != nil { |
| t.Fatalf("findUserId(%s): got unexpected error %v", tt.name, err) |
| } |
| if got.Uid != tt.uid { |
| t.Errorf("findUserId(%s): got uid %v, want %s", tt.name, got.Uid, tt.uid) |
| } |
| if got.Username != tt.name { |
| t.Errorf("findUserId(%s): got name %s, want %s", tt.name, got.Username, tt.name) |
| } |
| } |
| } |
| } |
| |
| func TestLookupUserPopulatesAllFields(t *testing.T) { |
| u, err := findUsername("allfields", strings.NewReader(testUserFile)) |
| if err != nil { |
| t.Fatal(err) |
| } |
| want := &User{ |
| Username: "allfields", |
| Uid: "6", |
| Gid: "12", |
| Name: "mansplit", |
| HomeDir: "/home/allfields", |
| } |
| if !reflect.DeepEqual(u, want) { |
| t.Errorf("findUsername: got %#v, want %#v", u, want) |
| } |
| } |
| |
| var userTests = []struct { |
| in string |
| name string |
| uid string |
| }{ |
| {testUserFile, "negative", "-5"}, |
| {testUserFile, "bin", "2"}, |
| {testUserFile, "notinthefile", ""}, |
| {testUserFile, "indented", "3"}, |
| {testUserFile, "plussign", ""}, |
| {testUserFile, "+plussign", ""}, |
| {testUserFile, "minussign", ""}, |
| {testUserFile, "-minussign", ""}, |
| {testUserFile, " indented", ""}, |
| {testUserFile, "commented", ""}, |
| {testUserFile, "commentindented", ""}, |
| {testUserFile, "malformed", ""}, |
| {testUserFile, "# commented", ""}, |
| {"", "emptyfile", ""}, |
| } |
| |
| func TestLookupUser(t *testing.T) { |
| for _, tt := range userTests { |
| got, err := findUsername(tt.name, strings.NewReader(tt.in)) |
| if tt.uid == "" { |
| if err == nil { |
| t.Errorf("lookupUser(%s): got nil error, expected err", tt.uid) |
| continue |
| } |
| switch terr := err.(type) { |
| case UnknownUserError: |
| if want := "user: unknown user " + tt.name; terr.Error() != want { |
| t.Errorf("lookupUser(%s): got %v, want %v", tt.name, terr, want) |
| } |
| default: |
| t.Errorf("lookupUser(%s): got unexpected error %v", tt.name, terr) |
| } |
| } else { |
| if err != nil { |
| t.Fatalf("lookupUser(%s): got unexpected error %v", tt.name, err) |
| } |
| if got.Uid != tt.uid { |
| t.Errorf("lookupUser(%s): got uid %v, want %s", tt.name, got.Uid, tt.uid) |
| } |
| if got.Username != tt.name { |
| t.Errorf("lookupUser(%s): got name %s, want %s", tt.name, got.Username, tt.name) |
| } |
| } |
| } |
| } |