1
2
3
4
5
6
7 package bsonrw
8
9 import (
10 "fmt"
11 "io/ioutil"
12 "reflect"
13 "strings"
14 "testing"
15
16 "go.mongodb.org/mongo-driver/bson/bsontype"
17 "go.mongodb.org/mongo-driver/bson/primitive"
18 )
19
20 func TestExtJSONValueWriter(t *testing.T) {
21 oid := primitive.ObjectID{0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C}
22 testCases := []struct {
23 name string
24 fn interface{}
25 params []interface{}
26 }{
27 {
28 "WriteBinary",
29 (*extJSONValueWriter).WriteBinary,
30 []interface{}{[]byte{0x01, 0x02, 0x03}},
31 },
32 {
33 "WriteBinaryWithSubtype (not 0x02)",
34 (*extJSONValueWriter).WriteBinaryWithSubtype,
35 []interface{}{[]byte{0x01, 0x02, 0x03}, byte(0xFF)},
36 },
37 {
38 "WriteBinaryWithSubtype (0x02)",
39 (*extJSONValueWriter).WriteBinaryWithSubtype,
40 []interface{}{[]byte{0x01, 0x02, 0x03}, byte(0x02)},
41 },
42 {
43 "WriteBoolean",
44 (*extJSONValueWriter).WriteBoolean,
45 []interface{}{true},
46 },
47 {
48 "WriteDBPointer",
49 (*extJSONValueWriter).WriteDBPointer,
50 []interface{}{"bar", oid},
51 },
52 {
53 "WriteDateTime",
54 (*extJSONValueWriter).WriteDateTime,
55 []interface{}{int64(12345678)},
56 },
57 {
58 "WriteDecimal128",
59 (*extJSONValueWriter).WriteDecimal128,
60 []interface{}{primitive.NewDecimal128(10, 20)},
61 },
62 {
63 "WriteDouble",
64 (*extJSONValueWriter).WriteDouble,
65 []interface{}{float64(3.14159)},
66 },
67 {
68 "WriteInt32",
69 (*extJSONValueWriter).WriteInt32,
70 []interface{}{int32(123456)},
71 },
72 {
73 "WriteInt64",
74 (*extJSONValueWriter).WriteInt64,
75 []interface{}{int64(1234567890)},
76 },
77 {
78 "WriteJavascript",
79 (*extJSONValueWriter).WriteJavascript,
80 []interface{}{"var foo = 'bar';"},
81 },
82 {
83 "WriteMaxKey",
84 (*extJSONValueWriter).WriteMaxKey,
85 []interface{}{},
86 },
87 {
88 "WriteMinKey",
89 (*extJSONValueWriter).WriteMinKey,
90 []interface{}{},
91 },
92 {
93 "WriteNull",
94 (*extJSONValueWriter).WriteNull,
95 []interface{}{},
96 },
97 {
98 "WriteObjectID",
99 (*extJSONValueWriter).WriteObjectID,
100 []interface{}{oid},
101 },
102 {
103 "WriteRegex",
104 (*extJSONValueWriter).WriteRegex,
105 []interface{}{"bar", "baz"},
106 },
107 {
108 "WriteString",
109 (*extJSONValueWriter).WriteString,
110 []interface{}{"hello, world!"},
111 },
112 {
113 "WriteSymbol",
114 (*extJSONValueWriter).WriteSymbol,
115 []interface{}{"symbollolz"},
116 },
117 {
118 "WriteTimestamp",
119 (*extJSONValueWriter).WriteTimestamp,
120 []interface{}{uint32(10), uint32(20)},
121 },
122 {
123 "WriteUndefined",
124 (*extJSONValueWriter).WriteUndefined,
125 []interface{}{},
126 },
127 }
128
129 for _, tc := range testCases {
130 t.Run(tc.name, func(t *testing.T) {
131 fn := reflect.ValueOf(tc.fn)
132 if fn.Kind() != reflect.Func {
133 t.Fatalf("fn must be of kind Func but it is a %v", fn.Kind())
134 }
135 if fn.Type().NumIn() != len(tc.params)+1 || fn.Type().In(0) != reflect.TypeOf((*extJSONValueWriter)(nil)) {
136 t.Fatalf("fn must have at least one parameter and the first parameter must be a *valueWriter")
137 }
138 if fn.Type().NumOut() != 1 || fn.Type().Out(0) != reflect.TypeOf((*error)(nil)).Elem() {
139 t.Fatalf("fn must have one return value and it must be an error.")
140 }
141 params := make([]reflect.Value, 1, len(tc.params)+1)
142 ejvw := newExtJSONWriter(ioutil.Discard, true, true, false)
143 params[0] = reflect.ValueOf(ejvw)
144 for _, param := range tc.params {
145 params = append(params, reflect.ValueOf(param))
146 }
147
148 t.Run("incorrect transition", func(t *testing.T) {
149 results := fn.Call(params)
150 got := results[0].Interface().(error)
151 fnName := tc.name
152 if strings.Contains(fnName, "WriteBinary") {
153 fnName = "WriteBinaryWithSubtype"
154 }
155 want := TransitionError{current: mTopLevel, name: fnName, modes: []mode{mElement, mValue},
156 action: "write"}
157 if !compareErrors(got, want) {
158 t.Errorf("Errors do not match. got %v; want %v", got, want)
159 }
160 })
161 })
162 }
163
164 t.Run("WriteArray", func(t *testing.T) {
165 ejvw := newExtJSONWriter(ioutil.Discard, true, true, false)
166 ejvw.push(mArray)
167 want := TransitionError{current: mArray, destination: mArray, parent: mTopLevel,
168 name: "WriteArray", modes: []mode{mElement, mValue}, action: "write"}
169 _, got := ejvw.WriteArray()
170 if !compareErrors(got, want) {
171 t.Errorf("Did not get expected error. got %v; want %v", got, want)
172 }
173 })
174 t.Run("WriteCodeWithScope", func(t *testing.T) {
175 ejvw := newExtJSONWriter(ioutil.Discard, true, true, false)
176 ejvw.push(mArray)
177 want := TransitionError{current: mArray, destination: mCodeWithScope, parent: mTopLevel,
178 name: "WriteCodeWithScope", modes: []mode{mElement, mValue}, action: "write"}
179 _, got := ejvw.WriteCodeWithScope("")
180 if !compareErrors(got, want) {
181 t.Errorf("Did not get expected error. got %v; want %v", got, want)
182 }
183 })
184 t.Run("WriteDocument", func(t *testing.T) {
185 ejvw := newExtJSONWriter(ioutil.Discard, true, true, false)
186 ejvw.push(mArray)
187 want := TransitionError{current: mArray, destination: mDocument, parent: mTopLevel,
188 name: "WriteDocument", modes: []mode{mElement, mValue, mTopLevel}, action: "write"}
189 _, got := ejvw.WriteDocument()
190 if !compareErrors(got, want) {
191 t.Errorf("Did not get expected error. got %v; want %v", got, want)
192 }
193 })
194 t.Run("WriteDocumentElement", func(t *testing.T) {
195 ejvw := newExtJSONWriter(ioutil.Discard, true, true, false)
196 ejvw.push(mElement)
197 want := TransitionError{current: mElement,
198 destination: mElement,
199 parent: mTopLevel,
200 name: "WriteDocumentElement",
201 modes: []mode{mDocument, mTopLevel, mCodeWithScope},
202 action: "write"}
203 _, got := ejvw.WriteDocumentElement("")
204 if !compareErrors(got, want) {
205 t.Errorf("Did not get expected error. got %v; want %v", got, want)
206 }
207 })
208 t.Run("WriteDocumentEnd", func(t *testing.T) {
209 ejvw := newExtJSONWriter(ioutil.Discard, true, true, false)
210 ejvw.push(mElement)
211 want := fmt.Errorf("incorrect mode to end document: %s", mElement)
212 got := ejvw.WriteDocumentEnd()
213 if !compareErrors(got, want) {
214 t.Errorf("Did not get expected error. got %v; want %v", got, want)
215 }
216 })
217 t.Run("WriteArrayElement", func(t *testing.T) {
218 ejvw := newExtJSONWriter(ioutil.Discard, true, true, false)
219 ejvw.push(mElement)
220 want := TransitionError{current: mElement,
221 destination: mValue,
222 parent: mTopLevel,
223 name: "WriteArrayElement",
224 modes: []mode{mArray},
225 action: "write"}
226 _, got := ejvw.WriteArrayElement()
227 if !compareErrors(got, want) {
228 t.Errorf("Did not get expected error. got %v; want %v", got, want)
229 }
230 })
231 t.Run("WriteArrayEnd", func(t *testing.T) {
232 ejvw := newExtJSONWriter(ioutil.Discard, true, true, false)
233 ejvw.push(mElement)
234 want := fmt.Errorf("incorrect mode to end array: %s", mElement)
235 got := ejvw.WriteArrayEnd()
236 if !compareErrors(got, want) {
237 t.Errorf("Did not get expected error. got %v; want %v", got, want)
238 }
239 })
240
241 t.Run("WriteBytes", func(t *testing.T) {
242 t.Run("writeElementHeader error", func(t *testing.T) {
243 ejvw := newExtJSONWriterFromSlice(nil, true, true)
244 want := TransitionError{current: mTopLevel, destination: mode(0),
245 name: "WriteBinaryWithSubtype", modes: []mode{mElement, mValue}, action: "write"}
246 got := ejvw.WriteBinaryWithSubtype(nil, (byte)(bsontype.EmbeddedDocument))
247 if !compareErrors(got, want) {
248 t.Errorf("Did not received expected error. got %v; want %v", got, want)
249 }
250 })
251 })
252
253 t.Run("FormatDoubleWithExponent", func(t *testing.T) {
254 want := "3E-12"
255 got := formatDouble(float64(0.000000000003))
256 if got != want {
257 t.Errorf("Did not receive expected string. got %s: want %s", got, want)
258 }
259 })
260 }
261
View as plain text