...

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

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

     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 bsonrw
     8  
     9  import (
    10  	"bytes"
    11  	"errors"
    12  	"fmt"
    13  	"io"
    14  	"math"
    15  	"testing"
    16  
    17  	"github.com/google/go-cmp/cmp"
    18  	"go.mongodb.org/mongo-driver/bson/bsontype"
    19  	"go.mongodb.org/mongo-driver/bson/primitive"
    20  	"go.mongodb.org/mongo-driver/x/bsonx/bsoncore"
    21  )
    22  
    23  func TestValueReader(t *testing.T) {
    24  	t.Run("ReadBinary", func(t *testing.T) {
    25  		testCases := []struct {
    26  			name   string
    27  			data   []byte
    28  			offset int64
    29  			btype  byte
    30  			b      []byte
    31  			err    error
    32  			vType  bsontype.Type
    33  		}{
    34  			{
    35  				"incorrect type",
    36  				[]byte{},
    37  				0,
    38  				0,
    39  				nil,
    40  				(&valueReader{stack: []vrState{{vType: bsontype.EmbeddedDocument}}, frame: 0}).typeError(bsontype.Binary),
    41  				bsontype.EmbeddedDocument,
    42  			},
    43  			{
    44  				"length too short",
    45  				[]byte{},
    46  				0,
    47  				0,
    48  				nil,
    49  				io.EOF,
    50  				bsontype.Binary,
    51  			},
    52  			{
    53  				"no byte available",
    54  				[]byte{0x00, 0x00, 0x00, 0x00},
    55  				0,
    56  				0,
    57  				nil,
    58  				io.EOF,
    59  				bsontype.Binary,
    60  			},
    61  			{
    62  				"not enough bytes for binary",
    63  				[]byte{0x05, 0x00, 0x00, 0x00, 0x00},
    64  				0,
    65  				0,
    66  				nil,
    67  				io.EOF,
    68  				bsontype.Binary,
    69  			},
    70  			{
    71  				"success",
    72  				[]byte{0x03, 0x00, 0x00, 0x00, 0xEA, 0x01, 0x02, 0x03},
    73  				0,
    74  				0xEA,
    75  				[]byte{0x01, 0x02, 0x03},
    76  				nil,
    77  				bsontype.Binary,
    78  			},
    79  		}
    80  
    81  		for _, tc := range testCases {
    82  			t.Run(tc.name, func(t *testing.T) {
    83  				vr := &valueReader{
    84  					offset: tc.offset,
    85  					d:      tc.data,
    86  					stack: []vrState{
    87  						{mode: mTopLevel},
    88  						{
    89  							mode:  mElement,
    90  							vType: tc.vType,
    91  						},
    92  					},
    93  					frame: 1,
    94  				}
    95  
    96  				b, btype, err := vr.ReadBinary()
    97  				if !errequal(t, err, tc.err) {
    98  					t.Errorf("Returned errors do not match. got %v; want %v", err, tc.err)
    99  				}
   100  				if btype != tc.btype {
   101  					t.Errorf("Incorrect binary type returned. got %v; want %v", btype, tc.btype)
   102  				}
   103  				if !bytes.Equal(b, tc.b) {
   104  					t.Errorf("Binary data does not match. got %v; want %v", b, tc.b)
   105  				}
   106  			})
   107  		}
   108  	})
   109  	t.Run("ReadBoolean", func(t *testing.T) {
   110  		testCases := []struct {
   111  			name    string
   112  			data    []byte
   113  			offset  int64
   114  			boolean bool
   115  			err     error
   116  			vType   bsontype.Type
   117  		}{
   118  			{
   119  				"incorrect type",
   120  				[]byte{},
   121  				0,
   122  				false,
   123  				(&valueReader{stack: []vrState{{vType: bsontype.EmbeddedDocument}}, frame: 0}).typeError(bsontype.Boolean),
   124  				bsontype.EmbeddedDocument,
   125  			},
   126  			{
   127  				"no byte available",
   128  				[]byte{},
   129  				0,
   130  				false,
   131  				io.EOF,
   132  				bsontype.Boolean,
   133  			},
   134  			{
   135  				"invalid byte for boolean",
   136  				[]byte{0x03},
   137  				0,
   138  				false,
   139  				fmt.Errorf("invalid byte for boolean, %b", 0x03),
   140  				bsontype.Boolean,
   141  			},
   142  			{
   143  				"success",
   144  				[]byte{0x01},
   145  				0,
   146  				true,
   147  				nil,
   148  				bsontype.Boolean,
   149  			},
   150  		}
   151  
   152  		for _, tc := range testCases {
   153  			t.Run(tc.name, func(t *testing.T) {
   154  				vr := &valueReader{
   155  					offset: tc.offset,
   156  					d:      tc.data,
   157  					stack: []vrState{
   158  						{mode: mTopLevel},
   159  						{
   160  							mode:  mElement,
   161  							vType: tc.vType,
   162  						},
   163  					},
   164  					frame: 1,
   165  				}
   166  
   167  				boolean, err := vr.ReadBoolean()
   168  				if !errequal(t, err, tc.err) {
   169  					t.Errorf("Returned errors do not match. got %v; want %v", err, tc.err)
   170  				}
   171  				if boolean != tc.boolean {
   172  					t.Errorf("Incorrect boolean returned. got %v; want %v", boolean, tc.boolean)
   173  				}
   174  			})
   175  		}
   176  	})
   177  	t.Run("ReadDocument", func(t *testing.T) {
   178  		t.Run("TopLevel", func(t *testing.T) {
   179  			doc := []byte{0x05, 0x00, 0x00, 0x00, 0x00}
   180  			vr := &valueReader{
   181  				offset: 0,
   182  				stack:  []vrState{{mode: mTopLevel}},
   183  				frame:  0,
   184  			}
   185  
   186  			// invalid length
   187  			vr.d = []byte{0x00, 0x00}
   188  			_, err := vr.ReadDocument()
   189  			if !errors.Is(err, io.EOF) {
   190  				t.Errorf("Expected io.EOF with document length too small. got %v; want %v", err, io.EOF)
   191  			}
   192  
   193  			vr.d = doc
   194  			_, err = vr.ReadDocument()
   195  			noerr(t, err)
   196  			if vr.stack[vr.frame].end != 5 {
   197  				t.Errorf("Incorrect end for document. got %d; want %d", vr.stack[vr.frame].end, 5)
   198  			}
   199  		})
   200  		t.Run("EmbeddedDocument", func(t *testing.T) {
   201  			vr := &valueReader{
   202  				offset: 0,
   203  				stack: []vrState{
   204  					{mode: mTopLevel},
   205  					{mode: mElement, vType: bsontype.Boolean},
   206  				},
   207  				frame: 1,
   208  			}
   209  
   210  			var wanterr = (&valueReader{stack: []vrState{{mode: mElement, vType: bsontype.Boolean}}}).typeError(bsontype.EmbeddedDocument)
   211  			_, err := vr.ReadDocument()
   212  			if err == nil || err.Error() != wanterr.Error() {
   213  				t.Errorf("Incorrect returned error. got %v; want %v", err, wanterr)
   214  			}
   215  
   216  			vr.stack[1].mode = mArray
   217  			wanterr = vr.invalidTransitionErr(mDocument, "ReadDocument", []mode{mTopLevel, mElement, mValue})
   218  			_, err = vr.ReadDocument()
   219  			if err == nil || err.Error() != wanterr.Error() {
   220  				t.Errorf("Incorrect returned error. got %v; want %v", err, wanterr)
   221  			}
   222  
   223  			vr.stack[1].mode, vr.stack[1].vType = mElement, bsontype.EmbeddedDocument
   224  			vr.d = []byte{0x0A, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00}
   225  			vr.offset = 4
   226  			_, err = vr.ReadDocument()
   227  			noerr(t, err)
   228  			if len(vr.stack) != 3 {
   229  				t.Errorf("Incorrect number of stack frames. got %d; want %d", len(vr.stack), 3)
   230  			}
   231  			if vr.stack[2].mode != mDocument {
   232  				t.Errorf("Incorrect mode set. got %v; want %v", vr.stack[2].mode, mDocument)
   233  			}
   234  			if vr.stack[2].end != 9 {
   235  				t.Errorf("End of embedded document is not correct. got %d; want %d", vr.stack[2].end, 9)
   236  			}
   237  			if vr.offset != 8 {
   238  				t.Errorf("Offset not incremented correctly. got %d; want %d", vr.offset, 8)
   239  			}
   240  
   241  			vr.frame--
   242  			_, err = vr.ReadDocument()
   243  			if !errors.Is(err, io.EOF) {
   244  				t.Errorf("Should return error when attempting to read length with not enough bytes. got %v; want %v", err, io.EOF)
   245  			}
   246  		})
   247  	})
   248  	t.Run("ReadBinary", func(t *testing.T) {
   249  		codeWithScope := []byte{
   250  			0x11, 0x00, 0x00, 0x00, // total length
   251  			0x4, 0x00, 0x00, 0x00, // string length
   252  			'f', 'o', 'o', 0x00, // string
   253  			0x05, 0x00, 0x00, 0x00, 0x00, // document
   254  		}
   255  		mismatchCodeWithScope := []byte{
   256  			0x11, 0x00, 0x00, 0x00, // total length
   257  			0x4, 0x00, 0x00, 0x00, // string length
   258  			'f', 'o', 'o', 0x00, // string
   259  			0x07, 0x00, 0x00, 0x00, // document
   260  			0x0A, 0x00, // null element, empty key
   261  			0x00, // document end
   262  		}
   263  		invalidCodeWithScope := []byte{
   264  			0x7, 0x00, 0x00, 0x00, // total length
   265  			0x0, 0x00, 0x00, 0x00, // string length = 0
   266  			0x05, 0x00, 0x00, 0x00, 0x00, // document
   267  		}
   268  		testCases := []struct {
   269  			name   string
   270  			data   []byte
   271  			offset int64
   272  			err    error
   273  			vType  bsontype.Type
   274  		}{
   275  			{
   276  				"incorrect type",
   277  				[]byte{},
   278  				0,
   279  				(&valueReader{stack: []vrState{{vType: bsontype.EmbeddedDocument}}, frame: 0}).typeError(bsontype.CodeWithScope),
   280  				bsontype.EmbeddedDocument,
   281  			},
   282  			{
   283  				"total length not enough bytes",
   284  				[]byte{},
   285  				0,
   286  				io.EOF,
   287  				bsontype.CodeWithScope,
   288  			},
   289  			{
   290  				"string length not enough bytes",
   291  				codeWithScope[:4],
   292  				0,
   293  				io.EOF,
   294  				bsontype.CodeWithScope,
   295  			},
   296  			{
   297  				"not enough string bytes",
   298  				codeWithScope[:8],
   299  				0,
   300  				io.EOF,
   301  				bsontype.CodeWithScope,
   302  			},
   303  			{
   304  				"document length not enough bytes",
   305  				codeWithScope[:12],
   306  				0,
   307  				io.EOF,
   308  				bsontype.CodeWithScope,
   309  			},
   310  			{
   311  				"length mismatch",
   312  				mismatchCodeWithScope,
   313  				0,
   314  				fmt.Errorf("length of CodeWithScope does not match lengths of components; total: %d; components: %d", 17, 19),
   315  				bsontype.CodeWithScope,
   316  			},
   317  			{
   318  				"invalid strLength",
   319  				invalidCodeWithScope,
   320  				0,
   321  				fmt.Errorf("invalid string length: %d", 0),
   322  				bsontype.CodeWithScope,
   323  			},
   324  		}
   325  
   326  		for _, tc := range testCases {
   327  			t.Run(tc.name, func(t *testing.T) {
   328  				vr := &valueReader{
   329  					offset: tc.offset,
   330  					d:      tc.data,
   331  					stack: []vrState{
   332  						{mode: mTopLevel},
   333  						{
   334  							mode:  mElement,
   335  							vType: tc.vType,
   336  						},
   337  					},
   338  					frame: 1,
   339  				}
   340  
   341  				_, _, err := vr.ReadCodeWithScope()
   342  				if !errequal(t, err, tc.err) {
   343  					t.Errorf("Returned errors do not match. got %v; want %v", err, tc.err)
   344  				}
   345  			})
   346  		}
   347  
   348  		t.Run("success", func(t *testing.T) {
   349  			doc := []byte{0x00, 0x00, 0x00, 0x00}
   350  			doc = append(doc, codeWithScope...)
   351  			doc = append(doc, 0x00)
   352  			vr := &valueReader{
   353  				offset: 4,
   354  				d:      doc,
   355  				stack: []vrState{
   356  					{mode: mTopLevel},
   357  					{mode: mElement, vType: bsontype.CodeWithScope},
   358  				},
   359  				frame: 1,
   360  			}
   361  
   362  			code, _, err := vr.ReadCodeWithScope()
   363  			noerr(t, err)
   364  			if code != "foo" {
   365  				t.Errorf("Code does not match. got %s; want %s", code, "foo")
   366  			}
   367  			if len(vr.stack) != 3 {
   368  				t.Errorf("Incorrect number of stack frames. got %d; want %d", len(vr.stack), 3)
   369  			}
   370  			if vr.stack[2].mode != mCodeWithScope {
   371  				t.Errorf("Incorrect mode set. got %v; want %v", vr.stack[2].mode, mDocument)
   372  			}
   373  			if vr.stack[2].end != 21 {
   374  				t.Errorf("End of scope is not correct. got %d; want %d", vr.stack[2].end, 21)
   375  			}
   376  			if vr.offset != 20 {
   377  				t.Errorf("Offset not incremented correctly. got %d; want %d", vr.offset, 20)
   378  			}
   379  		})
   380  	})
   381  	t.Run("ReadDBPointer", func(t *testing.T) {
   382  		testCases := []struct {
   383  			name   string
   384  			data   []byte
   385  			offset int64
   386  			ns     string
   387  			oid    primitive.ObjectID
   388  			err    error
   389  			vType  bsontype.Type
   390  		}{
   391  			{
   392  				"incorrect type",
   393  				[]byte{},
   394  				0,
   395  				"",
   396  				primitive.ObjectID{},
   397  				(&valueReader{stack: []vrState{{vType: bsontype.EmbeddedDocument}}, frame: 0}).typeError(bsontype.DBPointer),
   398  				bsontype.EmbeddedDocument,
   399  			},
   400  			{
   401  				"length too short",
   402  				[]byte{},
   403  				0,
   404  				"",
   405  				primitive.ObjectID{},
   406  				io.EOF,
   407  				bsontype.DBPointer,
   408  			},
   409  			{
   410  				"not enough bytes for namespace",
   411  				[]byte{0x04, 0x00, 0x00, 0x00},
   412  				0,
   413  				"",
   414  				primitive.ObjectID{},
   415  				io.EOF,
   416  				bsontype.DBPointer,
   417  			},
   418  			{
   419  				"not enough bytes for objectID",
   420  				[]byte{0x04, 0x00, 0x00, 0x00, 'f', 'o', 'o', 0x00},
   421  				0,
   422  				"",
   423  				primitive.ObjectID{},
   424  				io.EOF,
   425  				bsontype.DBPointer,
   426  			},
   427  			{
   428  				"success",
   429  				[]byte{
   430  					0x04, 0x00, 0x00, 0x00, 'f', 'o', 'o', 0x00,
   431  					0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C,
   432  				},
   433  				0,
   434  				"foo",
   435  				primitive.ObjectID{0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C},
   436  				nil,
   437  				bsontype.DBPointer,
   438  			},
   439  		}
   440  
   441  		for _, tc := range testCases {
   442  			t.Run(tc.name, func(t *testing.T) {
   443  				vr := &valueReader{
   444  					offset: tc.offset,
   445  					d:      tc.data,
   446  					stack: []vrState{
   447  						{mode: mTopLevel},
   448  						{
   449  							mode:  mElement,
   450  							vType: tc.vType,
   451  						},
   452  					},
   453  					frame: 1,
   454  				}
   455  
   456  				ns, oid, err := vr.ReadDBPointer()
   457  				if !errequal(t, err, tc.err) {
   458  					t.Errorf("Returned errors do not match. got %v; want %v", err, tc.err)
   459  				}
   460  				if ns != tc.ns {
   461  					t.Errorf("Incorrect namespace returned. got %v; want %v", ns, tc.ns)
   462  				}
   463  				if oid != tc.oid {
   464  					t.Errorf("ObjectIDs did not match. got %v; want %v", oid, tc.oid)
   465  				}
   466  			})
   467  		}
   468  	})
   469  	t.Run("ReadDateTime", func(t *testing.T) {
   470  		testCases := []struct {
   471  			name   string
   472  			data   []byte
   473  			offset int64
   474  			dt     int64
   475  			err    error
   476  			vType  bsontype.Type
   477  		}{
   478  			{
   479  				"incorrect type",
   480  				[]byte{},
   481  				0,
   482  				0,
   483  				(&valueReader{stack: []vrState{{vType: bsontype.EmbeddedDocument}}, frame: 0}).typeError(bsontype.DateTime),
   484  				bsontype.EmbeddedDocument,
   485  			},
   486  			{
   487  				"length too short",
   488  				[]byte{},
   489  				0,
   490  				0,
   491  				io.EOF,
   492  				bsontype.DateTime,
   493  			},
   494  			{
   495  				"success",
   496  				[]byte{0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
   497  				0,
   498  				255,
   499  				nil,
   500  				bsontype.DateTime,
   501  			},
   502  		}
   503  
   504  		for _, tc := range testCases {
   505  			t.Run(tc.name, func(t *testing.T) {
   506  				vr := &valueReader{
   507  					offset: tc.offset,
   508  					d:      tc.data,
   509  					stack: []vrState{
   510  						{mode: mTopLevel},
   511  						{
   512  							mode:  mElement,
   513  							vType: tc.vType,
   514  						},
   515  					},
   516  					frame: 1,
   517  				}
   518  
   519  				dt, err := vr.ReadDateTime()
   520  				if !errequal(t, err, tc.err) {
   521  					t.Errorf("Returned errors do not match. got %v; want %v", err, tc.err)
   522  				}
   523  				if dt != tc.dt {
   524  					t.Errorf("Incorrect datetime returned. got %d; want %d", dt, tc.dt)
   525  				}
   526  			})
   527  		}
   528  	})
   529  	t.Run("ReadDecimal128", func(t *testing.T) {
   530  		testCases := []struct {
   531  			name   string
   532  			data   []byte
   533  			offset int64
   534  			dc128  primitive.Decimal128
   535  			err    error
   536  			vType  bsontype.Type
   537  		}{
   538  			{
   539  				"incorrect type",
   540  				[]byte{},
   541  				0,
   542  				primitive.Decimal128{},
   543  				(&valueReader{stack: []vrState{{vType: bsontype.EmbeddedDocument}}, frame: 0}).typeError(bsontype.Decimal128),
   544  				bsontype.EmbeddedDocument,
   545  			},
   546  			{
   547  				"length too short",
   548  				[]byte{},
   549  				0,
   550  				primitive.Decimal128{},
   551  				io.EOF,
   552  				bsontype.Decimal128,
   553  			},
   554  			{
   555  				"success",
   556  				[]byte{
   557  					0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Low
   558  					0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // High
   559  				},
   560  				0,
   561  				primitive.NewDecimal128(65280, 255),
   562  				nil,
   563  				bsontype.Decimal128,
   564  			},
   565  		}
   566  
   567  		for _, tc := range testCases {
   568  			t.Run(tc.name, func(t *testing.T) {
   569  				vr := &valueReader{
   570  					offset: tc.offset,
   571  					d:      tc.data,
   572  					stack: []vrState{
   573  						{mode: mTopLevel},
   574  						{
   575  							mode:  mElement,
   576  							vType: tc.vType,
   577  						},
   578  					},
   579  					frame: 1,
   580  				}
   581  
   582  				dc128, err := vr.ReadDecimal128()
   583  				if !errequal(t, err, tc.err) {
   584  					t.Errorf("Returned errors do not match. got %v; want %v", err, tc.err)
   585  				}
   586  				gotHigh, gotLow := dc128.GetBytes()
   587  				wantHigh, wantLow := tc.dc128.GetBytes()
   588  				if gotHigh != wantHigh {
   589  					t.Errorf("Retuired high byte does not match. got %d; want %d", gotHigh, wantHigh)
   590  				}
   591  				if gotLow != wantLow {
   592  					t.Errorf("Returned low byte does not match. got %d; want %d", gotLow, wantLow)
   593  				}
   594  			})
   595  		}
   596  	})
   597  	t.Run("ReadDouble", func(t *testing.T) {
   598  		testCases := []struct {
   599  			name   string
   600  			data   []byte
   601  			offset int64
   602  			double float64
   603  			err    error
   604  			vType  bsontype.Type
   605  		}{
   606  			{
   607  				"incorrect type",
   608  				[]byte{},
   609  				0,
   610  				0,
   611  				(&valueReader{stack: []vrState{{vType: bsontype.EmbeddedDocument}}, frame: 0}).typeError(bsontype.Double),
   612  				bsontype.EmbeddedDocument,
   613  			},
   614  			{
   615  				"length too short",
   616  				[]byte{},
   617  				0,
   618  				0,
   619  				io.EOF,
   620  				bsontype.Double,
   621  			},
   622  			{
   623  				"success",
   624  				[]byte{0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
   625  				0,
   626  				math.Float64frombits(255),
   627  				nil,
   628  				bsontype.Double,
   629  			},
   630  		}
   631  
   632  		for _, tc := range testCases {
   633  			t.Run(tc.name, func(t *testing.T) {
   634  				vr := &valueReader{
   635  					offset: tc.offset,
   636  					d:      tc.data,
   637  					stack: []vrState{
   638  						{mode: mTopLevel},
   639  						{
   640  							mode:  mElement,
   641  							vType: tc.vType,
   642  						},
   643  					},
   644  					frame: 1,
   645  				}
   646  
   647  				double, err := vr.ReadDouble()
   648  				if !errequal(t, err, tc.err) {
   649  					t.Errorf("Returned errors do not match. got %v; want %v", err, tc.err)
   650  				}
   651  				if double != tc.double {
   652  					t.Errorf("Incorrect double returned. got %f; want %f", double, tc.double)
   653  				}
   654  			})
   655  		}
   656  	})
   657  	t.Run("ReadInt32", func(t *testing.T) {
   658  		testCases := []struct {
   659  			name   string
   660  			data   []byte
   661  			offset int64
   662  			i32    int32
   663  			err    error
   664  			vType  bsontype.Type
   665  		}{
   666  			{
   667  				"incorrect type",
   668  				[]byte{},
   669  				0,
   670  				0,
   671  				(&valueReader{stack: []vrState{{vType: bsontype.EmbeddedDocument}}, frame: 0}).typeError(bsontype.Int32),
   672  				bsontype.EmbeddedDocument,
   673  			},
   674  			{
   675  				"length too short",
   676  				[]byte{},
   677  				0,
   678  				0,
   679  				io.EOF,
   680  				bsontype.Int32,
   681  			},
   682  			{
   683  				"success",
   684  				[]byte{0xFF, 0x00, 0x00, 0x00},
   685  				0,
   686  				255,
   687  				nil,
   688  				bsontype.Int32,
   689  			},
   690  		}
   691  
   692  		for _, tc := range testCases {
   693  			t.Run(tc.name, func(t *testing.T) {
   694  				vr := &valueReader{
   695  					offset: tc.offset,
   696  					d:      tc.data,
   697  					stack: []vrState{
   698  						{mode: mTopLevel},
   699  						{
   700  							mode:  mElement,
   701  							vType: tc.vType,
   702  						},
   703  					},
   704  					frame: 1,
   705  				}
   706  
   707  				i32, err := vr.ReadInt32()
   708  				if !errequal(t, err, tc.err) {
   709  					t.Errorf("Returned errors do not match. got %v; want %v", err, tc.err)
   710  				}
   711  				if i32 != tc.i32 {
   712  					t.Errorf("Incorrect int32 returned. got %d; want %d", i32, tc.i32)
   713  				}
   714  			})
   715  		}
   716  	})
   717  	t.Run("ReadInt32", func(t *testing.T) {
   718  		testCases := []struct {
   719  			name   string
   720  			data   []byte
   721  			offset int64
   722  			i64    int64
   723  			err    error
   724  			vType  bsontype.Type
   725  		}{
   726  			{
   727  				"incorrect type",
   728  				[]byte{},
   729  				0,
   730  				0,
   731  				(&valueReader{stack: []vrState{{vType: bsontype.EmbeddedDocument}}, frame: 0}).typeError(bsontype.Int64),
   732  				bsontype.EmbeddedDocument,
   733  			},
   734  			{
   735  				"length too short",
   736  				[]byte{},
   737  				0,
   738  				0,
   739  				io.EOF,
   740  				bsontype.Int64,
   741  			},
   742  			{
   743  				"success",
   744  				[]byte{0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
   745  				0,
   746  				255,
   747  				nil,
   748  				bsontype.Int64,
   749  			},
   750  		}
   751  
   752  		for _, tc := range testCases {
   753  			t.Run(tc.name, func(t *testing.T) {
   754  				vr := &valueReader{
   755  					offset: tc.offset,
   756  					d:      tc.data,
   757  					stack: []vrState{
   758  						{mode: mTopLevel},
   759  						{
   760  							mode:  mElement,
   761  							vType: tc.vType,
   762  						},
   763  					},
   764  					frame: 1,
   765  				}
   766  
   767  				i64, err := vr.ReadInt64()
   768  				if !errequal(t, err, tc.err) {
   769  					t.Errorf("Returned errors do not match. got %v; want %v", err, tc.err)
   770  				}
   771  				if i64 != tc.i64 {
   772  					t.Errorf("Incorrect int64 returned. got %d; want %d", i64, tc.i64)
   773  				}
   774  			})
   775  		}
   776  	})
   777  	t.Run("ReadJavascript/ReadString/ReadSymbol", func(t *testing.T) {
   778  		testCases := []struct {
   779  			name   string
   780  			data   []byte
   781  			offset int64
   782  			fn     func(*valueReader) (string, error)
   783  			css    string // code, string, symbol :P
   784  			err    error
   785  			vType  bsontype.Type
   786  		}{
   787  			{
   788  				"ReadJavascript/incorrect type",
   789  				[]byte{},
   790  				0,
   791  				(*valueReader).ReadJavascript,
   792  				"",
   793  				(&valueReader{stack: []vrState{{vType: bsontype.EmbeddedDocument}}, frame: 0}).typeError(bsontype.JavaScript),
   794  				bsontype.EmbeddedDocument,
   795  			},
   796  			{
   797  				"ReadString/incorrect type",
   798  				[]byte{},
   799  				0,
   800  				(*valueReader).ReadString,
   801  				"",
   802  				(&valueReader{stack: []vrState{{vType: bsontype.EmbeddedDocument}}, frame: 0}).typeError(bsontype.String),
   803  				bsontype.EmbeddedDocument,
   804  			},
   805  			{
   806  				"ReadSymbol/incorrect type",
   807  				[]byte{},
   808  				0,
   809  				(*valueReader).ReadSymbol,
   810  				"",
   811  				(&valueReader{stack: []vrState{{vType: bsontype.EmbeddedDocument}}, frame: 0}).typeError(bsontype.Symbol),
   812  				bsontype.EmbeddedDocument,
   813  			},
   814  			{
   815  				"ReadJavascript/length too short",
   816  				[]byte{},
   817  				0,
   818  				(*valueReader).ReadJavascript,
   819  				"",
   820  				io.EOF,
   821  				bsontype.JavaScript,
   822  			},
   823  			{
   824  				"ReadString/length too short",
   825  				[]byte{},
   826  				0,
   827  				(*valueReader).ReadString,
   828  				"",
   829  				io.EOF,
   830  				bsontype.String,
   831  			},
   832  			{
   833  				"ReadSymbol/length too short",
   834  				[]byte{},
   835  				0,
   836  				(*valueReader).ReadSymbol,
   837  				"",
   838  				io.EOF,
   839  				bsontype.Symbol,
   840  			},
   841  			{
   842  				"ReadJavascript/incorrect end byte",
   843  				[]byte{0x01, 0x00, 0x00, 0x00, 0x05},
   844  				0,
   845  				(*valueReader).ReadJavascript,
   846  				"",
   847  				fmt.Errorf("string does not end with null byte, but with %v", 0x05),
   848  				bsontype.JavaScript,
   849  			},
   850  			{
   851  				"ReadString/incorrect end byte",
   852  				[]byte{0x01, 0x00, 0x00, 0x00, 0x05},
   853  				0,
   854  				(*valueReader).ReadString,
   855  				"",
   856  				fmt.Errorf("string does not end with null byte, but with %v", 0x05),
   857  				bsontype.String,
   858  			},
   859  			{
   860  				"ReadSymbol/incorrect end byte",
   861  				[]byte{0x01, 0x00, 0x00, 0x00, 0x05},
   862  				0,
   863  				(*valueReader).ReadSymbol,
   864  				"",
   865  				fmt.Errorf("string does not end with null byte, but with %v", 0x05),
   866  				bsontype.Symbol,
   867  			},
   868  			{
   869  				"ReadJavascript/success",
   870  				[]byte{0x04, 0x00, 0x00, 0x00, 'f', 'o', 'o', 0x00},
   871  				0,
   872  				(*valueReader).ReadJavascript,
   873  				"foo",
   874  				nil,
   875  				bsontype.JavaScript,
   876  			},
   877  			{
   878  				"ReadString/success",
   879  				[]byte{0x04, 0x00, 0x00, 0x00, 'f', 'o', 'o', 0x00},
   880  				0,
   881  				(*valueReader).ReadString,
   882  				"foo",
   883  				nil,
   884  				bsontype.String,
   885  			},
   886  			{
   887  				"ReadSymbol/success",
   888  				[]byte{0x04, 0x00, 0x00, 0x00, 'f', 'o', 'o', 0x00},
   889  				0,
   890  				(*valueReader).ReadSymbol,
   891  				"foo",
   892  				nil,
   893  				bsontype.Symbol,
   894  			},
   895  		}
   896  
   897  		for _, tc := range testCases {
   898  			t.Run(tc.name, func(t *testing.T) {
   899  				vr := &valueReader{
   900  					offset: tc.offset,
   901  					d:      tc.data,
   902  					stack: []vrState{
   903  						{mode: mTopLevel},
   904  						{
   905  							mode:  mElement,
   906  							vType: tc.vType,
   907  						},
   908  					},
   909  					frame: 1,
   910  				}
   911  
   912  				css, err := tc.fn(vr)
   913  				if !errequal(t, err, tc.err) {
   914  					t.Errorf("Returned errors do not match. got %v; want %v", err, tc.err)
   915  				}
   916  				if css != tc.css {
   917  					t.Errorf("Incorrect (JavaScript,String,Symbol) returned. got %s; want %s", css, tc.css)
   918  				}
   919  			})
   920  		}
   921  	})
   922  	t.Run("ReadMaxKey/ReadMinKey/ReadNull/ReadUndefined", func(t *testing.T) {
   923  		testCases := []struct {
   924  			name  string
   925  			fn    func(*valueReader) error
   926  			err   error
   927  			vType bsontype.Type
   928  		}{
   929  			{
   930  				"ReadMaxKey/incorrect type",
   931  				(*valueReader).ReadMaxKey,
   932  				(&valueReader{stack: []vrState{{vType: bsontype.EmbeddedDocument}}, frame: 0}).typeError(bsontype.MaxKey),
   933  				bsontype.EmbeddedDocument,
   934  			},
   935  			{
   936  				"ReadMaxKey/success",
   937  				(*valueReader).ReadMaxKey,
   938  				nil,
   939  				bsontype.MaxKey,
   940  			},
   941  			{
   942  				"ReadMinKey/incorrect type",
   943  				(*valueReader).ReadMinKey,
   944  				(&valueReader{stack: []vrState{{vType: bsontype.EmbeddedDocument}}, frame: 0}).typeError(bsontype.MinKey),
   945  				bsontype.EmbeddedDocument,
   946  			},
   947  			{
   948  				"ReadMinKey/success",
   949  				(*valueReader).ReadMinKey,
   950  				nil,
   951  				bsontype.MinKey,
   952  			},
   953  			{
   954  				"ReadNull/incorrect type",
   955  				(*valueReader).ReadNull,
   956  				(&valueReader{stack: []vrState{{vType: bsontype.EmbeddedDocument}}, frame: 0}).typeError(bsontype.Null),
   957  				bsontype.EmbeddedDocument,
   958  			},
   959  			{
   960  				"ReadNull/success",
   961  				(*valueReader).ReadNull,
   962  				nil,
   963  				bsontype.Null,
   964  			},
   965  			{
   966  				"ReadUndefined/incorrect type",
   967  				(*valueReader).ReadUndefined,
   968  				(&valueReader{stack: []vrState{{vType: bsontype.EmbeddedDocument}}, frame: 0}).typeError(bsontype.Undefined),
   969  				bsontype.EmbeddedDocument,
   970  			},
   971  			{
   972  				"ReadUndefined/success",
   973  				(*valueReader).ReadUndefined,
   974  				nil,
   975  				bsontype.Undefined,
   976  			},
   977  		}
   978  
   979  		for _, tc := range testCases {
   980  			t.Run(tc.name, func(t *testing.T) {
   981  				vr := &valueReader{
   982  					stack: []vrState{
   983  						{mode: mTopLevel},
   984  						{
   985  							mode:  mElement,
   986  							vType: tc.vType,
   987  						},
   988  					},
   989  					frame: 1,
   990  				}
   991  
   992  				err := tc.fn(vr)
   993  				if !errequal(t, err, tc.err) {
   994  					t.Errorf("Returned errors do not match. got %v; want %v", err, tc.err)
   995  				}
   996  			})
   997  		}
   998  	})
   999  	t.Run("ReadObjectID", func(t *testing.T) {
  1000  		testCases := []struct {
  1001  			name   string
  1002  			data   []byte
  1003  			offset int64
  1004  			oid    primitive.ObjectID
  1005  			err    error
  1006  			vType  bsontype.Type
  1007  		}{
  1008  			{
  1009  				"incorrect type",
  1010  				[]byte{},
  1011  				0,
  1012  				primitive.ObjectID{},
  1013  				(&valueReader{stack: []vrState{{vType: bsontype.EmbeddedDocument}}, frame: 0}).typeError(bsontype.ObjectID),
  1014  				bsontype.EmbeddedDocument,
  1015  			},
  1016  			{
  1017  				"not enough bytes for objectID",
  1018  				[]byte{},
  1019  				0,
  1020  				primitive.ObjectID{},
  1021  				io.EOF,
  1022  				bsontype.ObjectID,
  1023  			},
  1024  			{
  1025  				"success",
  1026  				[]byte{0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C},
  1027  				0,
  1028  				primitive.ObjectID{0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C},
  1029  				nil,
  1030  				bsontype.ObjectID,
  1031  			},
  1032  		}
  1033  
  1034  		for _, tc := range testCases {
  1035  			t.Run(tc.name, func(t *testing.T) {
  1036  				vr := &valueReader{
  1037  					offset: tc.offset,
  1038  					d:      tc.data,
  1039  					stack: []vrState{
  1040  						{mode: mTopLevel},
  1041  						{
  1042  							mode:  mElement,
  1043  							vType: tc.vType,
  1044  						},
  1045  					},
  1046  					frame: 1,
  1047  				}
  1048  
  1049  				oid, err := vr.ReadObjectID()
  1050  				if !errequal(t, err, tc.err) {
  1051  					t.Errorf("Returned errors do not match. got %v; want %v", err, tc.err)
  1052  				}
  1053  				if oid != tc.oid {
  1054  					t.Errorf("ObjectIDs did not match. got %v; want %v", oid, tc.oid)
  1055  				}
  1056  			})
  1057  		}
  1058  	})
  1059  	t.Run("ReadRegex", func(t *testing.T) {
  1060  		testCases := []struct {
  1061  			name    string
  1062  			data    []byte
  1063  			offset  int64
  1064  			pattern string
  1065  			options string
  1066  			err     error
  1067  			vType   bsontype.Type
  1068  		}{
  1069  			{
  1070  				"incorrect type",
  1071  				[]byte{},
  1072  				0,
  1073  				"",
  1074  				"",
  1075  				(&valueReader{stack: []vrState{{vType: bsontype.EmbeddedDocument}}, frame: 0}).typeError(bsontype.Regex),
  1076  				bsontype.EmbeddedDocument,
  1077  			},
  1078  			{
  1079  				"length too short",
  1080  				[]byte{},
  1081  				0,
  1082  				"",
  1083  				"",
  1084  				io.EOF,
  1085  				bsontype.Regex,
  1086  			},
  1087  			{
  1088  				"not enough bytes for options",
  1089  				[]byte{'f', 'o', 'o', 0x00},
  1090  				0,
  1091  				"",
  1092  				"",
  1093  				io.EOF,
  1094  				bsontype.Regex,
  1095  			},
  1096  			{
  1097  				"success",
  1098  				[]byte{'f', 'o', 'o', 0x00, 'b', 'a', 'r', 0x00},
  1099  				0,
  1100  				"foo",
  1101  				"bar",
  1102  				nil,
  1103  				bsontype.Regex,
  1104  			},
  1105  		}
  1106  
  1107  		for _, tc := range testCases {
  1108  			t.Run(tc.name, func(t *testing.T) {
  1109  				vr := &valueReader{
  1110  					offset: tc.offset,
  1111  					d:      tc.data,
  1112  					stack: []vrState{
  1113  						{mode: mTopLevel},
  1114  						{
  1115  							mode:  mElement,
  1116  							vType: tc.vType,
  1117  						},
  1118  					},
  1119  					frame: 1,
  1120  				}
  1121  
  1122  				pattern, options, err := vr.ReadRegex()
  1123  				if !errequal(t, err, tc.err) {
  1124  					t.Errorf("Returned errors do not match. got %v; want %v", err, tc.err)
  1125  				}
  1126  				if pattern != tc.pattern {
  1127  					t.Errorf("Incorrect pattern returned. got %s; want %s", pattern, tc.pattern)
  1128  				}
  1129  				if options != tc.options {
  1130  					t.Errorf("Incorrect options returned. got %s; want %s", options, tc.options)
  1131  				}
  1132  			})
  1133  		}
  1134  	})
  1135  	t.Run("ReadTimestamp", func(t *testing.T) {
  1136  		testCases := []struct {
  1137  			name   string
  1138  			data   []byte
  1139  			offset int64
  1140  			ts     uint32
  1141  			incr   uint32
  1142  			err    error
  1143  			vType  bsontype.Type
  1144  		}{
  1145  			{
  1146  				"incorrect type",
  1147  				[]byte{},
  1148  				0,
  1149  				0,
  1150  				0,
  1151  				(&valueReader{stack: []vrState{{vType: bsontype.EmbeddedDocument}}, frame: 0}).typeError(bsontype.Timestamp),
  1152  				bsontype.EmbeddedDocument,
  1153  			},
  1154  			{
  1155  				"not enough bytes for increment",
  1156  				[]byte{},
  1157  				0,
  1158  				0,
  1159  				0,
  1160  				io.EOF,
  1161  				bsontype.Timestamp,
  1162  			},
  1163  			{
  1164  				"not enough bytes for timestamp",
  1165  				[]byte{0x01, 0x02, 0x03, 0x04},
  1166  				0,
  1167  				0,
  1168  				0,
  1169  				io.EOF,
  1170  				bsontype.Timestamp,
  1171  			},
  1172  			{
  1173  				"success",
  1174  				[]byte{0xFF, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00},
  1175  				0,
  1176  				256,
  1177  				255,
  1178  				nil,
  1179  				bsontype.Timestamp,
  1180  			},
  1181  		}
  1182  
  1183  		for _, tc := range testCases {
  1184  			t.Run(tc.name, func(t *testing.T) {
  1185  				vr := &valueReader{
  1186  					offset: tc.offset,
  1187  					d:      tc.data,
  1188  					stack: []vrState{
  1189  						{mode: mTopLevel},
  1190  						{
  1191  							mode:  mElement,
  1192  							vType: tc.vType,
  1193  						},
  1194  					},
  1195  					frame: 1,
  1196  				}
  1197  
  1198  				ts, incr, err := vr.ReadTimestamp()
  1199  				if !errequal(t, err, tc.err) {
  1200  					t.Errorf("Returned errors do not match. got %v; want %v", err, tc.err)
  1201  				}
  1202  				if ts != tc.ts {
  1203  					t.Errorf("Incorrect timestamp returned. got %d; want %d", ts, tc.ts)
  1204  				}
  1205  				if incr != tc.incr {
  1206  					t.Errorf("Incorrect increment returned. got %d; want %d", incr, tc.incr)
  1207  				}
  1208  			})
  1209  		}
  1210  	})
  1211  
  1212  	t.Run("ReadBytes & Skip", func(t *testing.T) {
  1213  		index, docb := bsoncore.ReserveLength(nil)
  1214  		docb = bsoncore.AppendNullElement(docb, "foobar")
  1215  		docb = append(docb, 0x00)
  1216  		docb = bsoncore.UpdateLength(docb, index, int32(len(docb)))
  1217  		cwsbytes := bsoncore.AppendCodeWithScope(nil, "var hellow = world;", docb)
  1218  		strbytes := []byte{0x04, 0x00, 0x00, 0x00, 'f', 'o', 'o', 0x00}
  1219  		testCases := []struct {
  1220  			name           string
  1221  			t              bsontype.Type
  1222  			data           []byte
  1223  			err            error
  1224  			offset         int64
  1225  			startingOffset int64
  1226  		}{
  1227  			{
  1228  				"Array/invalid length",
  1229  				bsontype.Array,
  1230  				[]byte{0x01, 0x02, 0x03},
  1231  				io.EOF, 0, 0,
  1232  			},
  1233  			{
  1234  				"Array/not enough bytes",
  1235  				bsontype.Array,
  1236  				[]byte{0x0F, 0x00, 0x00, 0x00, 0x01, 0x02, 0x03},
  1237  				io.EOF, 0, 0,
  1238  			},
  1239  			{
  1240  				"Array/success",
  1241  				bsontype.Array,
  1242  				[]byte{0x08, 0x00, 0x00, 0x00, 0x0A, '1', 0x00, 0x00},
  1243  				nil, 8, 0,
  1244  			},
  1245  			{
  1246  				"EmbeddedDocument/invalid length",
  1247  				bsontype.EmbeddedDocument,
  1248  				[]byte{0x01, 0x02, 0x03},
  1249  				io.EOF, 0, 0,
  1250  			},
  1251  			{
  1252  				"EmbeddedDocument/not enough bytes",
  1253  				bsontype.EmbeddedDocument,
  1254  				[]byte{0x0F, 0x00, 0x00, 0x00, 0x01, 0x02, 0x03},
  1255  				io.EOF, 0, 0,
  1256  			},
  1257  			{
  1258  				"EmbeddedDocument/success",
  1259  				bsontype.EmbeddedDocument,
  1260  				[]byte{0x08, 0x00, 0x00, 0x00, 0x0A, 'A', 0x00, 0x00},
  1261  				nil, 8, 0,
  1262  			},
  1263  			{
  1264  				"CodeWithScope/invalid length",
  1265  				bsontype.CodeWithScope,
  1266  				[]byte{0x01, 0x02, 0x03},
  1267  				io.EOF, 0, 0,
  1268  			},
  1269  			{
  1270  				"CodeWithScope/not enough bytes",
  1271  				bsontype.CodeWithScope,
  1272  				[]byte{0x0F, 0x00, 0x00, 0x00, 0x01, 0x02, 0x03},
  1273  				io.EOF, 0, 0,
  1274  			},
  1275  			{
  1276  				"CodeWithScope/success",
  1277  				bsontype.CodeWithScope,
  1278  				cwsbytes,
  1279  				nil, 41, 0,
  1280  			},
  1281  			{
  1282  				"Binary/invalid length",
  1283  				bsontype.Binary,
  1284  				[]byte{0x01, 0x02, 0x03},
  1285  				io.EOF, 0, 0,
  1286  			},
  1287  			{
  1288  				"Binary/not enough bytes",
  1289  				bsontype.Binary,
  1290  				[]byte{0x0F, 0x00, 0x00, 0x00, 0x01, 0x02, 0x03},
  1291  				io.EOF, 0, 0,
  1292  			},
  1293  			{
  1294  				"Binary/success",
  1295  				bsontype.Binary,
  1296  				[]byte{0x03, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x03},
  1297  				nil, 8, 0,
  1298  			},
  1299  			{
  1300  				"Boolean/invalid length",
  1301  				bsontype.Boolean,
  1302  				[]byte{},
  1303  				io.EOF, 0, 0,
  1304  			},
  1305  			{
  1306  				"Boolean/success",
  1307  				bsontype.Boolean,
  1308  				[]byte{0x01},
  1309  				nil, 1, 0,
  1310  			},
  1311  			{
  1312  				"DBPointer/invalid length",
  1313  				bsontype.DBPointer,
  1314  				[]byte{0x01, 0x02, 0x03},
  1315  				io.EOF, 0, 0,
  1316  			},
  1317  			{
  1318  				"DBPointer/not enough bytes",
  1319  				bsontype.DBPointer,
  1320  				[]byte{0x0F, 0x00, 0x00, 0x00, 0x01, 0x02, 0x03},
  1321  				io.EOF, 0, 0,
  1322  			},
  1323  			{
  1324  				"DBPointer/success",
  1325  				bsontype.DBPointer,
  1326  				[]byte{0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C},
  1327  				nil, 17, 0,
  1328  			},
  1329  			{"DBPointer/not enough bytes", bsontype.DateTime, []byte{0x01, 0x02, 0x03, 0x04}, io.EOF, 0, 0},
  1330  			{"DBPointer/success", bsontype.DateTime, []byte{0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08}, nil, 8, 0},
  1331  			{"Double/not enough bytes", bsontype.Double, []byte{0x01, 0x02, 0x03, 0x04}, io.EOF, 0, 0},
  1332  			{"Double/success", bsontype.Double, []byte{0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08}, nil, 8, 0},
  1333  			{"Int64/not enough bytes", bsontype.Int64, []byte{0x01, 0x02, 0x03, 0x04}, io.EOF, 0, 0},
  1334  			{"Int64/success", bsontype.Int64, []byte{0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08}, nil, 8, 0},
  1335  			{"Timestamp/not enough bytes", bsontype.Timestamp, []byte{0x01, 0x02, 0x03, 0x04}, io.EOF, 0, 0},
  1336  			{"Timestamp/success", bsontype.Timestamp, []byte{0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08}, nil, 8, 0},
  1337  			{
  1338  				"Decimal128/not enough bytes",
  1339  				bsontype.Decimal128,
  1340  				[]byte{0x01, 0x02, 0x03, 0x04},
  1341  				io.EOF, 0, 0,
  1342  			},
  1343  			{
  1344  				"Decimal128/success",
  1345  				bsontype.Decimal128,
  1346  				[]byte{0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10},
  1347  				nil, 16, 0,
  1348  			},
  1349  			{"Int32/not enough bytes", bsontype.Int32, []byte{0x01, 0x02}, io.EOF, 0, 0},
  1350  			{"Int32/success", bsontype.Int32, []byte{0x01, 0x02, 0x03, 0x04}, nil, 4, 0},
  1351  			{"Javascript/invalid length", bsontype.JavaScript, strbytes[:2], io.EOF, 0, 0},
  1352  			{"Javascript/not enough bytes", bsontype.JavaScript, strbytes[:5], io.EOF, 0, 0},
  1353  			{"Javascript/success", bsontype.JavaScript, strbytes, nil, 8, 0},
  1354  			{"String/invalid length", bsontype.String, strbytes[:2], io.EOF, 0, 0},
  1355  			{"String/not enough bytes", bsontype.String, strbytes[:5], io.EOF, 0, 0},
  1356  			{"String/success", bsontype.String, strbytes, nil, 8, 0},
  1357  			{"Symbol/invalid length", bsontype.Symbol, strbytes[:2], io.EOF, 0, 0},
  1358  			{"Symbol/not enough bytes", bsontype.Symbol, strbytes[:5], io.EOF, 0, 0},
  1359  			{"Symbol/success", bsontype.Symbol, strbytes, nil, 8, 0},
  1360  			{"MaxKey/success", bsontype.MaxKey, []byte{}, nil, 0, 0},
  1361  			{"MinKey/success", bsontype.MinKey, []byte{}, nil, 0, 0},
  1362  			{"Null/success", bsontype.Null, []byte{}, nil, 0, 0},
  1363  			{"Undefined/success", bsontype.Undefined, []byte{}, nil, 0, 0},
  1364  			{
  1365  				"ObjectID/not enough bytes",
  1366  				bsontype.ObjectID,
  1367  				[]byte{0x01, 0x02, 0x03, 0x04},
  1368  				io.EOF, 0, 0,
  1369  			},
  1370  			{
  1371  				"ObjectID/success",
  1372  				bsontype.ObjectID,
  1373  				[]byte{0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C},
  1374  				nil, 12, 0,
  1375  			},
  1376  			{
  1377  				"Regex/not enough bytes (first string)",
  1378  				bsontype.Regex,
  1379  				[]byte{'f', 'o', 'o'},
  1380  				io.EOF, 0, 0,
  1381  			},
  1382  			{
  1383  				"Regex/not enough bytes (second string)",
  1384  				bsontype.Regex,
  1385  				[]byte{'f', 'o', 'o', 0x00, 'b', 'a', 'r'},
  1386  				io.EOF, 0, 0,
  1387  			},
  1388  			{
  1389  				"Regex/success",
  1390  				bsontype.Regex,
  1391  				[]byte{0x00, 0x00, 0x00, 'f', 'o', 'o', 0x00, 'i', 0x00},
  1392  				nil, 9, 3,
  1393  			},
  1394  			{
  1395  				"Unknown Type",
  1396  				bsontype.Type(0),
  1397  				nil,
  1398  				fmt.Errorf("attempted to read bytes of unknown BSON type %v", bsontype.Type(0)), 0, 0,
  1399  			},
  1400  		}
  1401  
  1402  		for _, tc := range testCases {
  1403  			t.Run(tc.name, func(t *testing.T) {
  1404  				t.Run("Skip", func(t *testing.T) {
  1405  					vr := &valueReader{
  1406  						d: tc.data,
  1407  						stack: []vrState{
  1408  							{mode: mTopLevel},
  1409  							{mode: mElement, vType: tc.t},
  1410  						},
  1411  						frame:  1,
  1412  						offset: tc.startingOffset,
  1413  					}
  1414  
  1415  					err := vr.Skip()
  1416  					if !errequal(t, err, tc.err) {
  1417  						t.Errorf("Did not receive expected error; got %v; want %v", err, tc.err)
  1418  					}
  1419  					if tc.err == nil && vr.offset != tc.offset {
  1420  						t.Errorf("Offset not set at correct position; got %d; want %d", vr.offset, tc.offset)
  1421  					}
  1422  				})
  1423  				t.Run("ReadBytes", func(t *testing.T) {
  1424  					vr := &valueReader{
  1425  						d: tc.data,
  1426  						stack: []vrState{
  1427  							{mode: mTopLevel},
  1428  							{mode: mElement, vType: tc.t},
  1429  						},
  1430  						frame:  1,
  1431  						offset: tc.startingOffset,
  1432  					}
  1433  
  1434  					_, got, err := vr.ReadValueBytes(nil)
  1435  					if !errequal(t, err, tc.err) {
  1436  						t.Errorf("Did not receive expected error; got %v; want %v", err, tc.err)
  1437  					}
  1438  					if tc.err == nil && vr.offset != tc.offset {
  1439  						t.Errorf("Offset not set at correct position; got %d; want %d", vr.offset, tc.offset)
  1440  					}
  1441  					if tc.err == nil && !bytes.Equal(got, tc.data[tc.startingOffset:]) {
  1442  						t.Errorf("Did not receive expected bytes. got %v; want %v", got, tc.data[tc.startingOffset:])
  1443  					}
  1444  				})
  1445  			})
  1446  		}
  1447  		t.Run("ReadValueBytes/Top Level Doc", func(t *testing.T) {
  1448  			testCases := []struct {
  1449  				name     string
  1450  				want     []byte
  1451  				wantType bsontype.Type
  1452  				wantErr  error
  1453  			}{
  1454  				{
  1455  					"success",
  1456  					bsoncore.BuildDocument(nil, bsoncore.AppendDoubleElement(nil, "pi", 3.14159)),
  1457  					bsontype.Type(0),
  1458  					nil,
  1459  				},
  1460  				{
  1461  					"wrong length",
  1462  					[]byte{0x01, 0x02, 0x03},
  1463  					bsontype.Type(0),
  1464  					io.EOF,
  1465  				},
  1466  				{
  1467  					"append bytes",
  1468  					[]byte{0x01, 0x02, 0x03, 0x04},
  1469  					bsontype.Type(0),
  1470  					io.EOF,
  1471  				},
  1472  			}
  1473  
  1474  			for _, tc := range testCases {
  1475  				tc := tc
  1476  				t.Run(tc.name, func(t *testing.T) {
  1477  					t.Parallel()
  1478  					vr := &valueReader{
  1479  						d: tc.want,
  1480  						stack: []vrState{
  1481  							{mode: mTopLevel},
  1482  						},
  1483  						frame: 0,
  1484  					}
  1485  					gotType, got, gotErr := vr.ReadValueBytes(nil)
  1486  					if !errors.Is(gotErr, tc.wantErr) {
  1487  						t.Errorf("Did not receive expected error. got %v; want %v", gotErr, tc.wantErr)
  1488  					}
  1489  					if tc.wantErr == nil && gotType != tc.wantType {
  1490  						t.Errorf("Did not receive expected type. got %v; want %v", gotType, tc.wantType)
  1491  					}
  1492  					if tc.wantErr == nil && !bytes.Equal(got, tc.want) {
  1493  						t.Errorf("Did not receive expected bytes. got %v; want %v", got, tc.want)
  1494  					}
  1495  				})
  1496  			}
  1497  		})
  1498  	})
  1499  
  1500  	t.Run("invalid transition", func(t *testing.T) {
  1501  		t.Run("Skip", func(t *testing.T) {
  1502  			vr := &valueReader{stack: []vrState{{mode: mTopLevel}}}
  1503  			wanterr := (&valueReader{stack: []vrState{{mode: mTopLevel}}}).invalidTransitionErr(0, "Skip", []mode{mElement, mValue})
  1504  			goterr := vr.Skip()
  1505  			if !cmp.Equal(goterr, wanterr, cmp.Comparer(compareErrors)) {
  1506  				t.Errorf("Expected correct invalid transition error. got %v; want %v", goterr, wanterr)
  1507  			}
  1508  		})
  1509  	})
  1510  	t.Run("ReadBytes", func(t *testing.T) {
  1511  		vr := &valueReader{stack: []vrState{{mode: mTopLevel}, {mode: mDocument}}, frame: 1}
  1512  		wanterr := (&valueReader{stack: []vrState{{mode: mTopLevel}, {mode: mDocument}}, frame: 1}).
  1513  			invalidTransitionErr(0, "ReadValueBytes", []mode{mElement, mValue})
  1514  		_, _, goterr := vr.ReadValueBytes(nil)
  1515  		if !cmp.Equal(goterr, wanterr, cmp.Comparer(compareErrors)) {
  1516  			t.Errorf("Expected correct invalid transition error. got %v; want %v", goterr, wanterr)
  1517  		}
  1518  	})
  1519  }
  1520  
  1521  func errequal(t *testing.T, err1, err2 error) bool {
  1522  	t.Helper()
  1523  	if err1 == nil && err2 == nil { // If they are both nil, they are equal
  1524  		return true
  1525  	}
  1526  	if err1 == nil || err2 == nil { // If only one is nil, they are not equal
  1527  		return false
  1528  	}
  1529  
  1530  	if errors.Is(err1, err2) { // They are the same error, they are equal
  1531  		return true
  1532  	}
  1533  
  1534  	if err1.Error() == err2.Error() { // They string formats match, they are equal
  1535  		return true
  1536  	}
  1537  
  1538  	return false
  1539  }
  1540  

View as plain text