cmdinfo_test.go raw
1 package btcjson_test
2
3 import (
4 "reflect"
5 "testing"
6
7 "github.com/p9c/p9/pkg/btcjson"
8 )
9
10 // TestCmdMethod tests the CmdMethod function to ensure it returns the expected methods and errors.
11 func TestCmdMethod(t *testing.T) {
12 t.Parallel()
13 tests := []struct {
14 name string
15 cmd interface{}
16 method string
17 e error
18 }{
19 {
20 name: "unregistered type",
21 cmd: (*int)(nil),
22 e: btcjson.GeneralError{ErrorCode: btcjson.ErrUnregisteredMethod},
23 },
24 {
25 name: "nil pointer of registered type",
26 cmd: (*btcjson.GetBlockCmd)(nil),
27 method: "getblock",
28 },
29 {
30 name: "nil instance of registered type",
31 cmd: &btcjson.GetBlockCountCmd{},
32 method: "getblockcount",
33 },
34 }
35 t.Logf("Running %d tests", len(tests))
36 for i, test := range tests {
37 method, e := btcjson.CmdMethod(test.cmd)
38 if reflect.TypeOf(e) != reflect.TypeOf(test.e) {
39 t.Errorf("Test #%d (%s) wrong error - got %T (%[3]v), "+
40 "want %T", i, test.name, e, test.e,
41 )
42 continue
43 }
44 if e != nil {
45 gotErrorCode := e.(btcjson.GeneralError).ErrorCode
46 if gotErrorCode != test.e.(btcjson.GeneralError).ErrorCode {
47 t.Errorf("Test #%d (%s) mismatched error code "+
48 "- got %v (%v), want %v", i, test.name,
49 gotErrorCode, e,
50 test.e.(btcjson.GeneralError).ErrorCode,
51 )
52 continue
53 }
54 continue
55 }
56 // Ensure method matches the expected value.
57 if method != test.method {
58 t.Errorf("Test #%d (%s) mismatched method - got %v, "+
59 "want %v", i, test.name, method, test.method,
60 )
61 continue
62 }
63 }
64 }
65
66 // TestMethodUsageFlags tests the MethodUsage function ensure it returns the expected flags and errors.
67 func TestMethodUsageFlags(t *testing.T) {
68 t.Parallel()
69 tests := []struct {
70 name string
71 method string
72 e error
73 flags btcjson.UsageFlag
74 }{
75 {
76 name: "unregistered type",
77 method: "bogusmethod",
78 e: btcjson.GeneralError{ErrorCode: btcjson.ErrUnregisteredMethod},
79 },
80 {
81 name: "getblock",
82 method: "getblock",
83 flags: 0,
84 },
85 {
86 name: "walletpassphrase",
87 method: "walletpassphrase",
88 flags: btcjson.UFWalletOnly,
89 },
90 }
91 t.Logf("Running %d tests", len(tests))
92 for i, test := range tests {
93 flags, e := btcjson.MethodUsageFlags(test.method)
94 if reflect.TypeOf(e) != reflect.TypeOf(test.e) {
95 t.Errorf("Test #%d (%s) wrong error - got %T (%[3]v), "+
96 "want %T", i, test.name, e, test.e,
97 )
98 continue
99 }
100 if e != nil {
101 gotErrorCode := e.(btcjson.GeneralError).ErrorCode
102 if gotErrorCode != test.e.(btcjson.GeneralError).ErrorCode {
103 t.Errorf("Test #%d (%s) mismatched error code "+
104 "- got %v (%v), want %v", i, test.name,
105 gotErrorCode, e,
106 test.e.(btcjson.GeneralError).ErrorCode,
107 )
108 continue
109 }
110 continue
111 }
112 // Ensure flags match the expected value.
113 if flags != test.flags {
114 t.Errorf("Test #%d (%s) mismatched flags - got %v, "+
115 "want %v", i, test.name, flags, test.flags,
116 )
117 continue
118 }
119 }
120 }
121
122 // TestMethodUsageText tests the MethodUsageText function ensure it returns the expected text.
123 func TestMethodUsageText(t *testing.T) {
124 t.Parallel()
125 tests := []struct {
126 name string
127 method string
128 e error
129 expected string
130 }{
131 {
132 name: "unregistered type",
133 method: "bogusmethod",
134 e: btcjson.GeneralError{ErrorCode: btcjson.ErrUnregisteredMethod},
135 },
136 {
137 name: "getblockcount",
138 method: "getblockcount",
139 expected: "getblockcount",
140 },
141 {
142 name: "getblock",
143 method: "getblock",
144 expected: `getblock "hash" (verbose=true verbosetx=false)`,
145 },
146 }
147 t.Logf("Running %d tests", len(tests))
148 for i, test := range tests {
149 usage, e := btcjson.MethodUsageText(test.method)
150 if reflect.TypeOf(e) != reflect.TypeOf(test.e) {
151 t.Errorf("Test #%d (%s) wrong error - got %T (%[3]v), "+
152 "want %T", i, test.name, e, test.e,
153 )
154 continue
155 }
156 if e != nil {
157 gotErrorCode := e.(btcjson.GeneralError).ErrorCode
158 if gotErrorCode != test.e.(btcjson.GeneralError).ErrorCode {
159 t.Errorf("Test #%d (%s) mismatched error code "+
160 "- got %v (%v), want %v", i, test.name,
161 gotErrorCode, e,
162 test.e.(btcjson.GeneralError).ErrorCode,
163 )
164 continue
165 }
166 continue
167 }
168 // Ensure usage matches the expected value.
169 if usage != test.expected {
170 t.Errorf("Test #%d (%s) mismatched usage - got %v, "+
171 "want %v", i, test.name, usage, test.expected,
172 )
173 continue
174 }
175 // Get the usage again to exercise caching.
176 usage, e = btcjson.MethodUsageText(test.method)
177 if e != nil {
178 t.Errorf("Test #%d (%s) unexpected error: %v", i,
179 test.name, e,
180 )
181 continue
182 }
183 // Ensure usage still matches the expected value.
184 if usage != test.expected {
185 t.Errorf("Test #%d (%s) mismatched usage - got %v, "+
186 "want %v", i, test.name, usage, test.expected,
187 )
188 continue
189 }
190 }
191 }
192
193 // TestFieldUsage tests the internal fieldUsage function ensure it returns the expected text.
194 func TestFieldUsage(t *testing.T) {
195 t.Parallel()
196 tests := []struct {
197 name string
198 field reflect.StructField
199 defValue *reflect.Value
200 expected string
201 }{
202 {
203 name: "jsonrpcusage tag override",
204 field: func() reflect.StructField {
205 type s struct {
206 Test int `jsonrpcusage:"testvalue"`
207 }
208 return reflect.TypeOf((*s)(nil)).Elem().Field(0)
209 }(),
210 defValue: nil,
211 expected: "testvalue",
212 },
213 {
214 name: "generic interface",
215 field: func() reflect.StructField {
216 type s struct {
217 Test interface{}
218 }
219 return reflect.TypeOf((*s)(nil)).Elem().Field(0)
220 }(),
221 defValue: nil,
222 expected: `test`,
223 },
224 {
225 name: "string without default value",
226 field: func() reflect.StructField {
227 type s struct {
228 Test string
229 }
230 return reflect.TypeOf((*s)(nil)).Elem().Field(0)
231 }(),
232 defValue: nil,
233 expected: `"test"`,
234 },
235 {
236 name: "string with default value",
237 field: func() reflect.StructField {
238 type s struct {
239 Test string
240 }
241 return reflect.TypeOf((*s)(nil)).Elem().Field(0)
242 }(),
243 defValue: func() *reflect.Value {
244 value := "default"
245 rv := reflect.ValueOf(&value)
246 return &rv
247 }(),
248 expected: `test="default"`,
249 },
250 {
251 name: "array of strings",
252 field: func() reflect.StructField {
253 type s struct {
254 Test []string
255 }
256 return reflect.TypeOf((*s)(nil)).Elem().Field(0)
257 }(),
258 defValue: nil,
259 expected: `["test",...]`,
260 },
261 {
262 name: "array of strings with plural field name 1",
263 field: func() reflect.StructField {
264 type s struct {
265 Keys []string
266 }
267 return reflect.TypeOf((*s)(nil)).Elem().Field(0)
268 }(),
269 defValue: nil,
270 expected: `["key",...]`,
271 },
272 {
273 name: "array of strings with plural field name 2",
274 field: func() reflect.StructField {
275 type s struct {
276 Addresses []string
277 }
278 return reflect.TypeOf((*s)(nil)).Elem().Field(0)
279 }(),
280 defValue: nil,
281 expected: `["address",...]`,
282 },
283 {
284 name: "array of strings with plural field name 3",
285 field: func() reflect.StructField {
286 type s struct {
287 Capabilities []string
288 }
289 return reflect.TypeOf((*s)(nil)).Elem().Field(0)
290 }(),
291 defValue: nil,
292 expected: `["capability",...]`,
293 },
294 {
295 name: "array of structs",
296 field: func() reflect.StructField {
297 type s2 struct {
298 Txid string
299 }
300 type s struct {
301 Capabilities []s2
302 }
303 return reflect.TypeOf((*s)(nil)).Elem().Field(0)
304 }(),
305 defValue: nil,
306 expected: `[{"txid":"value"},...]`,
307 },
308 {
309 name: "array of ints",
310 field: func() reflect.StructField {
311 type s struct {
312 Test []int
313 }
314 return reflect.TypeOf((*s)(nil)).Elem().Field(0)
315 }(),
316 defValue: nil,
317 expected: `[test,...]`,
318 },
319 {
320 name: "sub struct with jsonrpcusage tag override",
321 field: func() reflect.StructField {
322 type s2 struct {
323 Test string `jsonrpcusage:"testusage"`
324 }
325 type s struct {
326 Test s2
327 }
328 return reflect.TypeOf((*s)(nil)).Elem().Field(0)
329 }(),
330 defValue: nil,
331 expected: `{testusage}`,
332 },
333 {
334 name: "sub struct with string",
335 field: func() reflect.StructField {
336 type s2 struct {
337 Txid string
338 }
339 type s struct {
340 Test s2
341 }
342 return reflect.TypeOf((*s)(nil)).Elem().Field(0)
343 }(),
344 defValue: nil,
345 expected: `{"txid":"value"}`,
346 },
347 {
348 name: "sub struct with int",
349 field: func() reflect.StructField {
350 type s2 struct {
351 Vout int
352 }
353 type s struct {
354 Test s2
355 }
356 return reflect.TypeOf((*s)(nil)).Elem().Field(0)
357 }(),
358 defValue: nil,
359 expected: `{"vout":n}`,
360 },
361 {
362 name: "sub struct with float",
363 field: func() reflect.StructField {
364 type s2 struct {
365 Amount float64
366 }
367 type s struct {
368 Test s2
369 }
370 return reflect.TypeOf((*s)(nil)).Elem().Field(0)
371 }(),
372 defValue: nil,
373 expected: `{"amount":n.nnn}`,
374 },
375 {
376 name: "sub struct with sub struct",
377 field: func() reflect.StructField {
378 type s3 struct {
379 Amount float64
380 }
381 type s2 struct {
382 Template s3
383 }
384 type s struct {
385 Test s2
386 }
387 return reflect.TypeOf((*s)(nil)).Elem().Field(0)
388 }(),
389 defValue: nil,
390 expected: `{"template":{"amount":n.nnn}}`,
391 },
392 {
393 name: "sub struct with slice",
394 field: func() reflect.StructField {
395 type s2 struct {
396 Capabilities []string
397 }
398 type s struct {
399 Test s2
400 }
401 return reflect.TypeOf((*s)(nil)).Elem().Field(0)
402 }(),
403 defValue: nil,
404 expected: `{"capabilities":["capability",...]}`,
405 },
406 }
407 t.Logf("Running %d tests", len(tests))
408 for i, test := range tests {
409 // Ensure usage matches the expected value.
410 usage := btcjson.TstFieldUsage(test.field, test.defValue)
411 if usage != test.expected {
412 t.Errorf("Test #%d (%s) mismatched usage - got %v, "+
413 "want %v", i, test.name, usage, test.expected,
414 )
415 continue
416 }
417 }
418 }
419