cuelang.org/go@v0.13.0/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 *testing.T, m *cuetdtest.M) { 100 v := getValue(m, 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 func TestAttributeErr(t *testing.T) { 111 const config = ` 112 a: { 113 a: 0 @foo(a,b,c=1) 114 b: 1 @bar(a,b,c,d=1) @foo(a,,d=1) 115 } 116 ` 117 testCases := []struct { 118 path string 119 attr string 120 err error 121 }{{ 122 path: "a", 123 attr: "foo", 124 err: nil, 125 }, { 126 path: "a", 127 attr: "bar", 128 err: errors.New(`attribute "bar" does not exist`), 129 }, { 130 path: "xx", 131 attr: "bar", 132 err: errors.New(`attribute "bar" does not exist`), 133 }, { 134 path: "e", 135 attr: "bar", 136 err: errors.New(`attribute "bar" does not exist`), 137 }} 138 for _, tc := range testCases { 139 cuetdtest.FullMatrix.Run(t, tc.path+"-"+tc.attr, func(t *testing.T, m *cuetdtest.M) { 140 v := getValue(m, config).Lookup("a", tc.path) 141 a := v.Attribute(tc.attr) 142 err := a.Err() 143 if !cmpError(err, tc.err) { 144 t.Errorf("got %v; want %v", err, tc.err) 145 } 146 }) 147 } 148 } 149 150 func TestAttributeName(t *testing.T) { 151 const config = ` 152 a: 0 @foo(a,b,c=1) @bar() 153 ` 154 cuetdtest.FullMatrix.Do(t, func(t *testing.T, m *cuetdtest.M) { 155 v := getValue(m, config).Lookup("a") 156 a := v.Attribute("foo") 157 if got, want := a.Name(), "foo"; got != want { 158 t.Errorf("got %v; want %v", got, want) 159 } 160 }) 161 } 162 163 func TestAttributeString(t *testing.T) { 164 const config = ` 165 a: { 166 a: 0 @foo(a,b,c=1) 167 b: 1 @bar(a,b,c,d=1) @foo(a,,d=1,e="x y","f g") 168 } 169 ` 170 testCases := []struct { 171 path string 172 attr string 173 pos int 174 str string 175 err error 176 }{{ 177 path: "a", 178 attr: "foo", 179 pos: 0, 180 str: "a", 181 }, { 182 path: "a", 183 attr: "foo", 184 pos: 2, 185 str: "c=1", 186 }, { 187 path: "b", 188 attr: "bar", 189 pos: 3, 190 str: "d=1", 191 }, { 192 path: "b", 193 attr: "foo", 194 pos: 3, 195 str: `e="x y"`, 196 }, { 197 path: "b", 198 attr: "foo", 199 pos: 4, 200 str: `f g`, 201 }, { 202 path: "e", 203 attr: "bar", 204 err: errors.New(`attribute "bar" does not exist`), 205 }, { 206 path: "b", 207 attr: "foo", 208 pos: 5, 209 err: errors.New("field does not exist"), 210 }} 211 for _, tc := range testCases { 212 cuetdtest.FullMatrix.Run(t, fmt.Sprintf("%s.%s:%d", tc.path, tc.attr, tc.pos), func(t *testing.T, m *cuetdtest.M) { 213 v := getValue(m, config).Lookup("a", tc.path) 214 a := v.Attribute(tc.attr) 215 got, err := a.String(tc.pos) 216 if !cmpError(err, tc.err) { 217 t.Errorf("err: got %v; want %v", err, tc.err) 218 } 219 if got != tc.str { 220 t.Errorf("str: got %v; want %v", got, tc.str) 221 } 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 *testing.T, m *cuetdtest.M) { 274 v := getValue(m, 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 c: 2 @nongo(10Mi) 297 } 298 ` 299 testCases := []struct { 300 path string 301 attr string 302 pos int 303 val int64 304 err error 305 }{{ 306 path: "a", 307 attr: "foo", 308 pos: 0, 309 val: 1, 310 }, { 311 path: "b", 312 attr: "bar", 313 pos: 1, 314 val: -4, 315 }, { 316 path: "e", 317 attr: "bar", 318 err: errors.New(`attribute "bar" does not exist`), 319 }, { 320 path: "b", 321 attr: "foo", 322 pos: 4, 323 err: errors.New("field does not exist"), 324 }, { 325 path: "a", 326 attr: "foo", 327 pos: 2, 328 err: errors.New(`illegal number start "c=1"`), 329 }, { 330 path: "c", 331 attr: "nongo", 332 pos: 0, 333 val: 10 << 20, 334 }} 335 for _, tc := range testCases { 336 cuetdtest.FullMatrix.Run(t, fmt.Sprintf("%s.%s:%d", tc.path, tc.attr, tc.pos), func(t *testing.T, m *cuetdtest.M) { 337 v := getValue(m, config).Lookup("a", tc.path) 338 a := v.Attribute(tc.attr) 339 got, err := a.Int(tc.pos) 340 if !cmpError(err, tc.err) { 341 t.Errorf("err: got %v; want %v", err, tc.err) 342 } 343 if got != tc.val { 344 t.Errorf("val: got %v; want %v", got, tc.val) 345 } 346 }) 347 } 348 } 349 350 func TestAttributeFlag(t *testing.T) { 351 const config = ` 352 a: { 353 a: 0 @foo(a,b,c=1) 354 b: 1 @bar(a,b,c,d=1) @foo(a,,d=1) 355 } 356 ` 357 testCases := []struct { 358 path string 359 attr string 360 pos int 361 flag string 362 val bool 363 err error 364 }{{ 365 path: "a", 366 attr: "foo", 367 pos: 0, 368 flag: "a", 369 val: true, 370 }, { 371 path: "b", 372 attr: "bar", 373 pos: 1, 374 flag: "a", 375 val: false, 376 }, { 377 path: "b", 378 attr: "bar", 379 pos: 0, 380 flag: "c", 381 val: true, 382 }, { 383 path: "e", 384 attr: "bar", 385 err: errors.New(`attribute "bar" does not exist`), 386 }, { 387 path: "b", 388 attr: "foo", 389 pos: 4, 390 err: errors.New("field does not exist"), 391 }} 392 for _, tc := range testCases { 393 cuetdtest.FullMatrix.Run(t, fmt.Sprintf("%s.%s:%d", tc.path, tc.attr, tc.pos), func(t *testing.T, m *cuetdtest.M) { 394 v := getValue(m, config).Lookup("a", tc.path) 395 a := v.Attribute(tc.attr) 396 got, err := a.Flag(tc.pos, tc.flag) 397 if !cmpError(err, tc.err) { 398 t.Errorf("err: got %v; want %v", err, tc.err) 399 } 400 if got != tc.val { 401 t.Errorf("val: got %v; want %v", got, tc.val) 402 } 403 }) 404 } 405 } 406 407 func TestAttributeLookup(t *testing.T) { 408 const config = ` 409 a: { 410 a: 0 @foo(a,b,c=1) 411 b: 1 @bar(a,b,e =-5,d=1) @foo(a,,d=1) 412 } 413 ` 414 testCases := []struct { 415 path string 416 attr string 417 pos int 418 key string 419 val string 420 err error 421 }{{ 422 path: "a", 423 attr: "foo", 424 pos: 0, 425 key: "c", 426 val: "1", 427 }, { 428 path: "b", 429 attr: "bar", 430 pos: 1, 431 key: "a", 432 val: "", 433 }, { 434 path: "b", 435 attr: "bar", 436 pos: 0, 437 key: "e", 438 val: "-5", 439 }, { 440 path: "b", 441 attr: "bar", 442 pos: 0, 443 key: "d", 444 val: "1", 445 }, { 446 path: "b", 447 attr: "foo", 448 pos: 2, 449 key: "d", 450 val: "1", 451 }, { 452 path: "b", 453 attr: "foo", 454 pos: 2, 455 key: "f", 456 val: "", 457 }, { 458 path: "e", 459 attr: "bar", 460 err: errors.New(`attribute "bar" does not exist`), 461 }, { 462 path: "b", 463 attr: "foo", 464 pos: 4, 465 err: errors.New("field does not exist"), 466 }} 467 for _, tc := range testCases { 468 cuetdtest.FullMatrix.Run(t, fmt.Sprintf("%s.%s:%d", tc.path, tc.attr, tc.pos), func(t *testing.T, m *cuetdtest.M) { 469 v := getValue(m, config).Lookup("a", tc.path) 470 a := v.Attribute(tc.attr) 471 got, _, err := a.Lookup(tc.pos, tc.key) 472 if !cmpError(err, tc.err) { 473 t.Errorf("err: got %v; want %v", err, tc.err) 474 } 475 if got != tc.val { 476 t.Errorf("val: got %v; want %v", got, tc.val) 477 } 478 }) 479 } 480 }