package passwords import ( "strings" "testing" ) func TestGenerateRespectsProfileRequirements(t *testing.T) { t.Parallel() profile := Profile{ Name: "strong", Length: 24, Lowercase: true, Uppercase: true, Digits: true, Symbols: true, MinLowercase: 2, MinUppercase: 2, MinDigits: 2, MinSymbols: 2, ExcludeSimilar: true, } password, err := Generate(profile) if err != nil { t.Fatalf("Generate() error = %v", err) } if len(password) != 24 { t.Fatalf("len(password) = %d, want 24", len(password)) } if countFromSet(password, lowercaseChars) < 2 { t.Fatalf("lowercase count in %q is too small", password) } if countFromSet(password, uppercaseChars) < 2 { t.Fatalf("uppercase count in %q is too small", password) } if countFromSet(password, digitChars) < 2 { t.Fatalf("digit count in %q is too small", password) } if countFromSet(password, symbolChars) < 2 { t.Fatalf("symbol count in %q is too small", password) } if strings.ContainsAny(password, "O0Il1") { t.Fatalf("password %q contains excluded similar characters", password) } } func TestGenerateRejectsImpossibleProfiles(t *testing.T) { t.Parallel() _, err := Generate(Profile{ Name: "bad", Length: 6, Lowercase: true, Uppercase: true, Digits: true, Symbols: true, MinLowercase: 2, MinUppercase: 2, MinDigits: 2, MinSymbols: 2, }) if err == nil { t.Fatal("Generate() error = nil, want impossible profile error") } } func TestProfileSetReturnsNamedProfiles(t *testing.T) { t.Parallel() set := DefaultProfiles() profile, ok := set["strong"] if !ok { t.Fatalf("DefaultProfiles()[\"strong\"] missing") } if profile.Length < 20 || !profile.Symbols { t.Fatalf("strong profile = %#v, want a strong reusable profile", profile) } } func countFromSet(password, chars string) int { count := 0 for _, r := range password { if strings.ContainsRune(chars, r) { count++ } } return count }