Files
Agent-Intent/conformance/conformance.go
T
weichen 3a8468c83a Enable canonical versioned Go module consumption
Why: Allow consumers to download an immutable module revision without nested source checkouts or local path replacements.

Evidence: SELF package tests and the prior canonical-path rejection are recorded in the Dev dependency-workspace task card; remote consumption is replayed against the committed candidate.

Impact: Change the module identity and its Go imports while preserving API behavior. Existing historical submodule revisions remain buildable.

Refs: Versioned dependencies U1/U3; feature/dependency-workspace
2026-10-13 15:36:11 +00:00

81 lines
2.6 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// Package conformance 提供 Recognizer 公开契约的行为验收套件。
// 消费方在自己的测试里用真实配置组装 Registry 与 Recognizer 后调用 Run,
// 断言分支、Top、槽位,并附带确定性与并发冒烟检查。
package conformance
import (
"context"
"reflect"
"sync"
"testing"
"git-ssh.u1680832.nyat.app/weichen/Agent-Intent.git/intent"
)
// Case 单条行为验收用例。ExpectTopID 为空断言 Top 为 nil;
// ExpectSlots / ExpectMissingSlots 只对 Top 断言。
type Case struct {
Name string
Input string
ExpectBranch intent.Branch
ExpectTopID string
ExpectSlots map[string]string
ExpectMissingSlots []string
}
// Run 逐条执行用例并输出标准断言失败信息;任何用例失败使 t 失败。
func Run(t *testing.T, rec intent.Recognizer, snap *intent.Snapshot, cases []Case) {
t.Helper()
for _, tc := range cases {
t.Run(tc.Name, func(t *testing.T) {
res, err := rec.Recognize(context.Background(), tc.Input, snap)
if err != nil {
t.Fatalf("recognize %q: %v", tc.Input, err)
}
if res.Branch != tc.ExpectBranch {
t.Fatalf("branch = %s, want %s", res.Branch, tc.ExpectBranch)
}
switch {
case tc.ExpectTopID == "" && res.Top != nil:
t.Fatalf("expected no top, got %+v", res.Top)
case tc.ExpectTopID != "" && res.Top == nil:
t.Fatalf("expected top %s, got nil", tc.ExpectTopID)
case tc.ExpectTopID != "" && res.Top.ID != tc.ExpectTopID:
t.Fatalf("top = %s, want %s", res.Top.ID, tc.ExpectTopID)
}
if res.Top != nil {
for k, v := range tc.ExpectSlots {
if res.Top.Slots[k] != v {
t.Fatalf("slot %s = %q, want %q", k, res.Top.Slots[k], v)
}
}
}
if len(tc.ExpectMissingSlots) > 0 && (res.Top == nil || !reflect.DeepEqual(res.Top.MissingRequiredSlots, tc.ExpectMissingSlots)) {
t.Fatalf("missing slots = %+v, want %v", res.Top, tc.ExpectMissingSlots)
}
// 确定性:同输入 + 同快照 → 同结果。
again, err := rec.Recognize(context.Background(), tc.Input, snap)
if err != nil {
t.Fatalf("second recognize: %v", err)
}
if !reflect.DeepEqual(res, again) {
t.Fatalf("nondeterministic result for %q", tc.Input)
}
})
}
// 并发冒烟:同一快照并行识别互不影响(配合 -race)。
t.Run("parallel-smoke", func(t *testing.T) {
var wg sync.WaitGroup
for _, tc := range cases {
wg.Add(1)
go func(input string) {
defer wg.Done()
if _, err := rec.Recognize(context.Background(), input, snap); err != nil {
t.Errorf("parallel recognize %q: %v", input, err)
}
}(tc.Input)
}
wg.Wait()
})
}