Refact tests

This commit is contained in:
Jinzhu 2014-07-29 10:59:13 +08:00
parent 6a00344355
commit cb7d545ac0
9 changed files with 2109 additions and 2114 deletions

View File

@ -17,14 +17,14 @@ func SaveBeforeAssociations(scope *Scope) {
newDB := scope.NewDB() newDB := scope.NewDB()
if value.CanAddr() { if value.CanAddr() {
newDB.Save(value.Addr().Interface()) scope.Err(newDB.Save(value.Addr().Interface()).Error)
} else { } else {
// If can't take address, then clone the value and set it back // If can't take address, then clone the value and set it back
value = reflect.New(reflect.ValueOf(field.Value).Type()).Elem() value = reflect.New(reflect.ValueOf(field.Value).Type()).Elem()
for _, f := range newDB.NewScope(field.Value).Fields() { for _, f := range newDB.NewScope(field.Value).Fields() {
value.FieldByName(f.Name).Set(reflect.ValueOf(f.Value)) value.FieldByName(f.Name).Set(reflect.ValueOf(f.Value))
} }
newDB.Save(value.Addr().Interface()) scope.Err(newDB.Save(value.Addr().Interface()).Error)
scope.SetColumn(field.Name, value.Interface()) scope.SetColumn(field.Name, value.Interface())
} }
@ -50,13 +50,13 @@ func SaveAfterAssociations(scope *Scope) {
newDB.NewScope(elem).SetColumn(field.ForeignKey, scope.PrimaryKeyValue()) newDB.NewScope(elem).SetColumn(field.ForeignKey, scope.PrimaryKeyValue())
} }
newDB.Save(elem) scope.Err(newDB.Save(elem).Error)
} }
default: default:
newDB := scope.NewDB() newDB := scope.NewDB()
if value.CanAddr() { if value.CanAddr() {
newDB.NewScope(field.Value).SetColumn(field.ForeignKey, scope.PrimaryKeyValue()) newDB.NewScope(field.Value).SetColumn(field.ForeignKey, scope.PrimaryKeyValue())
newDB.Save(field.Value) scope.Err(newDB.Save(field.Value).Error)
} else { } else {
destValue := reflect.New(reflect.TypeOf(field.Value)).Elem() destValue := reflect.New(reflect.TypeOf(field.Value)).Elem()
@ -66,7 +66,7 @@ func SaveAfterAssociations(scope *Scope) {
elem := destValue.Addr().Interface() elem := destValue.Addr().Interface()
newDB.NewScope(elem).SetColumn(field.ForeignKey, scope.PrimaryKeyValue()) newDB.NewScope(elem).SetColumn(field.ForeignKey, scope.PrimaryKeyValue())
newDB.Save(elem) scope.Err(newDB.Save(elem).Error)
scope.SetColumn(field.Name, destValue.Interface()) scope.SetColumn(field.Name, destValue.Interface())
} }
} }

38
create_test.go Normal file
View File

@ -0,0 +1,38 @@
package gorm_test
import (
"reflect"
"testing"
"time"
)
func TestCreate(t *testing.T) {
user := User{Name: "1", Age: 18, Birthday: time.Now(), UserNum: Num(111), PasswordHash: []byte{'f', 'a', 'k', '4'}}
if !db.NewRecord(user) || !db.NewRecord(&user) {
t.Error("User should be new record before create")
}
if count := db.Save(&user).RowsAffected; count != 1 {
t.Error("There should be one record be affected when create record")
}
if db.NewRecord(user) || db.NewRecord(&user) {
t.Error("User should not new record after save")
}
var newUser User
db.First(&newUser, user.Id)
if !reflect.DeepEqual(newUser.PasswordHash, []byte{'f', 'a', 'k', '4'}) {
t.Errorf("User's PasswordHash should be saved ([]byte)")
}
if newUser.Age != 18 {
t.Errorf("User's Age should be saved (int)")
}
if newUser.UserNum != Num(111) {
t.Errorf("User's UserNum should be saved (custom type)")
}
}

68
delete_test.go Normal file
View File

