package auth import ( "strings" "testing" ) // fastParams keeps the test fast while still exercising the full PHC path. var fastParams = Argon2Params{Memory: 4 * 1024, Iterations: 1, Parallelism: 1, SaltLength: 16, KeyLength: 32} func TestHashPassword_PHCFormat(t *testing.T) { h, err := HashPassword("hunter2", fastParams) if err != nil { t.Fatalf("HashPassword: %v", err) } if !strings.HasPrefix(h, "$argon2id$v=19$") { t.Fatalf("unexpected PHC prefix: %s", h) } if strings.Count(h, "$") != 5 { t.Fatalf("expected 5 '$' separators, got %q", h) } } func TestVerifyPassword_RoundTrip(t *testing.T) { pw := "correct horse battery staple" h, err := HashPassword(pw, fastParams) if err != nil { t.Fatalf("HashPassword: %v", err) } if err := VerifyPassword(pw, h); err != nil { t.Fatalf("VerifyPassword correct: %v", err) } if err := VerifyPassword("wrong", h); err == nil { t.Fatal("VerifyPassword wrong: expected error, got nil") } } func TestVerifyPassword_Malformed(t *testing.T) { cases := []string{ "", "not-a-hash", "$argon2id$v=19$m=1024,t=1,p=1$AAAA$BB", "$argon2i$v=19$m=1024,t=1,p=1$AAAA$BBBB", "$argon2id$v=99$m=1024,t=1,p=1$AAAA$BBBB", "$argon2id$v=19$m=0,t=1,p=1$AAAA$BBBB", } for _, c := range cases { if err := VerifyPassword("x", c); err == nil { t.Fatalf("VerifyPassword(%q): expected error", c) } } } func TestHashPassword_DifferentSalts(t *testing.T) { a, _ := HashPassword("same", fastParams) b, _ := HashPassword("same", fastParams) if a == b { t.Fatal("two hashes of the same password should differ due to random salt") } // both must still verify against the original password if err := VerifyPassword("same", a); err != nil { t.Fatalf("verify a: %v", err) } if err := VerifyPassword("same", b); err != nil { t.Fatalf("verify b: %v", err) } }