| Current Path : /home/hotlineuser/mobius/hotline/ |
| Current File : //home/hotlineuser/mobius/hotline/account_test.go |
package hotline
import (
"encoding/binary"
"io"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"golang.org/x/crypto/bcrypt"
)
func TestNewAccount(t *testing.T) {
access := AccessBitmap{0xff, 0, 0, 0, 0, 0, 0, 0}
acct := NewAccount("jdoe", "John Doe", "secret123", access)
assert.Equal(t, "jdoe", acct.Login)
assert.Equal(t, "John Doe", acct.Name)
assert.Equal(t, access, acct.Access)
// Password should be a bcrypt hash, not the plaintext.
assert.NotEqual(t, "secret123", acct.Password)
err := bcrypt.CompareHashAndPassword([]byte(acct.Password), []byte("secret123"))
require.NoError(t, err, "password hash should validate against original plaintext")
}
func TestHashAndSalt(t *testing.T) {
t.Run("produces valid bcrypt hash", func(t *testing.T) {
hash := HashAndSalt([]byte("password"))
err := bcrypt.CompareHashAndPassword([]byte(hash), []byte("password"))
require.NoError(t, err)
})
t.Run("different calls produce different hashes", func(t *testing.T) {
h1 := HashAndSalt([]byte("same"))
h2 := HashAndSalt([]byte("same"))
assert.NotEqual(t, h1, h2, "bcrypt salts should differ between calls")
// Both should still verify against the original input.
require.NoError(t, bcrypt.CompareHashAndPassword([]byte(h1), []byte("same")))
require.NoError(t, bcrypt.CompareHashAndPassword([]byte(h2), []byte("same")))
})
}
func TestAccount_Read(t *testing.T) {
t.Run("with password set", func(t *testing.T) {
acct := NewAccount("admin", "Admin User", "pass", AccessBitmap{})
data, err := io.ReadAll(acct)
require.NoError(t, err)
// First two bytes are the field count (big-endian uint16).
require.GreaterOrEqual(t, len(data), 2)
fieldCount := binary.BigEndian.Uint16(data[:2])
assert.Equal(t, uint16(4), fieldCount, "should have 4 fields when password is set")
// Verify the password marker "x" appears in the serialized data.
assert.Contains(t, string(data), "x")
// Verify the user name appears in the serialized data.
assert.Contains(t, string(data), "Admin User")
})
t.Run("with empty password", func(t *testing.T) {
acct := &Account{
Login: "guest",
Name: "Guest",
Password: HashAndSalt([]byte("")),
Access: AccessBitmap{},
}
data, err := io.ReadAll(acct)
require.NoError(t, err)
require.GreaterOrEqual(t, len(data), 2)
fieldCount := binary.BigEndian.Uint16(data[:2])
assert.Equal(t, uint16(3), fieldCount, "should have 3 fields when password is empty")
})
t.Run("full read returns all serialized bytes", func(t *testing.T) {
acct := NewAccount("test", "Test", "pw", AccessBitmap{0x01})
data, err := io.ReadAll(acct)
require.NoError(t, err)
assert.Greater(t, len(data), 2, "serialized output should contain field data beyond the count header")
})
}
func TestNewAccount_GuestConstant(t *testing.T) {
assert.Equal(t, "guest", GuestAccount)
}