@ -0,0 +1,68 @@
package gorm_test
import (
"testing"
"time"
)
func TestDelete(t *testing.T) {
user1, user2 := User{Name: "delete1"}, User{Name: "delete2"}
db.Save(&user1)
db.Save(&user2)
if db.Delete(&user1).Error != nil {
t.Errorf("No error should happen when delete a record")
}
if !db.Where("name = ?", user1.Name).First(&User{}).RecordNotFound() {
t.Errorf("User can't be found after delete")
}
if db.Where("name = ?", user2.Name).First(&User{}).RecordNotFound() {
t.Errorf("Other users that not deleted should be found-able")
}
}
func TestInlineDelete(t *testing.T) {
user1, user2 := User{Name: "inline_delete1"}, User{Name: "inline_delete2"}
db.Save(&user1)
db.Save(&user2)
if db.Delete(&User{}, user1.Id).Error != nil {
t.Errorf("No error should happen when delete a record")
} else if !db.Where("name = ?", user1.Name).First(&User{}).RecordNotFound() {
t.Errorf("User can't be found after delete")
}
if db.Delete(&User{}, "name = ?", user2.Name).Error != nil {
t.Errorf("No error should happen when delete a record")
} else if !db.Where("name = ?", user2.Name).First(&User{}).RecordNotFound() {
t.Errorf("User can't be found after delete")
}
}
func TestSoftDelete(t *testing.T) {
type User struct {
Id int64
Name string
DeletedAt time.Time
}
db.AutoMigrate(&User{})
user := User{Name: "soft_delete"}
db.Save(&user)
db.Delete(&user)
if db.First(&User{}, "name = ?", user.Name).Error == nil {
t.Errorf("Can't find a soft deleted record")
}
if db.Unscoped().First(&User{}, "name = ?", user.Name).Error != nil {
t.Errorf("Should be able to find soft deleted record with Unscoped")
}
db.Unscoped().Delete(&user)
if !db.Unscoped().First(&User{}, "name = ?", user.Name).RecordNotFound() {
t.Errorf("Can't find permanently deleted record")
}
}

File diff suppressed because it is too large Load Diff

12
many2many_test.go Normal file
View File

@ -0,0 +1,12 @@
package gorm_test
import "testing"
func TestQueryManyToManyWithRelated(t *testing.T) {
db.Model(&User{}).Related(&[]Language{}, "Languages")
// SELECT `languages`.* FROM `languages` INNER JOIN `user_languages` ON `languages`.`id` = `user_languages`.`language_id` WHERE `user_languages`.`user_id` = 111
// db.Model(&User{}).Many2Many("Languages").Find(&[]Language{})
// db.Model(&User{}).Many2Many("Languages").Add(&Language{})
// db.Model(&User{}).Many2Many("Languages").Remove(&Language{})
// db.Model(&User{}).Many2Many("Languages").Replace(&[]Language{})
}

83
migration_test.go Normal file
View File

