1 package ldattr
2
3 import (
4 "encoding/json"
5 "fmt"
6 "testing"
7
8 "github.com/launchdarkly/go-sdk-common/v3/lderrors"
9
10 "github.com/stretchr/testify/assert"
11 )
12
13 func TestRefInvalid(t *testing.T) {
14 for _, p := range []struct {
15 input string
16 expectedError error
17 }{
18 {"", lderrors.ErrAttributeEmpty{}},
19 {"/", lderrors.ErrAttributeEmpty{}},
20 {"//", lderrors.ErrAttributeExtraSlash{}},
21 {"/a//b", lderrors.ErrAttributeExtraSlash{}},
22 {"/a/b/", lderrors.ErrAttributeExtraSlash{}},
23 {"/a~x", lderrors.ErrAttributeInvalidEscape{}},
24 {"/a~", lderrors.ErrAttributeInvalidEscape{}},
25 {"/a/b~x", lderrors.ErrAttributeInvalidEscape{}},
26 {"/a/b~", lderrors.ErrAttributeInvalidEscape{}},
27 } {
28 t.Run(fmt.Sprintf("input string %q", p.input), func(t *testing.T) {
29 a := NewRef(p.input)
30 assert.True(t, a.IsDefined())
31 assert.Equal(t, p.expectedError, a.Err())
32 assert.Equal(t, p.input, a.String())
33 assert.Equal(t, 0, a.Depth())
34 })
35 }
36
37 t.Run("uninitialized", func(t *testing.T) {
38 var a Ref
39 assert.False(t, a.IsDefined())
40 assert.Equal(t, lderrors.ErrAttributeEmpty{}, a.Err())
41 assert.Equal(t, "", a.String())
42 assert.Equal(t, 0, a.Depth())
43 })
44 }
45
46 func TestRefWithNoLeadingSlash(t *testing.T) {
47 for _, s := range []string{
48 "key",
49 "kind",
50 "name",
51 "name/with/slashes",
52 "name~0~1with-what-looks-like-escape-sequences",
53 } {
54 t.Run(fmt.Sprintf("input string %q", s), func(t *testing.T) {
55 a := NewRef(s)
56 assert.True(t, a.IsDefined())
57 assert.NoError(t, a.Err())
58 assert.Equal(t, s, a.String())
59 assert.Equal(t, 1, a.Depth())
60 assert.Equal(t, s, a.Component(0))
61 })
62 }
63 }
64
65 func TestRefSimpleWithLeadingSlash(t *testing.T) {
66 for _, params := range []struct {
67 input string
68 path string
69 }{
70 {"/key", "key"},
71 {"/kind", "kind"},
72 {"/name", "name"},
73 {"/custom", "custom"},
74 {"/0", "0"},
75 {"/name~1with~1slashes~0and~0tildes", "name/with/slashes~and~tildes"},
76 } {
77 t.Run(fmt.Sprintf("input string %q", params.input), func(t *testing.T) {
78 a := NewRef(params.input)
79 assert.True(t, a.IsDefined())
80 assert.NoError(t, a.Err())
81 assert.Equal(t, params.input, a.String())
82 assert.Equal(t, 1, a.Depth())
83 assert.Equal(t, params.path, a.Component(0))
84 })
85 }
86 }
87
88 func TestNewLiteralRef(t *testing.T) {
89 a0 := NewLiteralRef("name")
90 assert.Equal(t, NewRef("name"), a0)
91
92 a1 := NewLiteralRef("a/b")
93 assert.Equal(t, NewRef("a/b"), a1)
94
95 a2 := NewLiteralRef("/a/b~c")
96 assert.Equal(t, NewRef("/~1a~1b~0c"), a2)
97 assert.Equal(t, 1, a2.Depth())
98
99 a3 := NewLiteralRef("/")
100 assert.Equal(t, NewRef("/~1"), a3)
101 assert.Equal(t, 1, a3.Depth())
102
103 a4 := NewLiteralRef("")
104 assert.Equal(t, lderrors.ErrAttributeEmpty{}, a4.Err())
105 }
106
107 func TestRefComponents(t *testing.T) {
108 for _, params := range []struct {
109 input string
110 depth int
111 index int
112 expectedName string
113 }{
114 {"", 0, 0, ""},
115 {"key", 1, 0, "key"},
116 {"/key", 1, 0, "key"},
117 {"/a/b", 2, 0, "a"},
118 {"/a/b", 2, 1, "b"},
119 {"/a~1b/c", 2, 0, "a/b"},
120 {"/a~0b/c", 2, 0, "a~b"},
121 {"/a/10/20/30x", 4, 1, "10"},
122 {"/a/10/20/30x", 4, 2, "20"},
123 {"/a/10/20/30x", 4, 3, "30x"},
124
125
126 {"", 0, -1, ""},
127 {"key", 1, -1, ""},
128 {"key", 1, 1, ""},
129 {"/key", 1, -1, ""},
130 {"/key", 1, 1, ""},
131 {"/a/b", 2, -1, ""},
132 {"/a/b", 2, 2, ""},
133 } {
134 t.Run(fmt.Sprintf("input string %q, index %d", params.input, params.index), func(t *testing.T) {
135 a := NewRef(params.input)
136 assert.Equal(t, params.depth, a.Depth())
137 name := a.Component(params.index)
138 assert.Equal(t, params.expectedName, name)
139 })
140 }
141 }
142
143 func TestRefEqual(t *testing.T) {
144 refs := []Ref{
145 {},
146 NewRef(""),
147 NewRef("a"),
148 NewRef("b"),
149 NewRef("/a/b"),
150 NewRef("/a/c"),
151 NewRef("///"),
152 }
153 for i, a := range refs {
154 sameValue := a
155 assert.True(t, sameValue.Equal(a))
156 for j, differentValue := range refs {
157 if j == i {
158 continue
159 }
160 assert.False(t, differentValue.Equal(a))
161 }
162 }
163 }
164
165 func TestRefMarshalJSON(t *testing.T) {
166 for _, p := range []struct {
167 ref Ref
168 json string
169 }{
170 {Ref{}, `null`},
171 {NewRef("a"), `"a"`},
172 {NewRef("/a/b"), `"/a/b"`},
173 {NewRef("////invalid"), `"////invalid"`},
174 } {
175 t.Run(p.json, func(t *testing.T) {
176 bytes, err := json.Marshal(p.ref)
177 assert.NoError(t, err)
178 assert.Equal(t, p.json, string(bytes))
179 })
180 }
181 }
182
183 func TestRefUnmarshalJSON(t *testing.T) {
184 for _, p := range []struct {
185 json string
186 ref Ref
187 success bool
188 }{
189 {`null`, Ref{}, true},
190 {`"a"`, NewRef("a"), true},
191 {`"/a/b"`, NewRef("/a/b"), true},
192 {`"////invalid"`, NewRef("////invalid"), true},
193 {`true`, Ref{}, false},
194 {`2`, Ref{}, false},
195 {`[]`, Ref{}, false},
196 {`{}`, Ref{}, false},
197 {`.`, Ref{}, false},
198 {``, Ref{}, false},
199 } {
200 t.Run(p.json, func(t *testing.T) {
201 var ref Ref
202 err := json.Unmarshal([]byte(p.json), &ref)
203 assert.Equal(t, p.ref, ref)
204 if p.success {
205 assert.NoError(t, err)
206 } else {
207 assert.Error(t, err)
208 }
209 })
210 }
211 }
212
View as plain text