OSDN Git Service

Merge pull request #41 from Bytom/dev
[bytom/vapor.git] / vendor / github.com / btcsuite / btcd / btcjson / help_test.go
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.
4
5 package btcjson_test
6
7 import (
8         "reflect"
9         "testing"
10
11         "github.com/btcsuite/btcd/btcjson"
12 )
13
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) {
17         t.Parallel()
18
19         tests := []struct {
20                 name        string
21                 reflectType reflect.Type
22                 indentLevel int
23                 key         string
24                 examples    []string
25                 isComplex   bool
26                 help        string
27                 isInvalid   bool
28         }{
29                 {
30                         name:        "int",
31                         reflectType: reflect.TypeOf(int(0)),
32                         key:         "json-type-numeric",
33                         examples:    []string{"n"},
34                         help:        "n (json-type-numeric) fdk",
35                 },
36                 {
37                         name:        "*int",
38                         reflectType: reflect.TypeOf((*int)(nil)),
39                         key:         "json-type-value",
40                         examples:    []string{"n"},
41                         help:        "n (json-type-value) fdk",
42                         isInvalid:   true,
43                 },
44                 {
45                         name:        "int8",
46                         reflectType: reflect.TypeOf(int8(0)),
47                         key:         "json-type-numeric",
48                         examples:    []string{"n"},
49                         help:        "n (json-type-numeric) fdk",
50                 },
51                 {
52                         name:        "int16",
53                         reflectType: reflect.TypeOf(int16(0)),
54                         key:         "json-type-numeric",
55                         examples:    []string{"n"},
56                         help:        "n (json-type-numeric) fdk",
57                 },
58                 {
59                         name:        "int32",
60                         reflectType: reflect.TypeOf(int32(0)),
61                         key:         "json-type-numeric",
62                         examples:    []string{"n"},
63                         help:        "n (json-type-numeric) fdk",
64                 },
65                 {
66                         name:        "int64",
67                         reflectType: reflect.TypeOf(int64(0)),
68                         key:         "json-type-numeric",
69                         examples:    []string{"n"},
70                         help:        "n (json-type-numeric) fdk",
71                 },
72                 {
73                         name:        "uint",
74                         reflectType: reflect.TypeOf(uint(0)),
75                         key:         "json-type-numeric",
76                         examples:    []string{"n"},
77                         help:        "n (json-type-numeric) fdk",
78                 },
79                 {
80                         name:        "uint8",
81                         reflectType: reflect.TypeOf(uint8(0)),
82                         key:         "json-type-numeric",
83                         examples:    []string{"n"},
84                         help:        "n (json-type-numeric) fdk",
85                 },
86                 {
87                         name:        "uint16",
88                         reflectType: reflect.TypeOf(uint16(0)),
89                         key:         "json-type-numeric",
90                         examples:    []string{"n"},
91                         help:        "n (json-type-numeric) fdk",
92                 },
93                 {
94                         name:        "uint32",
95                         reflectType: reflect.TypeOf(uint32(0)),
96                         key:         "json-type-numeric",
97                         examples:    []string{"n"},
98                         help:        "n (json-type-numeric) fdk",
99                 },
100                 {
101                         name:        "uint64",
102                         reflectType: reflect.TypeOf(uint64(0)),
103                         key:         "json-type-numeric",
104                         examples:    []string{"n"},
105                         help:        "n (json-type-numeric) fdk",
106                 },
107                 {
108                         name:        "float32",
109                         reflectType: reflect.TypeOf(float32(0)),
110                         key:         "json-type-numeric",
111                         examples:    []string{"n.nnn"},
112                         help:        "n.nnn (json-type-numeric) fdk",
113                 },
114                 {
115                         name:        "float64",
116                         reflectType: reflect.TypeOf(float64(0)),
117                         key:         "json-type-numeric",
118                         examples:    []string{"n.nnn"},
119                         help:        "n.nnn (json-type-numeric) fdk",
120                 },
121                 {
122                         name:        "string",
123                         reflectType: reflect.TypeOf(""),
124                         key:         "json-type-string",
125                         examples:    []string{`"json-example-string"`},
126                         help:        "\"json-example-string\" (json-type-string) fdk",
127                 },
128                 {
129                         name:        "bool",
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",
134                 },
135                 {
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",
141                 },
142                 {
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",
148                 },
149                 {
150                         name:        "struct",
151                         reflectType: reflect.TypeOf(struct{}{}),
152                         key:         "json-type-object",
153                         examples:    []string{"{", "}\t\t"},
154                         isComplex:   true,
155                         help:        "{\n} ",
156                 },
157                 {
158                         name:        "struct indent level 1",
159                         reflectType: reflect.TypeOf(struct{ field int }{}),
160                         indentLevel: 1,
161                         key:         "json-type-object",
162                         examples: []string{
163                                 "  \"field\": n,\t(json-type-numeric)\t-field",
164                                 " },\t\t",
165                         },
166                         help: "{\n" +
167                                 " \"field\": n, (json-type-numeric) -field\n" +
168                                 "}            ",
169                         isComplex: true,
170                 },
171                 {
172                         name: "array of struct indent level 0",
173                         reflectType: func() reflect.Type {
174                                 type s struct {
175                                         field int
176                                 }
177                                 return reflect.TypeOf([]s{})
178                         }(),
179                         key: "json-type-arrayjson-type-object",
180                         examples: []string{
181                                 "[{",
182                                 " \"field\": n,\t(json-type-numeric)\ts-field",
183                                 "},...]",
184                         },
185                         help: "[{\n" +
186                                 " \"field\": n, (json-type-numeric) s-field\n" +
187                                 "},...]",
188                         isComplex: true,
189                 },
190                 {
191                         name: "array of struct indent level 1",
192                         reflectType: func() reflect.Type {
193                                 type s struct {
194                                         field int
195                                 }
196                                 return reflect.TypeOf([]s{})
197                         }(),
198                         indentLevel: 1,
199                         key:         "json-type-arrayjson-type-object",
200                         examples: []string{
201                                 "  \"field\": n,\t(json-type-numeric)\ts-field",
202                                 " },...],\t\t",
203                         },
204                         help: "[{\n" +
205                                 " \"field\": n, (json-type-numeric) s-field\n" +
206                                 "},...]",
207                         isComplex: true,
208                 },
209                 {
210                         name:        "map",
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",
215                                 " ...", "}",
216                         },
217                         help: "{\n" +
218                                 " \"fdk--key\": fdk--value, (json-type-object) fdk--desc\n" +
219                                 " ...\n" +
220                                 "}",
221                         isComplex: true,
222                 },
223                 {
224                         name:        "complex",
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",
229                         isInvalid:   true,
230                 },
231         }
232
233         xT := func(key string) string {
234                 return key
235         }
236
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)
241                 if key != test.key {
242                         t.Errorf("Test #%d (%s) unexpected key - got: %v, "+
243                                 "want: %v", i, test.name, key, test.key)
244                         continue
245                 }
246
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,
253                                 test.isComplex)
254                         continue
255                 }
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),
259                                 len(test.examples))
260                         continue
261                 }
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])
267                                 continue
268                         }
269                 }
270
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,
276                                 test.help)
277                         continue
278                 }
279
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)
284                         continue
285                 }
286         }
287 }
288
289 // TestResultStructHelp ensures the expected help text format is returned for
290 // various Go struct types.
291 func TestResultStructHelp(t *testing.T) {
292         t.Parallel()
293
294         tests := []struct {
295                 name        string
296                 reflectType reflect.Type
297                 expected    []string
298         }{
299                 {
300                         name: "empty struct",
301                         reflectType: func() reflect.Type {
302                                 type s struct{}
303                                 return reflect.TypeOf(s{})
304                         }(),
305                         expected: nil,
306                 },
307                 {
308                         name: "struct with primitive field",
309                         reflectType: func() reflect.Type {
310                                 type s struct {
311                                         field int
312                                 }
313                                 return reflect.TypeOf(s{})
314                         }(),
315                         expected: []string{
316                                 "\"field\": n,\t(json-type-numeric)\ts-field",
317                         },
318                 },
319                 {
320                         name: "struct with primitive field and json tag",
321                         reflectType: func() reflect.Type {
322                                 type s struct {
323                                         Field int `json:"f"`
324                                 }
325                                 return reflect.TypeOf(s{})
326                         }(),
327                         expected: []string{
328                                 "\"f\": n,\t(json-type-numeric)\ts-f",
329                         },
330                 },
331                 {
332                         name: "struct with array of primitive field",
333                         reflectType: func() reflect.Type {
334                                 type s struct {
335                                         field []int
336                                 }
337                                 return reflect.TypeOf(s{})
338                         }(),
339                         expected: []string{
340                                 "\"field\": [n,...],\t(json-type-arrayjson-type-numeric)\ts-field",
341                         },
342                 },
343                 {
344                         name: "struct with sub-struct field",
345                         reflectType: func() reflect.Type {
346                                 type s2 struct {
347                                         subField int
348                                 }
349                                 type s struct {
350                                         field s2
351                                 }
352                                 return reflect.TypeOf(s{})
353                         }(),
354                         expected: []string{
355                                 "\"field\": {\t(json-type-object)\ts-field",
356                                 "{",
357                                 " \"subfield\": n,\t(json-type-numeric)\ts2-subfield",
358                                 "}\t\t",
359                         },
360                 },
361                 {
362                         name: "struct with sub-struct field pointer",
363                         reflectType: func() reflect.Type {
364                                 type s2 struct {
365                                         subField int
366                                 }
367                                 type s struct {
368                                         field *s2
369                                 }
370                                 return reflect.TypeOf(s{})
371                         }(),
372                         expected: []string{
373                                 "\"field\": {\t(json-type-object)\ts-field",
374                                 "{",
375                                 " \"subfield\": n,\t(json-type-numeric)\ts2-subfield",
376                                 "}\t\t",
377                         },
378                 },
379                 {
380                         name: "struct with array of structs field",
381                         reflectType: func() reflect.Type {
382                                 type s2 struct {
383                                         subField int
384                                 }
385                                 type s struct {
386                                         field []s2
387                                 }
388                                 return reflect.TypeOf(s{})
389                         }(),
390                         expected: []string{
391                                 "\"field\": [{\t(json-type-arrayjson-type-object)\ts-field",
392                                 "[{",
393                                 " \"subfield\": n,\t(json-type-numeric)\ts2-subfield",
394                                 "},...]",
395                         },
396                 },
397         }
398
399         xT := func(key string) string {
400                 return key
401         }
402
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),
409                                 len(test.expected))
410                         continue
411                 }
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])
417                                 continue
418                         }
419                 }
420         }
421 }
422
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) {
426         t.Parallel()
427
428         tests := []struct {
429                 name        string
430                 method      string
431                 reflectType reflect.Type
432                 defaults    map[int]reflect.Value
433                 help        string
434         }{
435                 {
436                         name:   "command with no args",
437                         method: "test",
438                         reflectType: func() reflect.Type {
439                                 type s struct{}
440                                 return reflect.TypeOf((*s)(nil))
441                         }(),
442                         defaults: nil,
443                         help:     "",
444                 },
445                 {
446                         name:   "command with one required arg",
447                         method: "test",
448                         reflectType: func() reflect.Type {
449                                 type s struct {
450                                         Field int
451                                 }
452                                 return reflect.TypeOf((*s)(nil))
453                         }(),
454                         defaults: nil,
455                         help:     "1. field (json-type-numeric, help-required) test-field\n",
456                 },
457                 {
458                         name:   "command with one optional arg, no default",
459                         method: "test",
460                         reflectType: func() reflect.Type {
461                                 type s struct {
462                                         Optional *int
463                                 }
464                                 return reflect.TypeOf((*s)(nil))
465                         }(),
466                         defaults: nil,
467                         help:     "1. optional (json-type-numeric, help-optional) test-optional\n",
468                 },
469                 {
470                         name:   "command with one optional arg with default",
471                         method: "test",
472                         reflectType: func() reflect.Type {
473                                 type s struct {
474                                         Optional *string
475                                 }
476                                 return reflect.TypeOf((*s)(nil))
477                         }(),
478                         defaults: func() map[int]reflect.Value {
479                                 defVal := "test"
480                                 return map[int]reflect.Value{
481                                         0: reflect.ValueOf(&defVal),
482                                 }
483                         }(),
484                         help: "1. optional (json-type-string, help-optional, help-default=\"test\") test-optional\n",
485                 },
486                 {
487                         name:   "command with struct field",
488                         method: "test",
489                         reflectType: func() reflect.Type {
490                                 type s2 struct {
491                                         F int8
492                                 }
493                                 type s struct {
494                                         Field s2
495                                 }
496                                 return reflect.TypeOf((*s)(nil))
497                         }(),
498                         defaults: nil,
499                         help: "1. field (json-type-object, help-required) test-field\n" +
500                                 "{\n" +
501                                 " \"f\": n, (json-type-numeric) s2-f\n" +
502                                 "}        \n",
503                 },
504                 {
505                         name:   "command with map field",
506                         method: "test",
507                         reflectType: func() reflect.Type {
508                                 type s struct {
509                                         Field map[string]float64
510                                 }
511                                 return reflect.TypeOf((*s)(nil))
512                         }(),
513                         defaults: nil,
514                         help: "1. field (json-type-object, help-required) test-field\n" +
515                                 "{\n" +
516                                 " \"test-field--key\": test-field--value, (json-type-object) test-field--desc\n" +
517                                 " ...\n" +
518                                 "}\n",
519                 },
520                 {
521                         name:   "command with slice of primitives field",
522                         method: "test",
523                         reflectType: func() reflect.Type {
524                                 type s struct {
525                                         Field []int64
526                                 }
527                                 return reflect.TypeOf((*s)(nil))
528                         }(),
529                         defaults: nil,
530                         help:     "1. field (json-type-arrayjson-type-numeric, help-required) test-field\n",
531                 },
532                 {
533                         name:   "command with slice of structs field",
534                         method: "test",
535                         reflectType: func() reflect.Type {
536                                 type s2 struct {
537                                         F int64
538                                 }
539                                 type s struct {
540                                         Field []s2
541                                 }
542                                 return reflect.TypeOf((*s)(nil))
543                         }(),
544                         defaults: nil,
545                         help: "1. field (json-type-arrayjson-type-object, help-required) test-field\n" +
546                                 "[{\n" +
547                                 " \"f\": n, (json-type-numeric) s2-f\n" +
548                                 "},...]\n",
549                 },
550         }
551
552         xT := func(key string) string {
553                 return key
554         }
555
556         t.Logf("Running %d tests", len(tests))
557         for i, test := range tests {
558                 help := btcjson.TstArgHelp(xT, test.reflectType, test.defaults,
559                         test.method)
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)
563                         continue
564                 }
565         }
566 }
567
568 // TestMethodHelp ensures the method help function works as expected for various
569 // command structs.
570 func TestMethodHelp(t *testing.T) {
571         t.Parallel()
572
573         tests := []struct {
574                 name        string
575                 method      string
576                 reflectType reflect.Type
577                 defaults    map[int]reflect.Value
578                 resultTypes []interface{}
579                 help        string
580         }{
581                 {
582                         name:   "command with no args or results",
583                         method: "test",
584                         reflectType: func() reflect.Type {
585                                 type s struct{}
586                                 return reflect.TypeOf((*s)(nil))
587                         }(),
588                         help: "test\n\ntest--synopsis\n\n" +
589                                 "help-arguments:\nhelp-arguments-none\n\n" +
590                                 "help-result:\nhelp-result-nothing\n",
591                 },
592                 {
593                         name:   "command with no args and one primitive result",
594                         method: "test",
595                         reflectType: func() reflect.Type {
596                                 type s struct{}
597                                 return reflect.TypeOf((*s)(nil))
598                         }(),
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",
603                 },
604                 {
605                         name:   "command with no args and two results",
606                         method: "test",
607                         reflectType: func() reflect.Type {
608                                 type s struct{}
609                                 return reflect.TypeOf((*s)(nil))
610                         }(),
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",
616                 },
617                 {
618                         name:   "command with primitive arg and no results",
619                         method: "test",
620                         reflectType: func() reflect.Type {
621                                 type s struct {
622                                         Field bool
623                                 }
624                                 return reflect.TypeOf((*s)(nil))
625                         }(),
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",
629                 },
630                 {
631                         name:   "command with primitive optional and no results",
632                         method: "test",
633                         reflectType: func() reflect.Type {
634                                 type s struct {
635                                         Field *bool
636                                 }
637                                 return reflect.TypeOf((*s)(nil))
638                         }(),
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",
642                 },
643         }
644
645         xT := func(key string) string {
646                 return key
647         }
648
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)
656                         continue
657                 }
658         }
659 }
660
661 // TestGenerateHelpErrors ensures the GenerateHelp function returns the expected
662 // errors.
663 func TestGenerateHelpErrors(t *testing.T) {
664         t.Parallel()
665
666         tests := []struct {
667                 name        string
668                 method      string
669                 resultTypes []interface{}
670                 err         btcjson.Error
671         }{
672                 {
673                         name:   "unregistered command",
674                         method: "boguscommand",
675                         err:    btcjson.Error{ErrorCode: btcjson.ErrUnregisteredMethod},
676                 },
677                 {
678                         name:        "non-pointer result type",
679                         method:      "help",
680                         resultTypes: []interface{}{0},
681                         err:         btcjson.Error{ErrorCode: btcjson.ErrInvalidType},
682                 },
683                 {
684                         name:        "invalid result type",
685                         method:      "help",
686                         resultTypes: []interface{}{(*complex64)(nil)},
687                         err:         btcjson.Error{ErrorCode: btcjson.ErrInvalidType},
688                 },
689                 {
690                         name:        "missing description",
691                         method:      "help",
692                         resultTypes: []interface{}{(*string)(nil), nil},
693                         err:         btcjson.Error{ErrorCode: btcjson.ErrMissingDescription},
694                 },
695         }
696
697         t.Logf("Running %d tests", len(tests))
698         for i, test := range tests {
699                 _, err := btcjson.GenerateHelp(test.method, nil,
700                         test.resultTypes...)
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)
704                         continue
705                 }
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)
711                         continue
712                 }
713         }
714 }
715
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) {
720         t.Parallel()
721
722         descs := map[string]string{
723                 "help--synopsis": "test",
724                 "help-command":   "test",
725         }
726         help, err := btcjson.GenerateHelp("help", descs)
727         if err != nil {
728                 t.Fatalf("GenerateHelp: unexpected error: %v", err)
729         }
730         wantHelp := "help (\"command\")\n\n" +
731                 "test\n\nArguments:\n1. command (string, optional) test\n\n" +
732                 "Result:\nNothing\n"
733         if help != wantHelp {
734                 t.Fatalf("GenerateHelp: unexpected help - got\n%v\nwant\n%v",
735                         help, wantHelp)
736         }
737 }