From 7154d2c42d9d817f089cde3b7fb7b22d355ef4a6 Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Tue, 30 May 2017 20:33:30 +0800 Subject: [PATCH] add more tests (#595) * add more tests * fix tests --- engine.go | 7 +- session_find_test.go | 407 ++++++++++++++++++++++++ session_update_test.go | 130 ++++++++ tag_test.go => tag_cache_test.go | 0 tag_extends_test.go | 524 +++++++++++++++++++++++++++++++ test_mysql.sh | 1 + test_postgres.sh | 1 + test_sqlite.sh | 1 + types_test.go | 238 ++++++++++++++ xorm_test.go | 2 +- 10 files changed, 1309 insertions(+), 2 deletions(-) rename tag_test.go => tag_cache_test.go (100%) create mode 100644 tag_extends_test.go create mode 100755 test_mysql.sh create mode 100755 test_postgres.sh create mode 100755 test_sqlite.sh diff --git a/engine.go b/engine.go index 3fdbfcc3..5b087b37 100644 --- a/engine.go +++ b/engine.go @@ -143,7 +143,6 @@ func (engine *Engine) Quote(value string) string { // QuoteTo quotes string and writes into the buffer func (engine *Engine) QuoteTo(buf *bytes.Buffer, value string) { - if buf == nil { return } @@ -781,6 +780,12 @@ func (engine *Engine) Having(conditions string) *Session { return session.Having(conditions) } +func (engine *Engine) unMapType(t reflect.Type) { + engine.mutex.Lock() + defer engine.mutex.Unlock() + delete(engine.Tables, t) +} + func (engine *Engine) autoMapType(v reflect.Value) (*core.Table, error) { t := v.Type() engine.mutex.Lock() diff --git a/session_find_test.go b/session_find_test.go index ef60b68b..25928da9 100644 --- a/session_find_test.go +++ b/session_find_test.go @@ -5,8 +5,11 @@ package xorm import ( + "errors" + "fmt" "testing" + "github.com/go-xorm/core" "github.com/stretchr/testify/assert" ) @@ -57,3 +60,407 @@ func TestJoinLimit(t *testing.T) { Find(&salaries) assert.NoError(t, err) } + +func assertSync(t *testing.T, beans ...interface{}) { + for _, bean := range beans { + assert.NoError(t, testEngine.DropTables(bean)) + assert.NoError(t, testEngine.Sync(bean)) + } +} + +func TestWhere(t *testing.T) { + assert.NoError(t, prepareEngine()) + + assertSync(t, new(Userinfo)) + + users := make([]Userinfo, 0) + err := testEngine.Where("(id) > ?", 2).Find(&users) + if err != nil { + t.Error(err) + panic(err) + } + fmt.Println(users) + + err = testEngine.Where("(id) > ?", 2).And("(id) < ?", 10).Find(&users) + if err != nil { + t.Error(err) + panic(err) + } + fmt.Println(users) +} + +func TestFind(t *testing.T) { + assert.NoError(t, prepareEngine()) + assertSync(t, new(Userinfo)) + + users := make([]Userinfo, 0) + + err := testEngine.Find(&users) + if err != nil { + t.Error(err) + panic(err) + } + for _, user := range users { + fmt.Println(user) + } + + users2 := make([]Userinfo, 0) + userinfo := testEngine.TableMapper.Obj2Table("Userinfo") + err = testEngine.Sql("select * from " + testEngine.Quote(userinfo)).Find(&users2) + if err != nil { + t.Error(err) + panic(err) + } +} + +func TestFind2(t *testing.T) { + assert.NoError(t, prepareEngine()) + users := make([]*Userinfo, 0) + + assertSync(t, new(Userinfo)) + + err := testEngine.Find(&users) + if err != nil { + t.Error(err) + panic(err) + } + for _, user := range users { + fmt.Println(user) + } +} + +type Team struct { + Id int64 +} + +type TeamUser struct { + OrgId int64 + Uid int64 + TeamId int64 +} + +func TestFind3(t *testing.T) { + assert.NoError(t, prepareEngine()) + err := testEngine.Sync2(new(Team), new(TeamUser)) + if err != nil { + t.Error(err) + panic(err.Error()) + } + + var teams []Team + err = testEngine.Cols("`team`.id"). + Where("`team_user`.org_id=?", 1). + And("`team_user`.uid=?", 2). + Join("INNER", "`team_user`", "`team_user`.team_id=`team`.id"). + Find(&teams) + if err != nil { + t.Error(err) + panic(err.Error()) + } +} + +func TestFindMap(t *testing.T) { + assert.NoError(t, prepareEngine()) + assertSync(t, new(Userinfo)) + + users := make(map[int64]Userinfo) + err := testEngine.Find(&users) + if err != nil { + t.Error(err) + panic(err) + } + for _, user := range users { + fmt.Println(user) + } +} + +func TestFindMap2(t *testing.T) { + assert.NoError(t, prepareEngine()) + assertSync(t, new(Userinfo)) + + users := make(map[int64]*Userinfo) + err := testEngine.Find(&users) + if err != nil { + t.Error(err) + panic(err) + } + for id, user := range users { + fmt.Println(id, user) + } +} + +func TestDistinct(t *testing.T) { + assert.NoError(t, prepareEngine()) + assertSync(t, new(Userinfo)) + + _, err := testEngine.Insert(&Userinfo{ + Username: "lunny", + }) + assert.NoError(t, err) + + users := make([]Userinfo, 0) + departname := testEngine.TableMapper.Obj2Table("Departname") + err = testEngine.Distinct(departname).Find(&users) + if err != nil { + t.Error(err) + panic(err) + } + if len(users) != 1 { + t.Error(err) + panic(errors.New("should be one record")) + } + + fmt.Println(users) + + type Depart struct { + Departname string + } + + users2 := make([]Depart, 0) + err = testEngine.Distinct(departname).Table(new(Userinfo)).Find(&users2) + if err != nil { + t.Error(err) + panic(err) + } + if len(users2) != 1 { + t.Error(err) + panic(errors.New("should be one record")) + } + fmt.Println(users2) +} + +func TestOrder(t *testing.T) { + assert.NoError(t, prepareEngine()) + assertSync(t, new(Userinfo)) + + users := make([]Userinfo, 0) + err := testEngine.OrderBy("id desc").Find(&users) + if err != nil { + t.Error(err) + panic(err) + } + fmt.Println(users) + + users2 := make([]Userinfo, 0) + err = testEngine.Asc("id", "username").Desc("height").Find(&users2) + if err != nil { + t.Error(err) + panic(err) + } + fmt.Println(users2) +} + +func TestHaving(t *testing.T) { + assert.NoError(t, prepareEngine()) + assertSync(t, new(Userinfo)) + + users := make([]Userinfo, 0) + err := testEngine.GroupBy("username").Having("username='xlw'").Find(&users) + if err != nil { + t.Error(err) + panic(err) + } + fmt.Println(users) + + /*users = make([]Userinfo, 0) + err = testEngine.Cols("id, username").GroupBy("username").Having("username='xlw'").Find(&users) + if err != nil { + t.Error(err) + panic(err) + } + fmt.Println(users)*/ +} + +func TestOrderSameMapper(t *testing.T) { + assert.NoError(t, prepareEngine()) + testEngine.unMapType(rValue(new(Userinfo)).Type()) + + mapper := testEngine.TableMapper + testEngine.SetMapper(core.SameMapper{}) + + defer func() { + testEngine.unMapType(rValue(new(Userinfo)).Type()) + testEngine.SetMapper(mapper) + }() + + assertSync(t, new(Userinfo)) + + users := make([]Userinfo, 0) + err := testEngine.OrderBy("(id) desc").Find(&users) + if err != nil { + t.Error(err) + panic(err) + } + fmt.Println(users) + + users2 := make([]Userinfo, 0) + err = testEngine.Asc("(id)", "Username").Desc("Height").Find(&users2) + if err != nil { + t.Error(err) + panic(err) + } + fmt.Println(users2) +} + +func TestHavingSameMapper(t *testing.T) { + assert.NoError(t, prepareEngine()) + testEngine.unMapType(rValue(new(Userinfo)).Type()) + + mapper := testEngine.TableMapper + testEngine.SetMapper(core.SameMapper{}) + defer func() { + testEngine.unMapType(rValue(new(Userinfo)).Type()) + testEngine.SetMapper(mapper) + }() + assertSync(t, new(Userinfo)) + + users := make([]Userinfo, 0) + err := testEngine.GroupBy("`Username`").Having("`Username`='xlw'").Find(&users) + if err != nil { + t.Fatal(err) + } + fmt.Println(users) +} + +func TestFindInts(t *testing.T) { + assert.NoError(t, prepareEngine()) + assertSync(t, new(Userinfo)) + + userinfo := testEngine.TableMapper.Obj2Table("Userinfo") + var idsInt64 []int64 + err := testEngine.Table(userinfo).Cols("id").Desc("id").Find(&idsInt64) + if err != nil { + t.Fatal(err) + } + fmt.Println(idsInt64) + + var idsInt32 []int32 + err = testEngine.Table(userinfo).Cols("id").Desc("id").Find(&idsInt32) + if err != nil { + t.Fatal(err) + } + fmt.Println(idsInt32) + + var idsInt []int + err = testEngine.Table(userinfo).Cols("id").Desc("id").Find(&idsInt) + if err != nil { + t.Fatal(err) + } + fmt.Println(idsInt) + + var idsUint []uint + err = testEngine.Table(userinfo).Cols("id").Desc("id").Find(&idsUint) + if err != nil { + t.Fatal(err) + } + fmt.Println(idsUint) + + type MyInt int + var idsMyInt []MyInt + err = testEngine.Table(userinfo).Cols("id").Desc("id").Find(&idsMyInt) + if err != nil { + t.Fatal(err) + } + fmt.Println(idsMyInt) +} + +func TestFindStrings(t *testing.T) { + assert.NoError(t, prepareEngine()) + assertSync(t, new(Userinfo)) + userinfo := testEngine.TableMapper.Obj2Table("Userinfo") + username := testEngine.ColumnMapper.Obj2Table("Username") + var idsString []string + err := testEngine.Table(userinfo).Cols(username).Desc("id").Find(&idsString) + if err != nil { + t.Fatal(err) + } + fmt.Println(idsString) +} + +func TestFindMyString(t *testing.T) { + assert.NoError(t, prepareEngine()) + assertSync(t, new(Userinfo)) + userinfo := testEngine.TableMapper.Obj2Table("Userinfo") + username := testEngine.ColumnMapper.Obj2Table("Username") + + var idsMyString []MyString + err := testEngine.Table(userinfo).Cols(username).Desc("id").Find(&idsMyString) + if err != nil { + t.Fatal(err) + } + fmt.Println(idsMyString) +} + +func TestFindInterface(t *testing.T) { + assert.NoError(t, prepareEngine()) + assertSync(t, new(Userinfo)) + + userinfo := testEngine.TableMapper.Obj2Table("Userinfo") + username := testEngine.ColumnMapper.Obj2Table("Username") + var idsInterface []interface{} + err := testEngine.Table(userinfo).Cols(username).Desc("id").Find(&idsInterface) + if err != nil { + t.Fatal(err) + } + fmt.Println(idsInterface) +} + +func TestFindSliceBytes(t *testing.T) { + assert.NoError(t, prepareEngine()) + assertSync(t, new(Userinfo)) + + userinfo := testEngine.TableMapper.Obj2Table("Userinfo") + var ids [][][]byte + err := testEngine.Table(userinfo).Desc("id").Find(&ids) + if err != nil { + t.Fatal(err) + } + for _, record := range ids { + fmt.Println(record) + } +} + +func TestFindSlicePtrString(t *testing.T) { + assert.NoError(t, prepareEngine()) + assertSync(t, new(Userinfo)) + + userinfo := testEngine.TableMapper.Obj2Table("Userinfo") + var ids [][]*string + err := testEngine.Table(userinfo).Desc("id").Find(&ids) + if err != nil { + t.Fatal(err) + } + for _, record := range ids { + fmt.Println(record) + } +} + +func TestFindMapBytes(t *testing.T) { + assert.NoError(t, prepareEngine()) + assertSync(t, new(Userinfo)) + + userinfo := testEngine.TableMapper.Obj2Table("Userinfo") + var ids []map[string][]byte + err := testEngine.Table(userinfo).Desc("id").Find(&ids) + if err != nil { + t.Fatal(err) + } + for _, record := range ids { + fmt.Println(record) + } +} + +func TestFindMapPtrString(t *testing.T) { + assert.NoError(t, prepareEngine()) + assertSync(t, new(Userinfo)) + + userinfo := testEngine.TableMapper.Obj2Table("Userinfo") + var ids []map[string]*string + err := testEngine.Table(userinfo).Desc("id").Find(&ids) + if err != nil { + t.Fatal(err) + } + for _, record := range ids { + fmt.Println(record) + } +} diff --git a/session_update_test.go b/session_update_test.go index 9eeb6186..1b2351e5 100644 --- a/session_update_test.go +++ b/session_update_test.go @@ -5,7 +5,9 @@ package xorm import ( + "sync" "testing" + "time" "github.com/stretchr/testify/assert" ) @@ -72,3 +74,131 @@ func TestUpdateLimit(t *testing.T) { assert.EqualValues(t, 35, uts[0].Age) assert.EqualValues(t, 30, uts[1].Age) } + +type ForUpdate struct { + Id int64 `xorm:"pk"` + Name string +} + +func setupForUpdate(engine *Engine) error { + v := new(ForUpdate) + err := engine.DropTables(v) + if err != nil { + return err + } + err = engine.CreateTables(v) + if err != nil { + return err + } + + list := []ForUpdate{ + {1, "data1"}, + {2, "data2"}, + {3, "data3"}, + } + + for _, f := range list { + _, err = engine.Insert(f) + if err != nil { + return err + } + } + return nil +} + +func TestForUpdate(t *testing.T) { + if testEngine.DriverName() != "mysql" && testEngine.DriverName() != "mymysql" { + return + } + + err := setupForUpdate(testEngine) + if err != nil { + t.Error(err) + return + } + + session1 := testEngine.NewSession() + session2 := testEngine.NewSession() + session3 := testEngine.NewSession() + defer session1.Close() + defer session2.Close() + defer session3.Close() + + // start transaction + err = session1.Begin() + if err != nil { + t.Error(err) + return + } + + // use lock + fList := make([]ForUpdate, 0) + session1.ForUpdate() + session1.Where("(id) = ?", 1) + err = session1.Find(&fList) + switch { + case err != nil: + t.Error(err) + return + case len(fList) != 1: + t.Errorf("find not returned single row") + return + case fList[0].Name != "data1": + t.Errorf("for_update.name must be `data1`") + return + } + + // wait for lock + wg := &sync.WaitGroup{} + + // lock is used + wg.Add(1) + go func() { + f2 := new(ForUpdate) + session2.Where("(id) = ?", 1).ForUpdate() + has, err := session2.Get(f2) // wait release lock + switch { + case err != nil: + t.Error(err) + case !has: + t.Errorf("cannot find target row. for_update.id = 1") + case f2.Name != "updated by session1": + t.Errorf("read lock failed") + } + wg.Done() + }() + + // lock is NOT used + wg.Add(1) + go func() { + f3 := new(ForUpdate) + session3.Where("(id) = ?", 1) + has, err := session3.Get(f3) // wait release lock + switch { + case err != nil: + t.Error(err) + case !has: + t.Errorf("cannot find target row. for_update.id = 1") + case f3.Name != "data1": + t.Errorf("read lock failed") + } + wg.Done() + }() + + // wait for go rountines + time.Sleep(50 * time.Millisecond) + + f := new(ForUpdate) + f.Name = "updated by session1" + session1.Where("(id) = ?", 1) + session1.Update(f) + + // release lock + err = session1.Commit() + if err != nil { + t.Error(err) + return + } + + wg.Wait() +} diff --git a/tag_test.go b/tag_cache_test.go similarity index 100% rename from tag_test.go rename to tag_cache_test.go diff --git a/tag_extends_test.go b/tag_extends_test.go new file mode 100644 index 00000000..c497b8d4 --- /dev/null +++ b/tag_extends_test.go @@ -0,0 +1,524 @@ +// Copyright 2017 The Xorm Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package xorm + +import ( + "errors" + "fmt" + "testing" + "time" + + "github.com/stretchr/testify/assert" +) + +type tempUser struct { + Id int64 + Username string +} + +type tempUser2 struct { + TempUser tempUser `xorm:"extends"` + Departname string +} + +type tempUser3 struct { + Temp *tempUser `xorm:"extends"` + Departname string +} + +type tempUser4 struct { + TempUser2 tempUser2 `xorm:"extends"` +} + +type Userinfo struct { + Uid int64 `xorm:"id pk not null autoincr"` + Username string `xorm:"unique"` + Departname string + Alias string `xorm:"-"` + Created time.Time + Detail Userdetail `xorm:"detail_id int(11)"` + Height float64 + Avatar []byte + IsMan bool +} + +type Userdetail struct { + Id int64 + Intro string `xorm:"text"` + Profile string `xorm:"varchar(2000)"` +} + +type UserAndDetail struct { + Userinfo `xorm:"extends"` + Userdetail `xorm:"extends"` +} + +func TestExtends(t *testing.T) { + assert.NoError(t, prepareEngine()) + + err := testEngine.DropTables(&tempUser2{}) + if err != nil { + t.Error(err) + panic(err) + } + + err = testEngine.CreateTables(&tempUser2{}) + if err != nil { + t.Error(err) + panic(err) + } + + tu := &tempUser2{tempUser{0, "extends"}, "dev depart"} + _, err = testEngine.Insert(tu) + if err != nil { + t.Error(err) + panic(err) + } + + tu2 := &tempUser2{} + _, err = testEngine.Get(tu2) + if err != nil { + t.Error(err) + panic(err) + } + + tu3 := &tempUser2{tempUser{0, "extends update"}, ""} + _, err = testEngine.Id(tu2.TempUser.Id).Update(tu3) + if err != nil { + t.Error(err) + panic(err) + } + + err = testEngine.DropTables(&tempUser4{}) + if err != nil { + t.Error(err) + panic(err) + } + + err = testEngine.CreateTables(&tempUser4{}) + if err != nil { + t.Error(err) + panic(err) + } + + tu8 := &tempUser4{tempUser2{tempUser{0, "extends"}, "dev depart"}} + _, err = testEngine.Insert(tu8) + if err != nil { + t.Error(err) + panic(err) + } + + tu9 := &tempUser4{} + _, err = testEngine.Get(tu9) + if err != nil { + t.Error(err) + panic(err) + } + if tu9.TempUser2.TempUser.Username != tu8.TempUser2.TempUser.Username || tu9.TempUser2.Departname != tu8.TempUser2.Departname { + err = errors.New(fmt.Sprintln("not equal for", tu8, tu9)) + t.Error(err) + panic(err) + } + + tu10 := &tempUser4{tempUser2{tempUser{0, "extends update"}, ""}} + _, err = testEngine.Id(tu9.TempUser2.TempUser.Id).Update(tu10) + if err != nil { + t.Error(err) + panic(err) + } + + err = testEngine.DropTables(&tempUser3{}) + if err != nil { + t.Error(err) + panic(err) + } + + err = testEngine.CreateTables(&tempUser3{}) + if err != nil { + t.Error(err) + panic(err) + } + + tu4 := &tempUser3{&tempUser{0, "extends"}, "dev depart"} + _, err = testEngine.Insert(tu4) + if err != nil { + t.Error(err) + panic(err) + } + + tu5 := &tempUser3{} + _, err = testEngine.Get(tu5) + if err != nil { + t.Error(err) + panic(err) + } + if tu5.Temp == nil { + err = errors.New("error get data extends") + t.Error(err) + panic(err) + } + if tu5.Temp.Id != 1 || tu5.Temp.Username != "extends" || + tu5.Departname != "dev depart" { + err = errors.New("error get data extends") + t.Error(err) + panic(err) + } + + tu6 := &tempUser3{&tempUser{0, "extends update"}, ""} + _, err = testEngine.Id(tu5.Temp.Id).Update(tu6) + if err != nil { + t.Error(err) + panic(err) + } + + users := make([]tempUser3, 0) + err = testEngine.Find(&users) + if err != nil { + t.Error(err) + panic(err) + } + if len(users) != 1 { + err = errors.New("error get data not 1") + t.Error(err) + panic(err) + } + + assertSync(t, new(Userinfo), new(Userdetail)) + + detail := Userdetail{ + Intro: "I'm in China", + } + _, err = testEngine.Insert(&detail) + assert.NoError(t, err) + + _, err = testEngine.Insert(&Userinfo{ + Username: "lunny", + Detail: detail, + }) + assert.NoError(t, err) + + var info UserAndDetail + qt := testEngine.Quote + ui := testEngine.TableMapper.Obj2Table("Userinfo") + ud := testEngine.TableMapper.Obj2Table("Userdetail") + uiid := testEngine.TableMapper.Obj2Table("Id") + udid := "detail_id" + sql := fmt.Sprintf("select * from %s, %s where %s.%s = %s.%s", + qt(ui), qt(ud), qt(ui), qt(udid), qt(ud), qt(uiid)) + b, err := testEngine.Sql(sql).NoCascade().Get(&info) + if err != nil { + t.Error(err) + panic(err) + } + if !b { + err = errors.New("should has lest one record") + t.Error(err) + panic(err) + } + fmt.Println(info) + if info.Userinfo.Uid == 0 || info.Userdetail.Id == 0 { + err = errors.New("all of the id should has value") + t.Error(err) + panic(err) + } + + fmt.Println("----join--info2") + var info2 UserAndDetail + b, err = testEngine.Table(&Userinfo{}). + Join("LEFT", qt(ud), qt(ui)+"."+qt("detail_id")+" = "+qt(ud)+"."+qt(uiid)). + NoCascade().Get(&info2) + if err != nil { + t.Error(err) + panic(err) + } + if !b { + err = errors.New("should has lest one record") + t.Error(err) + panic(err) + } + if info2.Userinfo.Uid == 0 || info2.Userdetail.Id == 0 { + err = errors.New("all of the id should has value") + t.Error(err) + panic(err) + } + fmt.Println(info2) + + fmt.Println("----join--infos2") + var infos2 = make([]UserAndDetail, 0) + err = testEngine.Table(&Userinfo{}). + Join("LEFT", qt(ud), qt(ui)+"."+qt("detail_id")+" = "+qt(ud)+"."+qt(uiid)). + NoCascade(). + Find(&infos2) + if err != nil { + t.Error(err) + panic(err) + } + fmt.Println(infos2) +} + +type MessageBase struct { + Id int64 `xorm:"int(11) pk autoincr"` + TypeId int64 `xorm:"int(11) notnull"` +} + +type Message struct { + MessageBase `xorm:"extends"` + Title string `xorm:"varchar(100) notnull"` + Content string `xorm:"text notnull"` + Uid int64 `xorm:"int(11) notnull"` + ToUid int64 `xorm:"int(11) notnull"` + CreateTime time.Time `xorm:"datetime notnull created"` +} + +type MessageUser struct { + Id int64 + Name string +} + +type MessageType struct { + Id int64 + Name string +} + +type MessageExtend3 struct { + Message `xorm:"extends"` + Sender MessageUser `xorm:"extends"` + Receiver MessageUser `xorm:"extends"` + Type MessageType `xorm:"extends"` +} + +type MessageExtend4 struct { + Message `xorm:"extends"` + MessageUser `xorm:"extends"` + MessageType `xorm:"extends"` +} + +func TestExtends2(t *testing.T) { + assert.NoError(t, prepareEngine()) + + err := testEngine.DropTables(&Message{}, &MessageUser{}, &MessageType{}) + if err != nil { + t.Error(err) + panic(err) + } + + err = testEngine.CreateTables(&Message{}, &MessageUser{}, &MessageType{}) + if err != nil { + t.Error(err) + panic(err) + } + + var sender = MessageUser{Name: "sender"} + var receiver = MessageUser{Name: "receiver"} + var msgtype = MessageType{Name: "type"} + _, err = testEngine.Insert(&sender, &receiver, &msgtype) + if err != nil { + t.Error(err) + panic(err) + } + + msg := Message{ + MessageBase: MessageBase{ + Id: msgtype.Id, + }, + Title: "test", + Content: "test", + Uid: sender.Id, + ToUid: receiver.Id, + } + _, err = testEngine.Insert(&msg) + if err != nil { + t.Error(err) + panic(err) + } + + var mapper = testEngine.TableMapper.Obj2Table + userTableName := mapper("MessageUser") + typeTableName := mapper("MessageType") + msgTableName := mapper("Message") + + list := make([]Message, 0) + err = testEngine.Table(msgTableName).Join("LEFT", []string{userTableName, "sender"}, "`sender`.`"+mapper("Id")+"`=`"+msgTableName+"`.`"+mapper("Uid")+"`"). + Join("LEFT", []string{userTableName, "receiver"}, "`receiver`.`"+mapper("Id")+"`=`"+msgTableName+"`.`"+mapper("ToUid")+"`"). + Join("LEFT", []string{typeTableName, "type"}, "`type`.`"+mapper("Id")+"`=`"+msgTableName+"`.`"+mapper("Id")+"`"). + Find(&list) + if err != nil { + t.Error(err) + panic(err) + } + + if len(list) != 1 { + err = errors.New(fmt.Sprintln("should have 1 message, got", len(list))) + t.Error(err) + panic(err) + } + + if list[0].Id != msg.Id { + err = errors.New(fmt.Sprintln("should message equal", list[0], msg)) + t.Error(err) + panic(err) + } +} + +func TestExtends3(t *testing.T) { + assert.NoError(t, prepareEngine()) + + err := testEngine.DropTables(&Message{}, &MessageUser{}, &MessageType{}) + if err != nil { + t.Error(err) + panic(err) + } + + err = testEngine.CreateTables(&Message{}, &MessageUser{}, &MessageType{}) + if err != nil { + t.Error(err) + panic(err) + } + + var sender = MessageUser{Name: "sender"} + var receiver = MessageUser{Name: "receiver"} + var msgtype = MessageType{Name: "type"} + _, err = testEngine.Insert(&sender, &receiver, &msgtype) + if err != nil { + t.Error(err) + panic(err) + } + + msg := Message{ + MessageBase: MessageBase{ + Id: msgtype.Id, + }, + Title: "test", + Content: "test", + Uid: sender.Id, + ToUid: receiver.Id, + } + _, err = testEngine.Insert(&msg) + if err != nil { + t.Error(err) + panic(err) + } + + var mapper = testEngine.TableMapper.Obj2Table + userTableName := mapper("MessageUser") + typeTableName := mapper("MessageType") + msgTableName := mapper("Message") + + list := make([]MessageExtend3, 0) + err = testEngine.Table(msgTableName).Join("LEFT", []string{userTableName, "sender"}, "`sender`.`"+mapper("Id")+"`=`"+msgTableName+"`.`"+mapper("Uid")+"`"). + Join("LEFT", []string{userTableName, "receiver"}, "`receiver`.`"+mapper("Id")+"`=`"+msgTableName+"`.`"+mapper("ToUid")+"`"). + Join("LEFT", []string{typeTableName, "type"}, "`type`.`"+mapper("Id")+"`=`"+msgTableName+"`.`"+mapper("Id")+"`"). + Find(&list) + if err != nil { + t.Error(err) + panic(err) + } + + if len(list) != 1 { + err = errors.New(fmt.Sprintln("should have 1 message, got", len(list))) + t.Error(err) + panic(err) + } + + if list[0].Message.Id != msg.Id { + err = errors.New(fmt.Sprintln("should message equal", list[0].Message, msg)) + t.Error(err) + panic(err) + } + + if list[0].Sender.Id != sender.Id || list[0].Sender.Name != sender.Name { + err = errors.New(fmt.Sprintln("should sender equal", list[0].Sender, sender)) + t.Error(err) + panic(err) + } + + if list[0].Receiver.Id != receiver.Id || list[0].Receiver.Name != receiver.Name { + err = errors.New(fmt.Sprintln("should receiver equal", list[0].Receiver, receiver)) + t.Error(err) + panic(err) + } + + if list[0].Type.Id != msgtype.Id || list[0].Type.Name != msgtype.Name { + err = errors.New(fmt.Sprintln("should msgtype equal", list[0].Type, msgtype)) + t.Error(err) + panic(err) + } +} + +func TestExtends4(t *testing.T) { + assert.NoError(t, prepareEngine()) + + err := testEngine.DropTables(&Message{}, &MessageUser{}, &MessageType{}) + if err != nil { + t.Error(err) + panic(err) + } + + err = testEngine.CreateTables(&Message{}, &MessageUser{}, &MessageType{}) + if err != nil { + t.Error(err) + panic(err) + } + + var sender = MessageUser{Name: "sender"} + var msgtype = MessageType{Name: "type"} + _, err = testEngine.Insert(&sender, &msgtype) + if err != nil { + t.Error(err) + panic(err) + } + + msg := Message{ + MessageBase: MessageBase{ + Id: msgtype.Id, + }, + Title: "test", + Content: "test", + Uid: sender.Id, + } + _, err = testEngine.Insert(&msg) + if err != nil { + t.Error(err) + panic(err) + } + + var mapper = testEngine.TableMapper.Obj2Table + userTableName := mapper("MessageUser") + typeTableName := mapper("MessageType") + msgTableName := mapper("Message") + + list := make([]MessageExtend4, 0) + err = testEngine.Table(msgTableName).Join("LEFT", userTableName, "`"+userTableName+"`.`"+mapper("Id")+"`=`"+msgTableName+"`.`"+mapper("Uid")+"`"). + Join("LEFT", typeTableName, "`"+typeTableName+"`.`"+mapper("Id")+"`=`"+msgTableName+"`.`"+mapper("Id")+"`"). + Find(&list) + if err != nil { + t.Error(err) + panic(err) + } + + if len(list) != 1 { + err = errors.New(fmt.Sprintln("should have 1 message, got", len(list))) + t.Error(err) + panic(err) + } + + if list[0].Message.Id != msg.Id { + err = errors.New(fmt.Sprintln("should message equal", list[0].Message, msg)) + t.Error(err) + panic(err) + } + + if list[0].MessageUser.Id != sender.Id || list[0].MessageUser.Name != sender.Name { + err = errors.New(fmt.Sprintln("should sender equal", list[0].MessageUser, sender)) + t.Error(err) + panic(err) + } + + if list[0].MessageType.Id != msgtype.Id || list[0].MessageType.Name != msgtype.Name { + err = errors.New(fmt.Sprintln("should msgtype equal", list[0].MessageType, msgtype)) + t.Error(err) + panic(err) + } +} diff --git a/test_mysql.sh b/test_mysql.sh new file mode 100755 index 00000000..650e4ee1 --- /dev/null +++ b/test_mysql.sh @@ -0,0 +1 @@ +go test -db=mysql -conn_str="root:@/xorm_test" \ No newline at end of file diff --git a/test_postgres.sh b/test_postgres.sh new file mode 100755 index 00000000..dc1152e0 --- /dev/null +++ b/test_postgres.sh @@ -0,0 +1 @@ +go test -db=postgres -conn_str="dbname=xorm_test sslmode=disable" \ No newline at end of file diff --git a/test_sqlite.sh b/test_sqlite.sh new file mode 100755 index 00000000..6352b5cb --- /dev/null +++ b/test_sqlite.sh @@ -0,0 +1 @@ +go test -db=sqlite3 -conn_str="./test.db?cache=shared&mode=rwc" \ No newline at end of file diff --git a/types_test.go b/types_test.go index 900dac90..aadf5f69 100644 --- a/types_test.go +++ b/types_test.go @@ -5,8 +5,12 @@ package xorm import ( + "encoding/json" + "errors" + "fmt" "testing" + "github.com/go-xorm/core" "github.com/stretchr/testify/assert" ) @@ -95,3 +99,237 @@ func TestGetBytes(t *testing.T) { assert.Equal(t, true, has) assert.Equal(t, "test", string(b.Data)) } + +type ConvString string + +func (s *ConvString) FromDB(data []byte) error { + *s = ConvString("prefix---" + string(data)) + return nil +} + +func (s *ConvString) ToDB() ([]byte, error) { + return []byte(string(*s)), nil +} + +type ConvConfig struct { + Name string + Id int64 +} + +func (s *ConvConfig) FromDB(data []byte) error { + return json.Unmarshal(data, s) +} + +func (s *ConvConfig) ToDB() ([]byte, error) { + return json.Marshal(s) +} + +type SliceType []*ConvConfig + +func (s *SliceType) FromDB(data []byte) error { + return json.Unmarshal(data, s) +} + +func (s *SliceType) ToDB() ([]byte, error) { + return json.Marshal(s) +} + +type ConvStruct struct { + Conv ConvString + Conv2 *ConvString + Cfg1 ConvConfig + Cfg2 *ConvConfig `xorm:"TEXT"` + Cfg3 core.Conversion `xorm:"BLOB"` + Slice SliceType +} + +func (c *ConvStruct) BeforeSet(name string, cell Cell) { + if name == "cfg3" || name == "Cfg3" { + c.Cfg3 = new(ConvConfig) + } +} + +func TestConversion(t *testing.T) { + assert.NoError(t, prepareEngine()) + + c := new(ConvStruct) + assert.NoError(t, testEngine.DropTables(c)) + assert.NoError(t, testEngine.Sync(c)) + + var s ConvString = "sssss" + c.Conv = "tttt" + c.Conv2 = &s + c.Cfg1 = ConvConfig{"mm", 1} + c.Cfg2 = &ConvConfig{"xx", 2} + c.Cfg3 = &ConvConfig{"zz", 3} + c.Slice = []*ConvConfig{{"yy", 4}, {"ff", 5}} + + _, err := testEngine.Insert(c) + assert.NoError(t, err) + + c1 := new(ConvStruct) + has, err := testEngine.Get(c1) + assert.NoError(t, err) + assert.True(t, has) + assert.EqualValues(t, "prefix---tttt", string(c1.Conv)) + assert.NotNil(t, c1.Conv2) + assert.EqualValues(t, "prefix---"+s, *c1.Conv2) + assert.EqualValues(t, c.Cfg1, c1.Cfg1) + assert.NotNil(t, c1.Cfg2) + assert.EqualValues(t, *c.Cfg2, *c1.Cfg2) + assert.NotNil(t, c1.Cfg3) + assert.EqualValues(t, *c.Cfg3.(*ConvConfig), *c1.Cfg3.(*ConvConfig)) + assert.EqualValues(t, 2, len(c1.Slice)) + assert.EqualValues(t, *c.Slice[0], *c1.Slice[0]) + assert.EqualValues(t, *c.Slice[1], *c1.Slice[1]) +} + +type MyInt int +type MyUInt uint +type MyFloat float64 + +type MyStruct struct { + Type MyInt + U MyUInt + F MyFloat + S MyString + IA []MyInt + UA []MyUInt + FA []MyFloat + SA []MyString + NameArray []string + Name string + UIA []uint + UIA8 []uint8 + UIA16 []uint16 + UIA32 []uint32 + UIA64 []uint64 + UI uint + //C64 complex64 + MSS map[string]string +} + +func TestCustomType1(t *testing.T) { + assert.NoError(t, prepareEngine()) + + err := testEngine.DropTables(&MyStruct{}) + assert.NoError(t, err) + + err = testEngine.CreateTables(&MyStruct{}) + assert.NoError(t, err) + + i := MyStruct{Name: "Test", Type: MyInt(1)} + i.U = 23 + i.F = 1.34 + i.S = "fafdsafdsaf" + i.UI = 2 + i.IA = []MyInt{1, 3, 5} + i.UIA = []uint{1, 3} + i.UIA16 = []uint16{2} + i.UIA32 = []uint32{4, 5} + i.UIA64 = []uint64{6, 7, 9} + i.UIA8 = []uint8{1, 2, 3, 4} + i.NameArray = []string{"ssss", "fsdf", "lllll, ss"} + i.MSS = map[string]string{"s": "sfds,ss", "x": "lfjljsl"} + + cnt, err := testEngine.Insert(&i) + assert.NoError(t, err) + assert.EqualValues(t, 1, cnt) + + fmt.Println(i) + i.NameArray = []string{} + i.MSS = map[string]string{} + i.F = 0 + has, err := testEngine.Get(&i) + assert.NoError(t, err) + assert.True(t, has) + + ss := []MyStruct{} + err = testEngine.Find(&ss) + assert.NoError(t, err) + assert.EqualValues(t, 1, len(ss)) + assert.EqualValues(t, i, ss[0]) + + sss := MyStruct{} + has, err = testEngine.Get(&sss) + assert.NoError(t, err) + assert.True(t, has) + + sss.NameArray = []string{} + sss.MSS = map[string]string{} + cnt, err = testEngine.Delete(&sss) + assert.NoError(t, err) + assert.EqualValues(t, 1, cnt) +} + +type Status struct { + Name string + Color string +} + +var ( + _ core.Conversion = &Status{} + Registed Status = Status{"Registed", "white"} + Approved Status = Status{"Approved", "green"} + Removed Status = Status{"Removed", "red"} + Statuses map[string]Status = map[string]Status{ + Registed.Name: Registed, + Approved.Name: Approved, + Removed.Name: Removed, + } +) + +func (s *Status) FromDB(bytes []byte) error { + if r, ok := Statuses[string(bytes)]; ok { + *s = r + return nil + } else { + return errors.New("no this data") + } +} + +func (s *Status) ToDB() ([]byte, error) { + return []byte(s.Name), nil +} + +type UserCus struct { + Id int64 + Name string + Status Status `xorm:"varchar(40)"` +} + +func TestCustomType2(t *testing.T) { + assert.NoError(t, prepareEngine()) + + err := testEngine.CreateTables(&UserCus{}) + assert.NoError(t, err) + + tableName := testEngine.TableMapper.Obj2Table("UserCus") + _, err = testEngine.Exec("delete from " + testEngine.Quote(tableName)) + assert.NoError(t, err) + + if testEngine.Dialect().DBType() == core.MSSQL { + return + /*_, err = engine.Exec("set IDENTITY_INSERT " + tableName + " on") + if err != nil { + t.Fatal(err) + }*/ + } + + _, err = testEngine.Insert(&UserCus{1, "xlw", Registed}) + assert.NoError(t, err) + + user := UserCus{} + exist, err := testEngine.Id(1).Get(&user) + assert.NoError(t, err) + assert.True(t, exist) + + fmt.Println(user) + + users := make([]UserCus, 0) + err = testEngine.Where("`"+testEngine.ColumnMapper.Obj2Table("Status")+"` = ?", "Registed").Find(&users) + assert.NoError(t, err) + assert.EqualValues(t, 1, len(users)) + + fmt.Println(users) +} diff --git a/xorm_test.go b/xorm_test.go index 8c4aff87..66868b65 100644 --- a/xorm_test.go +++ b/xorm_test.go @@ -58,7 +58,7 @@ func TestMain(m *testing.M) { dbType = *db if *db == "sqlite3" { if ptrConnStr == nil { - connString = "./test.db" + connString = "./test.db?cache=shared&mode=rwc" } else { connString = *ptrConnStr }