cuelang.org/go@v0.10.1/cue/path_test.go (about) 1 // Copyright 2020 CUE Authors 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package cue 16 17 import ( 18 "fmt" 19 "testing" 20 ) 21 22 func TestPaths(t *testing.T) { 23 var r Runtime 24 inst, _ := r.Compile("", ` 25 #Foo: a: b: 1 26 "#Foo": c: d: 2 27 _foo: b: 5 28 a: 3 29 b: [4, 5, 6] 30 c: "#Foo": 7 31 map: [string]: int 32 list: [...int] 33 34 // Issue 2060 35 let X = {a: b: 0} 36 x: y: X.a 37 `) 38 testCases := []struct { 39 path Path 40 out string 41 str string 42 err bool 43 }{{ 44 path: MakePath(Str("list"), AnyIndex), 45 out: "int", 46 str: "list.[_]", 47 }, { 48 49 path: MakePath(Def("#Foo"), Str("a"), Str("b")), 50 out: "1", 51 str: "#Foo.a.b", 52 }, { 53 path: ParsePath(`#Foo.a.b`), 54 out: "1", 55 str: "#Foo.a.b", 56 }, { 57 path: ParsePath(`"#Foo".c.d`), 58 out: "2", 59 str: `"#Foo".c.d`, 60 }, { 61 // fallback Def(Foo) -> Def(#Foo) 62 path: MakePath(Def("Foo"), Str("a"), Str("b")), 63 out: "1", 64 str: "#Foo.a.b", 65 }, { 66 path: MakePath(Str("b"), Index(2)), 67 out: "6", 68 str: "b[2]", // #Foo.b.2 69 }, { 70 path: MakePath(Str("c"), Str("#Foo")), 71 out: "7", 72 str: `c."#Foo"`, 73 }, { 74 path: MakePath(Hid("_foo", "_"), Str("b")), 75 out: "5", 76 str: `_foo.b`, 77 }, { 78 path: ParsePath("#Foo.a.b"), 79 str: "#Foo.a.b", 80 out: "1", 81 }, { 82 path: ParsePath("#Foo.a.c"), 83 str: "#Foo.a.c", 84 out: `_|_ // field not found: c`, 85 }, { 86 path: ParsePath(`b[2]`), 87 str: `b[2]`, 88 out: "6", 89 }, { 90 path: ParsePath(`c."#Foo"`), 91 str: `c."#Foo"`, 92 out: "7", 93 }, { 94 path: ParsePath("foo._foo"), 95 str: "_|_", 96 err: true, 97 out: `_|_ // invalid path: hidden label _foo not allowed`, 98 }, { 99 path: ParsePath(`c."#Foo`), 100 str: "_|_", 101 err: true, 102 out: `_|_ // string literal not terminated`, 103 }, { 104 path: ParsePath(`b[a]`), 105 str: "_|_", 106 err: true, 107 out: `_|_ // non-constant expression a`, 108 }, { 109 path: ParsePath(`b['1']`), 110 str: "_|_", 111 err: true, 112 out: `_|_ // invalid string index '1'`, 113 }, { 114 path: ParsePath(`b[3T]`), 115 str: "_|_", 116 err: true, 117 out: `_|_ // int label out of range (3000000000000 not >=0 and <= 268435454)`, 118 }, { 119 path: ParsePath(`b[3.3]`), 120 str: "_|_", 121 err: true, 122 out: `_|_ // invalid literal 3.3`, 123 }, { 124 path: MakePath(Str("map"), AnyString), 125 out: "int", 126 str: "map.[_]", 127 }, { 128 path: MakePath(Str("list"), AnyIndex), 129 out: "int", 130 str: "list.[_]", 131 }, { 132 path: ParsePath("x.y"), 133 out: "{\n\tb: 0\n}", 134 str: "x.y", 135 }, { 136 path: ParsePath("x.y.b"), 137 out: "0", 138 str: "x.y.b", 139 }} 140 141 v := inst.Value() 142 for _, tc := range testCases { 143 t.Run(tc.str, func(t *testing.T) { 144 if gotErr := tc.path.Err() != nil; gotErr != tc.err { 145 t.Errorf("error: got %v; want %v", gotErr, tc.err) 146 } 147 148 w := v.LookupPath(tc.path) 149 150 if got := fmt.Sprint(w); got != tc.out { 151 t.Errorf("Value: got %v; want %v", got, tc.out) 152 } 153 154 if got := tc.path.String(); got != tc.str { 155 t.Errorf("String: got %v; want %v", got, tc.str) 156 } 157 158 if w.Err() != nil { 159 return 160 } 161 162 if got := w.Path().String(); got != tc.str { 163 t.Errorf("Path: got %v; want %v", got, tc.str) 164 } 165 }) 166 } 167 } 168 169 var selectorTests = []struct { 170 sel Selector 171 stype SelectorType 172 string string 173 unquoted string 174 index int 175 isHidden bool 176 isConstraint bool 177 isDefinition bool 178 isString bool 179 pkgPath string 180 }{{ 181 sel: Str("foo"), 182 stype: StringLabel, 183 string: "foo", 184 unquoted: "foo", 185 isString: true, 186 }, { 187 sel: Str("_foo"), 188 stype: StringLabel, 189 string: `"_foo"`, 190 unquoted: "_foo", 191 isString: true, 192 }, { 193 sel: Str(`a "b`), 194 stype: StringLabel, 195 string: `"a \"b"`, 196 unquoted: `a "b`, 197 isString: true, 198 }, { 199 sel: Index(5), 200 stype: IndexLabel, 201 string: "5", 202 index: 5, 203 }, { 204 sel: Def("foo"), 205 stype: DefinitionLabel, 206 string: "#foo", 207 isDefinition: true, 208 }, { 209 sel: Str("foo").Optional(), 210 stype: StringLabel | OptionalConstraint, 211 string: "foo?", 212 unquoted: "foo", 213 isString: true, 214 isConstraint: true, 215 }, { 216 sel: Str("foo").Required(), 217 stype: StringLabel | RequiredConstraint, 218 string: "foo!", 219 unquoted: "foo", 220 isString: true, 221 isConstraint: true, 222 }, { 223 sel: Def("foo").Required().Optional(), 224 stype: DefinitionLabel | OptionalConstraint, 225 string: "#foo?", 226 isDefinition: true, 227 isConstraint: true, 228 }, { 229 sel: Def("foo").Optional().Required(), 230 stype: DefinitionLabel | RequiredConstraint, 231 string: "#foo!", 232 isDefinition: true, 233 isConstraint: true, 234 }, { 235 sel: AnyString, 236 stype: StringLabel | PatternConstraint, 237 string: "[_]", 238 isConstraint: true, 239 }, { 240 sel: AnyIndex, 241 stype: IndexLabel | PatternConstraint, 242 string: "[_]", 243 isConstraint: true, 244 }, { 245 sel: Hid("_foo", "example.com"), 246 stype: HiddenLabel, 247 string: "_foo", 248 isHidden: true, 249 pkgPath: "example.com", 250 }, { 251 sel: Hid("_#foo", "example.com"), 252 stype: HiddenDefinitionLabel, 253 string: "_#foo", 254 isHidden: true, 255 isDefinition: true, 256 pkgPath: "example.com", 257 }} 258 259 func TestSelector(t *testing.T) { 260 for _, tc := range selectorTests { 261 t.Run(tc.sel.String(), func(t *testing.T) { 262 sel := tc.sel 263 if got, want := sel.Type(), tc.stype; got != want { 264 t.Errorf("unexpected type; got %v want %v", got, want) 265 } 266 if got, want := sel.String(), tc.string; got != want { 267 t.Errorf("unexpected sel.String result; got %q want %q", got, want) 268 } 269 if tc.unquoted == "" { 270 checkPanic(t, "Selector.Unquoted invoked on non-string label", func() { 271 sel.Unquoted() 272 }) 273 } else { 274 if got, want := sel.Unquoted(), tc.unquoted; got != want { 275 t.Errorf("unexpected sel.Unquoted result; got %q want %q", got, want) 276 } 277 } 278 if sel.Type() != IndexLabel { 279 checkPanic(t, "Index called on non-index selector", func() { 280 sel.Index() 281 }) 282 } else { 283 if got, want := sel.Index(), tc.index; got != want { 284 t.Errorf("unexpected sel.Index result; got %v want %v", got, want) 285 } 286 } 287 if got, want := sel.Type().IsHidden(), tc.isHidden; got != want { 288 t.Errorf("unexpected sel.IsHidden result; got %v want %v", got, want) 289 } 290 if got, want := sel.IsConstraint(), tc.isConstraint; got != want { 291 t.Errorf("unexpected sel.IsOptional result; got %v want %v", got, want) 292 } 293 if got, want := sel.IsString(), tc.isString; got != want { 294 t.Errorf("unexpected sel.IsString result; got %v want %v", got, want) 295 } 296 if got, want := sel.IsDefinition(), tc.isDefinition; got != want { 297 t.Errorf("unexpected sel.IsDefinition result; got %v want %v", got, want) 298 } 299 if got, want := sel.PkgPath(), tc.pkgPath; got != want { 300 t.Errorf("unexpected sel.PkgPath result; got %v want %v", got, want) 301 } 302 }) 303 } 304 } 305 306 func TestSelectorTypeString(t *testing.T) { 307 if got, want := InvalidSelectorType.String(), "NoLabels"; got != want { 308 t.Errorf("unexpected SelectorType.String result; got %q want %q", got, want) 309 } 310 if got, want := PatternConstraint.String(), "PatternConstraint"; got != want { 311 t.Errorf("unexpected SelectorType.String result; got %q want %q", got, want) 312 } 313 if got, want := (StringLabel | OptionalConstraint).String(), "StringLabel|OptionalConstraint"; got != want { 314 t.Errorf("unexpected SelectorType.String result; got %q want %q", got, want) 315 } 316 if got, want := SelectorType(255).String(), "StringLabel|IndexLabel|DefinitionLabel|HiddenLabel|HiddenDefinitionLabel|OptionalConstraint|RequiredConstraint|PatternConstraint"; got != want { 317 t.Errorf("unexpected SelectorType.String result; got %q want %q", got, want) 318 } 319 } 320 321 func checkPanic(t *testing.T, wantPanicStr string, f func()) { 322 gotPanicStr := "" 323 func() { 324 defer func() { 325 e := recover() 326 if e == nil { 327 t.Errorf("function did not panic") 328 return 329 } 330 gotPanicStr = fmt.Sprint(e) 331 }() 332 f() 333 }() 334 if got, want := gotPanicStr, wantPanicStr; got != want { 335 t.Errorf("unexpected panic message; got %q want %q", got, want) 336 } 337 }