backend/pkg/library/cassandra/repository_test.go

548 lines
12 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package cassandra
import (
"reflect"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestContains(t *testing.T) {
tests := []struct {
name string
list []string
target string
want bool
}{
{
name: "target exists in list",
list: []string{"a", "b", "c"},
target: "b",
want: true,
},
{
name: "target at beginning",
list: []string{"a", "b", "c"},
target: "a",
want: true,
},
{
name: "target at end",
list: []string{"a", "b", "c"},
target: "c",
want: true,
},
{
name: "target not in list",
list: []string{"a", "b", "c"},
target: "d",
want: false,
},
{
name: "empty list",
list: []string{},
target: "a",
want: false,
},
{
name: "empty target",
list: []string{"a", "b", "c"},
target: "",
want: false,
},
{
name: "target in single element list",
list: []string{"a"},
target: "a",
want: true,
},
{
name: "case sensitive",
list: []string{"A", "B", "C"},
target: "a",
want: false,
},
{
name: "duplicate values",
list: []string{"a", "b", "a", "c"},
target: "a",
want: true,
},
{
name: "long list",
list: []string{"a", "b", "c", "d", "e", "f", "g", "h", "i", "j"},
target: "j",
want: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
result := contains(tt.list, tt.target)
assert.Equal(t, tt.want, result)
})
}
}
func TestIsZero(t *testing.T) {
tests := []struct {
name string
value any
expected bool
skip bool
}{
{
name: "nil pointer",
value: (*string)(nil),
expected: true,
skip: false,
},
{
name: "non-nil pointer",
value: stringPtr("test"),
expected: false,
skip: false,
},
{
name: "nil slice",
value: []string(nil),
expected: true,
skip: false,
},
{
name: "empty slice",
value: []string{},
expected: false, // 空 slice 不是 nil
skip: false,
},
{
name: "nil map",
value: map[string]int(nil),
expected: true,
skip: false,
},
{
name: "empty map",
value: map[string]int{},
expected: false, // 空 map 不是 nil
skip: false,
},
{
name: "zero int",
value: 0,
expected: true,
skip: false,
},
{
name: "non-zero int",
value: 42,
expected: false,
skip: false,
},
{
name: "zero int64",
value: int64(0),
expected: true,
skip: false,
},
{
name: "non-zero int64",
value: int64(42),
expected: false,
skip: false,
},
{
name: "zero float64",
value: 0.0,
expected: true,
skip: false,
},
{
name: "non-zero float64",
value: 3.14,
expected: false,
skip: false,
},
{
name: "empty string",
value: "",
expected: true,
skip: false,
},
{
name: "non-empty string",
value: "test",
expected: false,
skip: false,
},
{
name: "false bool",
value: false,
expected: true,
skip: false,
},
{
name: "true bool",
value: true,
expected: false,
skip: false,
},
{
name: "struct with zero values",
value: testUser{},
expected: true, // 所有欄位都是零值,應該返回 true
skip: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if tt.skip {
t.Skip("Skipping test")
return
}
// 使用 reflect.ValueOf 來獲取 reflect.Value
v := reflect.ValueOf(tt.value)
// 檢查是否為零值nil interface 會導致 zero Value
if !v.IsValid() {
// 對於 nil interface直接返回 true
assert.True(t, tt.expected)
return
}
result := isZero(v)
assert.Equal(t, tt.expected, result)
})
}
}
func TestNewRepository(t *testing.T) {
tests := []struct {
name string
keyspace string
wantErr bool
validate func(*testing.T, Repository[testUser], *DB)
}{
{
name: "valid keyspace",
keyspace: "test_keyspace",
wantErr: false,
validate: func(t *testing.T, repo Repository[testUser], db *DB) {
assert.NotNil(t, repo)
},
},
{
name: "empty keyspace uses default",
keyspace: "",
wantErr: false,
validate: func(t *testing.T, repo Repository[testUser], db *DB) {
assert.NotNil(t, repo)
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
// 注意:這需要一個有效的 DB 實例
// 在實際測試中,需要使用 mock 或 testcontainers
_ = tt
})
}
}
func TestRepository_Insert(t *testing.T) {
tests := []struct {
name string
description string
}{
{
name: "successful insert",
description: "should insert document successfully",
},
{
name: "duplicate key",
description: "should return error on duplicate key",
},
{
name: "invalid document",
description: "should return error for invalid document",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
// 注意:這需要 mock session 或實際的資料庫連接
_ = tt
})
}
}
func TestRepository_Get(t *testing.T) {
tests := []struct {
name string
pk any
description string
wantErr bool
}{
{
name: "found with string key",
pk: "test-id",
description: "should return document when found",
wantErr: false,
},
{
name: "not found",
pk: "non-existent",
description: "should return ErrNotFound when not found",
wantErr: true,
},
{
name: "invalid primary key structure",
pk: "single-key",
description: "should return error for invalid key structure",
wantErr: true,
},
{
name: "struct primary key",
pk: testUser{ID: "test-id"},
description: "should work with struct primary key",
wantErr: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
// 注意:這需要 mock session 或實際的資料庫連接
_ = tt
})
}
}
func TestRepository_Update(t *testing.T) {
tests := []struct {
name string
description string
wantErr bool
}{
{
name: "successful update",
description: "should update document successfully",
wantErr: false,
},
{
name: "not found",
description: "should return error when document not found",
wantErr: true,
},
{
name: "no fields to update",
description: "should return error when no fields to update",
wantErr: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
// 注意:這需要 mock session 或實際的資料庫連接
_ = tt
})
}
}
func TestRepository_Delete(t *testing.T) {
tests := []struct {
name string
pk any
description string
wantErr bool
}{
{
name: "successful delete",
pk: "test-id",
description: "should delete document successfully",
wantErr: false,
},
{
name: "not found",
pk: "non-existent",
description: "should not return error when not found (idempotent)",
wantErr: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
// 注意:這需要 mock session 或實際的資料庫連接
_ = tt
})
}
}
func TestRepository_InsertMany(t *testing.T) {
tests := []struct {
name string
docs []testUser
description string
wantErr bool
}{
{
name: "empty slice",
docs: []testUser{},
description: "should return nil for empty slice",
wantErr: false,
},
{
name: "single document",
docs: []testUser{{ID: "1", Name: "Alice"}},
description: "should insert single document",
wantErr: false,
},
{
name: "multiple documents",
docs: []testUser{{ID: "1", Name: "Alice"}, {ID: "2", Name: "Bob"}},
description: "should insert multiple documents",
wantErr: false,
},
{
name: "large batch",
docs: make([]testUser, 100),
description: "should handle large batch",
wantErr: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
// 注意:這需要 mock session 或實際的資料庫連接
_ = tt
})
}
}
func TestRepository_Query(t *testing.T) {
t.Run("should return QueryBuilder", func(t *testing.T) {
// 注意:這需要一個有效的 repository
// 實際的執行需要資料庫連接
})
}
func TestBuildUpdateStatement(t *testing.T) {
tests := []struct {
name string
setCols []string
whereCols []string
table string
validate func(*testing.T, string, []string)
}{
{
name: "single set column, single where column",
setCols: []string{"name"},
whereCols: []string{"id"},
table: "users",
validate: func(t *testing.T, stmt string, names []string) {
assert.Contains(t, stmt, "UPDATE")
assert.Contains(t, stmt, "users")
assert.Contains(t, stmt, "SET")
assert.Contains(t, stmt, "WHERE")
assert.Len(t, names, 2) // name, id
},
},
{
name: "multiple set columns, single where column",
setCols: []string{"name", "email", "age"},
whereCols: []string{"id"},
table: "users",
validate: func(t *testing.T, stmt string, names []string) {
assert.Contains(t, stmt, "UPDATE")
assert.Contains(t, stmt, "users")
assert.Len(t, names, 4) // name, email, age, id
},
},
{
name: "single set column, multiple where columns",
setCols: []string{"status"},
whereCols: []string{"user_id", "account_id"},
table: "accounts",
validate: func(t *testing.T, stmt string, names []string) {
assert.Contains(t, stmt, "UPDATE")
assert.Contains(t, stmt, "accounts")
assert.Len(t, names, 3) // status, user_id, account_id
},
},
{
name: "multiple set and where columns",
setCols: []string{"name", "email"},
whereCols: []string{"id", "version"},
table: "users",
validate: func(t *testing.T, stmt string, names []string) {
assert.Contains(t, stmt, "UPDATE")
assert.Len(t, names, 4) // name, email, id, version
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
// 創建一個臨時的 repository 來測試 buildUpdateStatement
// 注意:這需要一個有效的 metadata
// 使用 testUser 的 metadata
var zero testUser
metadata, err := generateMetadata(zero, "test_keyspace")
require.NoError(t, err)
repo := &repository[testUser]{
table: tt.table,
metadata: metadata,
}
stmt, names := repo.buildUpdateStatement(tt.setCols, tt.whereCols)
tt.validate(t, stmt, names)
})
}
}
func TestBuildUpdateFields(t *testing.T) {
tests := []struct {
name string
doc testUser
includeZero bool
wantErr bool
validate func(*testing.T, *updateFields)
}{
{
name: "update with includeZero false",
doc: testUser{ID: "1", Name: "Alice", Email: "alice@example.com"},
includeZero: false,
wantErr: false,
validate: func(t *testing.T, fields *updateFields) {
assert.NotEmpty(t, fields.setCols)
assert.Contains(t, fields.whereCols, "id")
},
},
{
name: "update with includeZero true",
doc: testUser{ID: "1", Name: "", Email: ""},
includeZero: true,
wantErr: false,
validate: func(t *testing.T, fields *updateFields) {
assert.NotEmpty(t, fields.setCols)
},
},
{
name: "no fields to update",
doc: testUser{ID: "1"},
includeZero: false,
wantErr: true,
validate: nil,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
// 注意:這需要一個有效的 repository 和 metadata
// 在實際測試中,需要使用 mock 或 testcontainers
_ = tt
})
}
}