Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
a35dd0d
[Autoloop: python-to-go-migration] Iteration 128: Extend 5 thin Go te…
github-actions[bot] May 18, 2026
cbc3b81
[Autoloop: python-to-go-migration] Iteration 129: Add extra tests for…
github-actions[bot] May 18, 2026
46f988a
ci: trigger checks
github-actions[bot] May 18, 2026
f03f72c
[Autoloop: python-to-go-migration] Iteration 130: Add extra test suit…
github-actions[bot] May 18, 2026
590874b
ci: trigger checks
github-actions[bot] May 18, 2026
2923f2f
[Autoloop: python-to-go-migration] Iteration 130: Add extra test suit…
github-actions[bot] May 18, 2026
a75265b
ci: trigger checks
github-actions[bot] May 18, 2026
2fc9ca8
[Autoloop: python-to-go-migration] Iteration 131: extra test suites f…
github-actions[bot] May 18, 2026
0b097af
ci: trigger checks
github-actions[bot] May 18, 2026
f955924
[Autoloop: python-to-go-migration] Iteration 132: Extra test suites f…
github-actions[bot] May 18, 2026
266993c
ci: trigger checks
github-actions[bot] May 18, 2026
f16e432
[Autoloop: python-to-go-migration] Iteration 133: Extra test suites f…
github-actions[bot] May 18, 2026
125b2ce
ci: trigger checks
github-actions[bot] May 18, 2026
2bfffc8
[Autoloop: python-to-go-migration] Iteration 134: Add extra_test.go f…
github-actions[bot] May 18, 2026
3bf3b90
ci: trigger checks
github-actions[bot] May 18, 2026
149ba85
[Autoloop: python-to-go-migration] Iteration 135: Register all 199 Go…
github-actions[bot] May 19, 2026
c3d3fa0
ci: trigger checks
github-actions[bot] May 19, 2026
0e856b2
[Autoloop: python-to-go-migration] Iteration 136: Add extra test file…
github-actions[bot] May 19, 2026
5552736
ci: trigger checks
github-actions[bot] May 19, 2026
573b40a
[Autoloop: python-to-go-migration] Iteration 137: Add extra test file…
github-actions[bot] May 19, 2026
17b143c
ci: trigger checks
github-actions[bot] May 19, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1,753 changes: 1,749 additions & 4 deletions benchmarks/migration-status.json

Large diffs are not rendered by default.

131 changes: 131 additions & 0 deletions internal/adapters/client/cursor/cursor_extra_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
package cursor

import (
"os"
"path/filepath"
"testing"
)

func TestNew_SetsProjectRoot(t *testing.T) {
a := New("/my/project", false)
if a.Adapter == nil {
t.Fatal("Adapter should not be nil")
}
if a.ProjectRoot != "/my/project" {
t.Errorf("ProjectRoot = %q, want /my/project", a.ProjectRoot)
}
}

func TestNew_SupportsRuntimeEnvSubstitutionFalse(t *testing.T) {
a := New("/project", false)
if a.Adapter.SupportsRuntimeEnvSubstitution {
t.Error("SupportsRuntimeEnvSubstitution should be false for cursor")
}
}

func TestTargetName_ReturnsConstant(t *testing.T) {
cases := []string{"/proj", "/other/root", ""}
for _, root := range cases {
a := New(root, false)
if a.TargetName() != "cursor" {
t.Errorf("TargetName() for root=%q = %q, want cursor", root, a.TargetName())
}
}
}

func TestMCPServersKey_ReturnsConstant(t *testing.T) {
a := New("/project", true)
if a.MCPServersKey() != "mcpServers" {
t.Errorf("MCPServersKey() = %q, want mcpServers", a.MCPServersKey())
}
}

func TestSupportsUserScope_AlwaysFalse(t *testing.T) {
for _, userScope := range []bool{true, false} {
a := New("/proj", userScope)
if a.SupportsUserScope() {
t.Errorf("SupportsUserScope() should be false (userScope=%v)", userScope)
}
}
}

func TestGetConfigPath_Structure(t *testing.T) {
a := New("/workspace/proj", false)
got := a.GetConfigPath()
if !filepath.IsAbs(got) {
t.Errorf("GetConfigPath should be absolute: %q", got)
}
base := filepath.Base(got)
if base != "mcp.json" {
t.Errorf("config file name = %q, want mcp.json", base)
}
dir := filepath.Dir(got)
if filepath.Base(dir) != ".cursor" {
t.Errorf("parent dir = %q, want .cursor", filepath.Base(dir))
}
}

func TestGetConfigPath_ContainsProjectRoot(t *testing.T) {
a := New("/home/user/my-project", false)
got := a.GetConfigPath()
if !filepath.HasPrefix(got, "/home/user/my-project") {
t.Errorf("config path should be under project root: %q", got)
}
}

