Assignment 4: add unit, integration, and e2e tests; refactor for testability
This commit is contained in:
+125
-20
@@ -1,25 +1,130 @@
|
||||
package auth
|
||||
|
||||
import "testing"
|
||||
import (
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestPasswordAndToken(t *testing.T) {
|
||||
pass := "secret123"
|
||||
hash, err := HashPassword(pass)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error hashing: %v", err)
|
||||
}
|
||||
if !CheckPassword(pass, hash) {
|
||||
t.Fatal("expected password check to succeed")
|
||||
}
|
||||
if CheckPassword("wrongpass", hash) {
|
||||
t.Fatal("expected wrong password to fail")
|
||||
}
|
||||
func TestHashPassword(t *testing.T) {
|
||||
t.Run("hash tidak sama dengan plaintext", func(t *testing.T) {
|
||||
password := "secret123"
|
||||
|
||||
tok, err := GenerateToken()
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error generating token: %v", err)
|
||||
}
|
||||
if len(tok) != 64 {
|
||||
t.Fatalf("expected 64 hex chars, got %d", len(tok))
|
||||
}
|
||||
hash, err := HashPassword(password)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
|
||||
if hash == password {
|
||||
t.Fatal("hash should not equal plaintext")
|
||||
}
|
||||
t.Run("password terlalu panjang menyebabkan error", func(t *testing.T) {
|
||||
// bcrypt rejects passwords > 72 bytes
|
||||
tooLong := strings.Repeat("a", 100)
|
||||
_, err := HashPassword(tooLong)
|
||||
if err == nil {
|
||||
t.Fatal("expected error for password > 72 bytes")
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
t.Run("password yang sama menghasilkan hash berbeda", func(t *testing.T) {
|
||||
password := "secret123"
|
||||
|
||||
hash1, err := HashPassword(password)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
|
||||
hash2, err := HashPassword(password)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
|
||||
if hash1 == hash2 {
|
||||
t.Fatal("hashes should be different because of salting")
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("hash dapat memverifikasi password asli", func(t *testing.T) {
|
||||
password := "secret123"
|
||||
|
||||
hash, err := HashPassword(password)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
|
||||
if !CheckPassword(password, hash) {
|
||||
t.Fatal("expected password check to succeed")
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func TestCheckPassword(t *testing.T) {
|
||||
hash, err := HashPassword("secret123")
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
|
||||
t.Run("password benar", func(t *testing.T) {
|
||||
if !CheckPassword("secret123", hash) {
|
||||
t.Fatal("expected correct password to return true")
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("password salah", func(t *testing.T) {
|
||||
if CheckPassword("wrongpass", hash) {
|
||||
t.Fatal("expected wrong password to return false")
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("password kosong", func(t *testing.T) {
|
||||
if CheckPassword("", hash) {
|
||||
t.Fatal("expected empty password to return false")
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("hash rusak tidak panic", func(t *testing.T) {
|
||||
if CheckPassword("secret123", "ini-bukan-hash-bcrypt") {
|
||||
t.Fatal("expected garbage hash to return false")
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func TestGenerateToken(t *testing.T) {
|
||||
const N = 1000
|
||||
tokens := make([]string, 0, N)
|
||||
|
||||
t.Run("menghasilkan token non-empty", func(t *testing.T) {
|
||||
for i := 0; i < N; i++ {
|
||||
token, err := GenerateToken()
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
if token == "" {
|
||||
t.Fatalf("token should not be empty at i=%d", i)
|
||||
}
|
||||
tokens = append(tokens, token)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("semua token distinct", func(t *testing.T) {
|
||||
seen := make(map[string]bool, len(tokens))
|
||||
for i, token := range tokens {
|
||||
if seen[token] {
|
||||
t.Fatalf("duplicate token at i=%d", i)
|
||||
}
|
||||
seen[token] = true
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("token tidak mengandung whitespace dan panjang >= 32", func(t *testing.T) {
|
||||
for i, token := range tokens {
|
||||
if len(token) < 32 {
|
||||
t.Fatalf("token too short (%d chars) at i=%d", len(token), i)
|
||||
}
|
||||
if strings.IndexAny(token, " \t\r\n") != -1 {
|
||||
t.Fatalf("token contains whitespace at i=%d", i)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user