From 301429e3aafd8d4f1dd34e17f2d9bfe16deb4127 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=89=E6=BE=9C?= Date: Thu, 13 Aug 2026 21:49:35 +0800 Subject: [PATCH] test(ci): cover canonical skill platform branches --- internal/app/skill_command_test.go | 3 ++ internal/app/skill_setup.go | 3 -- internal/app/skill_setup_canonical_test.go | 5 +- ...ll_setup_event_migration_universal_test.go | 47 +++++++++++++++++++ .../app/skill_setup_full_coverage_test.go | 20 ++++++++ internal/upgrade/canonical_skills_test.go | 5 +- 6 files changed, 78 insertions(+), 5 deletions(-) diff --git a/internal/app/skill_command_test.go b/internal/app/skill_command_test.go index 20288bae..b8406cb0 100644 --- a/internal/app/skill_command_test.go +++ b/internal/app/skill_command_test.go @@ -122,6 +122,9 @@ func TestResolveSkillTargetPath(t *testing.T) { func TestCrossPlatformCoverageUniversalSkillInstallTargetsUseCanonical(t *testing.T) { home := t.TempDir() testseam.Swap(t, &skillUserHomeDir, func() (string, error) { return home, nil }) + if isUniversalSkillInstallTarget("missing-agent") { + t.Fatal("unknown Agent target classified as universal") + } for _, target := range []string{ "amp", "antigravity", "antigravity-cli", "cline", "codex", "cursor", "deepagents", "dexto", "firebender", "gemini", "gemini-cli", "github", diff --git a/internal/app/skill_setup.go b/internal/app/skill_setup.go index ef728093..92c52f12 100644 --- a/internal/app/skill_setup.go +++ b/internal/app/skill_setup.go @@ -1121,9 +1121,6 @@ func detectExistingAgentHomes(home, mode string) []string { return } } - if base == "" { - return - } dest := agentHomeForMode(base, mode) key := skillSetupPathKey(dest) if !seen[key] { diff --git a/internal/app/skill_setup_canonical_test.go b/internal/app/skill_setup_canonical_test.go index 45f9aff4..c308298b 100644 --- a/internal/app/skill_setup_canonical_test.go +++ b/internal/app/skill_setup_canonical_test.go @@ -103,6 +103,7 @@ func TestCrossPlatformCoverageSkillSetupCanonicalTargetsAndAgentCapabilities(t * func TestCrossPlatformCoverageSkillSetupDetectsShallowAndApplicationAgents(t *testing.T) { home := t.TempDir() testseam.Swap(t, &skillSetupSystemHomeDir, func() (string, error) { return home, nil }) + testseam.Swap(t, &skillSetupGetenv, func(string) string { return "" }) for _, dir := range []string{filepath.Join(home, ".config", "kimchi"), filepath.Join(home, ".tabnine")} { if err := os.MkdirAll(dir, 0o755); err != nil { t.Fatal(err) @@ -116,9 +117,11 @@ func TestCrossPlatformCoverageSkillSetupDetectsShallowAndApplicationAgents(t *te if err != nil { t.Fatal(err) } + zcodeApp := filepath.Join(string(filepath.Separator), "Applications", "ZCode.app") + minimaxApp := filepath.Join(string(filepath.Separator), "Applications", "MiniMax Code.app") originalStat := skillSetupStat testseam.Swap(t, &skillSetupStat, func(path string) (os.FileInfo, error) { - if path == "/Applications/ZCode.app" || path == "/Applications/MiniMax Code.app" { + if path == zcodeApp || path == minimaxApp { return appInfo, nil } return originalStat(path) diff --git a/internal/app/skill_setup_event_migration_universal_test.go b/internal/app/skill_setup_event_migration_universal_test.go index 7800bb74..902aec6a 100644 --- a/internal/app/skill_setup_event_migration_universal_test.go +++ b/internal/app/skill_setup_event_migration_universal_test.go @@ -1,6 +1,8 @@ package app import ( + "errors" + "io" "os" "path/filepath" "strings" @@ -85,3 +87,48 @@ func TestCrossPlatformCoverageSkillSetupUnrelatedSelectionPreservesUniversalFold t.Fatalf("unselected chat changed: body=%q err=%v", body, err) } } + +func TestCrossPlatformCoverageSkillSetupUniversalRetirementFailures(t *testing.T) { + failure := errors.New("retirement denied") + + t.Run("home", func(t *testing.T) { + testseam.Swap(t, &skillSetupUserHomeDir, func() (string, error) { return "", failure }) + codex := filepath.Join(t.TempDir(), ".codex", "skills") + if err := retireMigratedUniversalSkills([]string{codex}, []string{multiEventSkill}, io.Discard); !errors.Is(err, failure) { + t.Fatalf("home failure = %v, want %v", err, failure) + } + }) + + t.Run("deduplicate", func(t *testing.T) { + home := t.TempDir() + testseam.Swap(t, &skillSetupUserHomeDir, func() (string, error) { return home, nil }) + codex := filepath.Join(home, ".codex", "skills") + if err := retireMigratedUniversalSkills( + []string{codex, codex}, + []string{multiEventSkill, multiEventSkill}, + io.Discard, + ); err != nil { + t.Fatalf("deduplicated retirement failed: %v", err) + } + }) + + t.Run("backup propagates through command", func(t *testing.T) { + home := t.TempDir() + testseam.Swap(t, &skillSetupUserHomeDir, func() (string, error) { return home, nil }) + codex := filepath.Join(home, ".codex", "skills") + writeFoldedEventMisc(t, codex) + src := writeMultiSkillSource(t, []string{multiEventSkill, multiSharedSkill, multiMiscSkill}) + testseam.Swap(t, &skillSetupBackupAndRemove, func(string, string) (string, error) { + return "", failure + }) + _, _, err := executeMultiSkillSetupTest( + t, + src, + []string{filepath.Join(home, ".agents", "skills"), codex}, + "--skill", "event", "--yes", + ) + if !errors.Is(err, failure) || !strings.Contains(err.Error(), "退役 universal Agent") { + t.Fatalf("retirement backup failure = %v, want wrapped %v", err, failure) + } + }) +} diff --git a/internal/app/skill_setup_full_coverage_test.go b/internal/app/skill_setup_full_coverage_test.go index b5e38e9c..8ead0740 100644 --- a/internal/app/skill_setup_full_coverage_test.go +++ b/internal/app/skill_setup_full_coverage_test.go @@ -537,6 +537,26 @@ func TestCrossPlatformCoverageSkillSetupEventMigrationFailureBranches(t *testing } }) + t.Run("canonical ordinary install error", func(t *testing.T) { + testseam.Swap(t, &skillSetupInstallMulti, func(string, []string, []string, io.Writer, io.Writer, bool) (int, int, error) { + return 0, 0, fail + }) + home := t.TempDir() + canonical := filepath.Join(home, ".agents", "skills") + universalMigration := filepath.Join(home, ".codex", "skills") + if _, _, err := installMultiSkillsWithEventMigration( + "src", + []string{multiEventSkill}, + []string{canonical, universalMigration}, + []string{universalMigration}, + true, + io.Discard, + io.Discard, + ); !errors.Is(err, fail) { + t.Fatalf("canonical ordinary install failure = %v, want %v", err, fail) + } + }) + t.Run("prerequisite install error", func(t *testing.T) { testseam.Swap(t, &skillSetupInstallMulti, func(string, []string, []string, io.Writer, io.Writer, bool) (int, int, error) { return 0, 0, fail diff --git a/internal/upgrade/canonical_skills_test.go b/internal/upgrade/canonical_skills_test.go index 79c0bbbe..17f27a27 100644 --- a/internal/upgrade/canonical_skills_test.go +++ b/internal/upgrade/canonical_skills_test.go @@ -164,6 +164,7 @@ func TestCrossPlatformCoverageCanonicalSkillLinksFallBackToCopies(t *testing.T) func TestCrossPlatformCoverageConfiguredRootsDetectShallowAndApplicationAgents(t *testing.T) { home := t.TempDir() testseam.Swap(t, &upgradeSystemHomeDir, func() (string, error) { return home, nil }) + testseam.Swap(t, &upgradeGetenv, func(string) string { return "" }) for _, dir := range []string{filepath.Join(home, ".config", "kimchi"), filepath.Join(home, ".tabnine")} { if err := os.MkdirAll(dir, 0o755); err != nil { t.Fatal(err) @@ -177,9 +178,11 @@ func TestCrossPlatformCoverageConfiguredRootsDetectShallowAndApplicationAgents(t if err != nil { t.Fatal(err) } + zcodeApp := filepath.Join(string(filepath.Separator), "Applications", "ZCode.app") + minimaxApp := filepath.Join(string(filepath.Separator), "Applications", "MiniMax Code.app") originalStat := upgradeStat testseam.Swap(t, &upgradeStat, func(path string) (os.FileInfo, error) { - if path == "/Applications/ZCode.app" || path == "/Applications/MiniMax Code.app" { + if path == zcodeApp || path == minimaxApp { return appInfo, nil } return originalStat(path)