@@ -251,7 +251,7 @@ func TestFieldsEmbedded(t *testing.T) {
251251 m := NewMapper ("db" )
252252
253253 type Person struct {
254- Name string `db:"name"`
254+ Name string `db:"name,size=64 "`
255255 }
256256 type Place struct {
257257 Name string `db:"name"`
@@ -311,6 +311,9 @@ func TestFieldsEmbedded(t *testing.T) {
311311 if fi .Path != "person.name" {
312312 t .Errorf ("Expecting %s, got %s" , "person.name" , fi .Path )
313313 }
314+ if fi .Options ["size" ] != "64" {
315+ t .Errorf ("Expecting %s, got %s" , "64" , fi .Options ["size" ])
316+ }
314317
315318 fi = fields .GetByTraversal ([]int {1 , 0 })
316319 if fi == nil {
@@ -508,6 +511,312 @@ func TestMapping(t *testing.T) {
508511 }
509512}
510513
514+ func TestGetByTraversal (t * testing.T ) {
515+ type C struct {
516+ C0 int
517+ C1 int
518+ }
519+ type B struct {
520+ B0 string
521+ B1 * C
522+ }
523+ type A struct {
524+ A0 int
525+ A1 B
526+ }
527+
528+ testCases := []struct {
529+ Index []int
530+ ExpectedName string
531+ ExpectNil bool
532+ }{
533+ {
534+ Index : []int {0 },
535+ ExpectedName : "A0" ,
536+ },
537+ {
538+ Index : []int {1 , 0 },
539+ ExpectedName : "B0" ,
540+ },
541+ {
542+ Index : []int {1 , 1 , 1 },
543+ ExpectedName : "C1" ,
544+ },
545+ {
546+ Index : []int {3 , 4 , 5 },
547+ ExpectNil : true ,
548+ },
549+ {
550+ Index : []int {},
551+ ExpectNil : true ,
552+ },
553+ {
554+ Index : nil ,
555+ ExpectNil : true ,
556+ },
557+ }
558+
559+ m := NewMapperFunc ("db" , func (n string ) string { return n })
560+ tm := m .TypeMap (reflect .TypeOf (A {}))
561+
562+ for i , tc := range testCases {
563+ fi := tm .GetByTraversal (tc .Index )
564+ if tc .ExpectNil {
565+ if fi != nil {
566+ t .Errorf ("%d: expected nil, got %v" , i , fi )
567+ }
568+ continue
569+ }
570+
571+ if fi == nil {
572+ t .Errorf ("%d: expected %s, got nil" , i , tc .ExpectedName )
573+ continue
574+ }
575+
576+ if fi .Name != tc .ExpectedName {
577+ t .Errorf ("%d: expected %s, got %s" , i , tc .ExpectedName , fi .Name )
578+ }
579+ }
580+ }
581+
582+ // TestMapperMethodsByName tests Mapper methods FieldByName and TraversalsByName
583+ func TestMapperMethodsByName (t * testing.T ) {
584+ type C struct {
585+ C0 string
586+ C1 int
587+ }
588+ type B struct {
589+ B0 * C `db:"B0"`
590+ B1 C `db:"B1"`
591+ B2 string `db:"B2"`
592+ }
593+ type A struct {
594+ A0 * B `db:"A0"`
595+ B `db:"A1"`
596+ A2 int
597+ a3 int
598+ }
599+
600+ val := & A {
601+ A0 : & B {
602+ B0 : & C {C0 : "0" , C1 : 1 },
603+ B1 : C {C0 : "2" , C1 : 3 },
604+ B2 : "4" ,
605+ },
606+ B : B {
607+ B0 : nil ,
608+ B1 : C {C0 : "5" , C1 : 6 },
609+ B2 : "7" ,
610+ },
611+ A2 : 8 ,
612+ }
613+
614+ testCases := []struct {
615+ Name string
616+ ExpectInvalid bool
617+ ExpectedValue interface {}
618+ ExpectedIndexes []int
619+ }{
620+ {
621+ Name : "A0.B0.C0" ,
622+ ExpectedValue : "0" ,
623+ ExpectedIndexes : []int {0 , 0 , 0 },
624+ },
625+ {
626+ Name : "A0.B0.C1" ,
627+ ExpectedValue : 1 ,
628+ ExpectedIndexes : []int {0 , 0 , 1 },
629+ },
630+ {
631+ Name : "A0.B1.C0" ,
632+ ExpectedValue : "2" ,
633+ ExpectedIndexes : []int {0 , 1 , 0 },
634+ },
635+ {
636+ Name : "A0.B1.C1" ,
637+ ExpectedValue : 3 ,
638+ ExpectedIndexes : []int {0 , 1 , 1 },
639+ },
640+ {
641+ Name : "A0.B2" ,
642+ ExpectedValue : "4" ,
643+ ExpectedIndexes : []int {0 , 2 },
644+ },
645+ {
646+ Name : "A1.B0.C0" ,
647+ ExpectedValue : "" ,
648+ ExpectedIndexes : []int {1 , 0 , 0 },
649+ },
650+ {
651+ Name : "A1.B0.C1" ,
652+ ExpectedValue : 0 ,
653+ ExpectedIndexes : []int {1 , 0 , 1 },
654+ },
655+ {
656+ Name : "A1.B1.C0" ,
657+ ExpectedValue : "5" ,
658+ ExpectedIndexes : []int {1 , 1 , 0 },
659+ },
660+ {
661+ Name : "A1.B1.C1" ,
662+ ExpectedValue : 6 ,
663+ ExpectedIndexes : []int {1 , 1 , 1 },
664+ },
665+ {
666+ Name : "A1.B2" ,
667+ ExpectedValue : "7" ,
668+ ExpectedIndexes : []int {1 , 2 },
669+ },
670+ {
671+ Name : "A2" ,
672+ ExpectedValue : 8 ,
673+ ExpectedIndexes : []int {2 },
674+ },
675+ {
676+ Name : "XYZ" ,
677+ ExpectInvalid : true ,
678+ ExpectedIndexes : []int {},
679+ },
680+ {
681+ Name : "a3" ,
682+ ExpectInvalid : true ,
683+ ExpectedIndexes : []int {},
684+ },
685+ }
686+
687+ // build the names array from the test cases
688+ names := make ([]string , len (testCases ))
689+ for i , tc := range testCases {
690+ names [i ] = tc .Name
691+ }
692+ m := NewMapperFunc ("db" , func (n string ) string { return n })
693+ v := reflect .ValueOf (val )
694+ values := m .FieldsByName (v , names )
695+ if len (values ) != len (testCases ) {
696+ t .Errorf ("expected %d values, got %d" , len (testCases ), len (values ))
697+ t .FailNow ()
698+ }
699+ indexes := m .TraversalsByName (v .Type (), names )
700+ if len (indexes ) != len (testCases ) {
701+ t .Errorf ("expected %d traversals, got %d" , len (testCases ), len (indexes ))
702+ t .FailNow ()
703+ }
704+ for i , val := range values {
705+ tc := testCases [i ]
706+ traversal := indexes [i ]
707+ if ! reflect .DeepEqual (tc .ExpectedIndexes , traversal ) {
708+ t .Errorf ("%d: expected %v, got %v" , tc .ExpectedIndexes , traversal )
709+ t .FailNow ()
710+ }
711+ val = reflect .Indirect (val )
712+ if tc .ExpectInvalid {
713+ if val .IsValid () {
714+ t .Errorf ("%d: expected zero value, got %v" , i , val )
715+ }
716+ continue
717+ }
718+ if ! val .IsValid () {
719+ t .Errorf ("%d: expected valid value, got %v" , i , val )
720+ continue
721+ }
722+ actualValue := reflect .Indirect (val ).Interface ()
723+ if ! reflect .DeepEqual (tc .ExpectedValue , actualValue ) {
724+ t .Errorf ("%d: expected %v, got %v" , i , tc .ExpectedValue , actualValue )
725+ }
726+ }
727+ }
728+
729+ func TestFieldByIndexes (t * testing.T ) {
730+ type C struct {
731+ C0 bool
732+ C1 string
733+ C2 int
734+ C3 map [string ]int
735+ }
736+ type B struct {
737+ B1 C
738+ B2 * C
739+ }
740+ type A struct {
741+ A1 B
742+ A2 * B
743+ }
744+ testCases := []struct {
745+ value interface {}
746+ indexes []int
747+ expectedValue interface {}
748+ readOnly bool
749+ }{
750+ {
751+ value : A {
752+ A1 : B {B1 : C {C0 : true }},
753+ },
754+ indexes : []int {0 , 0 , 0 },
755+ expectedValue : true ,
756+ readOnly : true ,
757+ },
758+ {
759+ value : A {
760+ A2 : & B {B2 : & C {C1 : "answer" }},
761+ },
762+ indexes : []int {1 , 1 , 1 },
763+ expectedValue : "answer" ,
764+ readOnly : true ,
765+ },
766+ {
767+ value : & A {},
768+ indexes : []int {1 , 1 , 3 },
769+ expectedValue : map [string ]int {},
770+ },
771+ }
772+
773+ for i , tc := range testCases {
774+ checkResults := func (v reflect.Value ) {
775+ if tc .expectedValue == nil {
776+ if ! v .IsNil () {
777+ t .Errorf ("%d: expected nil, actual %v" , i , v .Interface ())
778+ }
779+ } else {
780+ if ! reflect .DeepEqual (tc .expectedValue , v .Interface ()) {
781+ t .Errorf ("%d: expected %v, actual %v" , i , tc .expectedValue , v .Interface ())
782+ }
783+ }
784+ }
785+
786+ checkResults (FieldByIndexes (reflect .ValueOf (tc .value ), tc .indexes ))
787+ if tc .readOnly {
788+ checkResults (FieldByIndexesReadOnly (reflect .ValueOf (tc .value ), tc .indexes ))
789+ }
790+ }
791+ }
792+
793+ func TestMustBe (t * testing.T ) {
794+ typ := reflect .TypeOf (E1 {})
795+ mustBe (typ , reflect .Struct )
796+
797+ defer func () {
798+ if r := recover (); r != nil {
799+ valueErr , ok := r .(* reflect.ValueError )
800+ if ! ok {
801+ t .Errorf ("unexpected Method: %s" , valueErr .Method )
802+ t .Error ("expected panic with *reflect.ValueError" )
803+ return
804+ }
805+ if valueErr .Method != "github.com/jmoiron/sqlx/reflectx.TestMustBe" {
806+ }
807+ if valueErr .Kind != reflect .String {
808+ t .Errorf ("unexpected Kind: %s" , valueErr .Kind )
809+ }
810+ } else {
811+ t .Error ("expected panic" )
812+ }
813+ }()
814+
815+ typ = reflect .TypeOf ("string" )
816+ mustBe (typ , reflect .Struct )
817+ t .Error ("got here, didn't expect to" )
818+ }
819+
511820type E1 struct {
512821 A int
513822}
0 commit comments