Files
dingtalk-workspace-cli/internal/cli/schema_hint_emptiness_contract_test.go
玉澜andCursor d4f6aab04d chore(schema): rename remaining embeddedAgentMetadata fixtures
Finish Catalog/Agent-metadata naming debt so delivery and fixture symbols no
longer imply a retired go:embed Catalog or Hint overlay path.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-08-02 13:59:37 +08:00

115 lines
3.8 KiB
Go

// Copyright 2026 Alibaba Group
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package cli
import (
"os"
"path/filepath"
"sort"
"strconv"
"testing"
"github.com/DingTalk-Real-AI/dingtalk-workspace-cli/internal/corecmd/contract"
)
// TestDeletedProductionSchemaHintFilesStayGone locks stage-3 cleanup: the
// retired production hint init files must not return.
func TestDeletedProductionSchemaHintFilesStayGone(t *testing.T) {
deleted := []string{
"schema_hints_aitable.go",
"schema_hints_attendance.go",
"schema_hints_ding.go",
"schema_hints_helper_roots.go",
"schema_hints_runtime.go",
"schema_manual_hints.go",
"schema_hint_dirs.go",
"schema_hint_decls.go",
"schema_hint_decls_generated.go",
"schema_hints.go",
"schema_wukong_agent_hints_audit.json",
}
for _, name := range deleted {
path := filepath.Join(".", name)
if _, err := os.Stat(path); err == nil {
t.Fatalf("%s must stay deleted after Manual Hint / Schema Hint retirement", name)
} else if !os.IsNotExist(err) {
t.Fatalf("stat %s: %v", name, err)
}
}
}
// TestSchemaHintsDirectoryRetired locks the full schema_hints/ retirement:
// the directory must not reappear as a generation or runtime input.
func TestSchemaHintsDirectoryRetired(t *testing.T) {
if _, err := os.Stat("schema_hints"); !os.IsNotExist(err) {
t.Fatalf("schema_hints/ must stay deleted after HintFile retirement: %v", err)
}
}
// TestDeliveryCatalogHasNoToolSchemaHintProvenance asserts the published
// Catalog no longer selects tool_schema_hint as a provenance winner or
// retained candidate after RegisterSchemaHints → contract.ParamDecl migration.
func TestDeliveryCatalogHasNoToolSchemaHintProvenance(t *testing.T) {
if !deliverySchemaCatalogAvailable() {
t.Fatal("delivery schema Catalog unavailable")
}
loaded := deliverySchemaCatalog()
hits := make([]string, 0)
for _, product := range loaded.Registry.Products {
for _, tool := range product.Tools {
hits = append(hits, toolSchemaHintProvenanceHits(tool.Identity.CanonicalPath, tool.FieldProvenance)...)
for _, param := range tool.Parameters {
prefix := tool.Identity.CanonicalPath + "." + param.Name
hits = append(hits, toolSchemaHintProvenanceHits(prefix, param.FieldProvenance)...)
}
}
}
if total := len(hits); total != 0 {
sample := hits
if total > 20 {
sample = hits[:20]
}
t.Fatalf("catalog field_provenance still references tool_schema_hint (count=%d); sample=%v", total, sample)
}
}
func toolSchemaHintProvenanceHits(prefix string, provenance map[string]contract.FieldProvenance) []string {
if len(provenance) == 0 {
return nil
}
hits := make([]string, 0)
fields := make([]string, 0, len(provenance))
for field := range provenance {
fields = append(fields, field)
}
sort.Strings(fields)
for _, field := range fields {
prov := provenance[field]
if prov.Source == "tool_schema_hint" {
hits = append(hits, prefix+"."+field+"#winner")
}
for i, candidate := range prov.Candidates {
if candidate.Source == "tool_schema_hint" {
hits = append(hits, prefix+"."+field+"#candidate["+strconv.Itoa(i)+"]")
}
}
for i, candidate := range prov.OverriddenCandidates {
if candidate.Source == "tool_schema_hint" {
hits = append(hits, prefix+"."+field+"#overridden["+strconv.Itoa(i)+"]")
}
}
}
return hits
}