func TestGetCurrentConfig_ReturnsEmptyMapNotNil(t *testing.T) {
dir := t.TempDir()
a := New(dir, false)
cfg := a.GetCurrentConfig()
if cfg == nil {
t.Error("GetCurrentConfig should never return nil")
}
}

func TestGetCurrentConfig_ValidJSON(t *testing.T) {
dir := t.TempDir()
cursorDir := filepath.Join(dir, ".cursor")
os.MkdirAll(cursorDir, 0o755)
cfgPath := filepath.Join(cursorDir, "mcp.json")
os.WriteFile(cfgPath, []byte(`{"mcpServers":{"my-server":{"command":"npx"}}}`), 0o644)
a := New(dir, false)
cfg := a.GetCurrentConfig()
if _, ok := cfg["mcpServers"]; !ok {
t.Error("expected mcpServers key")
}
}

func TestUpdateConfig_CursorDirMustExist(t *testing.T) {
dir := t.TempDir()
a := New(dir, false)
// No .cursor dir: UpdateConfig should be a no-op (not an error)
if err := a.UpdateConfig(map[string]interface{}{"mcpServers": map[string]interface{}{}}); err != nil {
t.Errorf("expected no error when .cursor dir is absent: %v", err)
}
}

func TestUpdateConfig_CreatesMCPJSON(t *testing.T) {
dir := t.TempDir()
cursorDir := filepath.Join(dir, ".cursor")
os.MkdirAll(cursorDir, 0o755)
a := New(dir, false)
err := a.UpdateConfig(map[string]interface{}{"mcpServers": map[string]interface{}{}})
if err != nil {
t.Fatalf("UpdateConfig: %v", err)
}
cfgPath := filepath.Join(cursorDir, "mcp.json")
if _, err := os.Stat(cfgPath); os.IsNotExist(err) {
t.Error("mcp.json should have been created")
}
}

func TestNew_MultipleInstances_Independent(t *testing.T) {
a1 := New("/proj1", false)
a2 := New("/proj2", false)
if a1.ProjectRoot == a2.ProjectRoot {
t.Error("distinct adapters should have distinct ProjectRoot values")
}
if a1.GetConfigPath() == a2.GetConfigPath() {
t.Error("distinct adapters should have distinct config paths")
}
}
114 changes: 114 additions & 0 deletions internal/adapters/windsurf/windsurf_extra_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
package windsurf_test

import (
"strings"
"testing"

"github.com/githubnext/apm/internal/adapters/windsurf"
)

func TestNew_Returns_NonNil(t *testing.T) {
a := windsurf.New()
if a == nil {
t.Fatal("New() returned nil")
}
}

func TestGetConfigPath_NotEmpty(t *testing.T) {
a := windsurf.New()
p := a.GetConfigPath()
if p == "" {
t.Error("GetConfigPath() returned empty string")
}
}

func TestGetConfigPath_ContainsCodeium(t *testing.T) {
a := windsurf.New()
p := a.GetConfigPath()
if !strings.Contains(p, ".codeium") {
t.Errorf("GetConfigPath() should contain .codeium, got %q", p)
}
}

func TestGetConfigPath_ContainsWindsurfDir(t *testing.T) {
a := windsurf.New()
p := a.GetConfigPath()
if !strings.Contains(p, "windsurf") {
t.Errorf("GetConfigPath() should contain windsurf dir, got %q", p)
}
}

func TestGetConfigPath_EndsMCPConfig(t *testing.T) {
a := windsurf.New()
p := a.GetConfigPath()
if !strings.HasSuffix(p, "mcp_config.json") {
t.Errorf("GetConfigPath() should end with mcp_config.json, got %q", p)
}
}

func TestIsAvailable_AlwaysTrue(t *testing.T) {
for i := 0; i < 3; i++ {
a := windsurf.New()
if !a.IsAvailable() {
t.Error("IsAvailable() must always return true")
}
}
}

func TestGetRuntimeName_IsWindsurf(t *testing.T) {
a := windsurf.New()
if a.GetRuntimeName() != "windsurf" {
t.Errorf("GetRuntimeName() = %q, want windsurf", a.GetRuntimeName())
}
}

func TestClientLabel_Exact(t *testing.T) {
a := windsurf.New()
if a.ClientLabel != "Windsurf" {
t.Errorf("ClientLabel = %q, want Windsurf", a.ClientLabel)
}
}

func TestMCPServersKey_CamelCase(t *testing.T) {
a := windsurf.New()
if a.MCPServersKey != "mcpServers" {
t.Errorf("MCPServersKey = %q, want mcpServers", a.MCPServersKey)
}
}

func TestSupportsUserScope_True(t *testing.T) {
a := windsurf.New()
if !a.SupportsUserScope {
t.Error("SupportsUserScope must be true")
}
}

