github.com/whiteboxio/flow@v0.0.3-0.20190918184116-508d75d68a2c/pkg/cast/converter_test.go (about)

     1  package cast
     2  
     3  import (
     4  	"fmt"
     5  	"reflect"
     6  	"testing"
     7  
     8  	"github.com/awesome-flow/flow/pkg/types"
     9  )
    10  
    11  func intptr(v int) *int       { return &v }
    12  func strptr(v string) *string { return &v }
    13  func boolptr(v bool) *bool    { return &v }
    14  
    15  type convAct struct {
    16  	res types.Value
    17  	ok  bool
    18  }
    19  
    20  type testConverter struct {
    21  	conv func(kv *types.KeyValue) (*types.KeyValue, bool)
    22  }
    23  
    24  var _ Converter = (*testConverter)(nil)
    25  
    26  func newTestConverter(act convAct) *testConverter {
    27  	return &testConverter{
    28  		conv: func(kv *types.KeyValue) (*types.KeyValue, bool) {
    29  			if act.ok {
    30  				return &types.KeyValue{Key: kv.Key, Value: act.res}, act.ok
    31  			}
    32  			return nil, false
    33  		},
    34  	}
    35  }
    36  
    37  func (tc *testConverter) Convert(kv *types.KeyValue) (*types.KeyValue, bool) {
    38  	return tc.conv(kv)
    39  }
    40  
    41  func TestIdentityConverter(t *testing.T) {
    42  	tests := []struct {
    43  		inVal   interface{}
    44  		outVal  interface{}
    45  		outFlag bool
    46  	}{
    47  		{1, 1, true},
    48  		{nil, nil, true},
    49  		{'a', 'a', true},
    50  		{"asdf", "asdf", true},
    51  		{struct{}{}, struct{}{}, true},
    52  	}
    53  
    54  	t.Parallel()
    55  
    56  	for ix, testCase := range tests {
    57  		t.Run(fmt.Sprintf("Test #%d", ix), func(t *testing.T) {
    58  			in := &types.KeyValue{Key: nil, Value: testCase.inVal}
    59  			out, ok := Identity.Convert(in)
    60  			if ok != testCase.outFlag {
    61  				t.Errorf("Unexpected Convert flag: want: %t, got: %t", testCase.outFlag, ok)
    62  			}
    63  			if !ok {
    64  				return
    65  			}
    66  			if out == nil && testCase.outVal != nil {
    67  				t.Errorf("Expected a non-nil result, got nil")
    68  			}
    69  			if !reflect.DeepEqual(testCase.outVal, out.Value) {
    70  				t.Errorf("Unexpected Convert value: want: %#v, got: %#v", testCase.outVal, out.Value)
    71  			}
    72  		})
    73  	}
    74  }
    75  
    76  func TestIntToStrConverter(t *testing.T) {
    77  	tests := []struct {
    78  		inVal   interface{}
    79  		outVal  interface{}
    80  		outFlag bool
    81  	}{
    82  		{1, "1", true},
    83  		{-1, "-1", true},
    84  		{nil, nil, false},
    85  		{'a', nil, false},
    86  		{"asdf", nil, false},
    87  		{struct{}{}, nil, false},
    88  	}
    89  
    90  	t.Parallel()
    91  
    92  	for ix, testCase := range tests {
    93  		t.Run(fmt.Sprintf("Test #%d", ix), func(t *testing.T) {
    94  			in := &types.KeyValue{Key: nil, Value: testCase.inVal}
    95  			out, ok := IntToStr.Convert(in)
    96  			if ok != testCase.outFlag {
    97  				t.Errorf("Unexpected Convert flag: want: %t, got: %t", testCase.outFlag, ok)
    98  			}
    99  			if !ok {
   100  				return
   101  			}
   102  			if out == nil && testCase.outVal != nil {
   103  				t.Errorf("Expected a non-nil result, got nil")
   104  			}
   105  			if !reflect.DeepEqual(testCase.outVal, out.Value) {
   106  				t.Errorf("Unexpected Convert value: want: %#v, got: %#v", testCase.outVal, out.Value)
   107  			}
   108  		})
   109  	}
   110  }
   111  
   112  func TestIntPtrToIntConverter(t *testing.T) {
   113  	tests := []struct {
   114  		inVal   interface{}
   115  		outVal  interface{}
   116  		outFlag bool
   117  	}{
   118  		{1, nil, false},
   119  		{intptr(42), 42, true},
   120  		{nil, nil, false},
   121  		{'a', nil, false},
   122  		{"asdf", nil, false},
   123  		{struct{}{}, nil, false},
   124  	}
   125  
   126  	t.Parallel()
   127  
   128  	for ix, testCase := range tests {
   129  		t.Run(fmt.Sprintf("Test #%d", ix), func(t *testing.T) {
   130  			in := &types.KeyValue{Key: nil, Value: testCase.inVal}
   131  			out, ok := IntPtrToInt.Convert(in)
   132  			if ok != testCase.outFlag {
   133  				t.Errorf("Unexpected Convert flag: want: %t, got: %t", testCase.outFlag, ok)
   134  			}
   135  			if !ok {
   136  				return
   137  			}
   138  			if out == nil && testCase.outVal != nil {
   139  				t.Errorf("Expected a non-nil result, got nil")
   140  			}
   141  			if !reflect.DeepEqual(testCase.outVal, out.Value) {
   142  				t.Errorf("Unexpected Convert value: want: %#v, got: %#v", testCase.outVal, out.Value)
   143  			}
   144  		})
   145  	}
   146  }
   147  
   148  func TestStrPtrToStrConverter(t *testing.T) {
   149  	tests := []struct {
   150  		inVal   interface{}
   151  		outVal  interface{}
   152  		outFlag bool
   153  	}{
   154  		{1, nil, false},
   155  		{nil, nil, false},
   156  		{'a', nil, false},
   157  		{"asdf", nil, false},
   158  		{strptr("asdf"), "asdf", true},
   159  		{struct{}{}, nil, false},
   160  	}
   161  
   162  	t.Parallel()
   163  
   164  	for ix, testCase := range tests {
   165  		t.Run(fmt.Sprintf("Test #%d", ix), func(t *testing.T) {
   166  			in := &types.KeyValue{Key: nil, Value: testCase.inVal}
   167  			out, ok := StrPtrToStr.Convert(in)
   168  			if ok != testCase.outFlag {
   169  				t.Errorf("Unexpected Convert flag: want: %t, got: %t", testCase.outFlag, ok)
   170  			}
   171  			if !ok {
   172  				return
   173  			}
   174  			if out == nil && testCase.outVal != nil {
   175  				t.Errorf("Expected a non-nil result, got nil")
   176  			}
   177  			if !reflect.DeepEqual(testCase.outVal, out.Value) {
   178  				t.Errorf("Unexpected Convert value: want: %#v, got: %#v", testCase.outVal, out.Value)
   179  			}
   180  		})
   181  	}
   182  }
   183  
   184  func TestBoolPtrToBoolConverter(t *testing.T) {
   185  	tests := []struct {
   186  		inVal   interface{}
   187  		outVal  interface{}
   188  		outFlag bool
   189  	}{
   190  		{true, nil, false},
   191  		{boolptr(true), true, true},
   192  		{boolptr(false), false, true},
   193  		{nil, nil, false},
   194  	}
   195  
   196  	t.Parallel()
   197  
   198  	for ix, testCase := range tests {
   199  		t.Run(fmt.Sprintf("Test #%d", ix), func(t *testing.T) {
   200  			in := &types.KeyValue{Key: nil, Value: testCase.inVal}
   201  			out, ok := BoolPtrToBool.Convert(in)
   202  			if ok != testCase.outFlag {
   203  				t.Errorf("Unexpected Convert flag: want: %t, got: %t", testCase.outFlag, ok)
   204  			}
   205  			if !ok {
   206  				return
   207  			}
   208  			if out == nil && testCase.outVal != nil {
   209  				t.Errorf("Expected a non-nil result, got nil")
   210  			}
   211  			if !reflect.DeepEqual(testCase.outVal, out.Value) {
   212  				t.Errorf("Unexpected Convert value: want: %#v, got: %#v", testCase.outVal, out.Value)
   213  			}
   214  		})
   215  	}
   216  }
   217  
   218  func TestStrToIntConverter(t *testing.T) {
   219  	tests := []struct {
   220  		inVal   interface{}
   221  		outVal  interface{}
   222  		outFlag bool
   223  	}{
   224  		{1, nil, false},
   225  		{"1", 1, true},
   226  		{"-1", -1, true},
   227  		{"1234567890", 1234567890, true},
   228  		{"asdf", nil, false},
   229  		{'1', nil, false},
   230  	}
   231  
   232  	t.Parallel()
   233  
   234  	for ix, testCase := range tests {
   235  		t.Run(fmt.Sprintf("Test #%d", ix), func(t *testing.T) {
   236  			in := &types.KeyValue{Key: nil, Value: testCase.inVal}
   237  			out, ok := StrToInt.Convert(in)
   238  			if ok != testCase.outFlag {
   239  				t.Errorf("Unexpected Convert flag: want: %t, got: %t", testCase.outFlag, ok)
   240  			}
   241  			if !ok {
   242  				return
   243  			}
   244  			if out == nil && testCase.outVal != nil {
   245  				t.Errorf("Expected a non-nil result, got nil")
   246  			}
   247  			if !reflect.DeepEqual(testCase.outVal, out.Value) {
   248  				t.Errorf("Unexpected Convert value: want: %#v, got: %#v", testCase.outVal, out.Value)
   249  			}
   250  		})
   251  	}
   252  }
   253  
   254  func TestIfIntConverter(t *testing.T) {
   255  	tests := []struct {
   256  		inVal   interface{}
   257  		outVal  interface{}
   258  		outFlag bool
   259  	}{
   260  		{1, 1, true},
   261  		{-1, -1, true},
   262  		{0, 0, true},
   263  		{"asdf", nil, false},
   264  		{intptr(1), nil, false},
   265  		{"1", nil, false},
   266  		{nil, nil, false},
   267  	}
   268  
   269  	t.Parallel()
   270  
   271  	for ix, testCase := range tests {
   272  		t.Run(fmt.Sprintf("Test #%d", ix), func(t *testing.T) {
   273  			in := &types.KeyValue{Key: nil, Value: testCase.inVal}
   274  			out, ok := IfInt.Convert(in)
   275  			if ok != testCase.outFlag {
   276  				t.Errorf("Unexpected Convert flag: want: %t, got: %t", testCase.outFlag, ok)
   277  			}
   278  			if !ok {
   279  				return
   280  			}
   281  			if out == nil && testCase.outVal != nil {
   282  				t.Errorf("Expected a non-nil result, got nil")
   283  			}
   284  			if !reflect.DeepEqual(testCase.outVal, out.Value) {
   285  				t.Errorf("Unexpected Convert value: want: %#v, got: %#v", testCase.outVal, out.Value)
   286  			}
   287  		})
   288  	}
   289  }
   290  
   291  func TestIfStrConverter(t *testing.T) {
   292  	tests := []struct {
   293  		inVal   interface{}
   294  		outVal  interface{}
   295  		outFlag bool
   296  	}{
   297  		{1, nil, false},
   298  		{"asdf", "asdf", true},
   299  		{strptr("asdf"), nil, false},
   300  		{'a', nil, false},
   301  		{nil, nil, false},
   302  	}
   303  
   304  	t.Parallel()
   305  
   306  	for ix, testCase := range tests {
   307  		t.Run(fmt.Sprintf("Test #%d", ix), func(t *testing.T) {
   308  			in := &types.KeyValue{Key: nil, Value: testCase.inVal}
   309  			out, ok := IfStr.Convert(in)
   310  			if ok != testCase.outFlag {
   311  				t.Errorf("Unexpected Convert flag: want: %t, got: %t", testCase.outFlag, ok)
   312  			}
   313  			if !ok {
   314  				return
   315  			}
   316  			if out == nil && testCase.outVal != nil {
   317  				t.Errorf("Expected a non-nil result, got nil")
   318  			}
   319  			if !reflect.DeepEqual(testCase.outVal, out.Value) {
   320  				t.Errorf("Unexpected Convert value: want: %#v, got: %#v", testCase.outVal, out.Value)
   321  			}
   322  		})
   323  	}
   324  }
   325  
   326  func TestIfBoolConverter(t *testing.T) {
   327  	tests := []struct {
   328  		inVal   interface{}
   329  		outVal  interface{}
   330  		outFlag bool
   331  	}{
   332  		{true, true, true},
   333  		{false, false, true},
   334  		{nil, nil, false},
   335  		{"true", nil, false},
   336  		{1, nil, false},
   337  		{0, nil, false},
   338  	}
   339  
   340  	t.Parallel()
   341  
   342  	for ix, testCase := range tests {
   343  		t.Run(fmt.Sprintf("Test #%d", ix), func(t *testing.T) {
   344  			in := &types.KeyValue{Key: nil, Value: testCase.inVal}
   345  			out, ok := IfBool.Convert(in)
   346  			if ok != testCase.outFlag {
   347  				t.Errorf("Unexpected Convert flag: want: %t, got: %t", testCase.outFlag, ok)
   348  			}
   349  			if !ok {
   350  				return
   351  			}
   352  			if out == nil && testCase.outVal != nil {
   353  				t.Errorf("Expected a non-nil result, got nil")
   354  			}
   355  			if !reflect.DeepEqual(testCase.outVal, out.Value) {
   356  				t.Errorf("Unexpected Convert value: want: %#v, got: %#v", testCase.outVal, out.Value)
   357  			}
   358  		})
   359  	}
   360  }
   361  
   362  func TestCompositeConverter_CompAnd(t *testing.T) {
   363  	tests := []struct {
   364  		name   string
   365  		chain  []convAct
   366  		expVal types.Value
   367  		expOk  bool
   368  	}{
   369  		{
   370  			"Empty chain",
   371  			[]convAct{},
   372  			nil, false,
   373  		},
   374  		{
   375  			"1 positive",
   376  			[]convAct{
   377  				convAct{1, true},
   378  			},
   379  			1, true,
   380  		},
   381  		{
   382  			"2 positive",
   383  			[]convAct{
   384  				convAct{1, true},
   385  				convAct{2, true},
   386  			},
   387  			2, true,
   388  		},
   389  		{
   390  			"1 negative",
   391  			[]convAct{
   392  				convAct{nil, false},
   393  			},
   394  			nil, false,
   395  		},
   396  		{
   397  			"1 positive 1 negative",
   398  			[]convAct{
   399  				convAct{1, true},
   400  				convAct{nil, false},
   401  			},
   402  			nil, false,
   403  		},
   404  		{
   405  			"1 negative 1 positive",
   406  			[]convAct{
   407  				convAct{nil, false},
   408  				convAct{1, true},
   409  			},
   410  			nil, false,
   411  		},
   412  	}
   413  
   414  	t.Parallel()
   415  
   416  	for _, testCase := range tests {
   417  		t.Run(testCase.name, func(t *testing.T) {
   418  			convChain := make([]Converter, 0, len(testCase.chain))
   419  			for _, act := range testCase.chain {
   420  				convChain = append(convChain, newTestConverter(act))
   421  			}
   422  
   423  			comp := NewCompositeConverter(CompAnd, convChain...)
   424  			// None of the converters react to the input kv, so
   425  			// passing a nil value
   426  			got, gotOk := comp.Convert(&types.KeyValue{Key: nil, Value: nil})
   427  			if gotOk != testCase.expOk {
   428  				t.Errorf("Unexpected Convert flag: want: %t, got: %t", testCase.expOk, gotOk)
   429  			}
   430  			if !gotOk {
   431  				return
   432  			}
   433  			if !reflect.DeepEqual(testCase.expVal, got.Value) {
   434  				t.Errorf("Unexpected Convert value: want: %#v, got: %#v", testCase.expVal, got.Value)
   435  			}
   436  		})
   437  	}
   438  }
   439  
   440  func TestCompositeConverterCompOr(t *testing.T) {
   441  	tests := []struct {
   442  		name   string
   443  		chain  []convAct
   444  		expVal types.Value
   445  		expOk  bool
   446  	}{
   447  		{
   448  			"Empty chain",
   449  			[]convAct{},
   450  			nil, false,
   451  		},
   452  		{
   453  			"1 positive",
   454  			[]convAct{
   455  				convAct{1, true},
   456  			},
   457  			1, true,
   458  		},
   459  		{
   460  			"2 positive",
   461  			[]convAct{
   462  				convAct{1, true},
   463  				convAct{2, true},
   464  			},
   465  			1, true,
   466  		},
   467  		{
   468  			"1 negative",
   469  			[]convAct{
   470  				convAct{nil, false},
   471  			},
   472  			nil, false,
   473  		},
   474  		{
   475  			"1 positive 1 negative",
   476  			[]convAct{
   477  				convAct{1, true},
   478  				convAct{nil, false},
   479  			},
   480  			1, true,
   481  		},
   482  		{
   483  			"1 negative 1 positive",
   484  			[]convAct{
   485  				convAct{nil, false},
   486  				convAct{2, true},
   487  			},
   488  			2, true,
   489  		},
   490  		{
   491  			"1 negative 2 positives",
   492  			[]convAct{
   493  				convAct{nil, false},
   494  				convAct{1, true},
   495  				convAct{2, true},
   496  			},
   497  			1, true,
   498  		},
   499  	}
   500  
   501  	t.Parallel()
   502  
   503  	for _, testCase := range tests {
   504  		t.Run(testCase.name, func(t *testing.T) {
   505  			convChain := make([]Converter, 0, len(testCase.chain))
   506  			for _, act := range testCase.chain {
   507  				convChain = append(convChain, newTestConverter(act))
   508  			}
   509  
   510  			comp := NewCompositeConverter(CompOr, convChain...)
   511  			// None of the converters react to the input kv, so
   512  			// passing a nil value
   513  			got, gotOk := comp.Convert(&types.KeyValue{Key: nil, Value: nil})
   514  			if gotOk != testCase.expOk {
   515  				t.Errorf("Unexpected Convert flag: want: %t, got: %t", testCase.expOk, gotOk)
   516  			}
   517  			if !gotOk {
   518  				return
   519  			}
   520  			if !reflect.DeepEqual(testCase.expVal, got.Value) {
   521  				t.Errorf("Unexpected Convert value: want: %#v, got: %#v", testCase.expVal, got.Value)
   522  			}
   523  		})
   524  	}
   525  }
   526  
   527  func TestCompositeConverterCompFirst(t *testing.T) {
   528  	tests := []struct {
   529  		name   string
   530  		chain  []convAct
   531  		expVal types.Value
   532  		expOk  bool
   533  	}{
   534  		{
   535  			"Empty chain",
   536  			[]convAct{},
   537  			nil, false,
   538  		},
   539  		{
   540  			"1 positive",
   541  			[]convAct{
   542  				convAct{1, true},
   543  			},
   544  			1, true,
   545  		},
   546  		{
   547  			"2 positive",
   548  			[]convAct{
   549  				convAct{1, true},
   550  				convAct{2, true},
   551  			},
   552  			1, true,
   553  		},
   554  		{
   555  			"1 negative",
   556  			[]convAct{
   557  				convAct{nil, false},
   558  			},
   559  			nil, false,
   560  		},
   561  		{
   562  			"1 positive 1 negative",
   563  			[]convAct{
   564  				convAct{1, true},
   565  				convAct{nil, false},
   566  			},
   567  			1, true,
   568  		},
   569  		{
   570  			"1 negative 1 positive",
   571  			[]convAct{
   572  				convAct{nil, false},
   573  				convAct{2, true},
   574  			},
   575  			2, true,
   576  		},
   577  		{
   578  			"1 negative 2 positives",
   579  			[]convAct{
   580  				convAct{nil, false},
   581  				convAct{1, true},
   582  				convAct{2, true},
   583  			},
   584  			1, true,
   585  		},
   586  	}
   587  
   588  	t.Parallel()
   589  
   590  	for _, testCase := range tests {
   591  		t.Run(testCase.name, func(t *testing.T) {
   592  			convChain := make([]Converter, 0, len(testCase.chain))
   593  			for _, act := range testCase.chain {
   594  				convChain = append(convChain, newTestConverter(act))
   595  			}
   596  
   597  			comp := NewCompositeConverter(CompFirst, convChain...)
   598  			// None of the converters react to the input kv, so
   599  			// passing a nil value
   600  			got, gotOk := comp.Convert(&types.KeyValue{Key: nil, Value: nil})
   601  			if gotOk != testCase.expOk {
   602  				t.Errorf("Unexpected Convert flag: want: %t, got: %t", testCase.expOk, gotOk)
   603  			}
   604  			if !gotOk {
   605  				return
   606  			}
   607  			if !reflect.DeepEqual(testCase.expVal, got.Value) {
   608  				t.Errorf("Unexpected Convert value: want: %#v, got: %#v", testCase.expVal, got.Value)
   609  			}
   610  		})
   611  	}
   612  }
   613  
   614  func TestCompositeConverterCompLast(t *testing.T) {
   615  	tests := []struct {
   616  		name   string
   617  		chain  []convAct
   618  		expVal types.Value
   619  		expOk  bool
   620  	}{
   621  		{
   622  			"Empty chain",
   623  			[]convAct{},
   624  			nil, false,
   625  		},
   626  		{
   627  			"1 positive",
   628  			[]convAct{
   629  				convAct{1, true},
   630  			},
   631  			1, true,
   632  		},
   633  		{
   634  			"2 positive",
   635  			[]convAct{
   636  				convAct{1, true},
   637  				convAct{2, true},
   638  			},
   639  			2, true,
   640  		},
   641  		{
   642  			"1 negative",
   643  			[]convAct{
   644  				convAct{nil, false},
   645  			},
   646  			nil, false,
   647  		},
   648  		{
   649  			"1 positive 1 negative",
   650  			[]convAct{
   651  				convAct{1, true},
   652  				convAct{nil, false},
   653  			},
   654  			1, true,
   655  		},
   656  		{
   657  			"1 negative 1 positive",
   658  			[]convAct{
   659  				convAct{nil, false},
   660  				convAct{2, true},
   661  			},
   662  			2, true,
   663  		},
   664  		{
   665  			"1 negative 2 positives",
   666  			[]convAct{
   667  				convAct{nil, false},
   668  				convAct{1, true},
   669  				convAct{2, true},
   670  			},
   671  			2, true,
   672  		},
   673  	}
   674  
   675  	t.Parallel()
   676  
   677  	for _, testCase := range tests {
   678  		t.Run(testCase.name, func(t *testing.T) {
   679  			convChain := make([]Converter, 0, len(testCase.chain))
   680  			for _, act := range testCase.chain {
   681  				convChain = append(convChain, newTestConverter(act))
   682  			}
   683  
   684  			comp := NewCompositeConverter(CompLast, convChain...)
   685  			// None of the converters react to the input kv, so
   686  			// passing a nil value
   687  			got, gotOk := comp.Convert(&types.KeyValue{Key: nil, Value: nil})
   688  			if gotOk != testCase.expOk {
   689  				t.Errorf("Unexpected Convert flag: want: %t, got: %t", testCase.expOk, gotOk)
   690  			}
   691  			if !gotOk {
   692  				return
   693  			}
   694  			if !reflect.DeepEqual(testCase.expVal, got.Value) {
   695  				t.Errorf("Unexpected Convert value: want: %#v, got: %#v", testCase.expVal, got.Value)
   696  			}
   697  		})
   698  	}
   699  }