Compare commits

...
Author SHA1 Message Date
Dennis bee1a91b74 fix(calendar): keep pagination out of result data 2026-08-18 00:41:34 +08:00
3 changed files with 75 additions and 1 deletions
@@ -28,4 +28,22 @@ func TestCrossPlatformCoverageCalendarAgendaFinalSchemaPreservesCompositePropert
if got := schemaContractString(tool["interface_mode"]); got != "composite" {
t.Fatalf("calendar.shortcut_agenda interface_mode=%q, want composite", got)
}
result := schemaContractMap(tool["result"])
dataSchema := schemaContractMap(result["data_schema"])
properties := schemaContractMap(dataSchema["properties"])
for _, field := range []string{"hasMore", "nextCursor"} {
if _, exists := properties[field]; exists {
t.Fatalf("calendar.shortcut_agenda Result data_schema leaked pagination field %q", field)
}
}
if properties["complete"] == nil {
t.Fatal("calendar.shortcut_agenda Result data_schema is missing complete")
}
pagination, ok := tool["pagination"].(map[string]any)
if !ok {
t.Fatalf("calendar.shortcut_agenda pagination=%T, want object", tool["pagination"])
}
if got := schemaContractString(pagination["meta_path"]); got != "meta.pagination" {
t.Fatalf("calendar.shortcut_agenda pagination meta_path=%q, want meta.pagination", got)
}
}
@@ -4,6 +4,9 @@
package calendar
import (
"bytes"
"context"
"encoding/json"
"math"
"strconv"
"strings"
@@ -39,6 +42,21 @@ func TestCrossPlatformCoverageCalendarCommonBranches(t *testing.T) {
if calendarReadShortcut("+x", "x", "x", "items", nil, nil, nil).Contract.Result == nil {
t.Fatal("collection read shortcut did not build a result")
}
collectionResult := calendarCollectionResult("items", "items")
var collectionSchema struct {
Properties map[string]json.RawMessage `json:"properties"`
}
if err := json.Unmarshal(collectionResult.DataSchema, &collectionSchema); err != nil {
t.Fatalf("decode collection result schema: %v", err)
}
for _, field := range []string{"hasMore", "nextCursor"} {
if _, exists := collectionSchema.Properties[field]; exists {
t.Fatalf("pagination field %q leaked into business Result schema", field)
}
}
if _, exists := collectionSchema.Properties["complete"]; !exists {
t.Fatal("collection Result schema lost business completeness evidence")
}
if calendarWriteShortcut("+x", "x", "x", "dws calendar +x", nil, nil, nil).Safety.Confirmation != "user_required" {
t.Fatal("write shortcut did not build safety")
}
@@ -178,6 +196,44 @@ func TestCrossPlatformCoverageCalendarCommonBranches(t *testing.T) {
if err := runCalendarCoverage(t, legacyPage, &calendarCoverageCaller{responses: map[string][]string{}}, "--event", "event-1"); err != nil {
t.Fatalf("legacy pagination output: %v", err)
}
unifiedPage := EventGet
unifiedPage.OutputRollout = output.RolloutUnifiedActive
cmd := corecmd.New(shortcut.FromShortcut(unifiedPage))
ctx, _ := output.WithResultStore(context.Background())
cmd.SetContext(ctx)
var stdout bytes.Buffer
cmd.SetOut(&stdout)
rt := shortcut.RuntimeContextForTest(cmd, unifiedPage)
if err := outputCalendarPage(rt, map[string]any{"count": 1, "items": []any{map[string]any{"id": "item-1"}}}, calendarPageEvidence{Known: true, HasMore: true, NextCursor: "cursor-2"}); err != nil {
t.Fatalf("store unified pagination result: %v", err)
}
if code, emitted, err := output.EmitStoredResult(cmd); err != nil || !emitted || code != 0 {
t.Fatalf("emit unified pagination result: code=%d emitted=%v err=%v", code, emitted, err)
}
var envelope struct {
Data map[string]any `json:"data"`
Meta struct {
Pagination *struct {
EndpointExhausted bool `json:"endpoint_exhausted"`
NextToken string `json:"next_token"`
} `json:"pagination"`
} `json:"meta"`
}
if err := json.Unmarshal(stdout.Bytes(), &envelope); err != nil {
t.Fatalf("decode unified pagination output: %v\n%s", err, stdout.String())
}
for _, field := range []string{"hasMore", "nextCursor"} {
if _, exists := envelope.Data[field]; exists {
t.Fatalf("pagination field %q leaked into business data: %s", field, stdout.String())
}
}
if envelope.Data["complete"] != false {
t.Fatalf("business completeness=%#v, want false: %s", envelope.Data["complete"], stdout.String())
}
if envelope.Meta.Pagination == nil || envelope.Meta.Pagination.EndpointExhausted || envelope.Meta.Pagination.NextToken != "cursor-2" {
t.Fatalf("pagination meta=%+v: %s", envelope.Meta.Pagination, stdout.String())
}
}
func TestCrossPlatformCoverageCalendarEventGetSearchAndSuggestion(t *testing.T) {
+1 -1
View File
@@ -66,7 +66,7 @@ func calendarCollectionResult(collection, description string) *contract.ResultSp
return &contract.ResultSpec{
Outcomes: []contract.ResultOutcome{contract.ResultOutcomeSuccess, contract.ResultOutcomeFailure},
DataSchema: json.RawMessage(fmt.Sprintf(
`{"type":"object","description":%q,"properties":{"count":{"type":"integer","description":"本页有效业务记录数量"},%q:{"type":"array","description":%q,"items":{"type":"object","description":"Calendar 业务条目","additionalProperties":true}},"complete":{"type":"boolean","description":"服务端分页证据是否证明结果已完整"},"hasMore":{"type":"boolean","description":"服务端是否明确仍有后续页"},"nextCursor":{"type":"string","description":"服务端返回的下一页游标"}},"required":["count",%q,"complete"],"additionalProperties":true}`,
`{"type":"object","description":%q,"properties":{"count":{"type":"integer","description":"本页有效业务记录数量"},%q:{"type":"array","description":%q,"items":{"type":"object","description":"Calendar 业务条目","additionalProperties":true}},"complete":{"type":"boolean","description":"服务端分页证据是否证明结果已完整"}},"required":["count",%q,"complete"],"additionalProperties":true}`,
description, collection, description, collection,
)),
}