+++ /dev/null
-// Copyright (c) 2014 The btcsuite developers
-// Use of this source code is governed by an ISC
-// license that can be found in the LICENSE file.
-
-package btcjson_test
-
-import (
- "reflect"
- "testing"
-
- "github.com/btcsuite/btcd/btcjson"
-)
-
-// TestHelpReflectInternals ensures the various help functions which deal with
-// reflect types work as expected for various Go types.
-func TestHelpReflectInternals(t *testing.T) {
- t.Parallel()
-
- tests := []struct {
- name string
- reflectType reflect.Type
- indentLevel int
- key string
- examples []string
- isComplex bool
- help string
- isInvalid bool
- }{
- {
- name: "int",
- reflectType: reflect.TypeOf(int(0)),
- key: "json-type-numeric",
- examples: []string{"n"},
- help: "n (json-type-numeric) fdk",
- },
- {
- name: "*int",
- reflectType: reflect.TypeOf((*int)(nil)),
- key: "json-type-value",
- examples: []string{"n"},
- help: "n (json-type-value) fdk",
- isInvalid: true,
- },
- {
- name: "int8",
- reflectType: reflect.TypeOf(int8(0)),
- key: "json-type-numeric",
- examples: []string{"n"},
- help: "n (json-type-numeric) fdk",
- },
- {
- name: "int16",
- reflectType: reflect.TypeOf(int16(0)),
- key: "json-type-numeric",
- examples: []string{"n"},
- help: "n (json-type-numeric) fdk",
- },
- {
- name: "int32",
- reflectType: reflect.TypeOf(int32(0)),
- key: "json-type-numeric",
- examples: []string{"n"},
- help: "n (json-type-numeric) fdk",
- },
- {
- name: "int64",
- reflectType: reflect.TypeOf(int64(0)),
- key: "json-type-numeric",
- examples: []string{"n"},
- help: "n (json-type-numeric) fdk",
- },
- {
- name: "uint",
- reflectType: reflect.TypeOf(uint(0)),
- key: "json-type-numeric",
- examples: []string{"n"},
- help: "n (json-type-numeric) fdk",
- },
- {
- name: "uint8",
- reflectType: reflect.TypeOf(uint8(0)),
- key: "json-type-numeric",
- examples: []string{"n"},
- help: "n (json-type-numeric) fdk",
- },
- {
- name: "uint16",
- reflectType: reflect.TypeOf(uint16(0)),
- key: "json-type-numeric",
- examples: []string{"n"},
- help: "n (json-type-numeric) fdk",
- },
- {
- name: "uint32",
- reflectType: reflect.TypeOf(uint32(0)),
- key: "json-type-numeric",
- examples: []string{"n"},
- help: "n (json-type-numeric) fdk",
- },
- {
- name: "uint64",
- reflectType: reflect.TypeOf(uint64(0)),
- key: "json-type-numeric",
- examples: []string{"n"},
- help: "n (json-type-numeric) fdk",
- },
- {
- name: "float32",
- reflectType: reflect.TypeOf(float32(0)),
- key: "json-type-numeric",
- examples: []string{"n.nnn"},
- help: "n.nnn (json-type-numeric) fdk",
- },
- {
- name: "float64",
- reflectType: reflect.TypeOf(float64(0)),
- key: "json-type-numeric",
- examples: []string{"n.nnn"},
- help: "n.nnn (json-type-numeric) fdk",
- },
- {
- name: "string",
- reflectType: reflect.TypeOf(""),
- key: "json-type-string",
- examples: []string{`"json-example-string"`},
- help: "\"json-example-string\" (json-type-string) fdk",
- },
- {
- name: "bool",
- reflectType: reflect.TypeOf(true),
- key: "json-type-bool",
- examples: []string{"json-example-bool"},
- help: "json-example-bool (json-type-bool) fdk",
- },
- {
- name: "array of int",
- reflectType: reflect.TypeOf([1]int{0}),
- key: "json-type-arrayjson-type-numeric",
- examples: []string{"[n,...]"},
- help: "[n,...] (json-type-arrayjson-type-numeric) fdk",
- },
- {
- name: "slice of int",
- reflectType: reflect.TypeOf([]int{0}),
- key: "json-type-arrayjson-type-numeric",
- examples: []string{"[n,...]"},
- help: "[n,...] (json-type-arrayjson-type-numeric) fdk",
- },
- {
- name: "struct",
- reflectType: reflect.TypeOf(struct{}{}),
- key: "json-type-object",
- examples: []string{"{", "}\t\t"},
- isComplex: true,
- help: "{\n} ",
- },
- {
- name: "struct indent level 1",
- reflectType: reflect.TypeOf(struct{ field int }{}),
- indentLevel: 1,
- key: "json-type-object",
- examples: []string{
- " \"field\": n,\t(json-type-numeric)\t-field",
- " },\t\t",
- },
- help: "{\n" +
- " \"field\": n, (json-type-numeric) -field\n" +
- "} ",
- isComplex: true,
- },
- {
- name: "array of struct indent level 0",
- reflectType: func() reflect.Type {
- type s struct {
- field int
- }
- return reflect.TypeOf([]s{})
- }(),
- key: "json-type-arrayjson-type-object",
- examples: []string{
- "[{",
- " \"field\": n,\t(json-type-numeric)\ts-field",
- "},...]",
- },
- help: "[{\n" +
- " \"field\": n, (json-type-numeric) s-field\n" +
- "},...]",
- isComplex: true,
- },
- {
- name: "array of struct indent level 1",
- reflectType: func() reflect.Type {
- type s struct {
- field int
- }
- return reflect.TypeOf([]s{})
- }(),
- indentLevel: 1,
- key: "json-type-arrayjson-type-object",
- examples: []string{
- " \"field\": n,\t(json-type-numeric)\ts-field",
- " },...],\t\t",
- },
- help: "[{\n" +
- " \"field\": n, (json-type-numeric) s-field\n" +
- "},...]",
- isComplex: true,
- },
- {
- name: "map",
- reflectType: reflect.TypeOf(map[string]string{}),
- key: "json-type-object",
- examples: []string{"{",
- " \"fdk--key\": fdk--value, (json-type-object) fdk--desc",
- " ...", "}",
- },
- help: "{\n" +
- " \"fdk--key\": fdk--value, (json-type-object) fdk--desc\n" +
- " ...\n" +
- "}",
- isComplex: true,
- },
- {
- name: "complex",
- reflectType: reflect.TypeOf(complex64(0)),
- key: "json-type-value",
- examples: []string{"json-example-unknown"},
- help: "json-example-unknown (json-type-value) fdk",
- isInvalid: true,
- },
- }
-
- xT := func(key string) string {
- return key
- }
-
- t.Logf("Running %d tests", len(tests))
- for i, test := range tests {
- // Ensure the description key is the expected value.
- key := btcjson.TstReflectTypeToJSONType(xT, test.reflectType)
- if key != test.key {
- t.Errorf("Test #%d (%s) unexpected key - got: %v, "+
- "want: %v", i, test.name, key, test.key)
- continue
- }
-
- // Ensure the generated example is as expected.
- examples, isComplex := btcjson.TstReflectTypeToJSONExample(xT,
- test.reflectType, test.indentLevel, "fdk")
- if isComplex != test.isComplex {
- t.Errorf("Test #%d (%s) unexpected isComplex - got: %v, "+
- "want: %v", i, test.name, isComplex,
- test.isComplex)
- continue
- }
- if len(examples) != len(test.examples) {
- t.Errorf("Test #%d (%s) unexpected result length - "+
- "got: %v, want: %v", i, test.name, len(examples),
- len(test.examples))
- continue
- }
- for j, example := range examples {
- if example != test.examples[j] {
- t.Errorf("Test #%d (%s) example #%d unexpected "+
- "example - got: %v, want: %v", i,
- test.name, j, example, test.examples[j])
- continue
- }
- }
-
- // Ensure the generated result type help is as expected.
- helpText := btcjson.TstResultTypeHelp(xT, test.reflectType, "fdk")
- if helpText != test.help {
- t.Errorf("Test #%d (%s) unexpected result help - "+
- "got: %v, want: %v", i, test.name, helpText,
- test.help)
- continue
- }
-
- isValid := btcjson.TstIsValidResultType(test.reflectType.Kind())
- if isValid != !test.isInvalid {
- t.Errorf("Test #%d (%s) unexpected result type validity "+
- "- got: %v", i, test.name, isValid)
- continue
- }
- }
-}
-
-// TestResultStructHelp ensures the expected help text format is returned for
-// various Go struct types.
-func TestResultStructHelp(t *testing.T) {
- t.Parallel()
-
- tests := []struct {
- name string
- reflectType reflect.Type
- expected []string
- }{
- {
- name: "empty struct",
- reflectType: func() reflect.Type {
- type s struct{}
- return reflect.TypeOf(s{})
- }(),
- expected: nil,
- },
- {
- name: "struct with primitive field",
- reflectType: func() reflect.Type {
- type s struct {
- field int
- }
- return reflect.TypeOf(s{})
- }(),
- expected: []string{
- "\"field\": n,\t(json-type-numeric)\ts-field",
- },
- },
- {
- name: "struct with primitive field and json tag",
- reflectType: func() reflect.Type {
- type s struct {
- Field int `json:"f"`
- }
- return reflect.TypeOf(s{})
- }(),
- expected: []string{
- "\"f\": n,\t(json-type-numeric)\ts-f",
- },
- },
- {
- name: "struct with array of primitive field",
- reflectType: func() reflect.Type {
- type s struct {
- field []int
- }
- return reflect.TypeOf(s{})
- }(),
- expected: []string{
- "\"field\": [n,...],\t(json-type-arrayjson-type-numeric)\ts-field",
- },
- },
- {
- name: "struct with sub-struct field",
- reflectType: func() reflect.Type {
- type s2 struct {
- subField int
- }
- type s struct {
- field s2
- }
- return reflect.TypeOf(s{})
- }(),
- expected: []string{
- "\"field\": {\t(json-type-object)\ts-field",
- "{",
- " \"subfield\": n,\t(json-type-numeric)\ts2-subfield",
- "}\t\t",
- },
- },
- {
- name: "struct with sub-struct field pointer",
- reflectType: func() reflect.Type {
- type s2 struct {
- subField int
- }
- type s struct {
- field *s2
- }
- return reflect.TypeOf(s{})
- }(),
- expected: []string{
- "\"field\": {\t(json-type-object)\ts-field",
- "{",
- " \"subfield\": n,\t(json-type-numeric)\ts2-subfield",
- "}\t\t",
- },
- },
- {
- name: "struct with array of structs field",
- reflectType: func() reflect.Type {
- type s2 struct {
- subField int
- }
- type s struct {
- field []s2
- }
- return reflect.TypeOf(s{})
- }(),
- expected: []string{
- "\"field\": [{\t(json-type-arrayjson-type-object)\ts-field",
- "[{",
- " \"subfield\": n,\t(json-type-numeric)\ts2-subfield",
- "},...]",
- },
- },
- }
-
- xT := func(key string) string {
- return key
- }
-
- t.Logf("Running %d tests", len(tests))
- for i, test := range tests {
- results := btcjson.TstResultStructHelp(xT, test.reflectType, 0)
- if len(results) != len(test.expected) {
- t.Errorf("Test #%d (%s) unexpected result length - "+
- "got: %v, want: %v", i, test.name, len(results),
- len(test.expected))
- continue
- }
- for j, result := range results {
- if result != test.expected[j] {
- t.Errorf("Test #%d (%s) result #%d unexpected "+
- "result - got: %v, want: %v", i,
- test.name, j, result, test.expected[j])
- continue
- }
- }
- }
-}
-
-// TestHelpArgInternals ensures the various help functions which deal with
-// arguments work as expected for various argument types.
-func TestHelpArgInternals(t *testing.T) {
- t.Parallel()
-
- tests := []struct {
- name string
- method string
- reflectType reflect.Type
- defaults map[int]reflect.Value
- help string
- }{
- {
- name: "command with no args",
- method: "test",
- reflectType: func() reflect.Type {
- type s struct{}
- return reflect.TypeOf((*s)(nil))
- }(),
- defaults: nil,
- help: "",
- },
- {
- name: "command with one required arg",
- method: "test",
- reflectType: func() reflect.Type {
- type s struct {
- Field int
- }
- return reflect.TypeOf((*s)(nil))
- }(),
- defaults: nil,
- help: "1. field (json-type-numeric, help-required) test-field\n",
- },
- {
- name: "command with one optional arg, no default",
- method: "test",
- reflectType: func() reflect.Type {
- type s struct {
- Optional *int
- }
- return reflect.TypeOf((*s)(nil))
- }(),
- defaults: nil,
- help: "1. optional (json-type-numeric, help-optional) test-optional\n",
- },
- {
- name: "command with one optional arg with default",
- method: "test",
- reflectType: func() reflect.Type {
- type s struct {
- Optional *string
- }
- return reflect.TypeOf((*s)(nil))
- }(),
- defaults: func() map[int]reflect.Value {
- defVal := "test"
- return map[int]reflect.Value{
- 0: reflect.ValueOf(&defVal),
- }
- }(),
- help: "1. optional (json-type-string, help-optional, help-default=\"test\") test-optional\n",
- },
- {
- name: "command with struct field",
- method: "test",
- reflectType: func() reflect.Type {
- type s2 struct {
- F int8
- }
- type s struct {
- Field s2
- }
- return reflect.TypeOf((*s)(nil))
- }(),
- defaults: nil,
- help: "1. field (json-type-object, help-required) test-field\n" +
- "{\n" +
- " \"f\": n, (json-type-numeric) s2-f\n" +
- "} \n",
- },
- {
- name: "command with map field",
- method: "test",
- reflectType: func() reflect.Type {
- type s struct {
- Field map[string]float64
- }
- return reflect.TypeOf((*s)(nil))
- }(),
- defaults: nil,
- help: "1. field (json-type-object, help-required) test-field\n" +
- "{\n" +
- " \"test-field--key\": test-field--value, (json-type-object) test-field--desc\n" +
- " ...\n" +
- "}\n",
- },
- {
- name: "command with slice of primitives field",
- method: "test",
- reflectType: func() reflect.Type {
- type s struct {
- Field []int64
- }
- return reflect.TypeOf((*s)(nil))
- }(),
- defaults: nil,
- help: "1. field (json-type-arrayjson-type-numeric, help-required) test-field\n",
- },
- {
- name: "command with slice of structs field",
- method: "test",
- reflectType: func() reflect.Type {
- type s2 struct {
- F int64
- }
- type s struct {
- Field []s2
- }
- return reflect.TypeOf((*s)(nil))
- }(),
- defaults: nil,
- help: "1. field (json-type-arrayjson-type-object, help-required) test-field\n" +
- "[{\n" +
- " \"f\": n, (json-type-numeric) s2-f\n" +
- "},...]\n",
- },
- }
-
- xT := func(key string) string {
- return key
- }
-
- t.Logf("Running %d tests", len(tests))
- for i, test := range tests {
- help := btcjson.TstArgHelp(xT, test.reflectType, test.defaults,
- test.method)
- if help != test.help {
- t.Errorf("Test #%d (%s) unexpected help - got:\n%v\n"+
- "want:\n%v", i, test.name, help, test.help)
- continue
- }
- }
-}
-
-// TestMethodHelp ensures the method help function works as expected for various
-// command structs.
-func TestMethodHelp(t *testing.T) {
- t.Parallel()
-
- tests := []struct {
- name string
- method string
- reflectType reflect.Type
- defaults map[int]reflect.Value
- resultTypes []interface{}
- help string
- }{
- {
- name: "command with no args or results",
- method: "test",
- reflectType: func() reflect.Type {
- type s struct{}
- return reflect.TypeOf((*s)(nil))
- }(),
- help: "test\n\ntest--synopsis\n\n" +
- "help-arguments:\nhelp-arguments-none\n\n" +
- "help-result:\nhelp-result-nothing\n",
- },
- {
- name: "command with no args and one primitive result",
- method: "test",
- reflectType: func() reflect.Type {
- type s struct{}
- return reflect.TypeOf((*s)(nil))
- }(),
- resultTypes: []interface{}{(*int64)(nil)},
- help: "test\n\ntest--synopsis\n\n" +
- "help-arguments:\nhelp-arguments-none\n\n" +
- "help-result:\nn (json-type-numeric) test--result0\n",
- },
- {
- name: "command with no args and two results",
- method: "test",
- reflectType: func() reflect.Type {
- type s struct{}
- return reflect.TypeOf((*s)(nil))
- }(),
- resultTypes: []interface{}{(*int64)(nil), nil},
- help: "test\n\ntest--synopsis\n\n" +
- "help-arguments:\nhelp-arguments-none\n\n" +
- "help-result (test--condition0):\nn (json-type-numeric) test--result0\n\n" +
- "help-result (test--condition1):\nhelp-result-nothing\n",
- },
- {
- name: "command with primitive arg and no results",
- method: "test",
- reflectType: func() reflect.Type {
- type s struct {
- Field bool
- }
- return reflect.TypeOf((*s)(nil))
- }(),
- help: "test field\n\ntest--synopsis\n\n" +
- "help-arguments:\n1. field (json-type-bool, help-required) test-field\n\n" +
- "help-result:\nhelp-result-nothing\n",
- },
- {
- name: "command with primitive optional and no results",
- method: "test",
- reflectType: func() reflect.Type {
- type s struct {
- Field *bool
- }
- return reflect.TypeOf((*s)(nil))
- }(),
- help: "test (field)\n\ntest--synopsis\n\n" +
- "help-arguments:\n1. field (json-type-bool, help-optional) test-field\n\n" +
- "help-result:\nhelp-result-nothing\n",
- },
- }
-
- xT := func(key string) string {
- return key
- }
-
- t.Logf("Running %d tests", len(tests))
- for i, test := range tests {
- help := btcjson.TestMethodHelp(xT, test.reflectType,
- test.defaults, test.method, test.resultTypes)
- if help != test.help {
- t.Errorf("Test #%d (%s) unexpected help - got:\n%v\n"+
- "want:\n%v", i, test.name, help, test.help)
- continue
- }
- }
-}
-
-// TestGenerateHelpErrors ensures the GenerateHelp function returns the expected
-// errors.
-func TestGenerateHelpErrors(t *testing.T) {
- t.Parallel()
-
- tests := []struct {
- name string
- method string
- resultTypes []interface{}
- err btcjson.Error
- }{
- {
- name: "unregistered command",
- method: "boguscommand",
- err: btcjson.Error{ErrorCode: btcjson.ErrUnregisteredMethod},
- },
- {
- name: "non-pointer result type",
- method: "help",
- resultTypes: []interface{}{0},
- err: btcjson.Error{ErrorCode: btcjson.ErrInvalidType},
- },
- {
- name: "invalid result type",
- method: "help",
- resultTypes: []interface{}{(*complex64)(nil)},
- err: btcjson.Error{ErrorCode: btcjson.ErrInvalidType},
- },
- {
- name: "missing description",
- method: "help",
- resultTypes: []interface{}{(*string)(nil), nil},
- err: btcjson.Error{ErrorCode: btcjson.ErrMissingDescription},
- },
- }
-
- t.Logf("Running %d tests", len(tests))
- for i, test := range tests {
- _, err := btcjson.GenerateHelp(test.method, nil,
- test.resultTypes...)
- if reflect.TypeOf(err) != reflect.TypeOf(test.err) {
- t.Errorf("Test #%d (%s) wrong error - got %T (%[2]v), "+
- "want %T", i, test.name, err, test.err)
- continue
- }
- gotErrorCode := err.(btcjson.Error).ErrorCode
- if gotErrorCode != test.err.ErrorCode {
- t.Errorf("Test #%d (%s) mismatched error code - got "+
- "%v (%v), want %v", i, test.name, gotErrorCode,
- err, test.err.ErrorCode)
- continue
- }
- }
-}
-
-// TestGenerateHelp performs a very basic test to ensure GenerateHelp is working
-// as expected. The internal are testd much more thoroughly in other tests, so
-// there is no need to add more tests here.
-func TestGenerateHelp(t *testing.T) {
- t.Parallel()
-
- descs := map[string]string{
- "help--synopsis": "test",
- "help-command": "test",
- }
- help, err := btcjson.GenerateHelp("help", descs)
- if err != nil {
- t.Fatalf("GenerateHelp: unexpected error: %v", err)
- }
- wantHelp := "help (\"command\")\n\n" +
- "test\n\nArguments:\n1. command (string, optional) test\n\n" +
- "Result:\nNothing\n"
- if help != wantHelp {
- t.Fatalf("GenerateHelp: unexpected help - got\n%v\nwant\n%v",
- help, wantHelp)
- }
-}