dnote/pkg/server/cmd/user_test.go
2025-11-01 19:59:51 -07:00

158 lines
5 KiB
Go

/* Copyright 2025 Dnote Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cmd
import (
"bytes"
"fmt"
"strings"
"testing"
"github.com/dnote/dnote/pkg/assert"
"github.com/dnote/dnote/pkg/server/database"
"github.com/dnote/dnote/pkg/server/testutils"
"golang.org/x/crypto/bcrypt"
)
func TestUserCreateCmd(t *testing.T) {
tmpDB := t.TempDir() + "/test.db"
// Call the function directly
userCreateCmd([]string{"--dbPath", tmpDB, "--email", "test@example.com", "--password", "password123"})
// Verify user was created in database
db := testutils.InitDB(tmpDB)
defer func() {
sqlDB, _ := db.DB()
sqlDB.Close()
}()
var count int64
testutils.MustExec(t, db.Model(&database.User{}).Count(&count), "counting users")
assert.Equal(t, count, int64(1), "should have 1 user")
var user database.User
testutils.MustExec(t, db.Where("email = ?", "test@example.com").First(&user), "finding user")
assert.Equal(t, user.Email.String, "test@example.com", "email mismatch")
}
func TestUserRemoveCmd(t *testing.T) {
tmpDB := t.TempDir() + "/test.db"
// Create a user first
db := testutils.InitDB(tmpDB)
testutils.SetupUserData(db, "test@example.com", "password123")
sqlDB, _ := db.DB()
sqlDB.Close()
// Remove the user with mock stdin that responds "y"
mockStdin := strings.NewReader("y\n")
userRemoveCmd([]string{"--dbPath", tmpDB, "--email", "test@example.com"}, mockStdin)
// Verify user was removed
db2 := testutils.InitDB(tmpDB)
defer func() {
sqlDB2, _ := db2.DB()
sqlDB2.Close()
}()
var count int64
testutils.MustExec(t, db2.Model(&database.User{}).Count(&count), "counting users")
assert.Equal(t, count, int64(0), "should have 0 users")
}
func TestUserResetPasswordCmd(t *testing.T) {
tmpDB := t.TempDir() + "/test.db"
// Create a user first
db := testutils.InitDB(tmpDB)
user := testutils.SetupUserData(db, "test@example.com", "oldpassword123")
oldPasswordHash := user.Password.String
sqlDB, _ := db.DB()
sqlDB.Close()
// Reset password
userResetPasswordCmd([]string{"--dbPath", tmpDB, "--email", "test@example.com", "--password", "newpassword123"})
// Verify password was changed
db2 := testutils.InitDB(tmpDB)
defer func() {
sqlDB2, _ := db2.DB()
sqlDB2.Close()
}()
var updatedUser database.User
testutils.MustExec(t, db2.Where("email = ?", "test@example.com").First(&updatedUser), "finding user")
// Verify password hash changed
assert.Equal(t, updatedUser.Password.String != oldPasswordHash, true, "password hash should be different")
assert.Equal(t, len(updatedUser.Password.String) > 0, true, "password should be set")
// Verify new password works
err := bcrypt.CompareHashAndPassword([]byte(updatedUser.Password.String), []byte("newpassword123"))
assert.Equal(t, err, nil, "new password should match")
// Verify old password doesn't work
err = bcrypt.CompareHashAndPassword([]byte(updatedUser.Password.String), []byte("oldpassword123"))
assert.Equal(t, err != nil, true, "old password should not match")
}
func TestUserListCmd(t *testing.T) {
t.Run("multiple users", func(t *testing.T) {
tmpDB := t.TempDir() + "/test.db"
// Create multiple users
db := testutils.InitDB(tmpDB)
user1 := testutils.SetupUserData(db, "alice@example.com", "password123")
user2 := testutils.SetupUserData(db, "bob@example.com", "password123")
user3 := testutils.SetupUserData(db, "charlie@example.com", "password123")
sqlDB, _ := db.DB()
sqlDB.Close()
// Capture output
var buf bytes.Buffer
userListCmd([]string{"--dbPath", tmpDB}, &buf)
// Verify output matches expected format
output := strings.TrimSpace(buf.String())
lines := strings.Split(output, "\n")
expectedLine1 := fmt.Sprintf("%s,alice@example.com,%s", user1.UUID, user1.CreatedAt.UTC().Format("2006-01-02T15:04:05Z"))
expectedLine2 := fmt.Sprintf("%s,bob@example.com,%s", user2.UUID, user2.CreatedAt.UTC().Format("2006-01-02T15:04:05Z"))
expectedLine3 := fmt.Sprintf("%s,charlie@example.com,%s", user3.UUID, user3.CreatedAt.UTC().Format("2006-01-02T15:04:05Z"))
assert.Equal(t, lines[0], expectedLine1, "line 1 should match")
assert.Equal(t, lines[1], expectedLine2, "line 2 should match")
assert.Equal(t, lines[2], expectedLine3, "line 3 should match")
})
t.Run("empty database", func(t *testing.T) {
tmpDB := t.TempDir() + "/test.db"
// Initialize empty database
db := testutils.InitDB(tmpDB)
sqlDB, _ := db.DB()
sqlDB.Close()
// Capture output
var buf bytes.Buffer
userListCmd([]string{"--dbPath", tmpDB}, &buf)
// Verify no output
output := buf.String()
assert.Equal(t, output, "", "should have no output for empty database")
})
}