...

Source file src/go.mongodb.org/mongo-driver/bson/bson_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  	"bytes"
    11  	"fmt"
    12  	"reflect"
    13  	"strconv"
    14  	"strings"
    15  	"testing"
    16  	"time"
    17  
    18  	"github.com/google/go-cmp/cmp"
    19  	"go.mongodb.org/mongo-driver/bson/bsoncodec"
    20  	"go.mongodb.org/mongo-driver/bson/bsonoptions"
    21  	"go.mongodb.org/mongo-driver/bson/bsontype"
    22  	"go.mongodb.org/mongo-driver/internal/assert"
    23  	"go.mongodb.org/mongo-driver/x/bsonx/bsoncore"
    24  )
    25  
    26  func noerr(t *testing.T, err error) {
    27  	if err != nil {
    28  		t.Helper()
    29  		t.Errorf("Unexpected error: (%T)%v", err, err)
    30  		t.FailNow()
    31  	}
    32  }
    33  
    34  func TestTimeRoundTrip(t *testing.T) {
    35  	val := struct {
    36  		Value time.Time
    37  		ID    string
    38  	}{
    39  		ID: "time-rt-test",
    40  	}
    41  
    42  	if !val.Value.IsZero() {
    43  		t.Errorf("Did not get zero time as expected.")
    44  	}
    45  
    46  	bsonOut, err := Marshal(val)
    47  	noerr(t, err)
    48  	rtval := struct {
    49  		Value time.Time
    50  		ID    string
    51  	}{}
    52  
    53  	err = Unmarshal(bsonOut, &rtval)
    54  	noerr(t, err)
    55  	if !cmp.Equal(val, rtval) {
    56  		t.Errorf("Did not round trip properly. got %v; want %v", val, rtval)
    57  	}
    58  	if !rtval.Value.IsZero() {
    59  		t.Errorf("Did not get zero time as expected.")
    60  	}
    61  }
    62  
    63  func TestNonNullTimeRoundTrip(t *testing.T) {
    64  	now := time.Now()
    65  	now = time.Unix(now.Unix(), 0)
    66  	val := struct {
    67  		Value time.Time
    68  		ID    string
    69  	}{
    70  		ID:    "time-rt-test",
    71  		Value: now,
    72  	}
    73  
    74  	bsonOut, err := Marshal(val)
    75  	noerr(t, err)
    76  	rtval := struct {
    77  		Value time.Time
    78  		ID    string
    79  	}{}
    80  
    81  	err = Unmarshal(bsonOut, &rtval)
    82  	noerr(t, err)
    83  	if !cmp.Equal(val, rtval) {
    84  		t.Errorf("Did not round trip properly. got %v; want %v", val, rtval)
    85  	}
    86  }
    87  
    88  func TestD(t *testing.T) {
    89  	t.Run("can marshal", func(t *testing.T) {
    90  		d := D{{"foo", "bar"}, {"hello", "world"}, {"pi", 3.14159}}
    91  		idx, want := bsoncore.AppendDocumentStart(nil)
    92  		want = bsoncore.AppendStringElement(want, "foo", "bar")
    93  		want = bsoncore.AppendStringElement(want, "hello", "world")
    94  		want = bsoncore.AppendDoubleElement(want, "pi", 3.14159)
    95  		want, err := bsoncore.AppendDocumentEnd(want, idx)
    96  		noerr(t, err)
    97  		got, err := Marshal(d)
    98  		noerr(t, err)
    99  		if !bytes.Equal(got, want) {
   100  			t.Errorf("Marshaled documents do not match. got %v; want %v", Raw(got), Raw(want))
   101  		}
   102  	})
   103  	t.Run("can unmarshal", func(t *testing.T) {
   104  		want := D{{"foo", "bar"}, {"hello", "world"}, {"pi", 3.14159}}
   105  		idx, doc := bsoncore.AppendDocumentStart(nil)
   106  		doc = bsoncore.AppendStringElement(doc, "foo", "bar")
   107  		doc = bsoncore.AppendStringElement(doc, "hello", "world")
   108  		doc = bsoncore.AppendDoubleElement(doc, "pi", 3.14159)
   109  		doc, err := bsoncore.AppendDocumentEnd(doc, idx)
   110  		noerr(t, err)
   111  		var got D
   112  		err = Unmarshal(doc, &got)
   113  		noerr(t, err)
   114  		if !cmp.Equal(got, want) {
   115  			t.Errorf("Unmarshaled documents do not match. got %v; want %v", got, want)
   116  		}
   117  	})
   118  }
   119  
   120  type stringerString string
   121  
   122  func (ss stringerString) String() string {
   123  	return "bar"
   124  }
   125  
   126  type keyBool bool
   127  
   128  func (kb keyBool) MarshalKey() (string, error) {
   129  	return fmt.Sprintf("%v", kb), nil
   130  }
   131  
   132  func (kb *keyBool) UnmarshalKey(key string) error {
   133  	switch key {
   134  	case "true":
   135  		*kb = true
   136  	case "false":
   137  		*kb = false
   138  	default:
   139  		return fmt.Errorf("invalid bool value %v", key)
   140  	}
   141  	return nil
   142  }
   143  
   144  type keyStruct struct {
   145  	val int64
   146  }
   147  
   148  func (k keyStruct) MarshalText() (text []byte, err error) {
   149  	str := strconv.FormatInt(k.val, 10)
   150  
   151  	return []byte(str), nil
   152  }
   153  
   154  func (k *keyStruct) UnmarshalText(text []byte) error {
   155  	val, err := strconv.ParseInt(string(text), 10, 64)
   156  	if err != nil {
   157  		return err
   158  	}
   159  
   160  	*k = keyStruct{
   161  		val: val,
   162  	}
   163  
   164  	return nil
   165  }
   166  
   167  func TestMapCodec(t *testing.T) {
   168  	t.Run("EncodeKeysWithStringer", func(t *testing.T) {
   169  		strstr := stringerString("foo")
   170  		mapObj := map[stringerString]int{strstr: 1}
   171  		testCases := []struct {
   172  			name string
   173  			opts *bsonoptions.MapCodecOptions
   174  			key  string
   175  		}{
   176  			{"default", bsonoptions.MapCodec(), "foo"},
   177  			{"true", bsonoptions.MapCodec().SetEncodeKeysWithStringer(true), "bar"},
   178  			{"false", bsonoptions.MapCodec().SetEncodeKeysWithStringer(false), "foo"},
   179  		}
   180  		for _, tc := range testCases {
   181  			t.Run(tc.name, func(t *testing.T) {
   182  				mapCodec := bsoncodec.NewMapCodec(tc.opts)
   183  				mapRegistry := NewRegistryBuilder().RegisterDefaultEncoder(reflect.Map, mapCodec).Build()
   184  				val, err := MarshalWithRegistry(mapRegistry, mapObj)
   185  				assert.Nil(t, err, "Marshal error: %v", err)
   186  				assert.True(t, strings.Contains(string(val), tc.key), "expected result to contain %v, got: %v", tc.key, string(val))
   187  			})
   188  		}
   189  	})
   190  
   191  	t.Run("keys implements keyMarshaler and keyUnmarshaler", func(t *testing.T) {
   192  		mapObj := map[keyBool]int{keyBool(true): 1}
   193  
   194  		doc, err := Marshal(mapObj)
   195  		assert.Nil(t, err, "Marshal error: %v", err)
   196  		idx, want := bsoncore.AppendDocumentStart(nil)
   197  		want = bsoncore.AppendInt32Element(want, "true", 1)
   198  		want, _ = bsoncore.AppendDocumentEnd(want, idx)
   199  		assert.Equal(t, want, doc, "expected result %v, got %v", string(want), string(doc))
   200  
   201  		var got map[keyBool]int
   202  		err = Unmarshal(doc, &got)
   203  		assert.Nil(t, err, "Unmarshal error: %v", err)
   204  		assert.Equal(t, mapObj, got, "expected result %v, got %v", mapObj, got)
   205  
   206  	})
   207  
   208  	t.Run("keys implements encoding.TextMarshaler and encoding.TextUnmarshaler", func(t *testing.T) {
   209  		mapObj := map[keyStruct]int{
   210  			{val: 10}: 100,
   211  		}
   212  
   213  		doc, err := Marshal(mapObj)
   214  		assert.Nil(t, err, "Marshal error: %v", err)
   215  		idx, want := bsoncore.AppendDocumentStart(nil)
   216  		want = bsoncore.AppendInt32Element(want, "10", 100)
   217  		want, _ = bsoncore.AppendDocumentEnd(want, idx)
   218  		assert.Equal(t, want, doc, "expected result %v, got %v", string(want), string(doc))
   219  
   220  		var got map[keyStruct]int
   221  		err = Unmarshal(doc, &got)
   222  		assert.Nil(t, err, "Unmarshal error: %v", err)
   223  		assert.Equal(t, mapObj, got, "expected result %v, got %v", mapObj, got)
   224  
   225  	})
   226  }
   227  
   228  func TestExtJSONEscapeKey(t *testing.T) {
   229  	doc := D{{Key: "\\usb#", Value: int32(1)}}
   230  	b, err := MarshalExtJSON(&doc, false, false)
   231  	noerr(t, err)
   232  
   233  	want := "{\"\\\\usb#\":1}"
   234  	if diff := cmp.Diff(want, string(b)); diff != "" {
   235  		t.Errorf("Marshaled documents do not match. got %v, want %v", string(b), want)
   236  	}
   237  
   238  	var got D
   239  	err = UnmarshalExtJSON(b, false, &got)
   240  	noerr(t, err)
   241  	if !cmp.Equal(got, doc) {
   242  		t.Errorf("Unmarshaled documents do not match. got %v; want %v", got, doc)
   243  	}
   244  }
   245  
   246  func TestBsoncoreArray(t *testing.T) {
   247  	type BSONDocumentArray struct {
   248  		Array []D `bson:"array"`
   249  	}
   250  
   251  	type BSONArray struct {
   252  		Array bsoncore.Array `bson:"array"`
   253  	}
   254  
   255  	bda := BSONDocumentArray{
   256  		Array: []D{
   257  			{{"x", 1}},
   258  			{{"x", 2}},
   259  			{{"x", 3}},
   260  		},
   261  	}
   262  
   263  	expectedBSON, err := Marshal(bda)
   264  	assert.Nil(t, err, "Marshal bsoncore.Document array error: %v", err)
   265  
   266  	var ba BSONArray
   267  	err = Unmarshal(expectedBSON, &ba)
   268  	assert.Nil(t, err, "Unmarshal error: %v", err)
   269  
   270  	actualBSON, err := Marshal(ba)
   271  	assert.Nil(t, err, "Marshal bsoncore.Array error: %v", err)
   272  
   273  	assert.Equal(t, expectedBSON, actualBSON,
   274  		"expected BSON to be %v after Marshalling again; got %v", expectedBSON, actualBSON)
   275  
   276  	doc := bsoncore.Document(actualBSON)
   277  	v := doc.Lookup("array")
   278  	assert.Equal(t, bsontype.Array, v.Type, "expected type array, got %v", v.Type)
   279  }
   280  

View as plain text