@ -0,0 +1,83 @@
package gorm_test
import (
"fmt"
"testing"
)
func runMigration() {
if err := db.DropTable(&User{}).Error; err != nil {
fmt.Printf("Got error when try to delete table users, %+v\n", err)
}
db.Exec("drop table products;")
db.Exec("drop table emails;")
db.Exec("drop table addresses")
db.Exec("drop table credit_cards")
db.Exec("drop table roles")
db.Exec("drop table companies")
db.Exec("drop table animals")
db.Exec("drop table user_companies")
if err := db.CreateTable(&Animal{}).Error; err != nil {
panic(fmt.Sprintf("No error should happen when create table, but got %+v", err))
}
if err := db.CreateTable(&User{}).Error; err != nil {
panic(fmt.Sprintf("No error should happen when create table, but got %+v", err))
}
if err := db.CreateTable(&Product{}).Error; err != nil {
panic(fmt.Sprintf("No error should happen when create table, but got %+v", err))
}
if err := db.CreateTable(Email{}).Error; err != nil {
panic(fmt.Sprintf("No error should happen when create table, but got %+v", err))
}
if err := db.AutoMigrate(Address{}).Error; err != nil {
panic(fmt.Sprintf("No error should happen when create table, but got %+v", err))
}
if err := db.AutoMigrate(&CreditCard{}).Error; err != nil {
panic(fmt.Sprintf("No error should happen when create table, but got %+v", err))
}
if err := db.AutoMigrate(Company{}).Error; err != nil {
panic(fmt.Sprintf("No error should happen when create table, but got %+v", err))
}
if err := db.AutoMigrate(Role{}).Error; err != nil {
panic(fmt.Sprintf("No error should happen when create table, but got %+v", err))
}
if err := db.AutoMigrate(UserCompany{}).Error; err != nil {
panic(fmt.Sprintf("No error should happen when create table, but got %+v", err))
}
}
func TestIndexes(t *testing.T) {
if err := db.Model(&Email{}).AddIndex("idx_email_email", "email").Error; err != nil {
t.Errorf("Got error when tried to create index: %+v", err)
}
if err := db.Model(&Email{}).RemoveIndex("idx_email_email").Error; err != nil {
t.Errorf("Got error when tried to remove index: %+v", err)
}
if err := db.Model(&Email{}).AddIndex("idx_email_email_and_user_id", "user_id", "email").Error; err != nil {
t.Errorf("Got error when tried to create index: %+v", err)
}
if err := db.Model(&Email{}).RemoveIndex("idx_email_email_and_user_id").Error; err != nil {
t.Errorf("Got error when tried to remove index: %+v", err)
}
if err := db.Model(&Email{}).AddUniqueIndex("idx_email_email_and_user_id", "user_id", "email").Error; err != nil {
t.Errorf("Got error when tried to create index: %+v", err)
}
fmt.Println(db.Save(&User{Name: "unique_indexes", Emails: []Email{{Email: "user1@example.comiii"}, {Email: "user1@example.com"}, {Email: "user1@example.com"}}}).Error)
if db.Debug().Save(&User{Name: "unique_indexes", Emails: []Email{{Email: "user1@example.comiii"}, {Email: "user1@example.com"}, {Email: "user1@example.com"}}}).Error == nil {
t.Errorf("Should get to create duplicate record when having unique index")
}
}

57
query_test.go Normal file
View File

@ -0,0 +1,57 @@
package gorm_test
import "testing"
func TestFirstAndLast(t *testing.T) {
db.Save(&User{Name: "user1", Emails: []Email{{Email: "user1@example.com"}}})
db.Save(&User{Name: "user2", Emails: []Email{{Email: "user2@example.com"}}})
var user1, user2, user3, user4 User
db.First(&user1)
db.Order("id").Find(&user2)
db.Last(&user3)
db.Order("id desc").Find(&user4)
if user1.Id != user2.Id || user3.Id != user4.Id {
t.Errorf("First and Last should by order by primary key")
}
var users []User
db.First(&users)
if len(users) != 1 {
t.Errorf("Find first record as slice")
}
if db.Joins("left join emails on emails.user_id = users.id").First(&User{}).Error != nil {
t.Errorf("Should not raise any error when order with Join table")
}
}
func TestFirstAndLastWithNoStdPrimaryKey(t *testing.T) {
db.Save(&Animal{Name: "animal1"})
db.Save(&Animal{Name: "animal2"})
var animal1, animal2, animal3, animal4 Animal
db.First(&animal1)
db.Order("counter").Find(&animal2)
db.Last(&animal3)
db.Order("counter desc").Find(&animal4)
if animal1.Counter != animal2.Counter || animal3.Counter != animal4.Counter {
t.Errorf("First and Last should work correctly")
}
}
func TestFindAsSliceOfPointers(t *testing.T) {
db.Save(&User{Name: "user"})
var users []User
db.Find(&users)
var userPointers []*User
db.Find(&userPointers)
if len(users) == 0 || len(users) != len(userPointers) {
t.Errorf("Find slice of pointers")
}
}

224
structs_test.go Normal file
View File

