1 // Copyright (c) 2014 The btcsuite developers
2 // Use of this source code is governed by an ISC
3 // license that can be found in the LICENSE file.
11 "github.com/btcsuite/btcd/btcjson"
14 // TestHelpReflectInternals ensures the various help functions which deal with
15 // reflect types work as expected for various Go types.
16 func TestHelpReflectInternals(t *testing.T) {
21 reflectType reflect.Type
31 reflectType: reflect.TypeOf(int(0)),
32 key: "json-type-numeric",
33 examples: []string{"n"},
34 help: "n (json-type-numeric) fdk",
38 reflectType: reflect.TypeOf((*int)(nil)),
39 key: "json-type-value",
40 examples: []string{"n"},
41 help: "n (json-type-value) fdk",
46 reflectType: reflect.TypeOf(int8(0)),
47 key: "json-type-numeric",
48 examples: []string{"n"},
49 help: "n (json-type-numeric) fdk",
53 reflectType: reflect.TypeOf(int16(0)),
54 key: "json-type-numeric",
55 examples: []string{"n"},
56 help: "n (json-type-numeric) fdk",
60 reflectType: reflect.TypeOf(int32(0)),
61 key: "json-type-numeric",
62 examples: []string{"n"},
63 help: "n (json-type-numeric) fdk",
67 reflectType: reflect.TypeOf(int64(0)),
68 key: "json-type-numeric",
69 examples: []string{"n"},
70 help: "n (json-type-numeric) fdk",
74 reflectType: reflect.TypeOf(uint(0)),
75 key: "json-type-numeric",
76 examples: []string{"n"},
77 help: "n (json-type-numeric) fdk",
81 reflectType: reflect.TypeOf(uint8(0)),
82 key: "json-type-numeric",
83 examples: []string{"n"},
84 help: "n (json-type-numeric) fdk",
88 reflectType: reflect.TypeOf(uint16(0)),
89 key: "json-type-numeric",
90 examples: []string{"n"},
91 help: "n (json-type-numeric) fdk",
95 reflectType: reflect.TypeOf(uint32(0)),
96 key: "json-type-numeric",
97 examples: []string{"n"},
98 help: "n (json-type-numeric) fdk",
102 reflectType: reflect.TypeOf(uint64(0)),
103 key: "json-type-numeric",
104 examples: []string{"n"},
105 help: "n (json-type-numeric) fdk",
109 reflectType: reflect.TypeOf(float32(0)),
110 key: "json-type-numeric",
111 examples: []string{"n.nnn"},
112 help: "n.nnn (json-type-numeric) fdk",
116 reflectType: reflect.TypeOf(float64(0)),
117 key: "json-type-numeric",
118 examples: []string{"n.nnn"},
119 help: "n.nnn (json-type-numeric) fdk",
123 reflectType: reflect.TypeOf(""),
124 key: "json-type-string",
125 examples: []string{`"json-example-string"`},
126 help: "\"json-example-string\" (json-type-string) fdk",
130 reflectType: reflect.TypeOf(true),
131 key: "json-type-bool",
132 examples: []string{"json-example-bool"},
133 help: "json-example-bool (json-type-bool) fdk",
136 name: "array of int",
137 reflectType: reflect.TypeOf([1]int{0}),
138 key: "json-type-arrayjson-type-numeric",
139 examples: []string{"[n,...]"},
140 help: "[n,...] (json-type-arrayjson-type-numeric) fdk",
143 name: "slice of int",
144 reflectType: reflect.TypeOf([]int{0}),
145 key: "json-type-arrayjson-type-numeric",
146 examples: []string{"[n,...]"},
147 help: "[n,...] (json-type-arrayjson-type-numeric) fdk",
151 reflectType: reflect.TypeOf(struct{}{}),
152 key: "json-type-object",
153 examples: []string{"{", "}\t\t"},
158 name: "struct indent level 1",
159 reflectType: reflect.TypeOf(struct{ field int }{}),
161 key: "json-type-object",
163 " \"field\": n,\t(json-type-numeric)\t-field",
167 " \"field\": n, (json-type-numeric) -field\n" +
172 name: "array of struct indent level 0",
173 reflectType: func() reflect.Type {
177 return reflect.TypeOf([]s{})
179 key: "json-type-arrayjson-type-object",
182 " \"field\": n,\t(json-type-numeric)\ts-field",
186 " \"field\": n, (json-type-numeric) s-field\n" +
191 name: "array of struct indent level 1",
192 reflectType: func() reflect.Type {
196 return reflect.TypeOf([]s{})
199 key: "json-type-arrayjson-type-object",
201 " \"field\": n,\t(json-type-numeric)\ts-field",
205 " \"field\": n, (json-type-numeric) s-field\n" +
211 reflectType: reflect.TypeOf(map[string]string{}),
212 key: "json-type-object",
213 examples: []string{"{",
214 " \"fdk--key\": fdk--value, (json-type-object) fdk--desc",
218 " \"fdk--key\": fdk--value, (json-type-object) fdk--desc\n" +
225 reflectType: reflect.TypeOf(complex64(0)),
226 key: "json-type-value",
227 examples: []string{"json-example-unknown"},
228 help: "json-example-unknown (json-type-value) fdk",
233 xT := func(key string) string {
237 t.Logf("Running %d tests", len(tests))
238 for i, test := range tests {
239 // Ensure the description key is the expected value.
240 key := btcjson.TstReflectTypeToJSONType(xT, test.reflectType)
242 t.Errorf("Test #%d (%s) unexpected key - got: %v, "+
243 "want: %v", i, test.name, key, test.key)
247 // Ensure the generated example is as expected.
248 examples, isComplex := btcjson.TstReflectTypeToJSONExample(xT,
249 test.reflectType, test.indentLevel, "fdk")
250 if isComplex != test.isComplex {
251 t.Errorf("Test #%d (%s) unexpected isComplex - got: %v, "+
252 "want: %v", i, test.name, isComplex,
256 if len(examples) != len(test.examples) {
257 t.Errorf("Test #%d (%s) unexpected result length - "+
258 "got: %v, want: %v", i, test.name, len(examples),
262 for j, example := range examples {
263 if example != test.examples[j] {
264 t.Errorf("Test #%d (%s) example #%d unexpected "+
265 "example - got: %v, want: %v", i,
266 test.name, j, example, test.examples[j])
271 // Ensure the generated result type help is as expected.
272 helpText := btcjson.TstResultTypeHelp(xT, test.reflectType, "fdk")
273 if helpText != test.help {
274 t.Errorf("Test #%d (%s) unexpected result help - "+
275 "got: %v, want: %v", i, test.name, helpText,
280 isValid := btcjson.TstIsValidResultType(test.reflectType.Kind())
281 if isValid != !test.isInvalid {
282 t.Errorf("Test #%d (%s) unexpected result type validity "+
283 "- got: %v", i, test.name, isValid)
289 // TestResultStructHelp ensures the expected help text format is returned for
290 // various Go struct types.
291 func TestResultStructHelp(t *testing.T) {
296 reflectType reflect.Type
300 name: "empty struct",
301 reflectType: func() reflect.Type {
303 return reflect.TypeOf(s{})
308 name: "struct with primitive field",
309 reflectType: func() reflect.Type {
313 return reflect.TypeOf(s{})
316 "\"field\": n,\t(json-type-numeric)\ts-field",
320 name: "struct with primitive field and json tag",
321 reflectType: func() reflect.Type {
325 return reflect.TypeOf(s{})
328 "\"f\": n,\t(json-type-numeric)\ts-f",
332 name: "struct with array of primitive field",
333 reflectType: func() reflect.Type {
337 return reflect.TypeOf(s{})
340 "\"field\": [n,...],\t(json-type-arrayjson-type-numeric)\ts-field",
344 name: "struct with sub-struct field",
345 reflectType: func() reflect.Type {
352 return reflect.TypeOf(s{})
355 "\"field\": {\t(json-type-object)\ts-field",
357 " \"subfield\": n,\t(json-type-numeric)\ts2-subfield",
362 name: "struct with sub-struct field pointer",
363 reflectType: func() reflect.Type {
370 return reflect.TypeOf(s{})
373 "\"field\": {\t(json-type-object)\ts-field",
375 " \"subfield\": n,\t(json-type-numeric)\ts2-subfield",
380 name: "struct with array of structs field",
381 reflectType: func() reflect.Type {
388 return reflect.TypeOf(s{})
391 "\"field\": [{\t(json-type-arrayjson-type-object)\ts-field",
393 " \"subfield\": n,\t(json-type-numeric)\ts2-subfield",
399 xT := func(key string) string {
403 t.Logf("Running %d tests", len(tests))
404 for i, test := range tests {
405 results := btcjson.TstResultStructHelp(xT, test.reflectType, 0)
406 if len(results) != len(test.expected) {
407 t.Errorf("Test #%d (%s) unexpected result length - "+
408 "got: %v, want: %v", i, test.name, len(results),
412 for j, result := range results {
413 if result != test.expected[j] {
414 t.Errorf("Test #%d (%s) result #%d unexpected "+
415 "result - got: %v, want: %v", i,
416 test.name, j, result, test.expected[j])
423 // TestHelpArgInternals ensures the various help functions which deal with
424 // arguments work as expected for various argument types.
425 func TestHelpArgInternals(t *testing.T) {
431 reflectType reflect.Type
432 defaults map[int]reflect.Value
436 name: "command with no args",
438 reflectType: func() reflect.Type {
440 return reflect.TypeOf((*s)(nil))
446 name: "command with one required arg",
448 reflectType: func() reflect.Type {
452 return reflect.TypeOf((*s)(nil))
455 help: "1. field (json-type-numeric, help-required) test-field\n",
458 name: "command with one optional arg, no default",
460 reflectType: func() reflect.Type {
464 return reflect.TypeOf((*s)(nil))
467 help: "1. optional (json-type-numeric, help-optional) test-optional\n",
470 name: "command with one optional arg with default",
472 reflectType: func() reflect.Type {
476 return reflect.TypeOf((*s)(nil))
478 defaults: func() map[int]reflect.Value {
480 return map[int]reflect.Value{
481 0: reflect.ValueOf(&defVal),
484 help: "1. optional (json-type-string, help-optional, help-default=\"test\") test-optional\n",
487 name: "command with struct field",
489 reflectType: func() reflect.Type {
496 return reflect.TypeOf((*s)(nil))
499 help: "1. field (json-type-object, help-required) test-field\n" +
501 " \"f\": n, (json-type-numeric) s2-f\n" +
505 name: "command with map field",
507 reflectType: func() reflect.Type {
509 Field map[string]float64
511 return reflect.TypeOf((*s)(nil))
514 help: "1. field (json-type-object, help-required) test-field\n" +
516 " \"test-field--key\": test-field--value, (json-type-object) test-field--desc\n" +
521 name: "command with slice of primitives field",
523 reflectType: func() reflect.Type {
527 return reflect.TypeOf((*s)(nil))
530 help: "1. field (json-type-arrayjson-type-numeric, help-required) test-field\n",
533 name: "command with slice of structs field",
535 reflectType: func() reflect.Type {
542 return reflect.TypeOf((*s)(nil))
545 help: "1. field (json-type-arrayjson-type-object, help-required) test-field\n" +
547 " \"f\": n, (json-type-numeric) s2-f\n" +
552 xT := func(key string) string {
556 t.Logf("Running %d tests", len(tests))
557 for i, test := range tests {
558 help := btcjson.TstArgHelp(xT, test.reflectType, test.defaults,
560 if help != test.help {
561 t.Errorf("Test #%d (%s) unexpected help - got:\n%v\n"+
562 "want:\n%v", i, test.name, help, test.help)
568 // TestMethodHelp ensures the method help function works as expected for various
570 func TestMethodHelp(t *testing.T) {
576 reflectType reflect.Type
577 defaults map[int]reflect.Value
578 resultTypes []interface{}
582 name: "command with no args or results",
584 reflectType: func() reflect.Type {
586 return reflect.TypeOf((*s)(nil))
588 help: "test\n\ntest--synopsis\n\n" +
589 "help-arguments:\nhelp-arguments-none\n\n" +
590 "help-result:\nhelp-result-nothing\n",
593 name: "command with no args and one primitive result",
595 reflectType: func() reflect.Type {
597 return reflect.TypeOf((*s)(nil))
599 resultTypes: []interface{}{(*int64)(nil)},
600 help: "test\n\ntest--synopsis\n\n" +
601 "help-arguments:\nhelp-arguments-none\n\n" +
602 "help-result:\nn (json-type-numeric) test--result0\n",
605 name: "command with no args and two results",
607 reflectType: func() reflect.Type {
609 return reflect.TypeOf((*s)(nil))
611 resultTypes: []interface{}{(*int64)(nil), nil},
612 help: "test\n\ntest--synopsis\n\n" +
613 "help-arguments:\nhelp-arguments-none\n\n" +
614 "help-result (test--condition0):\nn (json-type-numeric) test--result0\n\n" +
615 "help-result (test--condition1):\nhelp-result-nothing\n",
618 name: "command with primitive arg and no results",
620 reflectType: func() reflect.Type {
624 return reflect.TypeOf((*s)(nil))
626 help: "test field\n\ntest--synopsis\n\n" +
627 "help-arguments:\n1. field (json-type-bool, help-required) test-field\n\n" +
628 "help-result:\nhelp-result-nothing\n",
631 name: "command with primitive optional and no results",
633 reflectType: func() reflect.Type {
637 return reflect.TypeOf((*s)(nil))
639 help: "test (field)\n\ntest--synopsis\n\n" +
640 "help-arguments:\n1. field (json-type-bool, help-optional) test-field\n\n" +
641 "help-result:\nhelp-result-nothing\n",
645 xT := func(key string) string {
649 t.Logf("Running %d tests", len(tests))
650 for i, test := range tests {
651 help := btcjson.TestMethodHelp(xT, test.reflectType,
652 test.defaults, test.method, test.resultTypes)
653 if help != test.help {
654 t.Errorf("Test #%d (%s) unexpected help - got:\n%v\n"+
655 "want:\n%v", i, test.name, help, test.help)
661 // TestGenerateHelpErrors ensures the GenerateHelp function returns the expected
663 func TestGenerateHelpErrors(t *testing.T) {
669 resultTypes []interface{}
673 name: "unregistered command",
674 method: "boguscommand",
675 err: btcjson.Error{ErrorCode: btcjson.ErrUnregisteredMethod},
678 name: "non-pointer result type",
680 resultTypes: []interface{}{0},
681 err: btcjson.Error{ErrorCode: btcjson.ErrInvalidType},
684 name: "invalid result type",
686 resultTypes: []interface{}{(*complex64)(nil)},
687 err: btcjson.Error{ErrorCode: btcjson.ErrInvalidType},
690 name: "missing description",
692 resultTypes: []interface{}{(*string)(nil), nil},
693 err: btcjson.Error{ErrorCode: btcjson.ErrMissingDescription},
697 t.Logf("Running %d tests", len(tests))
698 for i, test := range tests {
699 _, err := btcjson.GenerateHelp(test.method, nil,
701 if reflect.TypeOf(err) != reflect.TypeOf(test.err) {
702 t.Errorf("Test #%d (%s) wrong error - got %T (%[2]v), "+
703 "want %T", i, test.name, err, test.err)
706 gotErrorCode := err.(btcjson.Error).ErrorCode
707 if gotErrorCode != test.err.ErrorCode {
708 t.Errorf("Test #%d (%s) mismatched error code - got "+
709 "%v (%v), want %v", i, test.name, gotErrorCode,
710 err, test.err.ErrorCode)
716 // TestGenerateHelp performs a very basic test to ensure GenerateHelp is working
717 // as expected. The internal are testd much more thoroughly in other tests, so
718 // there is no need to add more tests here.
719 func TestGenerateHelp(t *testing.T) {
722 descs := map[string]string{
723 "help--synopsis": "test",
724 "help-command": "test",
726 help, err := btcjson.GenerateHelp("help", descs)
728 t.Fatalf("GenerateHelp: unexpected error: %v", err)
730 wantHelp := "help (\"command\")\n\n" +
731 "test\n\nArguments:\n1. command (string, optional) test\n\n" +
733 if help != wantHelp {
734 t.Fatalf("GenerateHelp: unexpected help - got\n%v\nwant\n%v",