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