func TestSupportsRuntimeEnvSubstitution_False(t *testing.T) {
a := windsurf.New()
if a.SupportsRuntimeEnvSubstitution {
t.Error("SupportsRuntimeEnvSubstitution must be false")
}
}

func TestTargetName_Windsurf(t *testing.T) {
a := windsurf.New()
if a.TargetName != "windsurf" {
t.Errorf("TargetName = %q, want windsurf", a.TargetName)
}
}

func TestGetRuntimeName_ConsistentWithTargetName(t *testing.T) {
a := windsurf.New()
if a.GetRuntimeName() != a.TargetName {
t.Errorf("GetRuntimeName() %q != TargetName %q", a.GetRuntimeName(), a.TargetName)
}
}

func TestMultipleInstances_Independent(t *testing.T) {
a1 := windsurf.New()
a2 := windsurf.New()
a1.ClientLabel = "Modified"
if a2.ClientLabel == "Modified" {
t.Error("instances should be independent")
}
}
125 changes: 125 additions & 0 deletions internal/cache/cachepaths/cachepaths_extra_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
package cachepaths_test

import (
"os"
"path/filepath"
"strings"
"testing"

"github.com/githubnext/apm/internal/cache/cachepaths"
)

func TestGetCacheRoot_APMCacheDirAbsolute(t *testing.T) {
tmp := t.TempDir()
t.Setenv("APM_CACHE_DIR", tmp)
t.Setenv("APM_NO_CACHE", "")
dir, err := cachepaths.GetCacheRoot(false)
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
// Result should be absolute
if !filepath.IsAbs(dir) {
t.Errorf("expected absolute path, got %q", dir)
}
}

func TestGetCacheRoot_APMCacheDirCreated(t *testing.T) {
tmp := t.TempDir()
sub := filepath.Join(tmp, "apm-test-cache")
t.Setenv("APM_CACHE_DIR", sub)
t.Setenv("APM_NO_CACHE", "")
_, err := cachepaths.GetCacheRoot(false)
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
if _, statErr := os.Stat(sub); statErr != nil {
t.Errorf("directory should be created: %v", statErr)
}
}

func TestGetCacheRoot_NoCacheParamTrue_IsTempDir(t *testing.T) {
t.Setenv("APM_NO_CACHE", "")
dir, err := cachepaths.GetCacheRoot(true)
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
// Must be a real directory
if info, err2 := os.Stat(dir); err2 != nil || !info.IsDir() {
t.Errorf("result should be an existing directory: %v", err2)
}
}

func TestGetCacheRoot_DefaultReturnsDir(t *testing.T) {
t.Setenv("APM_NO_CACHE", "")
t.Setenv("APM_CACHE_DIR", "")
dir, err := cachepaths.GetCacheRoot(false)
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
if dir == "" {
t.Error("default cache root must not be empty")
}
}

func TestGetCacheRoot_DefaultContainsApm(t *testing.T) {
t.Setenv("APM_NO_CACHE", "")
t.Setenv("APM_CACHE_DIR", "")
dir, err := cachepaths.GetCacheRoot(false)
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
if !strings.Contains(strings.ToLower(dir), "apm") {
t.Errorf("default cache root should contain 'apm': %q", dir)
}
}

func TestConstants_ContainV1(t *testing.T) {
for _, c := range []string{cachepaths.GitDBBucket, cachepaths.GitCheckoutsBucket, cachepaths.HTTPBucket} {
if !strings.Contains(c, "_v1") {
t.Errorf("bucket should contain _v1: %q", c)
}
}
}

func TestConstants_DistinctValues(t *testing.T) {
buckets := []string{cachepaths.GitDBBucket, cachepaths.GitCheckoutsBucket, cachepaths.HTTPBucket}
seen := map[string]bool{}
for _, b := range buckets {
if seen[b] {
t.Errorf("duplicate bucket: %q", b)
}
seen[b] = true
}
}

func TestGetCacheRoot_NoCacheEnvValues(t *testing.T) {
for _, val := range []string{"1", "true", "yes"} {
t.Run("APM_NO_CACHE="+val, func(t *testing.T) {
t.Setenv("APM_NO_CACHE", val)
dir, err := cachepaths.GetCacheRoot(false)
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
if dir == "" {
t.Error("expected non-empty dir")
}
})
}
}

func TestGetCacheRoot_NoCacheEnvOtherValues_NoTmp(t *testing.T) {
// "false", "0", "no" should NOT trigger no-cache
for _, val := range []string{"false", "0", "no"} {
t.Run("APM_NO_CACHE="+val, func(t *testing.T) {
t.Setenv("APM_NO_CACHE", val)
t.Setenv("APM_CACHE_DIR", t.TempDir())
dir, err := cachepaths.GetCacheRoot(false)
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
if dir == "" {
t.Error("expected non-empty dir")
}
})
}
}
Loading
Loading