1// +build go1.7
2
3package expression
4
5import (
6	"reflect"
7	"strings"
8	"testing"
9
10	"github.com/aws/aws-sdk-go/aws"
11	"github.com/aws/aws-sdk-go/service/dynamodb"
12)
13
14// opeErrorMode will help with error cases and checking error types
15type opeErrorMode string
16
17const (
18	noOperandError opeErrorMode = ""
19	// unsetName error will occur if an empty string is passed into NameBuilder
20	unsetName = "unset parameter: NameBuilder"
21	// invalidName error will occur if a nested name has an empty intermediary
22	// attribute name (i.e. foo.bar..baz)
23	invalidName = "invalid parameter: NameBuilder"
24	// unsetKey error will occur if an empty string is passed into KeyBuilder
25	unsetKey = "unset parameter: KeyBuilder"
26)
27
28func TestBuildOperand(t *testing.T) {
29	cases := []struct {
30		name     string
31		input    OperandBuilder
32		expected exprNode
33		err      opeErrorMode
34	}{
35		{
36			name:  "basic name",
37			input: Name("foo"),
38			expected: exprNode{
39				names:   []string{"foo"},
40				fmtExpr: "$n",
41			},
42		},
43		{
44			name:  "duplicate name name",
45			input: Name("foo.foo"),
46			expected: exprNode{
47				names:   []string{"foo", "foo"},
48				fmtExpr: "$n.$n",
49			},
50		},
51		{
52			name:  "basic value",
53			input: Value(5),
54			expected: exprNode{
55				values: []dynamodb.AttributeValue{
56					{
57						N: aws.String("5"),
58					},
59				},
60				fmtExpr: "$v",
61			},
62		},
63		{
64			name:  "nested name",
65			input: Name("foo.bar"),
66			expected: exprNode{
67				names:   []string{"foo", "bar"},
68				fmtExpr: "$n.$n",
69			},
70		},
71		{
72			name:  "nested name with index",
73			input: Name("foo.bar[0].baz"),
74			expected: exprNode{
75				names:   []string{"foo", "bar", "baz"},
76				fmtExpr: "$n.$n[0].$n",
77			},
78		},
79		{
80			name:  "basic size",
81			input: Name("foo").Size(),
82			expected: exprNode{
83				names:   []string{"foo"},
84				fmtExpr: "size ($n)",
85			},
86		},
87		{
88			name:  "key",
89			input: Key("foo"),
90			expected: exprNode{
91				names:   []string{"foo"},
92				fmtExpr: "$n",
93			},
94		},
95		{
96			name:     "unset key error",
97			input:    Key(""),
98			expected: exprNode{},
99			err:      unsetKey,
100		},
101		{
102			name:     "empty name error",
103			input:    Name(""),
104			expected: exprNode{},
105			err:      unsetName,
106		},
107		{
108			name:     "invalid name",
109			input:    Name("foo..bar"),
110			expected: exprNode{},
111			err:      invalidName,
112		},
113		{
114			name:     "invalid index",
115			input:    Name("[foo]"),
116			expected: exprNode{},
117			err:      invalidName,
118		},
119	}
120
121	for _, c := range cases {
122		t.Run(c.name, func(t *testing.T) {
123			operand, err := c.input.BuildOperand()
124
125			if c.err != noOperandError {
126				if err == nil {
127					t.Errorf("expect error %q, got no error", c.err)
128				} else {
129					if e, a := string(c.err), err.Error(); !strings.Contains(a, e) {
130						t.Errorf("expect %q error message to be in %q", e, a)
131					}
132				}
133			} else {
134				if err != nil {
135					t.Errorf("expect no error, got unexpected Error %q", err)
136				}
137
138				if e, a := c.expected, operand.exprNode; !reflect.DeepEqual(a, e) {
139					t.Errorf("expect %v, got %v", e, a)
140				}
141			}
142		})
143	}
144}
145