@ -0,0 +1,224 @@
package gorm_test
import (
"database/sql"
"database/sql/driver"
"errors"
"github.com/jinzhu/gorm"
"reflect"
"time"
)
type Company struct {
Id int64
Name string
}
type Role struct {
Name string
}
func (role *Role) Scan(value interface{}) error {
role.Name = string(value.([]uint8))
return nil
}
func (role Role) Value() (driver.Value, error) {
return role.Name, nil
}
func (role Role) IsAdmin() bool {
return role.Name == "admin"
}
type Language struct {
Id int
Name string
}
type Ignored struct {
Name string
}
type Num int64
func (i *Num) Scan(src interface{}) error {
switch s := src.(type) {
case []byte:
case int64:
*i = Num(s)
default:
return errors.New("Cannot scan NamedInt from " + reflect.ValueOf(src).String())
}
return nil
}
type User struct {
Id int64
Age int64
UserNum Num
Name string `sql:"size:255"`
Birthday time.Time // Time
CreatedAt time.Time // CreatedAt: Time of record is created, will be insert automatically
UpdatedAt time.Time // UpdatedAt: Time of record is updated, will be updated automatically
Emails []Email // Embedded structs
Ignored Ignored `sql:"-"`
BillingAddress Address // Embedded struct
BillingAddressId sql.NullInt64 // Embedded struct's foreign key
ShippingAddress Address // Embedded struct
ShippingAddressId int64 // Embedded struct's foreign key
CreditCard CreditCard
Latitude float64
CompanyId int64
Company
Role
PasswordHash []byte
IgnoreMe int64 `sql:"-"`
IgnoreStringSlice []string `sql:"-"`
}
type UserCompany struct {
Id int64
UserId int64
CompanyId int64
}
func (t UserCompany) TableName() string {
return "user_companies"
}
type CreditCard struct {
Id int8
Number string
UserId sql.NullInt64
CreatedAt time.Time
UpdatedAt time.Time
DeletedAt time.Time
}
type Email struct {
Id int16
UserId int
Email string `sql:"type:varchar(100); unique"`
CreatedAt time.Time
UpdatedAt time.Time
}
type Address struct {
Id int
Address1 string
Address2 string
Post string
CreatedAt time.Time
UpdatedAt time.Time
DeletedAt time.Time
}
type Product struct {
Id int64
Code string
Price int64
CreatedAt time.Time
UpdatedAt time.Time
AfterFindCallTimes int64
BeforeCreateCallTimes int64
AfterCreateCallTimes int64
BeforeUpdateCallTimes int64
AfterUpdateCallTimes int64
BeforeSaveCallTimes int64
AfterSaveCallTimes int64
BeforeDeleteCallTimes int64
AfterDeleteCallTimes int64
}
type Animal struct {
Counter int64 `primaryKey:"yes"`
Name string
From string //test reserved sql keyword as field name
CreatedAt time.Time
UpdatedAt time.Time
}
type Details struct {
Id int64
Bulk gorm.Hstore
}
type Category struct {
Id int64
Name string
}
type Post struct {
Id int64
CategoryId sql.NullInt64
MainCategoryId int64
Title string
Body string
Comments []Comment
Category Category
MainCategory Category
}
type Comment struct {
Id int64
PostId int64
Content string
Post Post
}
type Order struct {
}
type Cart struct {
}
func (c Cart) TableName() string {
return "shopping_cart"
}
type BigEmail struct {
Id int64
UserId int64
Email string
UserAgent string
RegisteredAt time.Time
CreatedAt time.Time
UpdatedAt time.Time
}
func (b BigEmail) TableName() string {
return "emails"
}
type NullTime struct {
Time time.Time
Valid bool
}
func (nt *NullTime) Scan(value interface{}) error {
if value == nil {
nt.Valid = false
return nil
}
nt.Time, nt.Valid = value.(time.Time), true
return nil
}
func (nt NullTime) Value() (driver.Value, error) {
if !nt.Valid {
return nil, nil
}
return nt.Time, nil
}
type NullValue struct {
Id int64
Name sql.NullString `sql:"not null"`
Age sql.NullInt64
Male sql.NullBool
Height sql.NullFloat64
AddedAt NullTime
}

