this repo has no description
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

internal/cuetxtar: fix deduplication for at= directives

selectActiveDirectives was keyed solely on directive name, so
multiple @test(err, at=X) directives with different at= values
on one field were collapsed to a single check.

Fix by keying on (directive, at-value) pairs, so each at= target
is an independent assertion.

Signed-off-by: Marcel van Lohuizen <mpvl@gmail.com>
Change-Id: I227b9eaf7159b8e9acef5de7125ce460bd5720fc
Reviewed-on: https://cue.gerrithub.io/c/cue-lang/cue/+/1235390
TryBot-Result: CUEcueckoo <cueckoo@cuelang.org>
Reviewed-by: Daniel Martí <mvdan@mvdan.cc>
Unity-Result: CUE porcuepine <cue.porcuepine@gmail.com>

+70 -11
+8 -6
internal/cuetxtar/inline.go
··· 604 604 candidates = append(candidates, entry{pa: pa, versioned: versioned}) 605 605 } 606 606 607 - // For each directive name, prefer the versioned form. 607 + // For each (directive, at) pair, prefer the versioned form. 608 + // Two directives with the same name but different at= values are independent 609 + // assertions and must both survive deduplication. 608 610 byDirective := make(map[string]parsedTestAttr) 609 611 hasVersioned := make(map[string]bool) 610 612 for _, c := range candidates { 611 - dir := c.pa.directive 613 + key := directiveKey(c.pa) 612 614 if c.versioned { 613 - byDirective[dir] = c.pa 614 - hasVersioned[dir] = true 615 - } else if !hasVersioned[dir] { 616 - byDirective[dir] = c.pa 615 + byDirective[key] = c.pa 616 + hasVersioned[key] = true 617 + } else if !hasVersioned[key] { 618 + byDirective[key] = c.pa 617 619 } 618 620 } 619 621
+12
internal/cuetxtar/inline_attr.go
··· 518 518 // - Integer segments as list-index selectors, e.g. "items.0" → 519 519 // [items, Index(0)]. 520 520 // 521 + // directiveKey returns the deduplication key for a directive. Two directives 522 + // with the same name but different at= values are independent assertions and 523 + // must both survive deduplication in selectActiveDirectives. 524 + func directiveKey(pa parsedTestAttr) string { 525 + for i := 1; i < len(pa.raw.Fields); i++ { 526 + if kv := pa.raw.Fields[i]; kv.Key() == "at" { 527 + return pa.directive + "\x00" + kv.Value() 528 + } 529 + } 530 + return pa.directive 531 + } 532 + 521 533 // Dotted paths are split on "." and each segment is processed independently, 522 534 // so "a._foo$pkg.0" works correctly. 523 535 func parseAtPath(at string) (cue.Path, error) {
+50 -5
internal/cuetxtar/inline_test.go
··· 305 305 parsed: parsedTestAttr{ 306 306 directive: directive, 307 307 version: version, 308 + raw: internal.ParseAttr(&ast.Attribute{Text: "@test(" + directive + ")"}), 308 309 }, 309 310 } 310 311 } 312 + 313 + // makeRecAt creates an attrRecord whose @test directive includes an at= field. 314 + // This is used to test that directives with different at= values are treated 315 + // as independent assertions and both survive deduplication. 316 + func makeRecAt(path, directive, atVal string) attrRecord { 317 + body := directive + ", at=" + atVal 318 + return attrRecord{ 319 + path: testMakePath(path), 320 + parsed: parsedTestAttr{ 321 + directive: directive, 322 + raw: internal.ParseAttr(&ast.Attribute{Text: "@test(" + body + ")"}), 323 + }, 324 + } 325 + } 326 + 311 327 func TestSelectActiveDirectives(t *testing.T) { 312 328 tests := []struct { 313 - name string 314 - records []attrRecord 315 - path string 316 - version string 317 - wantDirs []string 329 + name string 330 + records []attrRecord 331 + path string 332 + version string 333 + wantDirs []string 334 + wantCount int // if non-zero, check exact result count 318 335 }{ 319 336 { 320 337 name: "unversioned applies to all", ··· 360 377 version: "v3", 361 378 wantDirs: []string{"eq", "err"}, 362 379 }, 380 + { 381 + // Two err directives with different at= values must both survive; 382 + // a single err without at= would be collapsed to one. 383 + name: "multiple err directives with distinct at= values both survive", 384 + records: []attrRecord{ 385 + makeRecAt("field1", "err", "path.a"), 386 + makeRecAt("field1", "err", "path.b"), 387 + }, 388 + path: "field1", 389 + version: "v3", 390 + wantDirs: []string{"err", "err"}, 391 + wantCount: 2, 392 + }, 393 + { 394 + // Same at= value: treated as one directive, last wins. 395 + name: "duplicate err directives with same at= value deduplicated", 396 + records: []attrRecord{ 397 + makeRecAt("field1", "err", "path.a"), 398 + makeRecAt("field1", "err", "path.a"), 399 + }, 400 + path: "field1", 401 + version: "v3", 402 + wantDirs: []string{"err"}, 403 + wantCount: 1, 404 + }, 363 405 } 364 406 for _, tt := range tests { 365 407 t.Run(tt.name, func(t *testing.T) { 366 408 got := selectActiveDirectives(tt.records, testMakePath(tt.path), tt.version) 409 + if tt.wantCount != 0 && len(got) != tt.wantCount { 410 + t.Errorf("got %d results, want %d", len(got), tt.wantCount) 411 + } 367 412 var gotDirs []string 368 413 for _, pa := range got { 369 414 gotDirs = append(gotDirs, pa.directive)