1 package qapi
2
3 import (
4 "encoding/json"
5 "fmt"
6 "reflect"
7 "strings"
8 "testing"
9 )
10
11 func TestTypeStrOrNull(t *testing.T) {
12 var nilPtr *string
13 validString := "QAPI Spec"
14 emptyString := ""
15
16 structToJson := []struct {
17 s StrOrNull
18 output string
19 shouldError bool
20 errMsg string
21 }{
22
23 {s: StrOrNull{}, output: `null`},
24 {s: StrOrNull{Value: nilPtr}, output: `null`},
25
26 {s: StrOrNull{Value: "QEMU 42"}, output: `"QEMU 42"`},
27 {s: StrOrNull{Value: &validString}, output: fmt.Sprintf(`"%s"`, validString)},
28 {s: StrOrNull{Value: &emptyString}, output: `""`},
29
30 {s: StrOrNull{Value: 42}, shouldError: true, errMsg: "Type is not supported"},
31 }
32
33 for _, data := range structToJson {
34 b, err := json.Marshal(&data.s)
35 if err != nil {
36 if data.shouldError {
37 if !strings.Contains(err.Error(), data.errMsg) {
38 t.Fatalf("Error messages do not match:\nGot:%s\nHas:%s\n", err.Error(), data.errMsg)
39 }
40 } else {
41 t.Fatalf("Unexpected error: %T -> %s\n", data, err.Error())
42 }
43 } else if strings.Compare(string(b), string(data.output)) != 0 {
44 t.Fatalf("Marshal does not match:\nGot:%s\nHas:%s\n", string(b), string(data.output))
45 }
46 }
47
48 jsonToStruct := []struct {
49 input string
50 expectedType string
51 expectedValue string
52 shouldError bool
53 errMsg string
54 }{
55
56 {input: `null`, expectedType: "<nil>"},
57
58 {input: `""`, expectedType: "string", expectedValue: ""},
59 {input: `"Pineapple pizza"`, expectedType: "string", expectedValue: "Pineapple pizza"},
60
61 {input: `42`, shouldError: true, errMsg: "Unsupported type"},
62 }
63
64 for _, data := range jsonToStruct {
65 s := StrOrNull{}
66 if err := json.Unmarshal([]byte(data.input), &s); err != nil {
67 if data.shouldError {
68 if !strings.Contains(err.Error(), data.errMsg) {
69 t.Fatalf("Error messages do not match:\nGot:%s\nHas:%s\n", err.Error(), data.errMsg)
70 }
71 } else {
72 t.Fatalf("Unexpected error: %T -> %s\n", data, err.Error())
73 }
74 } else {
75 gotType := fmt.Sprintf("%T", s.Value)
76 if strings.Compare(gotType, string(data.expectedType)) != 0 {
77 t.Fatalf("Marshal does not match:\nGot:%s\nHas:%s\n", gotType, string(data.expectedType))
78 }
79 if s.Value != nil && strings.Compare(s.Value.(string), data.expectedValue) != 0 {
80 t.Fatalf("Marshal value does not match:\nGot:%s\nHas:%s\n", s.Value.(string), string(data.expectedValue))
81 }
82 }
83 }
84 }
85
86 func TestTypeBlockdevRef(t *testing.T) {
87 var nilPtr *string
88 validString := "Some ID"
89
90 structToJson := []struct {
91 s BlockdevRef
92 output string
93 shouldError bool
94 errMsg string
95 }{
96
97 {s: BlockdevRef{Value: `my-existing-block-device-id`}, output: `"my-existing-block-device-id"`},
98 {s: BlockdevRef{Value: ""}, output: `""`},
99 {s: BlockdevRef{Value: validString}, output: fmt.Sprintf(`"%s"`, validString)},
100
101 {s: BlockdevRef{Value: func() BlockdevOptions {
102 qcow2 := BlockdevOptionsQcow2{}
103 qcow2.File = BlockdevRef{Value: "/some/place/my-image"}
104 opt := BlockdevOptions{}
105 opt.Driver = BlockdevDriverQcow2
106 opt.Value = qcow2
107 return opt
108 }()}, output: `{"driver":"qcow2","file":"/some/place/my-image"}`},
109
110 {s: BlockdevRef{Value: 42}, shouldError: true, errMsg: "Type is not supported"},
111 {s: BlockdevRef{Value: &validString}, shouldError: true, errMsg: "Type is not supported"},
112 {s: BlockdevRef{Value: nilPtr}, shouldError: true, errMsg: "Type is not supported"},
113 }
114
115 for _, data := range structToJson {
116 b, err := json.Marshal(data.s)
117 if err != nil {
118 if data.shouldError {
119 if !strings.Contains(err.Error(), data.errMsg) {
120 t.Fatalf("Error messages do not match:\nGot:%s\nHas:%s\n", err.Error(), data.errMsg)
121 }
122 } else {
123 t.Fatalf("Unexpected error: %T -> %s\n", data, err.Error())
124 }
125 } else if strings.Compare(string(b), string(data.output)) != 0 {
126 t.Fatalf("Marshal does not match:\nGot:%s\nHas:%s\n", string(b), string(data.output))
127 }
128
129 }
130
131 jsonToStruct := []struct {
132 expected BlockdevRef
133 input string
134 shouldError bool
135 errMsg string
136 }{
137
138 {input: `"my-existing-block-device-id"`, expected: BlockdevRef{Value: `my-existing-block-device-id`}},
139 {input: `""`, expected: BlockdevRef{Value: ``}},
140
141 {input: `{"driver":"qcow2","file":"/some/place/my-image"}`,
142 expected: BlockdevRef{Value: func() BlockdevOptions {
143 qcow2 := BlockdevOptionsQcow2{}
144 qcow2.File = BlockdevRef{Value: "/some/place/my-image"}
145 opt := BlockdevOptions{}
146 opt.Driver = BlockdevDriverQcow2
147 opt.Value = qcow2
148 return opt
149 }()}},
150
151 {input: `42`, shouldError: true, errMsg: "Unsupported type"},
152 }
153
154 for _, data := range jsonToStruct {
155 k := BlockdevRef{}
156 if err := json.Unmarshal([]byte(data.input), &k); err != nil {
157 if data.shouldError {
158 if !strings.Contains(err.Error(), data.errMsg) {
159 t.Fatalf("Unexpected error: %T -> %s\n", data, err.Error())
160 }
161 } else {
162 t.Fatalf("Unexpected error: %T -> %s\n", data, err.Error())
163 }
164 } else if !reflect.DeepEqual(k, data.expected) {
165 t.Fatalf("Unexpected error:\n%v\n%v\n", data.expected.Value, k.Value)
166 }
167 }
168 }
169
170 func TestTypeBlockdevRefOrNull(t *testing.T) {
171 var nilPtr *string
172 validString := "Some ID"
173
174 structToJson := []struct {
175 s BlockdevRefOrNull
176 output string
177 shouldError bool
178 errMsg string
179 }{
180
181 {s: BlockdevRefOrNull{}, output: `null`},
182 {s: BlockdevRefOrNull{Value: nilPtr}, output: `null`},
183
184 {s: BlockdevRefOrNull{Value: `my-existing-block-device-id`}, output: `"my-existing-block-device-id"`},
185 {s: BlockdevRefOrNull{Value: ""}, output: `""`},
186 {s: BlockdevRefOrNull{Value: validString}, output: fmt.Sprintf(`"%s"`, validString)},
187 {s: BlockdevRefOrNull{Value: &validString}, output: fmt.Sprintf(`"%s"`, validString)},
188
189 {s: BlockdevRefOrNull{Value: func() BlockdevOptions {
190 qcow2 := BlockdevOptionsQcow2{}
191 qcow2.File = BlockdevRef{Value: "/some/place/my-image"}
192 opt := BlockdevOptions{}
193 opt.Driver = BlockdevDriverQcow2
194 opt.Value = qcow2
195 return opt
196 }()}, output: `{"driver":"qcow2","file":"/some/place/my-image"}`},
197
198 {s: BlockdevRefOrNull{Value: 42}, shouldError: true, errMsg: "Type is not supported"},
199 }
200
201 for _, data := range structToJson {
202 b, err := json.Marshal(data.s)
203 if err != nil {
204 if data.shouldError {
205 if !strings.Contains(err.Error(), data.errMsg) {
206 t.Fatalf("Error messages do not match:\nGot:%s\nHas:%s\n", err.Error(), data.errMsg)
207 }
208 } else {
209 t.Fatalf("Unexpected error: %T -> %s\n", data, err.Error())
210 }
211 } else if strings.Compare(string(b), string(data.output)) != 0 {
212 t.Fatalf("Marshal does not match:\nGot:%s\nHas:%s\n", string(b), string(data.output))
213 }
214 }
215
216 jsonToStruct := []struct {
217 expected BlockdevRefOrNull
218 input string
219 shouldError bool
220 errMsg string
221 }{
222
223 {input: `null`, expected: BlockdevRefOrNull{}},
224
225 {input: `"my-existing-block-device-id"`, expected: BlockdevRefOrNull{Value: `my-existing-block-device-id`}},
226 {input: `""`, expected: BlockdevRefOrNull{Value: ""}},
227
228 {input: `42`, shouldError: true, errMsg: "Unsupported type"},
229 }
230
231 for _, data := range jsonToStruct {
232 k := BlockdevRefOrNull{}
233 if err := json.Unmarshal([]byte(data.input), &k); err != nil {
234 if data.shouldError {
235 if !strings.Contains(err.Error(), data.errMsg) {
236 t.Fatalf("Unexpected error: %T -> %s\n", data, err.Error())
237 }
238 } else {
239 t.Fatalf("Unexpected error: %T -> %s\n", data, err.Error())
240 }
241 } else if !reflect.DeepEqual(k, data.expected) {
242 t.Fatalf("Unexpected error:\n%v\n%v\n", data.expected.Value, k.Value)
243 }
244 }
245 }
246
247 func TestTypeQcow2OverlapChecks(t *testing.T) {
248 isTrue := true
249 cached := Qcow2OverlapCheckModeCached
250 modeAll := Qcow2OverlapCheckModeAll
251 constant := Qcow2OverlapCheckModeConstant
252 none := Qcow2OverlapCheckModeNone
253 structToJson := []struct {
254 s Qcow2OverlapChecks
255 output string
256 shouldError bool
257 errMsg string
258 }{
259
260 {s: Qcow2OverlapChecks{}, output: `null`},
261
262 {s: Qcow2OverlapChecks{Value: Qcow2OverlapCheckFlags{
263 Template: &cached,
264 }}, output: `{"template":"cached"}`},
265 {s: Qcow2OverlapChecks{Value: Qcow2OverlapCheckFlags{
266 Template: &modeAll,
267 RefcountTable: &isTrue,
268 ActiveL2: &isTrue,
269 }}, output: `{"template":"all","active-l2":true,"refcount-table":true}`},
270
271 {s: Qcow2OverlapChecks{Value: &none}, output: `"none"`},
272 {s: Qcow2OverlapChecks{Value: &constant}, output: `"constant"`},
273 {s: Qcow2OverlapChecks{Value: &cached}, output: `"cached"`},
274 {s: Qcow2OverlapChecks{Value: &modeAll}, output: `"all"`},
275
276 {s: Qcow2OverlapChecks{Value: 42}, shouldError: true, errMsg: "Type is not supported"},
277 {s: Qcow2OverlapChecks{Value: "forty-two"}, shouldError: true, errMsg: "Type is not supported"},
278 }
279
280 for _, data := range structToJson {
281 b, err := json.Marshal(data.s)
282 if err != nil {
283 if data.shouldError {
284 if !strings.Contains(err.Error(), data.errMsg) {
285 t.Fatalf("Error messages do not match:\nGot:%s\nHas:%s\n", err.Error(), data.errMsg)
286 }
287 } else {
288 t.Fatalf("Unexpected error: %T -> %s\n", data, err.Error())
289 }
290 } else if strings.Compare(string(b), string(data.output)) != 0 {
291 t.Fatalf("Marshal does not match:\nGot:%s\nHas:%s\n", string(b), string(data.output))
292 }
293 }
294
295 jsonToStruct := []struct {
296 expected Qcow2OverlapChecks
297 input string
298 shouldError bool
299 errMsg string
300 }{
301
302 {input: `{"template":"cached"}`,
303 expected: Qcow2OverlapChecks{Value: Qcow2OverlapCheckFlags{
304 Template: &cached,
305 }}},
306 {input: `{"template":"all","active-l2":true,"refcount-table":true}`,
307 expected: Qcow2OverlapChecks{Value: Qcow2OverlapCheckFlags{
308 Template: &modeAll,
309 RefcountTable: &isTrue,
310 ActiveL2: &isTrue,
311 }}},
312
313 {input: `"none"`, expected: Qcow2OverlapChecks{Value: Qcow2OverlapCheckModeNone}},
314 {input: `"constant"`, expected: Qcow2OverlapChecks{Value: Qcow2OverlapCheckModeConstant}},
315 {input: `"cached"`, expected: Qcow2OverlapChecks{Value: Qcow2OverlapCheckModeCached}},
316 {input: `"all"`, expected: Qcow2OverlapChecks{Value: Qcow2OverlapCheckModeAll}},
317
318 {input: `42`, shouldError: true, errMsg: "Unsupported type"},
319 }
320
321 for _, data := range jsonToStruct {
322 k := Qcow2OverlapChecks{}
323 if err := json.Unmarshal([]byte(data.input), &k); err != nil {
324 if data.shouldError {
325 if !strings.Contains(err.Error(), data.errMsg) {
326 t.Fatalf("Unexpected error: %T -> %s\n", data, err.Error())
327 }
328 } else {
329 t.Fatalf("Unexpected error: %T -> %s\n", data, err.Error())
330 }
331 } else if !reflect.DeepEqual(k, data.expected) {
332 t.Fatalf("Unexpected error:\n%v\n%v\n", data.expected.Value, k.Value)
333 }
334 }
335 }
336
337 func TestTypeBlockDirtyBitmapMergeSource(t *testing.T) {
338 structToJson := []struct {
339 s BlockDirtyBitmapMergeSource
340 output string
341 shouldError bool
342 errMsg string
343 }{
344
345 {s: BlockDirtyBitmapMergeSource{}, output: `null`},
346
347 {s: BlockDirtyBitmapMergeSource{Value: "local-bitmap-name-id"}, output: `"local-bitmap-name-id"`},
348
349 {s: BlockDirtyBitmapMergeSource{Value: BlockDirtyBitmap{
350 Node: "that-node-or-device-id",
351 Name: "name-or-dirty-bitmap",
352 }}, output: `{"node":"that-node-or-device-id","name":"name-or-dirty-bitmap"}`},
353
354 {s: BlockDirtyBitmapMergeSource{Value: 42}, shouldError: true, errMsg: "Type is not supported"},
355 }
356
357 for _, data := range structToJson {
358 b, err := json.Marshal(data.s)
359 if err != nil {
360 if data.shouldError {
361 if !strings.Contains(err.Error(), data.errMsg) {
362 t.Fatalf("Error messages do not match:\nGot:%s\nHas:%s\n", err.Error(), data.errMsg)
363 }
364 } else {
365 t.Fatalf("Unexpected error: %T -> %s\n", data, err.Error())
366 }
367 } else if strings.Compare(string(b), string(data.output)) != 0 {
368 t.Fatalf("Marshal does not match:\nGot:%s\nHas:%s\n", string(b), string(data.output))
369 }
370 }
371
372 jsonToStruct := []struct {
373 expected BlockDirtyBitmapMergeSource
374 input string
375 shouldError bool
376 errMsg string
377 }{
378 {input: `"local-bitmap-name-id"`, expected: BlockDirtyBitmapMergeSource{Value: "local-bitmap-name-id"}},
379
380 {input: `{"node":"that-node-or-device-id","name":"name-or-dirty-bitmap"}`,
381 expected: BlockDirtyBitmapMergeSource{Value: BlockDirtyBitmap{
382 Node: "that-node-or-device-id",
383 Name: "name-or-dirty-bitmap",
384 }}},
385
386 {input: `42`, shouldError: true, errMsg: "Unsupported type"},
387 }
388
389 for _, data := range jsonToStruct {
390 k := BlockDirtyBitmapMergeSource{}
391 if err := json.Unmarshal([]byte(data.input), &k); err != nil {
392 if data.shouldError {
393 if !strings.Contains(err.Error(), data.errMsg) {
394 t.Fatalf("Unexpected error: %T -> %s\n", data, err.Error())
395 }
396 } else {
397 t.Fatalf("Unexpected error: %T -> %s\n", data, err.Error())
398 }
399 } else if !reflect.DeepEqual(k, data.expected) {
400 t.Fatalf("Unexpected error:\n%v\n%v\n", data.expected.Value, k.Value)
401 }
402 }
403 }
404
View as plain text