package adapter import ( "os" "path/filepath" "testing" "skillmgr/internal/types" ) func setupAdapterTestEnv(t *testing.T) (string, func()) { t.Helper() tmpDir, err := os.MkdirTemp("", "skillmgr-adapter-test-*") if err != nil { t.Fatalf("创建临时目录失败: %v", err) } os.Setenv("SKILLMGR_TEST_BASE", tmpDir) cleanup := func() { os.Unsetenv("SKILLMGR_TEST_BASE") os.RemoveAll(tmpDir) } return tmpDir, cleanup } func TestClaudeAdapter_GetSkillInstallPath_Global(t *testing.T) { tmpDir, cleanup := setupAdapterTestEnv(t) defer cleanup() adapter := &ClaudeAdapter{} path, err := adapter.GetSkillInstallPath(types.ScopeGlobal, "test-skill") if err != nil { t.Fatalf("GetSkillInstallPath 失败: %v", err) } expected := filepath.Join(tmpDir, ".claude", "skills", "test-skill") if path != expected { t.Errorf("期望 %s,得到 %s", expected, path) } } func TestClaudeAdapter_GetSkillInstallPath_Project(t *testing.T) { _, cleanup := setupAdapterTestEnv(t) defer cleanup() adapter := &ClaudeAdapter{} path, err := adapter.GetSkillInstallPath(types.ScopeProject, "test-skill") if err != nil { t.Fatalf("GetSkillInstallPath 失败: %v", err) } // 项目级路径是相对当前目录的 if !filepath.IsAbs(path) { // 相对路径应该包含 .claude/skills if filepath.Base(filepath.Dir(path)) != "skills" { t.Errorf("期望路径包含 skills 目录,得到 %s", path) } } } func TestClaudeAdapter_GetCommandInstallPath_Global(t *testing.T) { tmpDir, cleanup := setupAdapterTestEnv(t) defer cleanup() adapter := &ClaudeAdapter{} path, err := adapter.GetCommandInstallPath(types.ScopeGlobal, "test-cmd") if err != nil { t.Fatalf("GetCommandInstallPath 失败: %v", err) } expected := filepath.Join(tmpDir, ".claude", "commands", "test-cmd") if path != expected { t.Errorf("期望 %s,得到 %s", expected, path) } } func TestClaudeAdapter_AdaptSkill(t *testing.T) { tmpDir, cleanup := setupAdapterTestEnv(t) defer cleanup() // 创建源目录 srcDir := filepath.Join(tmpDir, "src-skill") os.MkdirAll(srcDir, 0755) os.WriteFile(filepath.Join(srcDir, "SKILL.md"), []byte("test"), 0644) os.WriteFile(filepath.Join(srcDir, "helper.md"), []byte("test"), 0644) destDir := filepath.Join(tmpDir, "dest-skill") adapter := &ClaudeAdapter{} mapping, err := adapter.AdaptSkill(srcDir, destDir) if err != nil { t.Fatalf("AdaptSkill 失败: %v", err) } if len(mapping) != 2 { t.Errorf("期望 2 个文件映射,得到 %d 个", len(mapping)) } } func TestClaudeAdapter_AdaptCommand(t *testing.T) { tmpDir, cleanup := setupAdapterTestEnv(t) defer cleanup() // 创建源目录 srcDir := filepath.Join(tmpDir, "src-cmd") os.MkdirAll(srcDir, 0755) os.WriteFile(filepath.Join(srcDir, "init.md"), []byte("test"), 0644) os.WriteFile(filepath.Join(srcDir, "run.md"), []byte("test"), 0644) destDir := filepath.Join(tmpDir, "dest-cmd") adapter := &ClaudeAdapter{} mapping, err := adapter.AdaptCommand(srcDir, destDir, "test-cmd") if err != nil { t.Fatalf("AdaptCommand 失败: %v", err) } if len(mapping) != 2 { t.Errorf("期望 2 个文件映射,得到 %d 个", len(mapping)) } // 验证文件名保持原样 for src, dest := range mapping { srcBase := filepath.Base(src) destBase := filepath.Base(dest) if srcBase != destBase { t.Errorf("Claude 适配器应保持文件名:源 %s,目标 %s", srcBase, destBase) } } }