import { describe, test, expect } from 'bun:test' // Dynamic import — module may not exist yet (TDD) let hashPassword: ((password: string) => string) | undefined let verifyPassword: ((password: string, hash: string) => boolean) | undefined try { const mod = await import('../auth/password') hashPassword = mod.hashPassword verifyPassword = mod.verifyPassword } catch { // Module not implemented yet — tests will fail on assertions } describe('hashPassword', () => { test('returns a string containing argon2id identifier', () => { expect(hashPassword).toBeDefined() const hash = hashPassword!('my-secure-password') expect(typeof hash).toBe('string') expect(hash).toContain('argon2id') }) test('same password hashed twice produces different results (different salt)', () => { expect(hashPassword).toBeDefined() const hash1 = hashPassword!('same-password') const hash2 = hashPassword!('same-password') expect(hash1).not.toBe(hash2) }) test('hash length is reasonable (between 50 and 200 chars)', () => { expect(hashPassword).toBeDefined() const hash = hashPassword!('test-password-123') expect(hash.length).toBeGreaterThan(50) expect(hash.length).toBeLessThan(200) }) }) describe('verifyPassword', () => { test('returns true for correct password', () => { expect(hashPassword).toBeDefined() expect(verifyPassword).toBeDefined() const password = 'correct-horse-battery-staple' const hash = hashPassword!(password) expect(verifyPassword!(password, hash)).toBe(true) }) test('returns false for wrong password', () => { expect(hashPassword).toBeDefined() expect(verifyPassword).toBeDefined() const hash = hashPassword!('correct-password') expect(verifyPassword!('wrong-password', hash)).toBe(false) }) test('returns false for empty token', () => { expect(hashPassword).toBeDefined() expect(verifyPassword).toBeDefined() const hash = hashPassword!('some-password') expect(verifyPassword!('', hash)).toBe(false) }) test('returns false for tampered hash', () => { expect(hashPassword).toBeDefined() expect(verifyPassword).toBeDefined() const hash = hashPassword!('my-password') // Tamper with the hash by changing a character in the encoded part const parts = hash.split('$') // Argon2id format: $argon2id$v=19$m=...,t=...,p=...$$ // Tamper with the last segment (the actual hash) const lastPart = parts[parts.length - 1] const tampered = lastPart.length > 4 ? parts.slice(0, -1).join('$') + '$' + 'XXXX' + lastPart.slice(4) : hash + 'x' expect(verifyPassword!('my-password', tampered)).toBe(false) }) })