package netrc import ( "os" "path/filepath" "strings" "testing" ) func TestUpsertEmptyFile(t *testing.T) { dir := t.TempDir() path := filepath.Join(dir, "netrc") if err := Upsert(path, "cache.example.com", "token123"); err != nil { t.Fatalf("unexpected error: %v", err) } pw, err := GetPassword(path, "cache.example.com") if err != nil { t.Fatalf("unexpected error: %v", err) } if pw != "token123" { t.Errorf("password = %q, want %q", pw, "token123") } } func TestUpsertUpdateExisting(t *testing.T) { dir := t.TempDir() path := filepath.Join(dir, "netrc") initial := "machine other.host\nlogin dummy\npassword otherpass\n\nmachine cache.example.com\nlogin dummy\npassword oldtoken\n" if err := os.WriteFile(path, []byte(initial), 0600); err != nil { t.Fatal(err) } if err := Upsert(path, "cache.example.com", "newtoken"); err != nil { t.Fatalf("unexpected error: %v", err) } // Check updated entry pw, err := GetPassword(path, "cache.example.com") if err != nil { t.Fatalf("unexpected error: %v", err) } if pw != "newtoken" { t.Errorf("password = %q, want %q", pw, "newtoken") } // Check other entry preserved pw, err = GetPassword(path, "other.host") if err != nil { t.Fatalf("unexpected error: %v", err) } if pw != "otherpass" { t.Errorf("other password = %q, want %q", pw, "otherpass") } } func TestUpsertUpdateExistingOneLineEntry(t *testing.T) { dir := t.TempDir() path := filepath.Join(dir, "netrc") initial := "machine other.host login dummy password otherpass\nmachine cache.example.com login dummy password oldtoken\n" if err := os.WriteFile(path, []byte(initial), 0600); err != nil { t.Fatal(err) } if err := Upsert(path, "cache.example.com", "newtoken"); err != nil { t.Fatalf("unexpected error: %v", err) } pw, err := GetPassword(path, "cache.example.com") if err != nil { t.Fatalf("unexpected error: %v", err) } if pw != "newtoken" { t.Errorf("password = %q, want %q", pw, "newtoken") } } func TestUpsertAppend(t *testing.T) { dir := t.TempDir() path := filepath.Join(dir, "netrc") initial := "machine existing.host\nlogin dummy\npassword existingpass\n" if err := os.WriteFile(path, []byte(initial), 0600); err != nil { t.Fatal(err) } if err := Upsert(path, "cache.example.com", "newtoken"); err != nil { t.Fatalf("unexpected error: %v", err) } pw, err := GetPassword(path, "cache.example.com") if err != nil { t.Fatalf("unexpected error: %v", err) } if pw != "newtoken" { t.Errorf("password = %q, want %q", pw, "newtoken") } pw, err = GetPassword(path, "existing.host") if err != nil { t.Fatalf("unexpected error: %v", err) } if pw != "existingpass" { t.Errorf("existing password = %q, want %q", pw, "existingpass") } } func TestRemove(t *testing.T) { dir := t.TempDir() path := filepath.Join(dir, "netrc") initial := "machine keep.host\nlogin dummy\npassword keeppass\n\nmachine remove.host\nlogin dummy\npassword removepass\n" if err := os.WriteFile(path, []byte(initial), 0600); err != nil { t.Fatal(err) } if err := Remove(path, "remove.host"); err != nil { t.Fatalf("unexpected error: %v", err) } pw, err := GetPassword(path, "remove.host") if err != nil { t.Fatalf("unexpected error: %v", err) } if pw != "" { t.Errorf("removed entry still has password = %q", pw) } pw, err = GetPassword(path, "keep.host") if err != nil { t.Fatalf("unexpected error: %v", err) } if pw != "keeppass" { t.Errorf("kept password = %q, want %q", pw, "keeppass") } } func TestRemoveNonexistentFile(t *testing.T) { dir := t.TempDir() path := filepath.Join(dir, "nonexistent") if err := Remove(path, "anything"); err != nil { t.Fatalf("unexpected error: %v", err) } } func TestGetPasswordNoFile(t *testing.T) { dir := t.TempDir() path := filepath.Join(dir, "nonexistent") pw, err := GetPassword(path, "anything") if err != nil { t.Fatalf("unexpected error: %v", err) } if pw != "" { t.Errorf("password = %q, want empty", pw) } } func TestGetPasswordNotFound(t *testing.T) { dir := t.TempDir() path := filepath.Join(dir, "netrc") content := "machine other.host\nlogin dummy\npassword otherpass\n" if err := os.WriteFile(path, []byte(content), 0600); err != nil { t.Fatal(err) } pw, err := GetPassword(path, "missing.host") if err != nil { t.Fatalf("unexpected error: %v", err) } if pw != "" { t.Errorf("password = %q, want empty", pw) } } func TestFilePermissions(t *testing.T) { dir := t.TempDir() path := filepath.Join(dir, "netrc") if err := Upsert(path, "cache.example.com", "token"); err != nil { t.Fatalf("unexpected error: %v", err) } info, err := os.Stat(path) if err != nil { t.Fatalf("stat error: %v", err) } perm := info.Mode().Perm() if perm != 0600 { t.Errorf("file permissions = %o, want 0600", perm) } } func TestFilePermissionsCorrected(t *testing.T) { dir := t.TempDir() path := filepath.Join(dir, "netrc") // Create file with overly permissive mode if err := os.WriteFile(path, []byte("machine old.host\nlogin dummy\npassword oldpass\n"), 0644); err != nil { t.Fatal(err) } if err := Upsert(path, "cache.example.com", "token"); err != nil { t.Fatalf("unexpected error: %v", err) } info, err := os.Stat(path) if err != nil { t.Fatalf("stat error: %v", err) } perm := info.Mode().Perm() if perm != 0600 { t.Errorf("file permissions = %o, want 0600", perm) } } func TestWriteUsesOneLineFormatAndDummyLoginFallback(t *testing.T) { dir := t.TempDir() path := filepath.Join(dir, "netrc") // Existing one-line entry with missing login should be normalized. if err := os.WriteFile(path, []byte("machine cache.example.com password oldtoken\n"), 0600); err != nil { t.Fatal(err) } if err := Upsert(path, "cache.example.com", "newtoken"); err != nil { t.Fatalf("unexpected error: %v", err) } content, err := os.ReadFile(path) if err != nil { t.Fatalf("read error: %v", err) } text := string(content) if !strings.Contains(text, "machine cache.example.com login dummy password newtoken\n") { t.Fatalf("unexpected netrc content: %q", text) } if strings.Contains(text, "\nlogin ") || strings.Contains(text, "\npassword ") { t.Fatalf("netrc entry should be written on one line: %q", text) } }