Files
Agent-Intent/conformance/conformance.go
T
weichen b58595fb38 Implement the intent core
Details (original message):
Implement the intent core, conformance suite, catalog alignment, examples, and the intentctl diagnostics CLI.
2026-09-29 15:35:18 +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"
"agent-intent/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()
})
}