cuelang.org/go@v0.10.1/cue/attribute_test.go (about) 1 // Copyright 2021 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_test 16 17 import ( 18 "fmt" 19 "testing" 20 21 "cuelang.org/go/cue" 22 "cuelang.org/go/cue/errors" 23 "cuelang.org/go/internal/cuetdtest" 24 ) 25 26 func TestAttributes(t *testing.T) { 27 const config = ` 28 a: { 29 a: 0 @foo(a,b,c=1) 30 b: 1 @bar(a,b,c,d=1) @foo(a,,d=1) 31 } 32 b: { 33 @embed(foo) 34 3 35 } @field(foo) 36 37 c1: {} @step(1) 38 if true { 39 c2: { @step(2a) } @step(2b) 40 @step(2c) 41 } 42 c3: {} @step(3) 43 if false { 44 c4: { @step(4a) } @step(4b) 45 @step(4c) 46 } 47 ` 48 49 testCases := []struct { 50 flags cue.AttrKind 51 path string 52 out string 53 }{{ 54 flags: cue.FieldAttr, 55 path: "a.a", 56 out: "[@foo(a,b,c=1)]", 57 }, { 58 flags: cue.FieldAttr, 59 path: "a.b", 60 out: "[@bar(a,b,c,d=1) @foo(a,,d=1)]", 61 }, { 62 flags: cue.DeclAttr, 63 path: "b", 64 out: "[@embed(foo)]", 65 }, { 66 flags: cue.FieldAttr, 67 path: "b", 68 out: "[@field(foo)]", 69 }, { 70 flags: cue.ValueAttr, 71 path: "b", 72 out: "[@field(foo) @embed(foo)]", 73 }, { 74 flags: cue.ValueAttr, 75 path: "c1", 76 out: "[@step(1)]", 77 }, { 78 flags: cue.DeclAttr, 79 path: "c2", 80 out: "[@step(2a)]", 81 }, { 82 flags: cue.FieldAttr, 83 path: "c2", 84 out: "[@step(2b)]", 85 }, { 86 flags: cue.DeclAttr, 87 path: "", 88 out: "[@step(2c)]", 89 }, { 90 flags: cue.ValueAttr | cue.FieldAttr, 91 path: "c3", 92 out: "[@step(3)]", 93 }, { 94 flags: cue.ValueAttr | cue.FieldAttr, 95 path: "c4", 96 out: "[]", 97 }} 98 for _, tc := range testCases { 99 cuetdtest.FullMatrix.Run(t, tc.path, func(t *cuetdtest.M) { 100 v := getValue(t, config).LookupPath(cue.ParsePath(tc.path)) 101 a := v.Attributes(tc.flags) 102 got := fmt.Sprint(a) 103 if got != tc.out { 104 t.Errorf("got %v; want %v", got, tc.out) 105 } 106 107 }) 108 } 109 } 110 111 func TestAttributeErr(t *testing.T) { 112 const config = ` 113 a: { 114 a: 0 @foo(a,b,c=1) 115 b: 1 @bar(a,b,c,d=1) @foo(a,,d=1) 116 } 117 ` 118 testCases := []struct { 119 path string 120 attr string 121 err error 122 }{{ 123 path: "a", 124 attr: "foo", 125 err: nil, 126 }, { 127 path: "a", 128 attr: "bar", 129 err: errors.New(`attribute "bar" does not exist`), 130 }, { 131 path: "xx", 132 attr: "bar", 133 err: errors.New(`attribute "bar" does not exist`), 134 }, { 135 path: "e", 136 attr: "bar", 137 err: errors.New(`attribute "bar" does not exist`), 138 }} 139 for _, tc := range testCases { 140 cuetdtest.FullMatrix.Run(t, tc.path+"-"+tc.attr, func(t *cuetdtest.M) { 141 v := getValue(t, config).Lookup("a", tc.path) 142 a := v.Attribute(tc.attr) 143 err := a.Err() 144 if !cmpError(err, tc.err) { 145 t.Errorf("got %v; want %v", err, tc.err) 146 } 147 }) 148 } 149 } 150 151 func TestAttributeName(t *testing.T) { 152 const config = ` 153 a: 0 @foo(a,b,c=1) @bar() 154 ` 155 cuetdtest.FullMatrix.Do(t, func(t *cuetdtest.M) { 156 v := getValue(t, config).Lookup("a") 157 a := v.Attribute("foo") 158 if got, want := a.Name(), "foo"; got != want { 159 t.Errorf("got %v; want %v", got, want) 160 } 161 }) 162 } 163 164 func TestAttributeString(t *testing.T) { 165 const config = ` 166 a: { 167 a: 0 @foo(a,b,c=1) 168 b: 1 @bar(a,b,c,d=1) @foo(a,,d=1,e="x y","f g") 169 } 170 ` 171 testCases := []struct { 172 path string 173 attr string 174 pos int 175 str string 176 err error 177 }{{ 178 path: "a", 179 attr: "foo", 180 pos: 0, 181 str: "a", 182 }, { 183 path: "a", 184 attr: "foo", 185 pos: 2, 186 str: "c=1", 187 }, { 188 path: "b", 189 attr: "bar", 190 pos: 3, 191 str: "d=1", 192 }, { 193 path: "b", 194 attr: "foo", 195 pos: 3, 196 str: `e="x y"`, 197 }, { 198 path: "b", 199 attr: "foo", 200 pos: 4, 201 str: `f g`, 202 }, { 203 path: "e", 204 attr: "bar", 205 err: errors.New(`attribute "bar" does not exist`), 206 }, { 207 path: "b", 208 attr: "foo", 209 pos: 5, 210 err: errors.New("field does not exist"), 211 }} 212 for _, tc := range testCases { 213 cuetdtest.FullMatrix.Run(t, fmt.Sprintf("%s.%s:%d", tc.path, tc.attr, tc.pos), func(t *cuetdtest.M) { 214 v := getValue(t, config).Lookup("a", tc.path) 215 a := v.Attribute(tc.attr) 216 got, err := a.String(tc.pos) 217 if !cmpError(err, tc.err) { 218 t.Errorf("err: got %v; want %v", err, tc.err) 219 } 220 if got != tc.str { 221 t.Errorf("str: got %v; want %v", got, tc.str) 222 } 223 }) 224 } 225 } 226 227 func TestAttributeArg(t *testing.T) { 228 const config = ` 229 a: 1 @foo(a,,d=1,e="x y","f g", with spaces , s= spaces in value ) 230 ` 231 testCases := []struct { 232 pos int 233 key string 234 val string 235 raw string 236 }{{ 237 pos: 0, 238 key: "a", 239 val: "", 240 raw: "a", 241 }, { 242 pos: 1, 243 key: "", 244 val: "", 245 raw: "", 246 }, { 247 pos: 2, 248 key: "d", 249 val: "1", 250 raw: "d=1", 251 }, { 252 pos: 3, 253 key: "e", 254 val: "x y", 255 raw: `e="x y"`, 256 }, { 257 pos: 4, 258 key: "f g", 259 val: "", 260 raw: `"f g"`, 261 }, { 262 pos: 5, 263 key: "with spaces", 264 val: "", 265 raw: " with spaces ", 266 }, { 267 pos: 6, 268 key: "s", 269 val: "spaces in value", 270 raw: " s= spaces in value ", 271 }} 272 for _, tc := range testCases { 273 cuetdtest.FullMatrix.Run(t, fmt.Sprintf("%d", tc.pos), func(t *cuetdtest.M) { 274 v := getValue(t, config).Lookup("a") 275 a := v.Attribute("foo") 276 key, val := a.Arg(tc.pos) 277 raw := a.RawArg(tc.pos) 278 if got, want := key, tc.key; got != want { 279 t.Errorf("unexpected key; got %q want %q", got, want) 280 } 281 if got, want := val, tc.val; got != want { 282 t.Errorf("unexpected value; got %q want %q", got, want) 283 } 284 if got, want := raw, tc.raw; got != want { 285 t.Errorf("unexpected raw value; got %q want %q", got, want) 286 } 287 }) 288 } 289 } 290 291 func TestAttributeInt(t *testing.T) { 292 const config = ` 293 a: { 294 a: 0 @foo(1,3,c=1) 295 b: 1 @bar(a,-4,c,d=1) @foo(a,,d=1) 296 } 297 ` 298 testCases := []struct { 299 path string 300 attr string 301 pos int 302 val int64 303 err error 304 }{{ 305 path: "a", 306 attr: "foo", 307 pos: 0, 308 val: 1, 309 }, { 310 path: "b", 311 attr: "bar", 312 pos: 1, 313 val: -4, 314 }, { 315 path: "e", 316 attr: "bar", 317 err: errors.New(`attribute "bar" does not exist`), 318 }, { 319 path: "b", 320 attr: "foo", 321 pos: 4, 322 err: errors.New("field does not exist"), 323 }, { 324 path: "a", 325 attr: "foo", 326 pos: 2, 327 err: errors.New(`strconv.ParseInt: parsing "c=1": invalid syntax`), 328 }} 329 for _, tc := range testCases { 330 cuetdtest.FullMatrix.Run(t, fmt.Sprintf("%s.%s:%d", tc.path, tc.attr, tc.pos), func(t *cuetdtest.M) { 331 v := getValue(t, config).Lookup("a", tc.path) 332 a := v.Attribute(tc.attr) 333 got, err := a.Int(tc.pos) 334 if !cmpError(err, tc.err) { 335 t.Errorf("err: got %v; want %v", err, tc.err) 336 } 337 if got != tc.val { 338 t.Errorf("val: got %v; want %v", got, tc.val) 339 } 340 }) 341 } 342 } 343 344 func TestAttributeFlag(t *testing.T) { 345 const config = ` 346 a: { 347 a: 0 @foo(a,b,c=1) 348 b: 1 @bar(a,b,c,d=1) @foo(a,,d=1) 349 } 350 ` 351 testCases := []struct { 352 path string 353 attr string 354 pos int 355 flag string 356 val bool 357 err error 358 }{{ 359 path: "a", 360 attr: "foo", 361 pos: 0, 362 flag: "a", 363 val: true, 364 }, { 365 path: "b", 366 attr: "bar", 367 pos: 1, 368 flag: "a", 369 val: false, 370 }, { 371 path: "b", 372 attr: "bar", 373 pos: 0, 374 flag: "c", 375 val: true, 376 }, { 377 path: "e", 378 attr: "bar", 379 err: errors.New(`attribute "bar" does not exist`), 380 }, { 381 path: "b", 382 attr: "foo", 383 pos: 4, 384 err: errors.New("field does not exist"), 385 }} 386 for _, tc := range testCases { 387 cuetdtest.FullMatrix.Run(t, fmt.Sprintf("%s.%s:%d", tc.path, tc.attr, tc.pos), func(t *cuetdtest.M) { 388 v := getValue(t, config).Lookup("a", tc.path) 389 a := v.Attribute(tc.attr) 390 got, err := a.Flag(tc.pos, tc.flag) 391 if !cmpError(err, tc.err) { 392 t.Errorf("err: got %v; want %v", err, tc.err) 393 } 394 if got != tc.val { 395 t.Errorf("val: got %v; want %v", got, tc.val) 396 } 397 }) 398 } 399 } 400 401 func TestAttributeLookup(t *testing.T) { 402 const config = ` 403 a: { 404 a: 0 @foo(a,b,c=1) 405 b: 1 @bar(a,b,e =-5,d=1) @foo(a,,d=1) 406 } 407 ` 408 testCases := []struct { 409 path string 410 attr string 411 pos int 412 key string 413 val string 414 err error 415 }{{ 416 path: "a", 417 attr: "foo", 418 pos: 0, 419 key: "c", 420 val: "1", 421 }, { 422 path: "b", 423 attr: "bar", 424 pos: 1, 425 key: "a", 426 val: "", 427 }, { 428 path: "b", 429 attr: "bar", 430 pos: 0, 431 key: "e", 432 val: "-5", 433 }, { 434 path: "b", 435 attr: "bar", 436 pos: 0, 437 key: "d", 438 val: "1", 439 }, { 440 path: "b", 441 attr: "foo", 442 pos: 2, 443 key: "d", 444 val: "1", 445 }, { 446 path: "b", 447 attr: "foo", 448 pos: 2, 449 key: "f", 450 val: "", 451 }, { 452 path: "e", 453 attr: "bar", 454 err: errors.New(`attribute "bar" does not exist`), 455 }, { 456 path: "b", 457 attr: "foo", 458 pos: 4, 459 err: errors.New("field does not exist"), 460 }} 461 for _, tc := range testCases { 462 cuetdtest.FullMatrix.Run(t, fmt.Sprintf("%s.%s:%d", tc.path, tc.attr, tc.pos), func(t *cuetdtest.M) { 463 v := getValue(t, config).Lookup("a", tc.path) 464 a := v.Attribute(tc.attr) 465 got, _, err := a.Lookup(tc.pos, tc.key) 466 if !cmpError(err, tc.err) { 467 t.Errorf("err: got %v; want %v", err, tc.err) 468 } 469 if got != tc.val { 470 t.Errorf("val: got %v; want %v", got, tc.val) 471 } 472 }) 473 } 474 }