gopkg.in/rethinkdb/rethinkdb-go.v6@v6.2.2/encoding/encoder_test.go (about)

     1  package encoding
     2  
     3  import (
     4  	"errors"
     5  	"image"
     6  	"reflect"
     7  	"testing"
     8  	"time"
     9  )
    10  
    11  var encodeExpected = map[string]interface{}{
    12  	"Level0":  int64(1),
    13  	"Level1b": int64(2),
    14  	"Level1c": int64(3),
    15  	"Level1a": int64(5),
    16  	"LEVEL1B": int64(6),
    17  	"e": map[string]interface{}{
    18  		"Level1a": int64(8),
    19  		"Level1b": int64(9),
    20  		"Level1c": int64(10),
    21  		"Level1d": int64(11),
    22  		"x":       int64(12),
    23  	},
    24  	"Loop1": int64(13),
    25  	"Loop2": int64(14),
    26  	"X":     int64(15),
    27  	"Y":     int64(16),
    28  	"Z":     int64(17),
    29  }
    30  
    31  func TestEncode(t *testing.T) {
    32  	// Top is defined in decoder_test.go
    33  	var in = Top{
    34  		Level0: 1,
    35  		Embed0: Embed0{
    36  			Level1b: 2,
    37  			Level1c: 3,
    38  		},
    39  		Embed0a: &Embed0a{
    40  			Level1a: 5,
    41  			Level1b: 6,
    42  		},
    43  		Embed0b: &Embed0b{
    44  			Level1a: 8,
    45  			Level1b: 9,
    46  			Level1c: 10,
    47  			Level1d: 11,
    48  			Level1e: 12,
    49  		},
    50  		Loop: Loop{
    51  			Loop1: 13,
    52  			Loop2: 14,
    53  		},
    54  		Embed0p: Embed0p{
    55  			Point: image.Point{X: 15, Y: 16},
    56  		},
    57  		Embed0q: Embed0q{
    58  			Point: Point{Z: 17},
    59  		},
    60  	}
    61  
    62  	got, err := Encode(&in)
    63  	if err != nil {
    64  		t.Fatal(err)
    65  	}
    66  	if !reflect.DeepEqual(got, encodeExpected) {
    67  		t.Errorf(" got: %v\nwant: %v\n", got, encodeExpected)
    68  	}
    69  }
    70  
    71  type Optionals struct {
    72  	Sr string `rethinkdb:"sr"`
    73  	So string `rethinkdb:"so,omitempty"`
    74  	Sw string `rethinkdb:"-"`
    75  
    76  	Ir int `rethinkdb:"omitempty"` // actually named omitempty, not an option
    77  	Io int `rethinkdb:"io,omitempty"`
    78  
    79  	Tr time.Time `rethinkdb:"tr"`
    80  	To time.Time `rethinkdb:"to,omitempty"`
    81  
    82  	Slr []string `rethinkdb:"slr"`
    83  	Slo []string `rethinkdb:"slo,omitempty"`
    84  
    85  	Mr map[string]interface{} `rethinkdb:"mr"`
    86  	Mo map[string]interface{} `rethinkdb:",omitempty"`
    87  }
    88  
    89  var optionalsExpected = map[string]interface{}{
    90  	"sr":        "",
    91  	"omitempty": int64(0),
    92  	"tr":        map[string]interface{}{"$reql_type$": "TIME", "epoch_time": 0, "timezone": "+00:00"},
    93  	"slr":       []interface{}(nil),
    94  	"mr":        map[string]interface{}{},
    95  }
    96  
    97  func TestOmitEmpty(t *testing.T) {
    98  	var o Optionals
    99  	o.Sw = "something"
   100  	o.Tr = time.Unix(0, 0).In(time.UTC)
   101  	o.Mr = map[string]interface{}{}
   102  	o.Mo = map[string]interface{}{}
   103  
   104  	got, err := Encode(&o)
   105  	if err != nil {
   106  		t.Fatal(err)
   107  	}
   108  	if !jsonEqual(got, optionalsExpected) {
   109  		t.Errorf("\ngot:  %#v\nwant: %#v\n", got, optionalsExpected)
   110  	}
   111  }
   112  
   113  type IntType int
   114  
   115  type MyStruct struct {
   116  	IntType
   117  }
   118  
   119  func TestAnonymousNonstruct(t *testing.T) {
   120  	var i IntType = 11
   121  	a := MyStruct{i}
   122  	var want = map[string]interface{}{"IntType": int64(11)}
   123  
   124  	got, err := Encode(a)
   125  	if err != nil {
   126  		t.Fatalf("Encode: %v", err)
   127  	}
   128  	if !reflect.DeepEqual(got, want) {
   129  		t.Errorf("got %v, want %v", got, want)
   130  	}
   131  }
   132  
   133  func TestEncodePointer(t *testing.T) {
   134  	v := Pointer{PPoint: &Point{Z: 1}, Point: Point{Z: 2}}
   135  	var want = map[string]interface{}{
   136  		"PPoint": map[string]interface{}{"Z": int64(1)},
   137  		"Point":  map[string]interface{}{"Z": int64(2)},
   138  	}
   139  
   140  	got, err := Encode(v)
   141  	if err != nil {
   142  		t.Fatalf("Encode: %v", err)
   143  	}
   144  	if !reflect.DeepEqual(got, want) {
   145  		t.Errorf("got %v, want %v", got, want)
   146  	}
   147  }
   148  
   149  func TestEncodeNilPointer(t *testing.T) {
   150  	v := Pointer{PPoint: nil, Point: Point{Z: 2}}
   151  	var want = map[string]interface{}{
   152  		"PPoint": nil,
   153  		"Point":  map[string]interface{}{"Z": int64(2)},
   154  	}
   155  
   156  	got, err := Encode(v)
   157  	if err != nil {
   158  		t.Fatalf("Encode: %v", err)
   159  	}
   160  	if !reflect.DeepEqual(got, want) {
   161  		t.Errorf("got %v, want %v", got, want)
   162  	}
   163  }
   164  
   165  type BugA struct {
   166  	S string
   167  }
   168  
   169  type BugB struct {
   170  	BugA
   171  	S string
   172  }
   173  
   174  type BugC struct {
   175  	S string
   176  }
   177  
   178  // Legal Go: We never use the repeated embedded field (S).
   179  type BugX struct {
   180  	A int
   181  	BugA
   182  	BugB
   183  }
   184  
   185  // Issue 5245.
   186  func TestEmbeddedBug(t *testing.T) {
   187  	v := BugB{
   188  		BugA{"A"},
   189  		"B",
   190  	}
   191  	got, err := Encode(v)
   192  	if err != nil {
   193  		t.Fatal("Encode:", err)
   194  	}
   195  	want := map[string]interface{}{"S": "B"}
   196  	if !reflect.DeepEqual(got, want) {
   197  		t.Fatalf("Encode: got %v want %v", got, want)
   198  	}
   199  	// Now check that the duplicate field, S, does not appear.
   200  	x := BugX{
   201  		A: 23,
   202  	}
   203  	got, err = Encode(x)
   204  	if err != nil {
   205  		t.Fatal("Encode:", err)
   206  	}
   207  	want = map[string]interface{}{"A": int64(23)}
   208  	if !reflect.DeepEqual(got, want) {
   209  		t.Fatalf("Encode: got %v want %v", got, want)
   210  	}
   211  }
   212  
   213  type BugD struct { // Same as BugA after tagging.
   214  	XXX string `rethinkdb:"S"`
   215  }
   216  
   217  // BugD's tagged S field should dominate BugA's.
   218  type BugY struct {
   219  	BugA
   220  	BugD
   221  }
   222  
   223  // Test that a field with a tag dominates untagged fields.
   224  func TestTaggedFieldDominates(t *testing.T) {
   225  	v := BugY{
   226  		BugA{"BugA"},
   227  		BugD{"BugD"},
   228  	}
   229  	got, err := Encode(v)
   230  	if err != nil {
   231  		t.Fatal("Encode:", err)
   232  	}
   233  	want := map[string]interface{}{"S": "BugD"}
   234  	if !reflect.DeepEqual(got, want) {
   235  		t.Fatalf("Encode: got %v want %v", got, want)
   236  	}
   237  }
   238  
   239  // There are no tags here, so S should not appear.
   240  type BugZ struct {
   241  	BugA
   242  	BugC
   243  	BugY // Contains a tagged S field through BugD; should not dominate.
   244  }
   245  
   246  func TestDuplicatedFieldDisappears(t *testing.T) {
   247  	v := BugZ{
   248  		BugA{"BugA"},
   249  		BugC{"BugC"},
   250  		BugY{
   251  			BugA{"nested BugA"},
   252  			BugD{"nested BugD"},
   253  		},
   254  	}
   255  	got, err := Encode(v)
   256  	if err != nil {
   257  		t.Fatal("Encode:", err)
   258  	}
   259  	want := map[string]interface{}{}
   260  	if !reflect.DeepEqual(got, want) {
   261  		t.Fatalf("Encode: got %v want %v", got, want)
   262  	}
   263  }
   264  
   265  func TestEncodeMapIntKeys(t *testing.T) {
   266  	input := map[int]int{1: 1, 2: 2, 3: 3}
   267  	want := map[string]int{"1": 1, "2": 2, "3": 3}
   268  
   269  	out, err := Encode(input)
   270  	if err != nil {
   271  		t.Errorf("got error %v, expected nil", err)
   272  	}
   273  	if !jsonEqual(out, want) {
   274  		t.Errorf("got %q, want %q", out, want)
   275  	}
   276  }
   277  
   278  type RefA struct {
   279  	ID string `rethinkdb:"id,omitempty"`
   280  	B  *RefB  `rethinkdb:"b_id,reference" rethinkdb_ref:"id"`
   281  }
   282  
   283  type RefB struct {
   284  	ID   string `rethinkdb:"id,omitempty"`
   285  	Name string `rethinkdb:"name"`
   286  }
   287  
   288  func TestReferenceField(t *testing.T) {
   289  	input := RefA{"1", &RefB{"2", "Name"}}
   290  	want := map[string]interface{}{"id": "1", "b_id": "2"}
   291  
   292  	out, err := Encode(input)
   293  	if err != nil {
   294  		t.Errorf("got error %v, expected nil", err)
   295  	}
   296  	if !jsonEqual(out, want) {
   297  		t.Errorf("got %q, want %q", out, want)
   298  	}
   299  }
   300  
   301  type RefC struct {
   302  	ID string `rethinkdb:"id,omitempty"`
   303  	B  *RefB  `rethinkdb:"b_id,reference" rethinkdb_ref:"b_id"`
   304  }
   305  
   306  func TestReferenceFieldMissing(t *testing.T) {
   307  	input := RefC{"1", &RefB{"2", "Name"}}
   308  
   309  	_, err := Encode(input)
   310  	if err == nil {
   311  		t.Errorf("expected non-nil error but got nil")
   312  	}
   313  }
   314  
   315  type RefD struct {
   316  	ID string `rethinkdb:"id,omitempty"`
   317  	B  string `rethinkdb:"b_id,reference" rethinkdb_ref:"b_id"`
   318  }
   319  
   320  func TestReferenceFieldInvalid(t *testing.T) {
   321  	input := RefD{"1", "B"}
   322  
   323  	_, err := Encode(input)
   324  	if err == nil {
   325  		t.Errorf("expected non-nil error but got nil")
   326  	}
   327  }
   328  
   329  type RefE struct {
   330  	ID   string  `rethinkdb:"id,omitempty"`
   331  	FIDs *[]RefF `rethinkdb:"f_ids,reference" rethinkdb_ref:"id"`
   332  }
   333  
   334  type RefF struct {
   335  	ID   string `rethinkdb:"id,omitempty"`
   336  	Name string `rethinkdb:"name"`
   337  }
   338  
   339  func TestReferenceFieldArray(t *testing.T) {
   340  	input := RefE{"1", &[]RefF{RefF{"2", "Name2"}, RefF{"3", "Name3"}}}
   341  	want := map[string]interface{}{"id": "1", "f_ids": []string{"2", "3"}}
   342  
   343  	out, err := Encode(input)
   344  	if err != nil {
   345  		t.Errorf("got error %v, expected nil", err)
   346  	}
   347  	if !jsonEqual(out, want) {
   348  		t.Errorf("got %q, want %q", out, want)
   349  	}
   350  }
   351  
   352  func TestEncodeBytes(t *testing.T) {
   353  	type BytesStruct struct {
   354  		A []byte
   355  		B [1]byte
   356  	}
   357  
   358  	input := BytesStruct{[]byte("A"), [1]byte{'B'}}
   359  	want := map[string]interface{}{
   360  		"A": map[string]interface{}{"$reql_type$": "BINARY", "data": "QQ=="},
   361  		"B": map[string]interface{}{"$reql_type$": "BINARY", "data": "Qg=="},
   362  	}
   363  
   364  	out, err := Encode(input)
   365  	if err != nil {
   366  		t.Errorf("got error %v, expected nil", err)
   367  	}
   368  	if !jsonEqual(out, want) {
   369  		t.Errorf("got %q, want %q", out, want)
   370  	}
   371  }
   372  
   373  type Compound struct {
   374  	PartA string `rethinkdb:"id[0]"`
   375  	PartB string `rethinkdb:"id[1]"`
   376  	ErrA  string `rethinkdb:"err_a[]"`
   377  	ErrB  string `rethinkdb:"err_b["`
   378  	ErrC  string `rethinkdb:"err_c]"`
   379  }
   380  
   381  func TestEncodeCompound(t *testing.T) {
   382  	input := Compound{"1", "2", "3", "4", "5"}
   383  	want := map[string]interface{}{"id": []string{"1", "2"}, "err_a[]": "3", "err_b[": "4", "err_c]": "5"}
   384  
   385  	out, err := Encode(input)
   386  	if err != nil {
   387  		t.Errorf("got error %v, expected nil", err)
   388  	}
   389  	if !jsonEqual(out, want) {
   390  		t.Errorf("got %q, want %q", out, want)
   391  	}
   392  }
   393  
   394  type CompoundRef struct {
   395  	PartA string `rethinkdb:"id[0]"`
   396  	PartB *RefB  `rethinkdb:"id[1],reference" rethinkdb_ref:"id"`
   397  }
   398  
   399  func TestEncodeCompoundRef(t *testing.T) {
   400  	input := CompoundRef{"1", &RefB{"2", "Name"}}
   401  	want := map[string]interface{}{"id": []string{"1", "2"}}
   402  
   403  	out, err := Encode(input)
   404  	if err != nil {
   405  		t.Errorf("got error %v, expected nil", err)
   406  	}
   407  	if !jsonEqual(out, want) {
   408  		t.Errorf("got %q, want %q", out, want)
   409  	}
   410  }
   411  
   412  func TestEncodeNilSlice(t *testing.T) {
   413  	input := SliceStruct{}
   414  	want := map[string]interface{}{"X": []string(nil)}
   415  
   416  	out, err := Encode(input)
   417  	if err != nil {
   418  		t.Errorf("got error %v, expected nil", err)
   419  	}
   420  	if !jsonEqual(out, want) {
   421  		t.Errorf("got %q, want %q", out, want)
   422  	}
   423  }
   424  
   425  func TestEncodeCustomTypeEncodingValue(t *testing.T) {
   426  	type innerType struct {
   427  		Val int
   428  	}
   429  
   430  	outer := struct {
   431  		Inner innerType `rethinkdb:"inner"`
   432  	}{Inner: innerType{Val: 5}}
   433  	want := map[string]interface{}{
   434  		"inner": map[string]interface{}{
   435  			"someval": 5,
   436  		},
   437  	}
   438  
   439  	SetTypeEncoding(reflect.TypeOf(innerType{}),
   440  		func(v interface{}) (interface{}, error) {
   441  			return map[string]interface{}{"someval": v.(innerType).Val}, nil
   442  		}, nil)
   443  
   444  	out, err := Encode(outer)
   445  	if err != nil {
   446  		t.Errorf("got error %v, expected nil", err)
   447  	}
   448  	if !jsonEqual(out, want) {
   449  		t.Errorf("got %q, want %q", out, want)
   450  	}
   451  }
   452  
   453  func TestEncodeCustomTypeEncodingPointer(t *testing.T) {
   454  	type innerType struct {
   455  		Val int
   456  	}
   457  
   458  	outer := struct {
   459  		Inner *innerType `rethinkdb:"inner"`
   460  	}{Inner: &innerType{Val: 5}}
   461  	want := map[string]interface{}{
   462  		"inner": map[string]interface{}{
   463  			"someval": 5,
   464  		},
   465  	}
   466  
   467  	SetTypeEncoding(reflect.TypeOf((*innerType)(nil)),
   468  		func(v interface{}) (interface{}, error) {
   469  			return map[string]interface{}{"someval": v.(*innerType).Val}, nil
   470  		}, nil)
   471  
   472  	out, err := Encode(outer)
   473  	if err != nil {
   474  		t.Errorf("got error %v, expected nil", err)
   475  	}
   476  	if !jsonEqual(out, want) {
   477  		t.Errorf("got %q, want %q", out, want)
   478  	}
   479  }
   480  
   481  func TestEncodeCustomRootTypeEncodingValue(t *testing.T) {
   482  	type cType struct {
   483  		Val int
   484  	}
   485  	in := cType{Val: 5}
   486  
   487  	want := map[string]interface{}{
   488  		"someval": 5,
   489  	}
   490  
   491  	SetTypeEncoding(reflect.TypeOf(cType{}),
   492  		func(v interface{}) (interface{}, error) {
   493  			return map[string]interface{}{"someval": v.(cType).Val}, nil
   494  		}, nil)
   495  
   496  	out, err := Encode(in)
   497  	if err != nil {
   498  		t.Errorf("got error %v, expected nil", err)
   499  	}
   500  	if !jsonEqual(out, want) {
   501  		t.Errorf("got %q, want %q", out, want)
   502  	}
   503  }
   504  
   505  func TestEncodeCustomRootTypeEncodingPointer(t *testing.T) {
   506  	type cType struct {
   507  		Val int
   508  	}
   509  	in := cType{Val: 5}
   510  
   511  	want := map[string]interface{}{
   512  		"someval": 5,
   513  	}
   514  
   515  	SetTypeEncoding(reflect.TypeOf((*cType)(nil)),
   516  		func(v interface{}) (interface{}, error) {
   517  			return map[string]interface{}{"someval": v.(*cType).Val}, nil
   518  		}, nil)
   519  
   520  	out, err := Encode(&in)
   521  	if err != nil {
   522  		t.Errorf("got error %v, expected nil", err)
   523  	}
   524  	if !jsonEqual(out, want) {
   525  		t.Errorf("got %q, want %q", out, want)
   526  	}
   527  }
   528  
   529  func TestEncodeCustomRootTypeEncodingError(t *testing.T) {
   530  	type cType struct {
   531  		Val int
   532  	}
   533  	in := cType{Val: 5}
   534  
   535  	cerr := errors.New("encode error")
   536  
   537  	SetTypeEncoding(reflect.TypeOf((*cType)(nil)),
   538  		func(v interface{}) (interface{}, error) {
   539  			return nil, cerr
   540  		}, nil)
   541  
   542  	_, err := Encode(&in)
   543  	if err == nil {
   544  		t.Errorf("got nil error, expected %v", cerr)
   545  	}
   546  	if err != cerr {
   547  		t.Errorf("got %q, want %q", err, cerr)
   548  	}
   549  }