package auth import ( "strings" "testing" "errors" ) func TestGenerateCodeShape(t *testing.T) { for range 100 { code, err := generateCode() if err != nil { t.Fatalf("generateCode: %v", err) } if len(code) != CodeLength { t.Fatalf("len(code) = %d, want %d (got %q)", len(code), CodeLength, code) } for _, r := range code { if r < '0' || r > '9' { t.Fatalf("non-digit rune %q in code %q", r, code) } } } } func TestGenerateCodeRandomness(t *testing.T) { seen := make(map[string]struct{}) const trials = 50 for range trials { code, err := generateCode() if err != nil { t.Fatalf("generateCode: %v", err) } seen[code] = struct{}{} } // 50 trials over a 10^6 space — duplicate is astronomically unlikely. if len(seen) < trials-1 { t.Fatalf("generateCode produced too many duplicates: %d/%d unique", len(seen), trials) } } func TestHashAndVerifyCodeRoundTrip(t *testing.T) { const code = "654321" hash, err := hashCode(code) if err != nil { t.Fatalf("hashCode: %v", err) } if !strings.HasPrefix(string(hash), "$2") { t.Fatalf("hash does not look like bcrypt: %q", string(hash)) } if err := verifyCode(hash, code); err != nil { t.Fatalf("verifyCode on matching code: %v", err) } } func TestVerifyCodeMismatch(t *testing.T) { hash, err := hashCode("111111") if err != nil { t.Fatalf("hashCode: %v", err) } err = verifyCode(hash, "222222") if !errors.Is(err, ErrCodeMismatch) { t.Fatalf("verifyCode mismatch returned %v, want ErrCodeMismatch", err) } } func TestVerifyCodeMalformedHash(t *testing.T) { err := verifyCode([]byte("not-a-hash"), "111111") if err == nil { t.Fatalf("verifyCode with garbage hash returned nil") } if errors.Is(err, ErrCodeMismatch) { t.Fatalf("malformed hash classified as mismatch: %v", err) } }