package pipeline import ( "encoding/json" "strings" "testing" "gitea.maximumdirect.net/eric/notarius/internal/core/source" ) func TestChunkCanonicalizationAndClonePreserveAnnotationScopes(t *testing.T) { doc := validSourceDocument() plan := source.ChunkPlan{ SourceDigest: doc.Digest, Ranges: []source.ChunkRange{{ StartUnitID: doc.Units[0].ID, EndUnitID: doc.Units[0].ID, Annotations: source.ChunkAnnotations{"shared": json.RawMessage(` {"range": true} `)}, }}, Annotations: source.ChunkAnnotations{"shared": json.RawMessage(` {"plan": true} `)}, } canonical, chunks, err := validateAndMaterializeChunkPlan(doc, plan) if err != nil { t.Fatalf("validateAndMaterializeChunkPlan() error = %v", err) } if got := string(canonical.Ranges[0].Annotations["shared"]); got != `{"range":true}` { t.Fatalf("range annotation = %q", got) } if got := string(canonical.Annotations["shared"]); got != `{"plan":true}` { t.Fatalf("plan annotation = %q", got) } cloned, err := cloneSourceChunk(chunks[0]) if err != nil { t.Fatal(err) } cloned.Annotations["shared"][0] = '[' cloned.PlanAnnotations["shared"][0] = '[' if string(chunks[0].Annotations["shared"]) != `{"range":true}` || string(chunks[0].PlanAnnotations["shared"]) != `{"plan":true}` { t.Fatal("cloneSourceChunk() shares annotation bytes") } } func TestSerializedChunkValidationRepresentationIncludesAnnotationScopes(t *testing.T) { doc := validSourceDocument() chunks := []source.Chunk{{ ID: "chunk-1", SourceID: doc.ID, Ref: doc.Units[0].Ref, MediaType: "application/json", Units: doc.Units[:1], Annotations: source.ChunkAnnotations{"same": json.RawMessage(`{"range":1}`)}, PlanAnnotations: source.ChunkAnnotations{"same": json.RawMessage(`{"plan":2}`)}, }} encoded, err := json.Marshal(chunks) if err != nil { t.Fatalf("json.Marshal(chunks) error = %v", err) } got := string(encoded) if !strings.Contains(got, `"annotations":{"same":{"range":1}}`) || !strings.Contains(got, `"plan_annotations":{"same":{"plan":2}}`) { t.Fatalf("serialized chunks = %s, want both annotation scopes", got) } } func TestDebugChunkEnvelopeClonesAnnotationScopes(t *testing.T) { chunk := source.Chunk{ ID: "chunk-1", SourceID: "source-1", Annotations: source.ChunkAnnotations{"same": json.RawMessage(`{"range":1}`)}, PlanAnnotations: source.ChunkAnnotations{"same": json.RawMessage(`{"plan":2}`)}, } envelope := debugSourceChunkEnvelope(chunk) if string(envelope.Annotations["same"]) != `{"range":1}` || string(envelope.PlanAnnotations["same"]) != `{"plan":2}` { t.Fatalf("debug annotations = %#v / %#v", envelope.Annotations, envelope.PlanAnnotations) } envelope.Annotations["same"][0] = '[' envelope.PlanAnnotations["same"][0] = '[' if string(chunk.Annotations["same"]) != `{"range":1}` || string(chunk.PlanAnnotations["same"]) != `{"plan":2}` { t.Fatal("debugSourceChunkEnvelope() shares annotation bytes") } }