Black Lives Matter. Support the Equal Justice Initiative.

Source file src/os/user/lookup_unix_test.go

Documentation: os/user

     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  }
   290  

View as plain text