decred.org/dcrdex@v1.0.5/client/rpcserver/types_test.go (about)

     1  // This code is available on the terms of the project LICENSE.md file,
     2  // also available online at https://blueoakcouncil.org/license/1.0.0.
     3  
     4  package rpcserver
     5  
     6  import (
     7  	"bytes"
     8  	"errors"
     9  	"fmt"
    10  	"testing"
    11  
    12  	"decred.org/dcrdex/dex/encode"
    13  )
    14  
    15  func TestCheckNArgs(t *testing.T) {
    16  	tests := []struct {
    17  		name      string
    18  		have      []string
    19  		wantNArgs []int
    20  		wantErr   bool
    21  	}{{
    22  		name:      "ok exact",
    23  		have:      []string{"1", "2", "3"},
    24  		wantNArgs: []int{3},
    25  		wantErr:   false,
    26  	}, {
    27  		name:      "ok between",
    28  		have:      []string{"1", "2", "3"},
    29  		wantNArgs: []int{2, 4},
    30  		wantErr:   false,
    31  	}, {
    32  		name:      "ok lower",
    33  		have:      []string{"1", "2"},
    34  		wantNArgs: []int{2, 4},
    35  		wantErr:   false,
    36  	}, {
    37  		name:      "ok upper",
    38  		have:      []string{"1", "2", "3", "4"},
    39  		wantNArgs: []int{2, 4},
    40  		wantErr:   false,
    41  	}, {
    42  		name:      "not exact",
    43  		have:      []string{"1", "2", "3"},
    44  		wantNArgs: []int{2},
    45  		wantErr:   true,
    46  	}, {
    47  		name:      "too few",
    48  		have:      []string{"1", "2"},
    49  		wantNArgs: []int{3, 5},
    50  		wantErr:   true,
    51  	}, {
    52  		name:      "too many",
    53  		have:      []string{"1", "2", "3", "4", "5", "6"},
    54  		wantNArgs: []int{2, 5},
    55  		wantErr:   true,
    56  	}}
    57  	for _, test := range tests {
    58  		pwArgs := make([]encode.PassBytes, len(test.have))
    59  		for i, testValue := range test.have {
    60  			pwArgs[i] = encode.PassBytes(testValue)
    61  		}
    62  		err := checkNArgs(&RawParams{PWArgs: pwArgs, Args: test.have}, test.wantNArgs, test.wantNArgs)
    63  		if test.wantErr {
    64  			if err != nil {
    65  				continue
    66  			}
    67  			t.Fatalf("expected error for test %v", test.name)
    68  		}
    69  		if err != nil {
    70  			t.Fatalf("unexpected error %v for test %s", err, test.name)
    71  		}
    72  	}
    73  }
    74  
    75  func TestParseNewWalletArgs(t *testing.T) {
    76  	paramsWithAssetID := func(id string) *RawParams {
    77  		pw := encode.PassBytes("password123")
    78  		pwArgs := []encode.PassBytes{pw, pw}
    79  		args := []string{
    80  			id,
    81  			"spv",
    82  			"rpclisten=127.0.0.0",
    83  		}
    84  		return &RawParams{PWArgs: pwArgs, Args: args}
    85  	}
    86  	tests := []struct {
    87  		name    string
    88  		params  *RawParams
    89  		wantErr error
    90  	}{{
    91  		name:   "ok",
    92  		params: paramsWithAssetID("42"),
    93  	}, {
    94  		name:    "assetID is not int",
    95  		params:  paramsWithAssetID("42.1"),
    96  		wantErr: errArgs,
    97  	}}
    98  	for _, test := range tests {
    99  		nwf, err := parseNewWalletArgs(test.params)
   100  		if test.wantErr != nil {
   101  			if errors.Is(err, test.wantErr) {
   102  				continue
   103  			}
   104  			t.Fatalf("expected error for test %v", test.name)
   105  		}
   106  		if err != nil {
   107  			t.Fatalf("unexpected error %v for test %s", err, test.name)
   108  		}
   109  		if !bytes.Equal(nwf.appPass, test.params.PWArgs[0]) {
   110  			t.Fatalf("appPass doesn't match")
   111  		}
   112  		if !bytes.Equal(nwf.walletPass, test.params.PWArgs[1]) {
   113  			t.Fatalf("walletPass doesn't match")
   114  		}
   115  		if fmt.Sprint(nwf.assetID) != test.params.Args[0] {
   116  			t.Fatalf("assetID doesn't match")
   117  		}
   118  		if len(nwf.config) != 1 {
   119  			t.Fatalf("config length mismatch. expected 1, got %d", len(nwf.config))
   120  		}
   121  		v, found := nwf.config["rpclisten"]
   122  		if !found || v != "127.0.0.0" {
   123  			t.Fatalf("config opt mismatch. %s != 127.0.0.0 (found = %t)", v, found)
   124  		}
   125  	}
   126  }
   127  
   128  func TestParseOpenWalletArgs(t *testing.T) {
   129  	paramsWithAssetID := func(id string) *RawParams {
   130  		pw := encode.PassBytes("password123")
   131  		pwArgs := []encode.PassBytes{pw}
   132  		args := []string{id}
   133  		return &RawParams{PWArgs: pwArgs, Args: args}
   134  	}
   135  	tests := []struct {
   136  		name    string
   137  		params  *RawParams
   138  		wantErr error
   139  	}{{
   140  		name:   "ok",
   141  		params: paramsWithAssetID("42"),
   142  	}, {
   143  		name:    "assetID is not int",
   144  		params:  paramsWithAssetID("42.1"),
   145  		wantErr: errArgs,
   146  	}}
   147  	for _, test := range tests {
   148  		owf, err := parseOpenWalletArgs(test.params)
   149  		if test.wantErr != nil {
   150  			if errors.Is(err, test.wantErr) {
   151  				continue
   152  			}
   153  			t.Fatalf("expected error for test %v", test.name)
   154  		}
   155  		if err != nil {
   156  			t.Fatalf("unexpected error %v for test %s", err, test.name)
   157  		}
   158  		if !bytes.Equal(owf.appPass, test.params.PWArgs[0]) {
   159  			t.Fatalf("appPass doesn't match")
   160  		}
   161  		if fmt.Sprint(owf.assetID) != test.params.Args[0] {
   162  			t.Fatalf("assetID doesn't match")
   163  		}
   164  	}
   165  }
   166  
   167  func TestCheckUIntArg(t *testing.T) {
   168  	tests := []struct {
   169  		name    string
   170  		arg     string
   171  		want    uint64
   172  		bitSize int
   173  		wantErr error
   174  	}{{
   175  		name:    "ok",
   176  		arg:     "4294967295",
   177  		want:    4294967295,
   178  		bitSize: 32,
   179  	}, {
   180  		name:    "too big",
   181  		arg:     "4294967296",
   182  		bitSize: 32,
   183  		wantErr: errArgs,
   184  	}, {
   185  		name:    "not int",
   186  		arg:     "42.1",
   187  		bitSize: 32,
   188  		wantErr: errArgs,
   189  	}, {
   190  		name:    "negative",
   191  		arg:     "-42",
   192  		bitSize: 32,
   193  		wantErr: errArgs,
   194  	}}
   195  	for _, test := range tests {
   196  		res, err := checkUIntArg(test.arg, "name", test.bitSize)
   197  		if test.wantErr != nil {
   198  			if errors.Is(err, test.wantErr) {
   199  				continue
   200  			}
   201  			t.Fatalf("expected error for test %v", test.name)
   202  		}
   203  		if err != nil {
   204  			t.Fatalf("unexpected error %v for test %s", err, test.name)
   205  		}
   206  		if res != test.want {
   207  			t.Fatalf("expected %d but got %d for test %q", test.want, res, test.name)
   208  		}
   209  	}
   210  }
   211  
   212  func TestCheckBoolArg(t *testing.T) {
   213  	tests := []struct {
   214  		name    string
   215  		arg     string
   216  		want    bool
   217  		wantErr error
   218  	}{{
   219  		name: "ok string lower",
   220  		arg:  "true",
   221  		want: true,
   222  	}, {
   223  		name: "ok string upper",
   224  		arg:  "False",
   225  		want: false,
   226  	}, {
   227  		name: "ok int",
   228  		arg:  "1",
   229  		want: true,
   230  	}, {
   231  		name:    "string but not true or false",
   232  		arg:     "blue",
   233  		wantErr: errArgs,
   234  	}, {
   235  		name:    "int but not 0 or 1",
   236  		arg:     "2",
   237  		wantErr: errArgs,
   238  	}}
   239  	for _, test := range tests {
   240  		res, err := checkBoolArg(test.arg, "name")
   241  		if test.wantErr != nil {
   242  			if errors.Is(err, test.wantErr) {
   243  				continue
   244  			}
   245  			t.Fatalf("expected error for test %v", test.name)
   246  		}
   247  		if err != nil {
   248  			t.Fatalf("unexpected error %v for test %s", err, test.name)
   249  		}
   250  		if res != test.want {
   251  			t.Fatalf("wanted %v but got %v for test %v", test.want, res, test.name)
   252  		}
   253  	}
   254  }
   255  
   256  // TODO: TestParseBondAssetArgs
   257  
   258  func TestParseGetDEXConfigArgs(t *testing.T) {
   259  	tests := []struct {
   260  		name    string
   261  		params  *RawParams
   262  		wantErr error
   263  	}{{
   264  		name:   "host and cert",
   265  		params: &RawParams{PWArgs: nil, Args: []string{"host", "cert bytes"}},
   266  	}, {
   267  		name:   "just host",
   268  		params: &RawParams{PWArgs: nil, Args: []string{"host"}},
   269  	}}
   270  	for _, test := range tests {
   271  		host, cert, err := parseGetDEXConfigArgs(test.params)
   272  		if test.wantErr != nil {
   273  			if errors.Is(err, test.wantErr) {
   274  				continue
   275  			}
   276  			t.Fatalf("expected error for test %v", test.name)
   277  		}
   278  		if err != nil {
   279  			t.Fatalf("unexpected error %v for test %s", err, test.name)
   280  		}
   281  		if host != test.params.Args[0] {
   282  			t.Fatalf("url doesn't match")
   283  		}
   284  		if len(test.params.Args) > 1 && string(cert) != test.params.Args[1] {
   285  			t.Fatalf("cert doesn't match")
   286  		}
   287  	}
   288  }
   289  
   290  func TestParseHelpArgs(t *testing.T) {
   291  	tests := []struct {
   292  		name    string
   293  		args    []string
   294  		want    *helpForm
   295  		wantErr error
   296  	}{{
   297  		name: "ok no args",
   298  		want: &helpForm{},
   299  	}, {
   300  		name: "ok help with",
   301  		args: []string{"thing"},
   302  		want: &helpForm{helpWith: "thing"},
   303  	}, {
   304  		name: "ok help with include passwords",
   305  		args: []string{"thing", "true"},
   306  		want: &helpForm{helpWith: "thing", includePasswords: true},
   307  	}, {
   308  		name:    "include passwords not boolean",
   309  		args:    []string{"thing", "thing2"},
   310  		wantErr: errArgs,
   311  	}}
   312  	for _, test := range tests {
   313  		form, err := parseHelpArgs(&RawParams{Args: test.args})
   314  		if test.wantErr != nil {
   315  			if errors.Is(err, test.wantErr) {
   316  				continue
   317  			}
   318  			t.Fatalf("expected error for test %v", test.name)
   319  		}
   320  		if err != nil {
   321  			t.Fatalf("unexpected error %v for test %s", err, test.name)
   322  		}
   323  		if len(test.args) > 0 && form.helpWith != test.args[0] {
   324  			t.Fatalf("helpwith doesn't match")
   325  		}
   326  		if len(test.args) > 1 && fmt.Sprint(form.includePasswords) != test.args[1] {
   327  			t.Fatalf("includepasswords doesn't match")
   328  		}
   329  	}
   330  }
   331  
   332  func TestTradeArgs(t *testing.T) {
   333  	pw := encode.PassBytes("password123")
   334  	goodParams := &RawParams{
   335  		PWArgs: []encode.PassBytes{pw}, // 0. AppPass
   336  		Args: []string{
   337  			"1.2.3.4:3000", // 0. Host
   338  			"true",         // 1. IsLimit
   339  			"true",         // 2. Sell
   340  			"0",            // 3. Base
   341  			"42",           // 4. Quote
   342  			"1",            // 5. Qty
   343  			"1",            // 6. Rate
   344  			"true",         // 7. TifNow
   345  			`{"gas_price":"23","gas_limit":"120000"}`, // 8. Options
   346  		}}
   347  	paramsWith := func(idx int, thing string) *RawParams {
   348  		newParams := &RawParams{
   349  			PWArgs: make([]encode.PassBytes, 1),
   350  			Args:   make([]string, 9),
   351  		}
   352  		copy(newParams.PWArgs, goodParams.PWArgs)
   353  		copy(newParams.Args, goodParams.Args)
   354  		newParams.Args[idx] = thing
   355  		return newParams
   356  	}
   357  	tests := []struct {
   358  		name    string
   359  		params  *RawParams
   360  		wantErr error
   361  	}{{
   362  		name:   "ok",
   363  		params: goodParams,
   364  	}, {
   365  		name:    "isLimit not bool",
   366  		params:  paramsWith(1, "blue"),
   367  		wantErr: errArgs,
   368  	}, {
   369  		name:    "sell not bool",
   370  		params:  paramsWith(2, "blue"),
   371  		wantErr: errArgs,
   372  	}, {
   373  		name:    "base not uint32",
   374  		params:  paramsWith(3, "-1"),
   375  		wantErr: errArgs,
   376  	}, {
   377  		name:    "quote not uint32",
   378  		params:  paramsWith(4, "-1"),
   379  		wantErr: errArgs,
   380  	}, {
   381  		name:    "qty not uint64",
   382  		params:  paramsWith(5, "-1"),
   383  		wantErr: errArgs,
   384  	}, {
   385  		name:    "rate not uint64",
   386  		params:  paramsWith(6, "-1"),
   387  		wantErr: errArgs,
   388  	}, {
   389  		name:    "tifnow not bool",
   390  		params:  paramsWith(7, "blue"),
   391  		wantErr: errArgs,
   392  	}, {
   393  		name:    "options not map[string]string",
   394  		params:  paramsWith(8, "blue"),
   395  		wantErr: errArgs,
   396  	}}
   397  	for _, test := range tests {
   398  		reg, err := parseTradeArgs(test.params)
   399  		if test.wantErr != nil {
   400  			if errors.Is(err, test.wantErr) {
   401  				continue
   402  			}
   403  			t.Fatalf("expected error for test %v", test.name)
   404  		}
   405  		if err != nil {
   406  			t.Fatalf("unexpected error %v for test %s", err, test.name)
   407  		}
   408  		if !bytes.Equal(reg.appPass, test.params.PWArgs[0]) {
   409  			t.Fatalf("AppPass doesn't match")
   410  		}
   411  		if reg.srvForm.Host != test.params.Args[0] {
   412  			t.Fatalf("Host doesn't match")
   413  		}
   414  		if fmt.Sprint(reg.srvForm.IsLimit) != test.params.Args[1] {
   415  			t.Fatalf("IsLimit doesn't match")
   416  		}
   417  		if fmt.Sprint(reg.srvForm.Sell) != test.params.Args[2] {
   418  			t.Fatalf("Sell doesn't match")
   419  		}
   420  		if fmt.Sprint(reg.srvForm.Base) != test.params.Args[3] {
   421  			t.Fatalf("Base doesn't match")
   422  		}
   423  		if fmt.Sprint(reg.srvForm.Quote) != test.params.Args[4] {
   424  			t.Fatalf("Quote doesn't match")
   425  		}
   426  		if fmt.Sprint(reg.srvForm.Qty) != test.params.Args[5] {
   427  			t.Fatalf("Qty doesn't match")
   428  		}
   429  		if fmt.Sprint(reg.srvForm.Rate) != test.params.Args[6] {
   430  			t.Fatalf("Rate doesn't match")
   431  		}
   432  		if fmt.Sprint(reg.srvForm.TifNow) != test.params.Args[7] {
   433  			t.Fatalf("TifNow doesn't match")
   434  		}
   435  		wantOptions := fmt.Sprintf(
   436  			`{"%s":"%s","%s":"%s"}`,
   437  			"gas_price",
   438  			reg.srvForm.Options["gas_price"],
   439  			"gas_limit",
   440  			reg.srvForm.Options["gas_limit"],
   441  		)
   442  		if wantOptions != test.params.Args[8] {
   443  			t.Fatalf("Options doesn't match")
   444  		}
   445  	}
   446  }
   447  
   448  func TestParseCancelArgs(t *testing.T) {
   449  	paramsWithOrderID := func(orderID string) *RawParams {
   450  		return &RawParams{Args: []string{orderID}}
   451  	}
   452  	tests := []struct {
   453  		name    string
   454  		params  *RawParams
   455  		wantErr error
   456  	}{{
   457  		name:   "ok",
   458  		params: paramsWithOrderID("fb94fe99e4e32200a341f0f1cb33f34a08ac23eedab636e8adb991fa76343e1e"),
   459  	}, {
   460  		name:    "order ID incorrect length",
   461  		params:  paramsWithOrderID("94fe99e4e32200a341f0f1cb33f34a08ac23eedab636e8adb991fa76343e1e"),
   462  		wantErr: errArgs,
   463  	}, {
   464  		name:    "order ID not hex",
   465  		params:  paramsWithOrderID("zb94fe99e4e32200a341f0f1cb33f34a08ac23eedab636e8adb991fa76343e1e"),
   466  		wantErr: errArgs,
   467  	}}
   468  	for _, test := range tests {
   469  		reg, err := parseCancelArgs(test.params)
   470  		if test.wantErr != nil {
   471  			if errors.Is(err, test.wantErr) {
   472  				continue
   473  			}
   474  			t.Fatalf("expected error for test %v", test.name)
   475  		}
   476  		if err != nil {
   477  			t.Fatalf("unexpected error %v for test %s", err, test.name)
   478  		}
   479  		if fmt.Sprint(reg.orderID) != test.params.Args[0] {
   480  			t.Fatalf("order ID doesn't match")
   481  		}
   482  	}
   483  }
   484  
   485  func TestParseSendOrWithdrawArgs(t *testing.T) {
   486  	paramsWithArgs := func(id, value string) *RawParams {
   487  		pw := encode.PassBytes("password123")
   488  		pwArgs := []encode.PassBytes{pw}
   489  		args := []string{
   490  			id,
   491  			value,
   492  			"abc",
   493  		}
   494  		return &RawParams{PWArgs: pwArgs, Args: args}
   495  	}
   496  	tests := []struct {
   497  		name    string
   498  		params  *RawParams
   499  		wantErr error
   500  	}{{
   501  		name:   "ok",
   502  		params: paramsWithArgs("42", "5000"),
   503  	}, {
   504  		name:    "assetID is not int",
   505  		params:  paramsWithArgs("42.1", "5000"),
   506  		wantErr: errArgs,
   507  	}}
   508  	for _, test := range tests {
   509  		res, err := parseSendOrWithdrawArgs(test.params)
   510  		if test.wantErr != nil {
   511  			if errors.Is(err, test.wantErr) {
   512  				continue
   513  			}
   514  			t.Fatalf("expected error for test %v", test.name)
   515  		}
   516  		if err != nil {
   517  			t.Fatalf("unexpected error %v for test %s", err, test.name)
   518  		}
   519  		if !bytes.Equal(res.appPass, test.params.PWArgs[0]) {
   520  			t.Fatalf("appPass doesn't match")
   521  		}
   522  		if fmt.Sprint(res.assetID) != test.params.Args[0] {
   523  			t.Fatalf("assetID doesn't match")
   524  		}
   525  		if fmt.Sprint(res.value) != test.params.Args[1] {
   526  			t.Fatalf("value doesn't match")
   527  		}
   528  		if res.address != test.params.Args[2] {
   529  			t.Fatalf("address doesn't match")
   530  		}
   531  	}
   532  }
   533  
   534  func TestParseOrderBookArgs(t *testing.T) {
   535  	paramsWithArgs := func(base, quote, nOrders string) *RawParams {
   536  		args := []string{
   537  			"dex",
   538  			base,
   539  			quote,
   540  			nOrders,
   541  		}
   542  		return &RawParams{Args: args}
   543  	}
   544  	tests := []struct {
   545  		name    string
   546  		params  *RawParams
   547  		wantErr error
   548  	}{{
   549  		name:   "ok with nOrders",
   550  		params: paramsWithArgs("42", "0", "1"),
   551  	}, {
   552  		name:   "ok no nOrders",
   553  		params: &RawParams{Args: []string{"dex", "42", "0"}},
   554  	}, {
   555  		name:    "base not int",
   556  		params:  paramsWithArgs("42.1", "0", "1"),
   557  		wantErr: errArgs,
   558  	}, {
   559  		name:    "quote not int",
   560  		params:  paramsWithArgs("42", "0.1", "1"),
   561  		wantErr: errArgs,
   562  	}, {
   563  		name:    "nOrders not int",
   564  		params:  paramsWithArgs("42", "0.1", "1.1"),
   565  		wantErr: errArgs,
   566  	}}
   567  	for _, test := range tests {
   568  		res, err := parseOrderBookArgs(test.params)
   569  		if test.wantErr != nil {
   570  			if errors.Is(err, test.wantErr) {
   571  				continue
   572  			}
   573  			t.Fatalf("expected error for test %v", test.name)
   574  		}
   575  		if err != nil {
   576  			t.Fatalf("unexpected error %v for test %s", err, test.name)
   577  		}
   578  		if res.host != test.params.Args[0] {
   579  			t.Fatalf("host doesn't match")
   580  		}
   581  		if fmt.Sprint(res.base) != test.params.Args[1] {
   582  			t.Fatalf("base doesn't match")
   583  		}
   584  		if fmt.Sprint(res.quote) != test.params.Args[2] {
   585  			t.Fatalf("quote doesn't match")
   586  		}
   587  		if len(test.params.Args) > 3 {
   588  			if fmt.Sprint(res.nOrders) != test.params.Args[3] {
   589  				t.Fatalf("nOrders doesn't match")
   590  			}
   591  		}
   592  	}
   593  }
   594  
   595  func TestMyOrdersArgs(t *testing.T) {
   596  	paramsWithArgs := func(ss ...string) *RawParams {
   597  		args := []string{}
   598  		args = append(args, ss...)
   599  		return &RawParams{Args: args}
   600  	}
   601  	tests := []struct {
   602  		name    string
   603  		params  *RawParams
   604  		wantErr error
   605  	}{{
   606  		name:   "ok no params",
   607  		params: paramsWithArgs(),
   608  	}, {
   609  		name:   "ok with host",
   610  		params: paramsWithArgs("host"),
   611  	}, {
   612  		name:   "ok with host, base, and quote",
   613  		params: paramsWithArgs("host", "0", "42"),
   614  	}, {
   615  		name:   "ok with blank host, base, and quote",
   616  		params: paramsWithArgs("", "0", "42"),
   617  	}, {
   618  		name:    "base but no quote",
   619  		params:  paramsWithArgs("host", "0"),
   620  		wantErr: errArgs,
   621  	}, {
   622  		name:    "base not uint32",
   623  		params:  paramsWithArgs("host", "0.1", "42"),
   624  		wantErr: errArgs,
   625  	}, {
   626  		name:    "quote not uint32",
   627  		params:  paramsWithArgs("host", "0", "blue"),
   628  		wantErr: errArgs,
   629  	}}
   630  	for _, test := range tests {
   631  		res, err := parseMyOrdersArgs(test.params)
   632  		if test.wantErr != nil {
   633  			if errors.Is(err, test.wantErr) {
   634  				continue
   635  			}
   636  			t.Fatalf("expected error for test %v", test.name)
   637  		}
   638  		if err != nil {
   639  			t.Fatalf("unexpected error %v for test %s", err, test.name)
   640  		}
   641  		if len(test.params.Args) > 0 && res.host != test.params.Args[0] {
   642  			t.Fatalf("host doesn't match")
   643  		}
   644  		if len(test.params.Args) > 1 && fmt.Sprint(*res.base) != test.params.Args[1] {
   645  			t.Fatalf("base doesn't match")
   646  		}
   647  		if len(test.params.Args) > 2 && fmt.Sprint(*res.quote) != test.params.Args[2] {
   648  			t.Fatalf("quote doesn't match")
   649  		}
   650  	}
   651  }
   652  
   653  func TestParseAppSeedArgs(t *testing.T) {
   654  	pw := encode.PassBytes("password123")
   655  	pwArgs := []encode.PassBytes{pw}
   656  	args := &RawParams{PWArgs: pwArgs}
   657  	tests := []struct {
   658  		name    string
   659  		params  *RawParams
   660  		wantErr error
   661  	}{{
   662  		name:   "ok",
   663  		params: args,
   664  	}, {
   665  		name:    "no pass",
   666  		params:  &RawParams{},
   667  		wantErr: errArgs,
   668  	}}
   669  	for _, test := range tests {
   670  		appPass, err := parseAppSeedArgs(test.params)
   671  		if test.wantErr != nil {
   672  			if errors.Is(err, test.wantErr) {
   673  				continue
   674  			}
   675  			t.Fatalf("expected error for test %v", test.name)
   676  		}
   677  		if err != nil {
   678  			t.Fatalf("unexpected error %v for test %s", err, test.name)
   679  		}
   680  		if !bytes.Equal(appPass, test.params.PWArgs[0]) {
   681  			t.Fatalf("appPass doesn't match")
   682  		}
   683  	}
   684  }
   685  
   686  func TestParseDiscoverAcctArgs(t *testing.T) {
   687  	pw := encode.PassBytes("password123")
   688  	pwArgs := []encode.PassBytes{pw}
   689  	args := []string{"dex address", "da cert"}
   690  	tests := []struct {
   691  		name    string
   692  		params  *RawParams
   693  		wantErr error
   694  	}{{
   695  		name:   "ok",
   696  		params: &RawParams{PWArgs: pwArgs, Args: args},
   697  	}}
   698  	for _, test := range tests {
   699  		reg, err := parseDiscoverAcctArgs(test.params)
   700  		if test.wantErr != nil {
   701  			if errors.Is(err, test.wantErr) {
   702  				continue
   703  			}
   704  			t.Fatalf("expected error for test %v", test.name)
   705  		}
   706  		if err != nil {
   707  			t.Fatalf("unexpected error %v for test %s", err, test.name)
   708  		}
   709  		if !bytes.Equal(reg.appPass, test.params.PWArgs[0]) {
   710  			t.Fatalf("appPass doesn't match")
   711  		}
   712  		if reg.addr != test.params.Args[0] {
   713  			t.Fatalf("url doesn't match")
   714  		}
   715  		if string(reg.cert.([]byte)) != test.params.Args[1] {
   716  			t.Fatalf("cert doesn't match")
   717  		}
   718  	}
   719  }
   720  
   721  func TestDeleteArchivedRecordsArgs(t *testing.T) {
   722  	paramsWithArgs := func(args ...string) *RawParams {
   723  		return &RawParams{Args: args}
   724  	}
   725  	tests := []struct {
   726  		name    string
   727  		params  *RawParams
   728  		wantErr error
   729  	}{{
   730  		name:   "ok no params",
   731  		params: paramsWithArgs(),
   732  	}, {
   733  		name:   "ok just time",
   734  		params: paramsWithArgs("123"),
   735  	}, {
   736  		name:   "ok just matches file",
   737  		params: paramsWithArgs("", "abc"),
   738  	}, {
   739  		name:   "ok just orders file",
   740  		params: paramsWithArgs("", "", "def"),
   741  	}, {
   742  		name:   "ok all three",
   743  		params: paramsWithArgs("123", "abc", "def"),
   744  	}, {
   745  		name:    "time not a number",
   746  		params:  paramsWithArgs("abc"),
   747  		wantErr: errArgs,
   748  	}}
   749  	for _, test := range tests {
   750  		_, err := parseDeleteArchivedRecordsArgs(test.params)
   751  		if test.wantErr != nil {
   752  			if err != nil {
   753  				continue
   754  			}
   755  			t.Fatalf("%q: expected error", test.name)
   756  		}
   757  		if err != nil {
   758  			t.Fatalf("%q: unexpected error: %v", test.name, err)
   759  		}
   760  	}
   761  }
   762  
   763  func TestParseSetVSPArgs(t *testing.T) {
   764  	paramsWithArgs := func(args ...string) *RawParams {
   765  		return &RawParams{Args: args}
   766  	}
   767  	tests := []struct {
   768  		name    string
   769  		params  *RawParams
   770  		wantErr error
   771  	}{{
   772  		name:   "ok",
   773  		params: paramsWithArgs("42", "asdf"),
   774  	}, {
   775  		name:    "asset ID not a number",
   776  		params:  paramsWithArgs("def", "abc"),
   777  		wantErr: errArgs,
   778  	}}
   779  	for _, test := range tests {
   780  		_, err := parseSetVSPArgs(test.params)
   781  		if test.wantErr != nil {
   782  			if err != nil {
   783  				continue
   784  			}
   785  			t.Fatalf("%q: expected error", test.name)
   786  		}
   787  		if err != nil {
   788  			t.Fatalf("%q: unexpected error: %v", test.name, err)
   789  		}
   790  	}
   791  }
   792  
   793  func TestPurchaseTicketsArgs(t *testing.T) {
   794  	pw := encode.PassBytes("password123")
   795  	pwArgs := []encode.PassBytes{pw}
   796  	paramsWithArgs := func(args ...string) *RawParams {
   797  		return &RawParams{Args: args, PWArgs: pwArgs}
   798  	}
   799  	tests := []struct {
   800  		name    string
   801  		params  *RawParams
   802  		wantErr error
   803  	}{{
   804  		name:   "ok",
   805  		params: paramsWithArgs("42", "4"),
   806  	}, {
   807  		name:    "num of tickets not a number",
   808  		params:  paramsWithArgs("42", "abc"),
   809  		wantErr: errArgs,
   810  	}, {
   811  		name:    "asset ID not a number",
   812  		params:  paramsWithArgs("abc", "4"),
   813  		wantErr: errArgs,
   814  	}}
   815  	for _, test := range tests {
   816  		_, err := parsePurchaseTicketsArgs(test.params)
   817  		if test.wantErr != nil {
   818  			if err != nil {
   819  				continue
   820  			}
   821  			t.Fatalf("%q: expected error", test.name)
   822  		}
   823  		if err != nil {
   824  			t.Fatalf("%q: unexpected error: %v", test.name, err)
   825  		}
   826  	}
   827  }
   828  
   829  func TestStakeStatusArgs(t *testing.T) {
   830  	paramsWithArgs := func(args ...string) *RawParams {
   831  		return &RawParams{Args: args}
   832  	}
   833  	tests := []struct {
   834  		name    string
   835  		params  *RawParams
   836  		wantErr error
   837  	}{{
   838  		name:   "ok",
   839  		params: paramsWithArgs("42"),
   840  	}, {
   841  		name:    "asset ID not a number",
   842  		params:  paramsWithArgs("def"),
   843  		wantErr: errArgs,
   844  	}}
   845  	for _, test := range tests {
   846  		_, err := parseStakeStatusArgs(test.params)
   847  		if test.wantErr != nil {
   848  			if err != nil {
   849  				continue
   850  			}
   851  			t.Fatalf("%q: expected error", test.name)
   852  		}
   853  		if err != nil {
   854  			t.Fatalf("%q: unexpected error: %v", test.name, err)
   855  		}
   856  	}
   857  }
   858  
   859  func TestParseSetVotingPreferencesArgs(t *testing.T) {
   860  	paramsWithArgs := func(args ...string) *RawParams {
   861  		return &RawParams{Args: args}
   862  	}
   863  	aMap := `{"txidA":"yes","txidB":"no"}`
   864  	tests := []struct {
   865  		name    string
   866  		params  *RawParams
   867  		wantErr error
   868  	}{{
   869  		name:   "ok one arg",
   870  		params: paramsWithArgs("42"),
   871  	}, {
   872  		name:   "ok three map args",
   873  		params: paramsWithArgs("42", aMap, aMap, aMap),
   874  	}, {
   875  		name:   "ok two map args",
   876  		params: paramsWithArgs("42", aMap, aMap),
   877  	}, {
   878  		name:   "ok one map arg",
   879  		params: paramsWithArgs("42", aMap),
   880  	}, {
   881  		name:   "ok blank strings",
   882  		params: paramsWithArgs("42", "", "", aMap),
   883  	}, {
   884  		name:    "bad map",
   885  		params:  paramsWithArgs("42", "asdf"),
   886  		wantErr: errArgs,
   887  	}, {
   888  		name:    "asset ID not a number",
   889  		params:  paramsWithArgs("asdf"),
   890  		wantErr: errArgs,
   891  	}}
   892  	for _, test := range tests {
   893  		_, err := parseSetVotingPreferencesArgs(test.params)
   894  		if test.wantErr != nil {
   895  			if err != nil {
   896  				continue
   897  			}
   898  			t.Fatalf("%q: expected error", test.name)
   899  		}
   900  		if err != nil {
   901  			t.Fatalf("%q: unexpected error: %v", test.name, err)
   902  		}
   903  	}
   904  }