Artifact 1a65beea86d3c2292bc214a83bef6f4c5647735f8fd80e556053847379b20f94:
- File
conformance/horizon_annotate_test.go
— part of check-in
[1823fe8ca8]
at
2026-10-23 02:16:05
on branch feat/horizon-cones
— feat(annotate): report lines from at or below a structural horizon
draft-fossil-horizon-00 §5.5 requires an operation needing history below the horizon to detect the crossing and name the horizon. Annotating back past C stopped at the parent the store does not hold and credited every remaining line to the oldest version it reached, presenting a guess as an attribution.
The walk now asks content.BelowHorizon about the parent it could not load; when it lies below the structural horizon, the lines left without credit are marked BelowHorizon and reported against the horizon's check-in. The public AnnotatedLine carries the flag, and repo annotate prints such lines against ^<horizon> with one trailing note naming the horizon and repo cone deepen. A content horizon holds every manifest, so BelowHorizon never fires there; a conformance case clones both depths to show it. HZ-5.5-1 is now covered for every operation it lists. (user: [email protected], size: 3572) [annotate] [blame] [check-ins using] [more...]
package conformance import ( "context" "path/filepath" "testing" "github.com/danmestas/go-libfossil/internal/annotate" "github.com/danmestas/go-libfossil/internal/cone" "github.com/danmestas/go-libfossil/internal/repo" "github.com/danmestas/go-libfossil/internal/sync" ) var horizonStructAnnotate = Case{ID: "horizon.5.5.annotate-crossing", Req: "HZ-5.5-1"} func TestHorizonAnnotateCrossing(t *testing.T) { check(t, horizonStructAnnotate, func() error { return hzAnnotateCrossing(t) }) } // hzAnnotateCrossing: annotating back past C (draft-fossil-horizon-00 §5.5). // The origin's f gains a line at each of c1, c2 = C and c3, and g is // unchanged since c1. In a clone at C's structural horizon the lines whose // origin lies at or below C -- f's first two, g's -- are reported as // originating at the horizon, and f's c3 line keeps c3. A clone at C's // content horizon holds every manifest (§4.1): it marks no line, and g, whose // blob K names, is attributed to c1 as the origin attributes it. func hzAnnotateCrossing(t *testing.T) error { origin := newSCSyncRepo(t, map[string]string{"f": "old\n", "g": "shared\n"}) c2 := origin.commit(t, map[string]string{"f": "old\nmid\n", "g": "shared\n"}, origin.c1) c3 := origin.commit(t, map[string]string{"f": "old\nmid\nnew\n", "g": "shared\n"}, c2) c, tip, below := hzUUID(t, origin.r, c2), hzUUID(t, origin.r, c3), hzUUID(t, origin.r, origin.c1) clone := func(depth cone.HorizonDepth) (*repo.Repo, error) { h, err := cone.NewHorizon(c, cone.RuleDescendants, depth) if err != nil { return nil, err } sc, err := cone.NewWithHorizon(nil, nil, h) if err != nil { return nil, err } r, _, err := sync.Clone(context.Background(), filepath.Join(t.TempDir(), "clone.fossil"), &scSyncPeer{r: origin.r}, sync.CloneOpts{StoreCone: sc, PullPhantoms: true}) if err != nil { return nil, err } t.Cleanup(func() { r.Close() }) return r, nil } type want struct { uuid string below bool } run := func(r *repo.Repo, file string, wants []want) error { rid, err := hzRID(r, tip) if err != nil { return err } lines, err := annotate.Annotate(r, annotate.Options{FilePath: file, StartRID: rid}) if err != nil { return err } if len(lines) != len(wants) { return expectf("%s: %d lines, want %d", file, len(lines), len(wants)) } for i, w := range wants { if lines[i].Version.UUID != w.uuid || lines[i].BelowHorizon != w.below { return expectf("%s line %d %q: %.10s below=%v, want %.10s below=%v", file, i, lines[i].Text, lines[i].Version.UUID, lines[i].BelowHorizon, w.uuid, w.below) } } return nil } structural, err := clone(cone.DepthStructural) if err != nil { return err } if err := run(structural, "f", []want{{c, true}, {c, true}, {tip, false}}); err != nil { return err } if err := run(structural, "g", []want{{c, true}}); err != nil { return err } content, err := clone(cone.DepthContent) if err != nil { return err } if err := run(content, "g", []want{{below, false}}); err != nil { return err } // f's older versions are blobs below the horizon, which only a demand // fetch brings (§4.4); what annotate makes of their absence is no // crossing of a structural horizon. rid, err := hzRID(content, tip) if err != nil { return err } lines, err := annotate.Annotate(content, annotate.Options{FilePath: "f", StartRID: rid}) if err != nil { return err } for _, l := range lines { if l.BelowHorizon { return expectf("a content horizon marked %q below the horizon", l.Text) } } return nil }