this repo has no description
0
fork

Configure Feed

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

internal/cuetxtar: add custom eq formatter for hidden fields and disjunctions

Replace the v.Syntax()-based formatValue with a custom eqWriteValue
implementation that:

- Emits hidden fields in _foo$pkg notation (matching astcmp.go) instead
of silently omitting them, which the old v.Syntax(Hidden(true)) call
would include but with Go-internal package paths rather than the
$pkg-suffix notation the test framework uses.
- Preserves adt.Disjunction structure as *d1 | d2 | d3 (with * marking
defaults) instead of collapsing to the default value via cue.Final().
- Emits adt.Conjunction values as c1 & c2 & c3.
- Falls back to v.Syntax() + format.Node for scalars and lists.

stripTestAttrs is removed; the new formatter never calls v.Syntax() for
structs so there are no source-level @test attributes to strip.

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

+115 -39
+115 -39
internal/cuetxtar/inline.go
··· 55 55 "cuelang.org/go/cue/load" 56 56 "cuelang.org/go/cue/parser" 57 57 "cuelang.org/go/internal" 58 + "cuelang.org/go/internal/core/adt" 58 59 "cuelang.org/go/internal/core/debug" 59 60 "cuelang.org/go/internal/cuetdtest" 60 61 "cuelang.org/go/internal/cuetest" 62 + "cuelang.org/go/internal/value" 61 63 ) 62 64 63 65 // RunInlineTests iterates over txtar archives in dir, detects inline-assertion ··· 1446 1448 // _#def wrapping, then re-enables optional fields (value?: T) so the 1447 1449 // formatted expression round-trips through astCmp. 1448 1450 func (r *inlineRunner) formatValue(v cue.Value) string { 1449 - // cue.Final() routes to Vertex() export (no _#def wrapping) and sets 1450 - // omitOptional=true. cue.Optional(true) applied afterwards re-enables 1451 - // optional fields, giving us the complete value without internals. 1452 - syn := v.Syntax(cue.Docs(true), cue.Final(), cue.Optional(true), cue.Definitions(true), cue.Hidden(true)) 1453 - // Strip @test decl attributes from any struct literals in the exported 1454 - // syntax tree. v.Syntax() may carry over source-level attributes, which 1455 - // must not appear in the formatted expected-value expression. 1456 - stripTestAttrs(syn) 1457 - // Strip all comments from the AST. Error nodes (e.g. _|_) carry line 1458 - // comments like "// path: error message" from v.Syntax(); if these appear 1459 - // inside an @test(eq, ...) attribute body, the // sequence is parsed as a 1460 - // CUE comment, which would consume the closing ) and corrupt the attribute. 1451 + var b strings.Builder 1452 + eqWriteValue(value.OpContext(v), &b, v) 1453 + return b.String() 1454 + } 1455 + 1456 + // eqWriteValue writes a CUE value to b in @test(eq, ...) body notation. 1457 + // 1458 + // Compared with v.Syntax() + cue.Final() + format.Node: 1459 + // - Hidden fields use _foo$pkg notation (matching astcmp.go conventions). 1460 + // - adt.Disjunction values are emitted as *d1 | d2 (with * for defaults) 1461 + // instead of being collapsed to the default by cue.Final(). 1462 + // - adt.Conjunction values are emitted as c1 & c2. 1463 + func eqWriteValue(opCtx *adt.OpContext, b *strings.Builder, v cue.Value) { 1464 + tv := v.Core() 1465 + vx := tv.V.DerefValue() 1466 + 1467 + switch bv := vx.BaseValue.(type) { 1468 + case *adt.Disjunction: 1469 + eqWriteDisjunction(opCtx, b, bv) 1470 + return 1471 + case *adt.Conjunction: 1472 + eqWriteConjunction(opCtx, b, bv) 1473 + return 1474 + } 1475 + 1476 + // Use struct emission if the kind is struct OR if there are arcs — the 1477 + // latter handles error vertices that still carry child fields (e.g. a 1478 + // struct with one bad field: the parent vertex is _|_ but its arcs hold 1479 + // the successfully-evaluated sibling fields). 1480 + if v.IncompleteKind() == cue.StructKind || len(vx.Arcs) > 0 { 1481 + eqWriteStruct(opCtx, b, vx) 1482 + return 1483 + } 1484 + 1485 + // Scalar values and lists: fall back to the standard syntax formatter. 1486 + // cue.Final() resolves defaults and avoids _#def wrapping. 1487 + syn := v.Syntax(cue.Docs(false), cue.Final(), cue.Optional(true)) 1461 1488 stripComments(syn) 1462 - b, err := format.Node(syn, format.Simplify()) 1489 + bs, err := format.Node(syn, format.Simplify()) 1463 1490 if err != nil { 1464 - return fmt.Sprintf("%#v", v) 1491 + fmt.Fprintf(b, "%#v", v) 1492 + } else { 1493 + b.Write(bs) 1465 1494 } 1466 - return string(b) 1495 + } 1496 + 1497 + // eqWriteDisjunction emits disjuncts as *d1 | d2 | d3 (defaults first with *). 1498 + func eqWriteDisjunction(opCtx *adt.OpContext, b *strings.Builder, dj *adt.Disjunction) { 1499 + for i, v := range dj.Values { 1500 + if i > 0 { 1501 + b.WriteString(" | ") 1502 + } 1503 + if i < dj.NumDefaults { 1504 + b.WriteByte('*') 1505 + } 1506 + eqWriteValue(opCtx, b, value.Make(opCtx, v)) 1507 + } 1508 + } 1509 + 1510 + // eqWriteConjunction emits conjuncts as c1 & c2 & c3. 1511 + func eqWriteConjunction(opCtx *adt.OpContext, b *strings.Builder, conj *adt.Conjunction) { 1512 + for i, v := range conj.Values { 1513 + if i > 0 { 1514 + b.WriteString(" & ") 1515 + } 1516 + eqWriteValue(opCtx, b, value.Make(opCtx, v)) 1517 + } 1518 + } 1519 + 1520 + // eqWriteStruct emits a struct, using _foo$pkg notation for hidden-field labels. 1521 + func eqWriteStruct(opCtx *adt.OpContext, b *strings.Builder, vx *adt.Vertex) { 1522 + b.WriteByte('{') 1523 + first := true 1524 + for _, arc := range vx.Arcs { 1525 + if arc.ArcType == adt.ArcNotPresent || arc.Label.IsLet() { 1526 + continue 1527 + } 1528 + // Skip hidden fields from external packages: their PkgID is a full 1529 + // module path (e.g. "mod.test/pkg") which cannot be encoded as a 1530 + // valid CUE identifier in the $pkg suffix notation. 1531 + if arc.Label.IsHidden() { 1532 + pkg := arc.Label.PkgID(opCtx) 1533 + if pkg != "_" && !strings.HasPrefix(pkg, ":") { 1534 + continue 1535 + } 1536 + } 1537 + if !first { 1538 + b.WriteString(", ") 1539 + } 1540 + first = false 1541 + eqWriteLabel(opCtx, b, arc.Label, arc.ArcType) 1542 + b.WriteString(": ") 1543 + eqWriteValue(opCtx, b, value.Make(opCtx, arc)) 1544 + } 1545 + b.WriteByte('}') 1546 + } 1547 + 1548 + // eqWriteLabel writes a field label. 1549 + // For hidden labels the $pkg qualifier is included when the field is 1550 + // package-scoped (pkg != "_"). Callers must ensure the label's PkgID is 1551 + // either "_" or colon-prefixed (inline package) before calling — see 1552 + // the skip guard in eqWriteStruct. 1553 + func eqWriteLabel(opCtx *adt.OpContext, b *strings.Builder, f adt.Feature, arcType adt.ArcType) { 1554 + if f.IsHidden() { 1555 + name := f.IdentString(opCtx) 1556 + pkg := f.PkgID(opCtx) 1557 + if pkg != "_" { 1558 + // PkgID returns ":pkgname" for inline sources; convert to "$pkgname". 1559 + b.WriteString(name + "$" + strings.TrimPrefix(pkg, ":")) 1560 + } else { 1561 + b.WriteString(name) 1562 + } 1563 + } else { 1564 + b.WriteString(f.SelectorString(opCtx)) 1565 + } 1566 + b.WriteString(arcType.Suffix()) 1467 1567 } 1468 1568 1469 1569 // stripComments removes all comment groups from every node in the AST. ··· 1474 1574 func stripComments(node ast.Node) { 1475 1575 ast.Walk(node, func(n ast.Node) bool { 1476 1576 ast.SetComments(n, nil) 1477 - return true 1478 - }, nil) 1479 - } 1480 - 1481 - // stripTestAttrs removes @test(...) decl-level attributes from all struct 1482 - // literals in the AST node. This prevents source-level test annotations from 1483 - // leaking into @test(eq, ...) expected-value expressions written by CUE_UPDATE. 1484 - func stripTestAttrs(node ast.Node) { 1485 - ast.Walk(node, func(n ast.Node) bool { 1486 - sl, ok := n.(*ast.StructLit) 1487 - if !ok { 1488 - return true 1489 - } 1490 - elts := sl.Elts[:0] 1491 - for _, e := range sl.Elts { 1492 - if a, ok := e.(*ast.Attribute); ok { 1493 - k, _ := a.Split() 1494 - if k == "test" { 1495 - continue 1496 - } 1497 - } 1498 - elts = append(elts, e) 1499 - } 1500 - sl.Elts = elts 1501 1577 return true 1502 1578 }, nil) 1503 1579 }