215
update_test.go Normal file
View File

@ -0,0 +1,215 @@
package gorm_test
import (
"testing"
"time"
)
func TestUpdate(t *testing.T) {
product1 := Product{Code: "123"}
product2 := Product{Code: "234"}
animal1 := Animal{Name: "Ferdinand"}
animal2 := Animal{Name: "nerdz"}
db.Save(&product1).Save(&product2).Update("code", "456")
if product2.Code != "456" {
t.Errorf("Record should be updated with update attributes")
}
db.Save(&animal1).Save(&animal2).Update("name", "Francis")
if animal2.Name != "Francis" {
t.Errorf("Record should be updated with update attributes")
}
db.First(&product1, product1.Id)
db.First(&product2, product2.Id)
updated_at1 := product1.UpdatedAt
updated_at2 := product2.UpdatedAt
db.First(&animal1, animal1.Counter)
db.First(&animal2, animal2.Counter)
animalUpdated_at1 := animal1.UpdatedAt
animalUpdated_at2 := animal2.UpdatedAt
var product3 Product
db.First(&product3, product2.Id).Update("code", "456")
if updated_at2.Format(time.RFC3339Nano) != product3.UpdatedAt.Format(time.RFC3339Nano) {
t.Errorf("updated_at should not be updated if nothing changed")
}
if db.First(&Product{}, "code = '123'").Error != nil {
t.Errorf("Product 123 should not be updated")
}
if db.First(&Product{}, "code = '234'").Error == nil {
t.Errorf("Product 234 should be changed to 456")
}
if db.First(&Product{}, "code = '456'").Error != nil {
t.Errorf("Product 234 should be changed to 456")
}
var animal3 Animal
db.First(&animal3, animal2.Counter).Update("Name", "Robert")
if animalUpdated_at2.Format(time.RFC3339Nano) != animal2.UpdatedAt.Format(time.RFC3339Nano) {
t.Errorf("updated_at should not be updated if nothing changed")
}
if db.First(&Animal{}, "name = 'Ferdinand'").Error != nil {
t.Errorf("Animal 'Ferdinand' should not be updated")
}
if db.First(&Animal{}, "name = 'nerdz'").Error == nil {
t.Errorf("Animal 'nerdz' should be changed to 'Francis'")
}
if db.First(&Animal{}, "name = 'Robert'").Error != nil {
t.Errorf("Animal 'nerdz' should be changed to 'Robert'")
}
db.Table("products").Where("code in (?)", []string{"123"}).Update("code", "789")
var product4 Product
db.First(&product4, product1.Id)
if updated_at1.Format(time.RFC3339Nano) != product4.UpdatedAt.Format(time.RFC3339Nano) {
t.Errorf("updated_at should be updated if something changed")
}
if db.First(&Product{}, "code = '123'").Error == nil {
t.Errorf("Product 123 should be changed to 789")
}
if db.First(&Product{}, "code = '456'").Error != nil {
t.Errorf("Product 456 should not be changed to 789")
}
if db.First(&Product{}, "code = '789'").Error != nil {
t.Errorf("Product 123 should be changed to 789")
}
if db.Model(product2).Update("CreatedAt", time.Now().Add(time.Hour)).Error != nil {
t.Error("No error should raise when update with CamelCase")
}
if db.Model(&product2).UpdateColumn("CreatedAt", time.Now().Add(time.Hour)).Error != nil {
t.Error("No error should raise when update_column with CamelCase")
}
db.Table("animals").Where("name in (?)", []string{"Ferdinand"}).Update("name", "Franz")
var animal4 Animal
db.First(&animal4, animal1.Counter)
if animalUpdated_at1.Format(time.RFC3339Nano) != animal4.UpdatedAt.Format(time.RFC3339Nano) {
t.Errorf("animalUpdated_at should be updated if something changed")
}
if db.First(&Animal{}, "name = 'Ferdinand'").Error == nil {
t.Errorf("Animal 'Ferdinand' should be changed to 'Franz'")
}
if db.First(&Animal{}, "name = 'Robert'").Error != nil {
t.Errorf("Animal 'Robert' should not be changed to 'Francis'")
}
if db.First(&Animal{}, "name = 'Franz'").Error != nil {
t.Errorf("Animal 'nerdz' should be changed to 'Franz'")
}
if db.Model(animal2).Update("CreatedAt", time.Now().Add(time.Hour)).Error != nil {
t.Error("No error should raise when update with CamelCase")
}
if db.Model(&animal2).UpdateColumn("CreatedAt", time.Now().Add(time.Hour)).Error != nil {
t.Error("No error should raise when update_column with CamelCase")
}
var animals []Animal
db.Find(&animals)
if count := db.Model(Animal{}).Update("CreatedAt", time.Now().Add(2*time.Hour)).RowsAffected; count != int64(len(animals)) {
t.Error("RowsAffected should be correct when do batch update")
}
}
func TestUpdates(t *testing.T) {
product1 := Product{Code: "abc", Price: 10}
product2 := Product{Code: "cde", Price: 20}
db.Save(&product1).Save(&product2)
db.Model(&product2).Updates(map[string]interface{}{"code": "edf", "price": 100})
if product2.Code != "edf" || product2.Price != 100 {
t.Errorf("Record should be updated also with update attributes")
}
db.First(&product1, product1.Id)
db.First(&product2, product2.Id)
updated_at1 := product1.UpdatedAt
updated_at2 := product2.UpdatedAt
var product3 Product
db.First(&product3, product2.Id).Updates(Product{Code: "edf", Price: 100})
if product3.Code != "edf" || product3.Price != 100 {
t.Errorf("Record should be updated with update attributes")
}
if updated_at2.Format(time.RFC3339Nano) != product3.UpdatedAt.Format(time.RFC3339Nano) {
t.Errorf("updated_at should not be updated if nothing changed")
}
if db.First(&Product{}, "code = 'abc' and price = 10").Error != nil {
t.Errorf("Product abc should not be updated")
}
if db.First(&Product{}, "code = 'cde'").Error == nil {
t.Errorf("Product cde should be renamed to edf")
}
if db.First(&Product{}, "code = 'edf' and price = 100").Error != nil {
t.Errorf("Product cde should be renamed to edf")
}
db.Table("products").Where("code in (?)", []string{"abc"}).Updates(map[string]string{"code": "fgh", "price": "200"})
if db.First(&Product{}, "code = 'abc'").Error == nil {
t.Errorf("Product abc's code should be changed to fgh")
}
var product4 Product
db.First(&product4, product1.Id)
if updated_at1.Format(time.RFC3339Nano) != product4.UpdatedAt.Format(time.RFC3339Nano) {
t.Errorf("updated_at should be updated if something changed")
}
if db.First(&Product{}, "code = 'edf' and price = ?", 100).Error != nil {
t.Errorf("Product cde's code should not be changed to fgh")
}
if db.First(&Product{}, "code = 'fgh' and price = 200").Error != nil {
t.Errorf("We should have Product fgh")
}
}
func TestUpdateColumn(t *testing.T) {
product1 := Product{Code: "update_column 1", Price: 10}
product2 := Product{Code: "update_column 2", Price: 20}
db.Save(&product1).Save(&product2).UpdateColumn(map[string]interface{}{"code": "update_column 3", "price": 100})
if product2.Code != "update_column 3" || product2.Price != 100 {
t.Errorf("product 2 should be updated with update column")
}
var product3 Product
db.First(&product3, product1.Id)
if product3.Code != "update_column 1" || product3.Price != 10 {
t.Errorf("product 1 should not be updated")
}
var product4, product5 Product
db.First(&product4, product2.Id)
updated_at1 := product4.UpdatedAt
db.Model(Product{}).Where(product2.Id).UpdateColumn("code", "update_column_new")
db.First(&product5, product2.Id)
if updated_at1.Format(time.RFC3339Nano) != product5.UpdatedAt.Format(time.RFC3339Nano) {
t.Errorf("updated_at should not be updated with update column")
}
}