raw_test.go 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347
  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. package bson
  7. import (
  8. "bytes"
  9. "encoding/binary"
  10. "fmt"
  11. "io"
  12. "testing"
  13. "github.com/google/go-cmp/cmp"
  14. "github.com/stretchr/testify/require"
  15. "go.mongodb.org/mongo-driver/bson/bsontype"
  16. "go.mongodb.org/mongo-driver/x/bsonx/bsoncore"
  17. )
  18. func ExampleRaw_Validate() {
  19. rdr := make(Raw, 500)
  20. rdr[250], rdr[251], rdr[252], rdr[253], rdr[254] = '\x05', '\x00', '\x00', '\x00', '\x00'
  21. err := rdr[250:].Validate()
  22. fmt.Println(err)
  23. // Output: <nil>
  24. }
  25. func BenchmarkRawValidate(b *testing.B) {
  26. for i := 0; i < b.N; i++ {
  27. rdr := make(Raw, 500)
  28. rdr[250], rdr[251], rdr[252], rdr[253], rdr[254] = '\x05', '\x00', '\x00', '\x00', '\x00'
  29. _ = rdr[250:].Validate()
  30. }
  31. }
  32. func TestRaw(t *testing.T) {
  33. t.Run("Validate", func(t *testing.T) {
  34. t.Run("TooShort", func(t *testing.T) {
  35. want := bsoncore.NewInsufficientBytesError(nil, nil)
  36. got := Raw{'\x00', '\x00'}.Validate()
  37. if !compareErrors(got, want) {
  38. t.Errorf("Did not get expected error. got %v; want %v", got, want)
  39. }
  40. })
  41. t.Run("InvalidLength", func(t *testing.T) {
  42. want := bsoncore.DocumentValidationError("document length exceeds available bytes. length=200 remainingBytes=5")
  43. r := make(Raw, 5)
  44. binary.LittleEndian.PutUint32(r[0:4], 200)
  45. got := r.Validate()
  46. if got != want {
  47. t.Errorf("Did not get expected error. got %v; want %v", got, want)
  48. }
  49. })
  50. t.Run("keyLength-error", func(t *testing.T) {
  51. want := bsoncore.ErrMissingNull
  52. r := make(Raw, 8)
  53. binary.LittleEndian.PutUint32(r[0:4], 8)
  54. r[4], r[5], r[6], r[7] = '\x02', 'f', 'o', 'o'
  55. got := r.Validate()
  56. if got != want {
  57. t.Errorf("Did not get expected error. got %v; want %v", got, want)
  58. }
  59. })
  60. t.Run("Missing-Null-Terminator", func(t *testing.T) {
  61. want := bsoncore.ErrMissingNull
  62. r := make(Raw, 9)
  63. binary.LittleEndian.PutUint32(r[0:4], 9)
  64. r[4], r[5], r[6], r[7], r[8] = '\x0A', 'f', 'o', 'o', '\x00'
  65. got := r.Validate()
  66. if got != want {
  67. t.Errorf("Did not get expected error. got %v; want %v", got, want)
  68. }
  69. })
  70. t.Run("validateValue-error", func(t *testing.T) {
  71. want := bsoncore.ErrMissingNull
  72. r := make(Raw, 11)
  73. binary.LittleEndian.PutUint32(r[0:4], 11)
  74. r[4], r[5], r[6], r[7], r[8], r[9], r[10] = '\x01', 'f', 'o', 'o', '\x00', '\x01', '\x02'
  75. got := r.Validate()
  76. if !compareErrors(got, want) {
  77. t.Errorf("Did not get expected error. got %v; want %v", got, want)
  78. }
  79. })
  80. testCases := []struct {
  81. name string
  82. r Raw
  83. err error
  84. }{
  85. {"null", Raw{'\x08', '\x00', '\x00', '\x00', '\x0A', 'x', '\x00', '\x00'}, nil},
  86. {"subdocument",
  87. Raw{
  88. '\x15', '\x00', '\x00', '\x00',
  89. '\x03',
  90. 'f', 'o', 'o', '\x00',
  91. '\x0B', '\x00', '\x00', '\x00', '\x0A', 'a', '\x00',
  92. '\x0A', 'b', '\x00', '\x00', '\x00',
  93. },
  94. nil,
  95. },
  96. {"array",
  97. Raw{
  98. '\x15', '\x00', '\x00', '\x00',
  99. '\x04',
  100. 'f', 'o', 'o', '\x00',
  101. '\x0B', '\x00', '\x00', '\x00', '\x0A', '1', '\x00',
  102. '\x0A', '2', '\x00', '\x00', '\x00',
  103. },
  104. nil,
  105. },
  106. }
  107. for _, tc := range testCases {
  108. t.Run(tc.name, func(t *testing.T) {
  109. err := tc.r.Validate()
  110. if err != tc.err {
  111. t.Errorf("Returned error does not match. got %v; want %v", err, tc.err)
  112. }
  113. })
  114. }
  115. })
  116. t.Run("Lookup", func(t *testing.T) {
  117. t.Run("empty-key", func(t *testing.T) {
  118. rdr := Raw{'\x05', '\x00', '\x00', '\x00', '\x00'}
  119. _, err := rdr.LookupErr()
  120. if err != bsoncore.ErrEmptyKey {
  121. t.Errorf("Empty key lookup did not return expected result. got %v; want %v", err, bsoncore.ErrEmptyKey)
  122. }
  123. })
  124. t.Run("corrupted-subdocument", func(t *testing.T) {
  125. rdr := Raw{
  126. '\x0D', '\x00', '\x00', '\x00',
  127. '\x03', 'x', '\x00',
  128. '\x06', '\x00', '\x00', '\x00',
  129. '\x01',
  130. '\x00',
  131. '\x00',
  132. }
  133. _, err := rdr.LookupErr("x", "y")
  134. want := bsoncore.NewInsufficientBytesError(nil, nil)
  135. if !compareErrors(err, want) {
  136. t.Errorf("Empty key lookup did not return expected result. got %v; want %v", err, want)
  137. }
  138. })
  139. t.Run("corrupted-array", func(t *testing.T) {
  140. rdr := Raw{
  141. '\x0D', '\x00', '\x00', '\x00',
  142. '\x04', 'x', '\x00',
  143. '\x06', '\x00', '\x00', '\x00',
  144. '\x01',
  145. '\x00',
  146. '\x00',
  147. }
  148. _, err := rdr.LookupErr("x", "y")
  149. want := bsoncore.NewInsufficientBytesError(nil, nil)
  150. if !compareErrors(err, want) {
  151. t.Errorf("Empty key lookup did not return expected result. got %v; want %v", err, want)
  152. }
  153. })
  154. t.Run("invalid-traversal", func(t *testing.T) {
  155. rdr := Raw{'\x08', '\x00', '\x00', '\x00', '\x0A', 'x', '\x00', '\x00'}
  156. _, err := rdr.LookupErr("x", "y")
  157. want := bsoncore.InvalidDepthTraversalError{Key: "x", Type: bsontype.Null}
  158. if !compareErrors(err, want) {
  159. t.Errorf("Empty key lookup did not return expected result. got %v; want %v", err, want)
  160. }
  161. })
  162. testCases := []struct {
  163. name string
  164. r Raw
  165. key []string
  166. want RawValue
  167. err error
  168. }{
  169. {"first",
  170. Raw{
  171. '\x08', '\x00', '\x00', '\x00', '\x0A', 'x', '\x00', '\x00',
  172. },
  173. []string{"x"},
  174. RawValue{Type: bsontype.Null}, nil,
  175. },
  176. {"first-second",
  177. Raw{
  178. '\x15', '\x00', '\x00', '\x00',
  179. '\x03',
  180. 'f', 'o', 'o', '\x00',
  181. '\x0B', '\x00', '\x00', '\x00', '\x0A', 'a', '\x00',
  182. '\x0A', 'b', '\x00', '\x00', '\x00',
  183. },
  184. []string{"foo", "b"},
  185. RawValue{Type: bsontype.Null}, nil,
  186. },
  187. {"first-second-array",
  188. Raw{
  189. '\x15', '\x00', '\x00', '\x00',
  190. '\x04',
  191. 'f', 'o', 'o', '\x00',
  192. '\x0B', '\x00', '\x00', '\x00', '\x0A', '1', '\x00',
  193. '\x0A', '2', '\x00', '\x00', '\x00',
  194. },
  195. []string{"foo", "2"},
  196. RawValue{Type: bsontype.Null}, nil,
  197. },
  198. }
  199. for _, tc := range testCases {
  200. t.Run(tc.name, func(t *testing.T) {
  201. got, err := tc.r.LookupErr(tc.key...)
  202. if err != tc.err {
  203. t.Errorf("Returned error does not match. got %v; want %v", err, tc.err)
  204. }
  205. if !cmp.Equal(got, tc.want) {
  206. t.Errorf("Returned element does not match expected element. got %v; want %v", got, tc.want)
  207. }
  208. })
  209. }
  210. })
  211. t.Run("ElementAt", func(t *testing.T) {
  212. t.Run("Out of bounds", func(t *testing.T) {
  213. rdr := Raw{0xe, 0x0, 0x0, 0x0, 0xa, 0x78, 0x0, 0xa, 0x79, 0x0, 0xa, 0x7a, 0x0, 0x0}
  214. _, err := rdr.IndexErr(3)
  215. if err != bsoncore.ErrOutOfBounds {
  216. t.Errorf("Out of bounds should be returned when accessing element beyond end of document. got %v; want %v", err, bsoncore.ErrOutOfBounds)
  217. }
  218. })
  219. t.Run("Validation Error", func(t *testing.T) {
  220. rdr := Raw{0x07, 0x00, 0x00, 0x00, 0x00}
  221. _, err := rdr.IndexErr(1)
  222. want := bsoncore.NewInsufficientBytesError(nil, nil)
  223. if !compareErrors(err, want) {
  224. t.Errorf("Did not receive expected error. got %v; want %v", err, want)
  225. }
  226. })
  227. testCases := []struct {
  228. name string
  229. rdr Raw
  230. index uint
  231. want RawElement
  232. }{
  233. {"first",
  234. Raw{0xe, 0x0, 0x0, 0x0, 0xa, 0x78, 0x0, 0xa, 0x79, 0x0, 0xa, 0x7a, 0x0, 0x0},
  235. 0, bsoncore.AppendNullElement(nil, "x")},
  236. {"second",
  237. Raw{0xe, 0x0, 0x0, 0x0, 0xa, 0x78, 0x0, 0xa, 0x79, 0x0, 0xa, 0x7a, 0x0, 0x0},
  238. 1, bsoncore.AppendNullElement(nil, "y")},
  239. {"third",
  240. Raw{0xe, 0x0, 0x0, 0x0, 0xa, 0x78, 0x0, 0xa, 0x79, 0x0, 0xa, 0x7a, 0x0, 0x0},
  241. 2, bsoncore.AppendNullElement(nil, "z")},
  242. }
  243. for _, tc := range testCases {
  244. t.Run(tc.name, func(t *testing.T) {
  245. got, err := tc.rdr.IndexErr(tc.index)
  246. if err != nil {
  247. t.Errorf("Unexpected error from ElementAt: %s", err)
  248. }
  249. if diff := cmp.Diff(got, tc.want); diff != "" {
  250. t.Errorf("Documents differ: (-got +want)\n%s", diff)
  251. }
  252. })
  253. }
  254. })
  255. t.Run("NewFromIOReader", func(t *testing.T) {
  256. testCases := []struct {
  257. name string
  258. ioReader io.Reader
  259. bsonReader Raw
  260. err error
  261. }{
  262. {
  263. "nil reader",
  264. nil,
  265. nil,
  266. ErrNilReader,
  267. },
  268. {
  269. "premature end of reader",
  270. bytes.NewBuffer([]byte{}),
  271. nil,
  272. io.EOF,
  273. },
  274. {
  275. "empty document",
  276. bytes.NewBuffer([]byte{5, 0, 0, 0, 0}),
  277. []byte{5, 0, 0, 0, 0},
  278. nil,
  279. },
  280. {
  281. "non-empty document",
  282. bytes.NewBuffer([]byte{
  283. // length
  284. 0x17, 0x0, 0x0, 0x0,
  285. // type - string
  286. 0x2,
  287. // key - "foo"
  288. 0x66, 0x6f, 0x6f, 0x0,
  289. // value - string length
  290. 0x4, 0x0, 0x0, 0x0,
  291. // value - string "bar"
  292. 0x62, 0x61, 0x72, 0x0,
  293. // type - null
  294. 0xa,
  295. // key - "baz"
  296. 0x62, 0x61, 0x7a, 0x0,
  297. // null terminator
  298. 0x0,
  299. }),
  300. []byte{
  301. // length
  302. 0x17, 0x0, 0x0, 0x0,
  303. // type - string
  304. 0x2,
  305. // key - "foo"
  306. 0x66, 0x6f, 0x6f, 0x0,
  307. // value - string length
  308. 0x4, 0x0, 0x0, 0x0,
  309. // value - string "bar"
  310. 0x62, 0x61, 0x72, 0x0,
  311. // type - null
  312. 0xa,
  313. // key - "baz"
  314. 0x62, 0x61, 0x7a, 0x0,
  315. // null terminator
  316. 0x0,
  317. },
  318. nil,
  319. },
  320. }
  321. for _, tc := range testCases {
  322. t.Run(tc.name, func(t *testing.T) {
  323. reader, err := NewFromIOReader(tc.ioReader)
  324. require.Equal(t, err, tc.err)
  325. require.True(t, bytes.Equal(tc.bsonReader, reader))
  326. })
  327. }
  328. })
  329. }