package field import ( "context" "fmt" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) func TestArrayField_Decode(t *testing.T) { tests := []struct { name string field *Field data interface{} want interface{} wantErr bool }{ { "Correct", Array(Number("float")), []interface{}{1.0, 2.0}, []interface{}{1.0, 2.0}, false, }, { "With object inside with nil-data", Array( Object("a", String(), "b", String()), ), nil, nil, false, }, { "With object inside with data", Array( Object("a", String(), "b", String()), ), []interface{}{map[string]interface{}{"a": "1", "b": "2"}}, []interface{}{map[string]interface{}{"a": "1", "b": "2"}}, false, }, { "Incorrect type", Array(Number("int")), "1 2 3", "decode error: incorrect type: string, expected array or slice", true, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { got, err := Decode(context.Background(), tt.field, tt.data) if tt.wantErr { require.Error(t, err) assert.EqualError(t, err, tt.want.(string), fmt.Sprintf("Decode() error = %v, want %v", err, tt.want.(string))) } if !tt.wantErr { require.NoError(t, err) assert.ElementsMatch(t, got, tt.want, fmt.Sprintf("Decode() got = %v, want %v", got, tt.want)) } }) } } func TestArrayField_DecodeNonStrict(t *testing.T) { tests := []struct { name string field *Field data interface{} want interface{} wantErr bool }{ { "Nil data", Array(Number(NumberFormatFloat)), nil, nil, false, }, { "Correct data", Array(Number(NumberFormatFloat)), []interface{}{1.0, 2.0}, []interface{}{1.0, 2.0}, false, }, { "String as float", Array(Number(NumberFormatFloat)), []interface{}{"1.0", "2.0"}, []interface{}{1.0, 2.0}, false, }, { "String as int", Array(Number("int")), []interface{}{"1", "2"}, []interface{}{int64(1), int64(2)}, false, }, { "String as array", Array(String()), "string", []interface{}{"string"}, false, }, { "Single string number", Array(Number("int")), "2", []interface{}{int64(2)}, false, }, { "String array", Array(Number(NumberFormatFloat)), "1 2 3.5", []interface{}{1.0, 2.0, 3.5}, false, }, { "Incoorect type", Array(Bool()), "1 2 3", nil, true, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { got, err := Decode(context.Background(), tt.field, tt.data, NonStrictMode()) if tt.wantErr { require.Error(t, err) return } require.NoError(t, err) assert.ElementsMatch(t, got, tt.want, "Decode() got = %v, want %v", got, tt.want) }) } } func TestArrayField_Encode(t *testing.T) { tests := []struct { name string field *Field data interface{} want interface{} wantErr bool }{ { "Correct", Array(Number("float")), []interface{}{1.0, 2.0}, []interface{}{1.0, 2.0}, false, }, { "Incorrect type", Array(Number("int")), "1 2 3", "encode error: incorrect type: string, expected array or slice", true, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { got, err := Encode(context.Background(), tt.field, tt.data) if tt.wantErr { require.Error(t, err) assert.EqualError(t, err, tt.want.(string), fmt.Sprintf("Decode() error = %v, want %v", err, tt.want.(string))) } if !tt.wantErr { require.NoError(t, err) assert.ElementsMatch(t, got, tt.want, fmt.Sprintf("Decode() got = %v, want %v", got, tt.want)) } }) } } func TestArrayType_Walk(t *testing.T) { tests := []struct { name string field *Field v interface{} fn WalkFunc opts *WalkOptions want interface{} want1 bool wantErr assert.ErrorAssertionFunc }{ { name: "With nil data and WalkSchema = false", field: Array(Object("a", String(), "b", String())), v: nil, opts: &WalkOptions{WalkSchema: false}, want: nil, want1: false, wantErr: assert.NoError, }, { name: "With nil data and WalkSchema = true", field: Array(Object("a", String(), "b", String())), v: nil, opts: &WalkOptions{WalkSchema: true}, want: nil, want1: false, fn: func(_ context.Context, _ *Field, _ interface{}) (WalkFuncResult, error) { return WalkFuncResult{}, nil }, wantErr: assert.NoError, }, { name: "With empty data and WalkSchema = false", field: Array(Object("a", String(), "b", String())), v: []interface{}{map[string]interface{}{}}, opts: &WalkOptions{WalkSchema: false}, fn: func(ctx context.Context, fld *Field, v interface{}) (result WalkFuncResult, err error) { return WalkFuncResult{}, err }, want: []interface{}{map[string]interface{}{}}, want1: false, wantErr: assert.NoError, }, { name: "With data and WalkSchema = false", field: Array(Object("a", String(), "b", String())), v: []interface{}{map[string]interface{}{"a": "1", "b": "2"}}, opts: &WalkOptions{WalkSchema: false}, fn: func(ctx context.Context, fld *Field, v interface{}) (result WalkFuncResult, err error) { return WalkFuncResult{}, err }, want: []interface{}{map[string]interface{}{"a": "1", "b": "2"}}, want1: false, wantErr: assert.NoError, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { ar := ArrayType{} got, got1, err := ar.Walk(context.Background(), tt.field, tt.v, tt.fn, tt.opts) if !tt.wantErr(t, err, fmt.Sprintf("Walk(%v, %v, %v, %v)", tt.field, tt.v, tt.fn, tt.opts)) { return } assert.Equalf(t, tt.want, got, "Walk(%v, %v, %v, %v)", tt.field, tt.v, tt.fn, tt.opts) assert.Equalf(t, tt.want1, got1, "Walk(%v, %v, %v, %v)", tt.field, tt.v, tt.fn, tt.opts) }) } } type customFloat float64 type customInt int type customStr string type customMap map[string]interface{} func TestArrayField_WithType(t *testing.T) { t.Run("Nil", func(t *testing.T) { got, err := Decode(context.Background(), Array(Number("float")), nil) require.NoError(t, err) assert.ElementsMatch(t, got, nil) got, err = Encode(context.Background(), Array(Number("float")), nil) require.NoError(t, err) assert.ElementsMatch(t, got, nil) }) t.Run("With []float64", func(t *testing.T) { got, err := Decode(context.Background(), Array(Number("float")), []float64{1.0, 2.0}) require.NoError(t, err) assert.ElementsMatch(t, got, []interface{}{1.0, 2.0}) got, err = Encode(context.Background(), Array(Number("float")), []float64{1.0, 2.0}) require.NoError(t, err) assert.ElementsMatch(t, got, []interface{}{1.0, 2.0}) }) t.Run("With []int", func(t *testing.T) { got, err := Decode(context.Background(), Array(Number("int")), []int{1, 2}) require.NoError(t, err) assert.ElementsMatch(t, got, []interface{}{int64(1), int64(2)}) got, err = Encode(context.Background(), Array(Number("int")), []int{1, 2}) require.NoError(t, err) assert.ElementsMatch(t, got, []interface{}{int64(1), int64(2)}) }) t.Run("With []string", func(t *testing.T) { got, err := Decode(context.Background(), Array(String()), []string{"1", "2"}) require.NoError(t, err) assert.ElementsMatch(t, got, []interface{}{"1", "2"}) got, err = Encode(context.Background(), Array(String()), []string{"1", "2"}) require.NoError(t, err) assert.ElementsMatch(t, got, []interface{}{"1", "2"}) }) t.Run("With []map", func(t *testing.T) { got, err := Decode(context.Background(), Array(Object("a", String(), "b", String())), []map[string]interface{}{{"a": "1", "b": "2"}}) require.NoError(t, err) assert.ElementsMatch(t, got, []interface{}{map[string]interface{}{"a": "1", "b": "2"}}) got, err = Encode(context.Background(), Array(Object("a", String(), "b", String())), []map[string]interface{}{{"a": "1", "b": "2"}}) require.NoError(t, err) assert.ElementsMatch(t, got, []interface{}{map[string]interface{}{"a": "1", "b": "2"}}) }) t.Run("With []customFloat", func(t *testing.T) { got, err := Decode(context.Background(), Array(Number("float")), []customFloat{1.0, 2.0}) require.NoError(t, err) assert.ElementsMatch(t, got, []interface{}{1.0, 2.0}) got, err = Encode(context.Background(), Array(Number("float")), []customFloat{1.0, 2.0}) require.NoError(t, err) assert.ElementsMatch(t, got, []interface{}{1.0, 2.0}) }) t.Run("With []customInt", func(t *testing.T) { got, err := Decode(context.Background(), Array(Number("int")), []customInt{1, 2}) require.NoError(t, err) assert.ElementsMatch(t, got, []interface{}{int64(1), int64(2)}) got, err = Encode(context.Background(), Array(Number("int")), []customInt{1, 2}) require.NoError(t, err) assert.ElementsMatch(t, got, []interface{}{int64(1), int64(2)}) }) t.Run("With []customStr", func(t *testing.T) { got, err := Decode(context.Background(), Array(String()), []customStr{"1", "2"}) require.NoError(t, err) assert.ElementsMatch(t, got, []interface{}{"1", "2"}) got, err = Encode(context.Background(), Array(String()), []customStr{"1", "2"}) require.NoError(t, err) assert.ElementsMatch(t, got, []interface{}{"1", "2"}) }) t.Run("With []customMap", func(t *testing.T) { got, err := Decode(context.Background(), Array(Object("a", String(), "b", String())), []customMap{{"a": "1", "b": "2"}}) require.NoError(t, err) assert.ElementsMatch(t, got, []interface{}{map[string]interface{}{"a": "1", "b": "2"}}) got, err = Encode(context.Background(), Array(Object("a", String(), "b", String())), []customMap{{"a": "1", "b": "2"}}) require.NoError(t, err) assert.ElementsMatch(t, got, []interface{}{map[string]interface{}{"a": "1", "b": "2"}}) }) }