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 }) } }