116 lines
3.9 KiB
Go
116 lines
3.9 KiB
Go
// Copyright 2026 Alibaba Group
|
|
// Licensed under the Apache License, Version 2.0
|
|
|
|
package skillprovenance
|
|
|
|
import (
|
|
"errors"
|
|
"io/fs"
|
|
"os"
|
|
"path/filepath"
|
|
"reflect"
|
|
"testing"
|
|
)
|
|
|
|
type fakeDirEntry struct {
|
|
name string
|
|
mode fs.FileMode
|
|
}
|
|
|
|
func (entry fakeDirEntry) Name() string { return entry.name }
|
|
func (entry fakeDirEntry) IsDir() bool { return entry.mode.IsDir() }
|
|
func (entry fakeDirEntry) Type() fs.FileMode { return entry.mode.Type() }
|
|
func (entry fakeDirEntry) Info() (fs.FileInfo, error) { return nil, errors.New("unused") }
|
|
|
|
func swapProvenanceSeam[T any](t *testing.T, target *T, replacement T) {
|
|
t.Helper()
|
|
original := *target
|
|
*target = replacement
|
|
t.Cleanup(func() { *target = original })
|
|
}
|
|
|
|
func TestCrossPlatformCoverageSkillProvenanceBuildDigestAndMerge(t *testing.T) {
|
|
dir := t.TempDir()
|
|
if err := os.MkdirAll(filepath.Join(dir, "references"), 0o755); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := os.WriteFile(filepath.Join(dir, "SKILL.md"), []byte("skill"), 0o644); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := os.WriteFile(filepath.Join(dir, "references", "a.md"), []byte("ref"), 0o644); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
record, err := Build("dingtalk-a", dir, "", SourceUpgrade)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if record.Version != "unknown" || record.Source != SourceUpgrade || record.DigestScope != DigestScope {
|
|
t.Fatalf("record = %#v", record)
|
|
}
|
|
first := record.Digest
|
|
if err := os.WriteFile(filepath.Join(dir, "references", "a.md"), []byte("changed"), 0o644); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
second, err := Build("dingtalk-a", dir, "v2", SourceSkillSetup)
|
|
if err != nil || second.Digest == first {
|
|
t.Fatalf("second = %#v, %v", second, err)
|
|
}
|
|
merged := Merge([]Record{record, {Name: "dingtalk-b"}}, []Record{second, {}})
|
|
if !reflect.DeepEqual(merged, []Record{second, {Name: "dingtalk-b"}}) {
|
|
t.Fatalf("merged = %#v", merged)
|
|
}
|
|
if got := Names(merged); !got["dingtalk-a"] || !got["dingtalk-b"] || len(got) != 2 {
|
|
t.Fatalf("names = %#v", got)
|
|
}
|
|
if _, err := Build("", dir, "v1", "test"); err == nil {
|
|
t.Fatal("empty name accepted")
|
|
}
|
|
if _, err := Build("dingtalk-a", dir, "v1", " "); err == nil {
|
|
t.Fatal("empty source accepted")
|
|
}
|
|
if _, err := Build("dingtalk-a", filepath.Join(dir, "missing"), "v1", "test"); err == nil {
|
|
t.Fatal("missing Skill directory accepted")
|
|
}
|
|
}
|
|
|
|
func TestCrossPlatformCoverageSkillProvenanceDigestErrors(t *testing.T) {
|
|
want := errors.New("injected")
|
|
t.Run("walk", func(t *testing.T) {
|
|
swapProvenanceSeam(t, &provenanceWalkDir, func(string, fs.WalkDirFunc) error { return want })
|
|
if _, err := DigestDir(t.TempDir()); !errors.Is(err, want) {
|
|
t.Fatal(err)
|
|
}
|
|
})
|
|
t.Run("callback", func(t *testing.T) {
|
|
swapProvenanceSeam(t, &provenanceWalkDir, func(root string, walk fs.WalkDirFunc) error { return walk(root, nil, want) })
|
|
if _, err := DigestDir(t.TempDir()); !errors.Is(err, want) {
|
|
t.Fatal(err)
|
|
}
|
|
})
|
|
t.Run("relative", func(t *testing.T) {
|
|
swapProvenanceSeam(t, &provenanceWalkDir, func(root string, walk fs.WalkDirFunc) error {
|
|
return walk(filepath.Join(root, "file"), fakeDirEntry{name: "file"}, nil)
|
|
})
|
|
swapProvenanceSeam(t, &provenanceRelative, func(string, string) (string, error) { return "", want })
|
|
if _, err := DigestDir(t.TempDir()); !errors.Is(err, want) {
|
|
t.Fatal(err)
|
|
}
|
|
})
|
|
t.Run("nonregular", func(t *testing.T) {
|
|
swapProvenanceSeam(t, &provenanceWalkDir, func(root string, walk fs.WalkDirFunc) error {
|
|
return walk(filepath.Join(root, "link"), fakeDirEntry{name: "link", mode: fs.ModeSymlink}, nil)
|
|
})
|
|
if _, err := DigestDir(t.TempDir()); err == nil {
|
|
t.Fatal("nonregular accepted")
|
|
}
|
|
})
|
|
t.Run("read", func(t *testing.T) {
|
|
dir := t.TempDir()
|
|
_ = os.WriteFile(filepath.Join(dir, "SKILL.md"), []byte("x"), 0o644)
|
|
swapProvenanceSeam(t, &provenanceReadFile, func(string) ([]byte, error) { return nil, want })
|
|
if _, err := DigestDir(dir); !errors.Is(err, want) {
|
|
t.Fatal(err)
|
|
}
|
|
})
|
|
}
|