...

Source file src/go.mongodb.org/mongo-driver/bson/unmarshaling_cases_test.go

Documentation: go.mongodb.org/mongo-driver/bson

     1  // Copyright (C) MongoDB, Inc. 2017-present.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License"); you may
     4  // not use this file except in compliance with the License. You may obtain
     5  // a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
     6  
     7  package bson
     8  
     9  import (
    10  	"reflect"
    11  
    12  	"go.mongodb.org/mongo-driver/bson/bsonrw"
    13  	"go.mongodb.org/mongo-driver/bson/bsontype"
    14  )
    15  
    16  type unmarshalingTestCase struct {
    17  	name  string
    18  	sType reflect.Type
    19  	want  interface{}
    20  	data  []byte
    21  }
    22  
    23  func unmarshalingTestCases() []unmarshalingTestCase {
    24  	var zeroPtrStruct unmarshalerPtrStruct
    25  	{
    26  		i := myInt64(0)
    27  		m := myMap{}
    28  		b := myBytes{}
    29  		s := myString("")
    30  		zeroPtrStruct = unmarshalerPtrStruct{I: &i, M: &m, B: &b, S: &s}
    31  	}
    32  
    33  	var zeroNonPtrStruct unmarshalerNonPtrStruct
    34  	{
    35  		i := myInt64(0)
    36  		m := myMap{}
    37  		b := myBytes{}
    38  		s := myString("")
    39  		zeroNonPtrStruct = unmarshalerNonPtrStruct{I: i, M: m, B: b, S: s}
    40  	}
    41  
    42  	var valPtrStruct unmarshalerPtrStruct
    43  	{
    44  		i := myInt64(5)
    45  		m := myMap{"key": "value"}
    46  		b := myBytes{0x00, 0x01}
    47  		s := myString("test")
    48  		valPtrStruct = unmarshalerPtrStruct{I: &i, M: &m, B: &b, S: &s}
    49  	}
    50  
    51  	var valNonPtrStruct unmarshalerNonPtrStruct
    52  	{
    53  		i := myInt64(5)
    54  		m := myMap{"key": "value"}
    55  		b := myBytes{0x00, 0x01}
    56  		s := myString("test")
    57  		valNonPtrStruct = unmarshalerNonPtrStruct{I: i, M: m, B: b, S: s}
    58  	}
    59  
    60  	type fooBytes struct {
    61  		Foo []byte
    62  	}
    63  
    64  	return []unmarshalingTestCase{
    65  		{
    66  			name: "small struct",
    67  			sType: reflect.TypeOf(struct {
    68  				Foo bool
    69  			}{}),
    70  			want: &struct {
    71  				Foo bool
    72  			}{Foo: true},
    73  			data: docToBytes(D{{"foo", true}}),
    74  		},
    75  		{
    76  			name: "nested document",
    77  			sType: reflect.TypeOf(struct {
    78  				Foo struct {
    79  					Bar bool
    80  				}
    81  			}{}),
    82  			want: &struct {
    83  				Foo struct {
    84  					Bar bool
    85  				}
    86  			}{
    87  				Foo: struct {
    88  					Bar bool
    89  				}{Bar: true},
    90  			},
    91  			data: docToBytes(D{{"foo", D{{"bar", true}}}}),
    92  		},
    93  		{
    94  			name: "simple array",
    95  			sType: reflect.TypeOf(struct {
    96  				Foo []bool
    97  			}{}),
    98  			want: &struct {
    99  				Foo []bool
   100  			}{
   101  				Foo: []bool{true},
   102  			},
   103  			data: docToBytes(D{{"foo", A{true}}}),
   104  		},
   105  		{
   106  			name: "struct with mixed case fields",
   107  			sType: reflect.TypeOf(struct {
   108  				FooBar int32
   109  			}{}),
   110  			want: &struct {
   111  				FooBar int32
   112  			}{
   113  				FooBar: 10,
   114  			},
   115  			data: docToBytes(D{{"fooBar", int32(10)}}),
   116  		},
   117  		// GODRIVER-2252
   118  		// Test that a struct of pointer types with UnmarshalBSON functions defined marshal and
   119  		// unmarshal to the same Go values when the pointer values are "nil".
   120  		{
   121  			name:  "nil pointer fields with UnmarshalBSON function should marshal and unmarshal to the same values",
   122  			sType: reflect.TypeOf(unmarshalerPtrStruct{}),
   123  			want:  &unmarshalerPtrStruct{},
   124  			data:  docToBytes(unmarshalerPtrStruct{}),
   125  		},
   126  		// GODRIVER-2252
   127  		// Test that a struct of pointer types with UnmarshalBSON functions defined marshal and
   128  		// unmarshal to the same Go values when the pointer values are the respective zero values.
   129  		{
   130  			name:  "zero-value pointer fields with UnmarshalBSON function should marshal and unmarshal to the same values",
   131  			sType: reflect.TypeOf(unmarshalerPtrStruct{}),
   132  			want:  &zeroPtrStruct,
   133  			data:  docToBytes(zeroPtrStruct),
   134  		},
   135  		// GODRIVER-2252
   136  		// Test that a struct of pointer types with UnmarshalBSON functions defined marshal and
   137  		// unmarshal to the same Go values when the pointer values are non-zero values.
   138  		{
   139  			name:  "non-zero-value pointer fields with UnmarshalBSON function should marshal and unmarshal to the same values",
   140  			sType: reflect.TypeOf(unmarshalerPtrStruct{}),
   141  			want:  &valPtrStruct,
   142  			data:  docToBytes(valPtrStruct),
   143  		},
   144  		// GODRIVER-2311
   145  		// Test that an unmarshaled struct that has a byte slice value does not reference the same
   146  		// underlying array as the input.
   147  		{
   148  			name:  "struct with byte slice",
   149  			sType: reflect.TypeOf(fooBytes{}),
   150  			want: &fooBytes{
   151  				Foo: []byte{0, 1, 2, 3, 4, 5},
   152  			},
   153  			data: docToBytes(fooBytes{
   154  				Foo: []byte{0, 1, 2, 3, 4, 5},
   155  			}),
   156  		},
   157  		// GODRIVER-2427
   158  		// Test that a struct of non-pointer types with UnmarshalBSON functions defined for the pointer of the field
   159  		// will marshal and unmarshal to the same Go values when the non-pointer values are the respctive zero values.
   160  		{
   161  			name: `zero-value non-pointer fields with pointer UnmarshalBSON function should marshal and unmarshal to
   162  			the same values`,
   163  			sType: reflect.TypeOf(unmarshalerNonPtrStruct{}),
   164  			want:  &zeroNonPtrStruct,
   165  			data:  docToBytes(zeroNonPtrStruct),
   166  		},
   167  		// GODRIVER-2427
   168  		// Test that a struct of non-pointer types with UnmarshalBSON functions defined for the pointer of the field
   169  		// unmarshal to the same Go values when the non-pointer values are non-zero values.
   170  		{
   171  			name: `non-zero-value non-pointer fields with pointer UnmarshalBSON function should marshal and unmarshal
   172  			to the same values`,
   173  			sType: reflect.TypeOf(unmarshalerNonPtrStruct{}),
   174  			want:  &valNonPtrStruct,
   175  			data:  docToBytes(valNonPtrStruct),
   176  		},
   177  	}
   178  }
   179  
   180  // unmarshalerPtrStruct contains a collection of fields that are all pointers to custom types that
   181  // implement the bson.Unmarshaler interface. It is used to test the BSON unmarshal behavior for
   182  // pointer types with custom UnmarshalBSON functions.
   183  type unmarshalerPtrStruct struct {
   184  	I *myInt64
   185  	M *myMap
   186  	B *myBytes
   187  	S *myString
   188  }
   189  
   190  // unmarshalerNonPtrStruct contains a collection of non-pointer fields that are all to custom types that implement the
   191  // bson.Unmarshaler interface. It is used to test the BSON unmarshal behavior for types with custom UnmarshalBSON
   192  // functions.
   193  type unmarshalerNonPtrStruct struct {
   194  	I myInt64
   195  	M myMap
   196  	B myBytes
   197  	S myString
   198  }
   199  
   200  type myInt64 int64
   201  
   202  func (mi *myInt64) UnmarshalBSON(bytes []byte) error {
   203  	if len(bytes) == 0 {
   204  		return nil
   205  	}
   206  	i, err := bsonrw.NewBSONValueReader(bsontype.Int64, bytes).ReadInt64()
   207  	if err != nil {
   208  		return err
   209  	}
   210  	*mi = myInt64(i)
   211  	return nil
   212  }
   213  
   214  type myMap map[string]string
   215  
   216  func (mm *myMap) UnmarshalBSON(bytes []byte) error {
   217  	if len(bytes) == 0 {
   218  		return nil
   219  	}
   220  	var m map[string]string
   221  	err := Unmarshal(bytes, &m)
   222  	*mm = myMap(m)
   223  	return err
   224  }
   225  
   226  type myBytes []byte
   227  
   228  func (mb *myBytes) UnmarshalBSON(bytes []byte) error {
   229  	if len(bytes) == 0 {
   230  		return nil
   231  	}
   232  	b, _, err := bsonrw.NewBSONValueReader(bsontype.Binary, bytes).ReadBinary()
   233  	if err != nil {
   234  		return err
   235  	}
   236  	*mb = b
   237  	return nil
   238  }
   239  
   240  type myString string
   241  
   242  func (ms *myString) UnmarshalBSON(bytes []byte) error {
   243  	if len(bytes) == 0 {
   244  		return nil
   245  	}
   246  	s, err := bsonrw.NewBSONValueReader(bsontype.String, bytes).ReadString()
   247  	if err != nil {
   248  		return err
   249  	}
   250  	*ms = myString(s)
   251  	return nil
   252  }
   253  

View as plain text