...

Source file src/go.mongodb.org/mongo-driver/bson/unmarshal_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  	"errors"
    11  	"math/rand"
    12  	"reflect"
    13  	"sync"
    14  	"testing"
    15  
    16  	"go.mongodb.org/mongo-driver/bson/bsoncodec"
    17  	"go.mongodb.org/mongo-driver/bson/bsonrw"
    18  	"go.mongodb.org/mongo-driver/bson/primitive"
    19  	"go.mongodb.org/mongo-driver/internal/assert"
    20  	"go.mongodb.org/mongo-driver/x/bsonx/bsoncore"
    21  )
    22  
    23  func TestUnmarshal(t *testing.T) {
    24  	for _, tc := range unmarshalingTestCases() {
    25  		t.Run(tc.name, func(t *testing.T) {
    26  			// Make a copy of the test data so we can modify it later.
    27  			data := make([]byte, len(tc.data))
    28  			copy(data, tc.data)
    29  
    30  			// Assert that unmarshaling the input data results in the expected value.
    31  			got := reflect.New(tc.sType).Interface()
    32  			err := Unmarshal(data, got)
    33  			noerr(t, err)
    34  			assert.Equal(t, tc.want, got, "Did not unmarshal as expected.")
    35  
    36  			// Fill the input data slice with random bytes and then assert that the result still
    37  			// matches the expected value.
    38  			_, err = rand.Read(data)
    39  			noerr(t, err)
    40  			assert.Equal(t, tc.want, got, "unmarshaled value does not match expected after modifying the input bytes")
    41  		})
    42  	}
    43  }
    44  
    45  func TestUnmarshalWithRegistry(t *testing.T) {
    46  	for _, tc := range unmarshalingTestCases() {
    47  		t.Run(tc.name, func(t *testing.T) {
    48  			// Make a copy of the test data so we can modify it later.
    49  			data := make([]byte, len(tc.data))
    50  			copy(data, tc.data)
    51  
    52  			// Assert that unmarshaling the input data results in the expected value.
    53  			got := reflect.New(tc.sType).Interface()
    54  			err := UnmarshalWithRegistry(DefaultRegistry, data, got)
    55  			noerr(t, err)
    56  			assert.Equal(t, tc.want, got, "Did not unmarshal as expected.")
    57  
    58  			// Fill the input data slice with random bytes and then assert that the result still
    59  			// matches the expected value.
    60  			_, err = rand.Read(data)
    61  			noerr(t, err)
    62  			assert.Equal(t, tc.want, got, "unmarshaled value does not match expected after modifying the input bytes")
    63  		})
    64  	}
    65  }
    66  
    67  func TestUnmarshalWithContext(t *testing.T) {
    68  	for _, tc := range unmarshalingTestCases() {
    69  		t.Run(tc.name, func(t *testing.T) {
    70  			// Make a copy of the test data so we can modify it later.
    71  			data := make([]byte, len(tc.data))
    72  			copy(data, tc.data)
    73  
    74  			// Assert that unmarshaling the input data results in the expected value.
    75  			dc := bsoncodec.DecodeContext{Registry: DefaultRegistry}
    76  			got := reflect.New(tc.sType).Interface()
    77  			err := UnmarshalWithContext(dc, data, got)
    78  			noerr(t, err)
    79  			assert.Equal(t, tc.want, got, "Did not unmarshal as expected.")
    80  
    81  			// Fill the input data slice with random bytes and then assert that the result still
    82  			// matches the expected value.
    83  			_, err = rand.Read(data)
    84  			noerr(t, err)
    85  			assert.Equal(t, tc.want, got, "unmarshaled value does not match expected after modifying the input bytes")
    86  		})
    87  	}
    88  }
    89  
    90  func TestUnmarshalExtJSONWithRegistry(t *testing.T) {
    91  	t.Run("UnmarshalExtJSONWithContext", func(t *testing.T) {
    92  		type teststruct struct{ Foo int }
    93  		var got teststruct
    94  		data := []byte("{\"foo\":1}")
    95  		err := UnmarshalExtJSONWithRegistry(DefaultRegistry, data, true, &got)
    96  		noerr(t, err)
    97  		want := teststruct{1}
    98  		assert.Equal(t, want, got, "Did not unmarshal as expected.")
    99  	})
   100  
   101  	t.Run("UnmarshalExtJSONInvalidInput", func(t *testing.T) {
   102  		data := []byte("invalid")
   103  		err := UnmarshalExtJSONWithRegistry(DefaultRegistry, data, true, &M{})
   104  		if !errors.Is(err, bsonrw.ErrInvalidJSON) {
   105  			t.Fatalf("wanted ErrInvalidJSON, got %v", err)
   106  		}
   107  	})
   108  }
   109  
   110  func TestUnmarshalExtJSONWithContext(t *testing.T) {
   111  	type fooInt struct {
   112  		Foo int
   113  	}
   114  
   115  	type fooString struct {
   116  		Foo string
   117  	}
   118  
   119  	type fooBytes struct {
   120  		Foo []byte
   121  	}
   122  
   123  	var cases = []struct {
   124  		name  string
   125  		sType reflect.Type
   126  		want  interface{}
   127  		data  []byte
   128  	}{
   129  		{
   130  			name:  "Small struct",
   131  			sType: reflect.TypeOf(fooInt{}),
   132  			data:  []byte(`{"foo":1}`),
   133  			want:  &fooInt{Foo: 1},
   134  		},
   135  		{
   136  			name:  "Valid surrogate pair",
   137  			sType: reflect.TypeOf(fooString{}),
   138  			data:  []byte(`{"foo":"\uD834\uDd1e"}`),
   139  			want:  &fooString{Foo: "𝄞"},
   140  		},
   141  		{
   142  			name:  "Valid surrogate pair with other values",
   143  			sType: reflect.TypeOf(fooString{}),
   144  			data:  []byte(`{"foo":"abc \uD834\uDd1e 123"}`),
   145  			want:  &fooString{Foo: "abc 𝄞 123"},
   146  		},
   147  		{
   148  			name:  "High surrogate value with no following low surrogate value",
   149  			sType: reflect.TypeOf(fooString{}),
   150  			data:  []byte(`{"foo":"abc \uD834 123"}`),
   151  			want:  &fooString{Foo: "abc � 123"},
   152  		},
   153  		{
   154  			name:  "High surrogate value at end of string",
   155  			sType: reflect.TypeOf(fooString{}),
   156  			data:  []byte(`{"foo":"\uD834"}`),
   157  			want:  &fooString{Foo: "�"},
   158  		},
   159  		{
   160  			name:  "Low surrogate value with no preceding high surrogate value",
   161  			sType: reflect.TypeOf(fooString{}),
   162  			data:  []byte(`{"foo":"abc \uDd1e 123"}`),
   163  			want:  &fooString{Foo: "abc � 123"},
   164  		},
   165  		{
   166  			name:  "Low surrogate value at end of string",
   167  			sType: reflect.TypeOf(fooString{}),
   168  			data:  []byte(`{"foo":"\uDd1e"}`),
   169  			want:  &fooString{Foo: "�"},
   170  		},
   171  		{
   172  			name:  "High surrogate value with non-surrogate unicode value",
   173  			sType: reflect.TypeOf(fooString{}),
   174  			data:  []byte(`{"foo":"\uD834\u00BF"}`),
   175  			want:  &fooString{Foo: "�¿"},
   176  		},
   177  		// GODRIVER-2311
   178  		// Test that ExtJSON-encoded binary unmarshals correctly to a bson.D and that the
   179  		// unmarshaled value does not reference the same underlying byte array as the input.
   180  		{
   181  			name:  "bson.D with binary",
   182  			sType: reflect.TypeOf(D{}),
   183  			data:  []byte(`{"foo": {"$binary": {"subType": "0", "base64": "AAECAwQF"}}}`),
   184  			want:  &D{{"foo", primitive.Binary{Subtype: 0, Data: []byte{0, 1, 2, 3, 4, 5}}}},
   185  		},
   186  		// GODRIVER-2311
   187  		// Test that ExtJSON-encoded binary unmarshals correctly to a struct and that the
   188  		// unmarshaled value does not reference thesame  underlying byte array as the input.
   189  		{
   190  			name:  "struct with binary",
   191  			sType: reflect.TypeOf(fooBytes{}),
   192  			data:  []byte(`{"foo": {"$binary": {"subType": "0", "base64": "AAECAwQF"}}}`),
   193  			want:  &fooBytes{Foo: []byte{0, 1, 2, 3, 4, 5}},
   194  		},
   195  	}
   196  
   197  	for _, tc := range cases {
   198  		t.Run(tc.name, func(t *testing.T) {
   199  			// Make a copy of the test data so we can modify it later.
   200  			data := make([]byte, len(tc.data))
   201  			copy(data, tc.data)
   202  
   203  			// Assert that unmarshaling the input data results in the expected value.
   204  			got := reflect.New(tc.sType).Interface()
   205  			dc := bsoncodec.DecodeContext{Registry: DefaultRegistry}
   206  			err := UnmarshalExtJSONWithContext(dc, data, true, got)
   207  			noerr(t, err)
   208  			assert.Equal(t, tc.want, got, "Did not unmarshal as expected.")
   209  
   210  			// Fill the input data slice with random bytes and then assert that the result still
   211  			// matches the expected value.
   212  			_, err = rand.Read(data)
   213  			noerr(t, err)
   214  			assert.Equal(t, tc.want, got, "unmarshaled value does not match expected after modifying the input bytes")
   215  		})
   216  	}
   217  }
   218  
   219  func TestCachingDecodersNotSharedAcrossRegistries(t *testing.T) {
   220  	// Decoders that have caches for recursive decoder lookup should not be shared across Registry instances. Otherwise,
   221  	// the first DecodeValue call would cache an decoder and a subsequent call would see that decoder even if a
   222  	// different Registry is used.
   223  
   224  	// Create a custom Registry that negates BSON int32 values when decoding.
   225  	var decodeInt32 bsoncodec.ValueDecoderFunc = func(_ bsoncodec.DecodeContext, vr bsonrw.ValueReader, val reflect.Value) error {
   226  		i32, err := vr.ReadInt32()
   227  		if err != nil {
   228  			return err
   229  		}
   230  
   231  		val.SetInt(int64(-1 * i32))
   232  		return nil
   233  	}
   234  	customReg := NewRegistryBuilder().
   235  		RegisterTypeDecoder(tInt32, decodeInt32).
   236  		Build()
   237  
   238  	docBytes := bsoncore.BuildDocumentFromElements(
   239  		nil,
   240  		bsoncore.AppendInt32Element(nil, "x", 1),
   241  	)
   242  
   243  	// For all sub-tests, unmarshal docBytes into a struct and assert that value for "x" is 1 when using the default
   244  	// registry and -1 when using the custom registry.
   245  	t.Run("struct", func(t *testing.T) {
   246  		type Struct struct {
   247  			X int32
   248  		}
   249  
   250  		var first Struct
   251  		err := Unmarshal(docBytes, &first)
   252  		assert.Nil(t, err, "Unmarshal error: %v", err)
   253  		assert.Equal(t, int32(1), first.X, "expected X value to be 1, got %v", first.X)
   254  
   255  		var second Struct
   256  		err = UnmarshalWithRegistry(customReg, docBytes, &second)
   257  		assert.Nil(t, err, "Unmarshal error: %v", err)
   258  		assert.Equal(t, int32(-1), second.X, "expected X value to be -1, got %v", second.X)
   259  	})
   260  	t.Run("pointer", func(t *testing.T) {
   261  		type Struct struct {
   262  			X *int32
   263  		}
   264  
   265  		var first Struct
   266  		err := Unmarshal(docBytes, &first)
   267  		assert.Nil(t, err, "Unmarshal error: %v", err)
   268  		assert.Equal(t, int32(1), *first.X, "expected X value to be 1, got %v", *first.X)
   269  
   270  		var second Struct
   271  		err = UnmarshalWithRegistry(customReg, docBytes, &second)
   272  		assert.Nil(t, err, "Unmarshal error: %v", err)
   273  		assert.Equal(t, int32(-1), *second.X, "expected X value to be -1, got %v", *second.X)
   274  	})
   275  }
   276  
   277  func TestUnmarshalExtJSONWithUndefinedField(t *testing.T) {
   278  	// When unmarshalling extJSON, fields that are undefined in the destination struct are skipped.
   279  	// This process must not skip other, defined fields and must not raise errors.
   280  	type expectedResponse struct {
   281  		DefinedField interface{}
   282  	}
   283  
   284  	unmarshalExpectedResponse := func(t *testing.T, extJSON string) *expectedResponse {
   285  		t.Helper()
   286  		responseDoc := expectedResponse{}
   287  		err := UnmarshalExtJSON([]byte(extJSON), false, &responseDoc)
   288  		assert.Nil(t, err, "UnmarshalExtJSON error: %v", err)
   289  		return &responseDoc
   290  	}
   291  
   292  	testCases := []struct {
   293  		name          string
   294  		testJSON      string
   295  		expectedValue interface{}
   296  	}{
   297  		{
   298  			"no array",
   299  			`{
   300  				"UndefinedField": {"key": 1},
   301  				"DefinedField": "value"
   302  			}`,
   303  			"value",
   304  		},
   305  		{
   306  			"outer array",
   307  			`{
   308  				"UndefinedField": [{"key": 1}],
   309  				"DefinedField": "value"
   310  			}`,
   311  			"value",
   312  		},
   313  		{
   314  			"embedded array",
   315  			`{
   316  				"UndefinedField": {"keys": [2]},
   317  				"DefinedField": "value"
   318  			}`,
   319  			"value",
   320  		},
   321  		{
   322  			"outer array and embedded array",
   323  			`{
   324  				"UndefinedField": [{"keys": [2]}],
   325  				"DefinedField": "value"
   326  			}`,
   327  			"value",
   328  		},
   329  		{
   330  			"embedded document",
   331  			`{
   332  				"UndefinedField": {"key": {"one": "two"}},
   333  				"DefinedField": "value"
   334  			}`,
   335  			"value",
   336  		},
   337  		{
   338  			"doubly embedded document",
   339  			`{
   340  				"UndefinedField": {"key": {"one": {"two": "three"}}},
   341  				"DefinedField": "value"
   342  			}`,
   343  			"value",
   344  		},
   345  		{
   346  			"embedded document and embedded array",
   347  			`{
   348  				"UndefinedField": {"key": {"one": {"two": [3]}}},
   349  				"DefinedField": "value"
   350  			}`,
   351  			"value",
   352  		},
   353  		{
   354  			"embedded document and embedded array in outer array",
   355  			`{
   356  				"UndefinedField": [{"key": {"one": [3]}}],
   357  				"DefinedField": "value"
   358  			}`,
   359  			"value",
   360  		},
   361  		{
   362  			"code with scope",
   363  			`{
   364  				"UndefinedField": {"logic": {"$code": "foo", "$scope": {"bar": 1}}},
   365  				"DefinedField": "value"
   366  			}`,
   367  			"value",
   368  		},
   369  		{
   370  			"embedded array of code with scope",
   371  			`{
   372  				"UndefinedField": {"logic": [{"$code": "foo", "$scope": {"bar": 1}}]},
   373  				"DefinedField": "value"
   374  			}`,
   375  			"value",
   376  		},
   377  		{
   378  			"type definition embedded document",
   379  			`{
   380  				"UndefinedField": {"myDouble": {"$numberDouble": "1.24"}},
   381  				"DefinedField": "value"
   382  			}`,
   383  			"value",
   384  		},
   385  		{
   386  			"empty embedded document",
   387  			`{
   388  				"UndefinedField": {"empty": {}, "key": 1},
   389  				"DefinedField": "value"
   390  			}`,
   391  			"value",
   392  		},
   393  		{
   394  			"empty object before",
   395  			`{
   396  				"UndefinedField": {},
   397  				"DefinedField": {"value": "a"}
   398  			}`,
   399  			D{{"value", "a"}},
   400  		},
   401  		{
   402  			"empty object after",
   403  			`{
   404  				"DefinedField": {"value": "a"},
   405  				"UndefinedField": {}
   406  			}`,
   407  			D{{"value", "a"}},
   408  		},
   409  	}
   410  	for _, tc := range testCases {
   411  		t.Run(tc.name, func(t *testing.T) {
   412  			responseDoc := unmarshalExpectedResponse(t, tc.testJSON)
   413  			assert.Equal(t, tc.expectedValue, responseDoc.DefinedField, "expected DefinedField to be %v, got %q",
   414  				tc.expectedValue, responseDoc.DefinedField)
   415  		})
   416  	}
   417  }
   418  
   419  func TestUnmarshalBSONWithUndefinedField(t *testing.T) {
   420  	// When unmarshalling BSON, fields that are undefined in the destination struct are skipped.
   421  	// This process must not skip other, defined fields and must not raise errors.
   422  	type expectedResponse struct {
   423  		DefinedField string `bson:"DefinedField"`
   424  	}
   425  
   426  	createExpectedResponse := func(t *testing.T, doc D) *expectedResponse {
   427  		t.Helper()
   428  
   429  		marshalledBSON, err := Marshal(doc)
   430  		assert.Nil(t, err, "error marshalling BSON: %v", err)
   431  
   432  		responseDoc := expectedResponse{}
   433  		err = Unmarshal(marshalledBSON, &responseDoc)
   434  		assert.Nil(t, err, "error unmarshalling BSON: %v", err)
   435  		return &responseDoc
   436  	}
   437  
   438  	testCases := []struct {
   439  		name     string
   440  		testBSON D
   441  	}{
   442  		{
   443  			"no array",
   444  			D{
   445  				{"UndefinedField", D{
   446  					{"key", 1},
   447  				}},
   448  				{"DefinedField", "value"},
   449  			},
   450  		},
   451  		{
   452  			"outer array",
   453  			D{
   454  				{"UndefinedField", A{D{
   455  					{"key", 1},
   456  				}}},
   457  				{"DefinedField", "value"},
   458  			},
   459  		},
   460  		{
   461  			"embedded array",
   462  			D{
   463  				{"UndefinedField", D{
   464  					{"key", A{1}},
   465  				}},
   466  				{"DefinedField", "value"},
   467  			},
   468  		},
   469  		{
   470  			"outer array and embedded array",
   471  			D{
   472  				{"UndefinedField", A{D{
   473  					{"key", A{1}},
   474  				}}},
   475  				{"DefinedField", "value"},
   476  			},
   477  		},
   478  		{
   479  			"embedded document",
   480  			D{
   481  				{"UndefinedField", D{
   482  					{"key", D{
   483  						{"one", "two"},
   484  					}},
   485  				}},
   486  				{"DefinedField", "value"},
   487  			},
   488  		},
   489  		{
   490  			"doubly embedded document",
   491  			D{
   492  				{"UndefinedField", D{
   493  					{"key", D{
   494  						{"one", D{
   495  							{"two", "three"},
   496  						}},
   497  					}},
   498  				}},
   499  				{"DefinedField", "value"},
   500  			},
   501  		},
   502  		{
   503  			"embedded document and embedded array",
   504  			D{
   505  				{"UndefinedField", D{
   506  					{"key", D{
   507  						{"one", D{
   508  							{"two", A{3}},
   509  						}},
   510  					}},
   511  				}},
   512  				{"DefinedField", "value"},
   513  			},
   514  		},
   515  		{
   516  			"embedded document and embedded array in outer array",
   517  			D{
   518  				{"UndefinedField", A{D{
   519  					{"key", D{
   520  						{"one", A{3}},
   521  					}},
   522  				}}},
   523  				{"DefinedField", "value"},
   524  			},
   525  		},
   526  		{
   527  			"code with scope",
   528  			D{
   529  				{"UndefinedField", D{
   530  					{"logic", D{
   531  						{"$code", "foo"},
   532  						{"$scope", D{
   533  							{"bar", 1},
   534  						}},
   535  					}},
   536  				}},
   537  				{"DefinedField", "value"},
   538  			},
   539  		},
   540  		{
   541  			"embedded array of code with scope",
   542  			D{
   543  				{"UndefinedField", D{
   544  					{"logic", A{D{
   545  						{"$code", "foo"},
   546  						{"$scope", D{
   547  							{"bar", 1},
   548  						}},
   549  					}}},
   550  				}},
   551  				{"DefinedField", "value"},
   552  			},
   553  		},
   554  		{
   555  			"empty embedded document",
   556  			D{
   557  				{"UndefinedField", D{}},
   558  				{"DefinedField", "value"},
   559  			},
   560  		},
   561  	}
   562  	for _, tc := range testCases {
   563  		t.Run(tc.name, func(t *testing.T) {
   564  			responseDoc := createExpectedResponse(t, tc.testBSON)
   565  			assert.Equal(t, "value", responseDoc.DefinedField, "expected DefinedField to be 'value', got %q", responseDoc.DefinedField)
   566  		})
   567  	}
   568  }
   569  
   570  // GODRIVER-2311
   571  // Assert that unmarshaled values containing byte slices do not reference the same underlying byte
   572  // array as the BSON input data byte slice.
   573  func TestUnmarshalByteSlicesUseDistinctArrays(t *testing.T) {
   574  	type fooBytes struct {
   575  		Foo []byte
   576  	}
   577  
   578  	type myBytes []byte
   579  	type fooMyBytes struct {
   580  		Foo myBytes
   581  	}
   582  
   583  	type fooBinary struct {
   584  		Foo primitive.Binary
   585  	}
   586  
   587  	type fooObjectID struct {
   588  		Foo primitive.ObjectID
   589  	}
   590  
   591  	type fooDBPointer struct {
   592  		Foo primitive.DBPointer
   593  	}
   594  
   595  	testCases := []struct {
   596  		description string
   597  		data        []byte
   598  		sType       reflect.Type
   599  		want        interface{}
   600  
   601  		// getByteSlice returns the byte slice from the unmarshaled value, allowing the test to
   602  		// inspect the addresses of the underlying byte array.
   603  		getByteSlice func(interface{}) []byte
   604  	}{
   605  		{
   606  			description: "struct with byte slice",
   607  			data: docToBytes(fooBytes{
   608  				Foo: []byte{0, 1, 2, 3, 4, 5},
   609  			}),
   610  			sType: reflect.TypeOf(fooBytes{}),
   611  			want: &fooBytes{
   612  				Foo: []byte{0, 1, 2, 3, 4, 5},
   613  			},
   614  			getByteSlice: func(val interface{}) []byte {
   615  				return (*(val.(*fooBytes))).Foo
   616  			},
   617  		},
   618  		{
   619  			description: "bson.D with byte slice",
   620  			data: docToBytes(D{
   621  				{"foo", []byte{0, 1, 2, 3, 4, 5}},
   622  			}),
   623  			sType: reflect.TypeOf(D{}),
   624  			want: &D{
   625  				{"foo", primitive.Binary{Subtype: 0, Data: []byte{0, 1, 2, 3, 4, 5}}},
   626  			},
   627  			getByteSlice: func(val interface{}) []byte {
   628  				return (*(val.(*D)))[0].Value.(primitive.Binary).Data
   629  			},
   630  		},
   631  		{
   632  			description: "struct with custom byte slice type",
   633  			data: docToBytes(fooMyBytes{
   634  				Foo: myBytes{0, 1, 2, 3, 4, 5},
   635  			}),
   636  			sType: reflect.TypeOf(fooMyBytes{}),
   637  			want: &fooMyBytes{
   638  				Foo: myBytes{0, 1, 2, 3, 4, 5},
   639  			},
   640  			getByteSlice: func(val interface{}) []byte {
   641  				return (*(val.(*fooMyBytes))).Foo
   642  			},
   643  		},
   644  		{
   645  			description: "bson.D with custom byte slice type",
   646  			data: docToBytes(D{
   647  				{"foo", myBytes{0, 1, 2, 3, 4, 5}},
   648  			}),
   649  			sType: reflect.TypeOf(D{}),
   650  			want: &D{
   651  				{"foo", primitive.Binary{Subtype: 0, Data: myBytes{0, 1, 2, 3, 4, 5}}},
   652  			},
   653  			getByteSlice: func(val interface{}) []byte {
   654  				return (*(val.(*D)))[0].Value.(primitive.Binary).Data
   655  			},
   656  		},
   657  		{
   658  			description: "struct with primitive.Binary",
   659  			data: docToBytes(fooBinary{
   660  				Foo: primitive.Binary{Subtype: 0, Data: []byte{0, 1, 2, 3, 4, 5}},
   661  			}),
   662  			sType: reflect.TypeOf(fooBinary{}),
   663  			want: &fooBinary{
   664  				Foo: primitive.Binary{Subtype: 0, Data: []byte{0, 1, 2, 3, 4, 5}},
   665  			},
   666  			getByteSlice: func(val interface{}) []byte {
   667  				return (*(val.(*fooBinary))).Foo.Data
   668  			},
   669  		},
   670  		{
   671  			description: "bson.D with primitive.Binary",
   672  			data: docToBytes(D{
   673  				{"foo", primitive.Binary{Subtype: 0, Data: []byte{0, 1, 2, 3, 4, 5}}},
   674  			}),
   675  			sType: reflect.TypeOf(D{}),
   676  			want: &D{
   677  				{"foo", primitive.Binary{Subtype: 0, Data: []byte{0, 1, 2, 3, 4, 5}}},
   678  			},
   679  			getByteSlice: func(val interface{}) []byte {
   680  				return (*(val.(*D)))[0].Value.(primitive.Binary).Data
   681  			},
   682  		},
   683  		{
   684  			description: "struct with primitive.ObjectID",
   685  			data: docToBytes(fooObjectID{
   686  				Foo: primitive.ObjectID{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11},
   687  			}),
   688  			sType: reflect.TypeOf(fooObjectID{}),
   689  			want: &fooObjectID{
   690  				Foo: primitive.ObjectID{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11},
   691  			},
   692  			getByteSlice: func(val interface{}) []byte {
   693  				return (*(val.(*fooObjectID))).Foo[:]
   694  			},
   695  		},
   696  		{
   697  			description: "bson.D with primitive.ObjectID",
   698  			data: docToBytes(D{
   699  				{"foo", primitive.ObjectID{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}},
   700  			}),
   701  			sType: reflect.TypeOf(D{}),
   702  			want: &D{
   703  				{"foo", primitive.ObjectID{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}},
   704  			},
   705  			getByteSlice: func(val interface{}) []byte {
   706  				oid := (*(val.(*D)))[0].Value.(primitive.ObjectID)
   707  				return oid[:]
   708  			},
   709  		},
   710  		{
   711  			description: "struct with primitive.DBPointer",
   712  			data: docToBytes(fooDBPointer{
   713  				Foo: primitive.DBPointer{
   714  					DB:      "test",
   715  					Pointer: primitive.ObjectID{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11},
   716  				},
   717  			}),
   718  			sType: reflect.TypeOf(fooDBPointer{}),
   719  			want: &fooDBPointer{
   720  				Foo: primitive.DBPointer{
   721  					DB:      "test",
   722  					Pointer: primitive.ObjectID{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11},
   723  				},
   724  			},
   725  			getByteSlice: func(val interface{}) []byte {
   726  				return (*(val.(*fooDBPointer))).Foo.Pointer[:]
   727  			},
   728  		},
   729  		{
   730  			description: "bson.D with primitive.DBPointer",
   731  			data: docToBytes(D{
   732  				{"foo", primitive.DBPointer{
   733  					DB:      "test",
   734  					Pointer: primitive.ObjectID{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11},
   735  				}},
   736  			}),
   737  			sType: reflect.TypeOf(D{}),
   738  			want: &D{
   739  				{"foo", primitive.DBPointer{
   740  					DB:      "test",
   741  					Pointer: primitive.ObjectID{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11},
   742  				}},
   743  			},
   744  			getByteSlice: func(val interface{}) []byte {
   745  				oid := (*(val.(*D)))[0].Value.(primitive.DBPointer).Pointer
   746  				return oid[:]
   747  			},
   748  		},
   749  	}
   750  
   751  	for _, tc := range testCases {
   752  		tc := tc // Capture range variable.
   753  		t.Run(tc.description, func(t *testing.T) {
   754  			t.Parallel()
   755  
   756  			// Make a copy of the test data so we can modify it later.
   757  			data := make([]byte, len(tc.data))
   758  			copy(data, tc.data)
   759  
   760  			// Assert that unmarshaling the input data results in the expected value.
   761  			got := reflect.New(tc.sType).Interface()
   762  			err := Unmarshal(data, got)
   763  			noerr(t, err)
   764  			assert.Equal(t, tc.want, got, "unmarshaled value does not match the expected value")
   765  
   766  			// Fill the input data slice with random bytes and then assert that the result still
   767  			// matches the expected value.
   768  			_, err = rand.Read(data)
   769  			noerr(t, err)
   770  			assert.Equal(t, tc.want, got, "unmarshaled value does not match expected after modifying the input bytes")
   771  
   772  			// Assert that the byte slice in the unmarshaled value does not share any memory
   773  			// addresses with the input byte slice.
   774  			assert.DifferentAddressRanges(t, data, tc.getByteSlice(got))
   775  		})
   776  	}
   777  }
   778  
   779  func TestUnmarshalConcurrently(t *testing.T) {
   780  	t.Parallel()
   781  
   782  	const size = 10_000
   783  
   784  	data := []byte{16, 0, 0, 0, 10, 108, 97, 115, 116, 101, 114, 114, 111, 114, 0, 0}
   785  	wg := sync.WaitGroup{}
   786  	wg.Add(size)
   787  	for i := 0; i < size; i++ {
   788  		go func() {
   789  			defer wg.Done()
   790  			var res struct{ LastError error }
   791  			_ = Unmarshal(data, &res)
   792  		}()
   793  	}
   794  	wg.Wait()
   795  }
   796  

View as plain text