Skip to content

Commit 14b9a73

Browse files
authored
Merge pull request #56 from githubnext/autoloop/python-to-go-migration
[Autoloop: python-to-go-migration]
2 parents c63b4ac + 17b143c commit 14b9a73

63 files changed

Lines changed: 11191 additions & 4 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

benchmarks/migration-status.json

Lines changed: 1749 additions & 4 deletions
Large diffs are not rendered by default.
Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
package cursor
2+
3+
import (
4+
"os"
5+
"path/filepath"
6+
"testing"
7+
)
8+
9+
func TestNew_SetsProjectRoot(t *testing.T) {
10+
a := New("/my/project", false)
11+
if a.Adapter == nil {
12+
t.Fatal("Adapter should not be nil")
13+
}
14+
if a.ProjectRoot != "/my/project" {
15+
t.Errorf("ProjectRoot = %q, want /my/project", a.ProjectRoot)
16+
}
17+
}
18+
19+
func TestNew_SupportsRuntimeEnvSubstitutionFalse(t *testing.T) {
20+
a := New("/project", false)
21+
if a.Adapter.SupportsRuntimeEnvSubstitution {
22+
t.Error("SupportsRuntimeEnvSubstitution should be false for cursor")
23+
}
24+
}
25+
26+
func TestTargetName_ReturnsConstant(t *testing.T) {
27+
cases := []string{"/proj", "/other/root", ""}
28+
for _, root := range cases {
29+
a := New(root, false)
30+
if a.TargetName() != "cursor" {
31+
t.Errorf("TargetName() for root=%q = %q, want cursor", root, a.TargetName())
32+
}
33+
}
34+
}
35+
36+
func TestMCPServersKey_ReturnsConstant(t *testing.T) {
37+
a := New("/project", true)
38+
if a.MCPServersKey() != "mcpServers" {
39+
t.Errorf("MCPServersKey() = %q, want mcpServers", a.MCPServersKey())
40+
}
41+
}
42+
43+
func TestSupportsUserScope_AlwaysFalse(t *testing.T) {
44+
for _, userScope := range []bool{true, false} {
45+
a := New("/proj", userScope)
46+
if a.SupportsUserScope() {
47+
t.Errorf("SupportsUserScope() should be false (userScope=%v)", userScope)
48+
}
49+
}
50+
}
51+
52+
func TestGetConfigPath_Structure(t *testing.T) {
53+
a := New("/workspace/proj", false)
54+
got := a.GetConfigPath()
55+
if !filepath.IsAbs(got) {
56+
t.Errorf("GetConfigPath should be absolute: %q", got)
57+
}
58+
base := filepath.Base(got)
59+
if base != "mcp.json" {
60+
t.Errorf("config file name = %q, want mcp.json", base)
61+
}
62+
dir := filepath.Dir(got)
63+
if filepath.Base(dir) != ".cursor" {
64+
t.Errorf("parent dir = %q, want .cursor", filepath.Base(dir))
65+
}
66+
}
67+
68+
func TestGetConfigPath_ContainsProjectRoot(t *testing.T) {
69+
a := New("/home/user/my-project", false)
70+
got := a.GetConfigPath()
71+
if !filepath.HasPrefix(got, "/home/user/my-project") {
72+
t.Errorf("config path should be under project root: %q", got)
73+
}
74+
}
75+
76+
func TestGetCurrentConfig_ReturnsEmptyMapNotNil(t *testing.T) {
77+
dir := t.TempDir()
78+
a := New(dir, false)
79+
cfg := a.GetCurrentConfig()
80+
if cfg == nil {
81+
t.Error("GetCurrentConfig should never return nil")
82+
}
83+
}
84+
85+
func TestGetCurrentConfig_ValidJSON(t *testing.T) {
86+
dir := t.TempDir()
87+
cursorDir := filepath.Join(dir, ".cursor")
88+
os.MkdirAll(cursorDir, 0o755)
89+
cfgPath := filepath.Join(cursorDir, "mcp.json")
90+
os.WriteFile(cfgPath, []byte(`{"mcpServers":{"my-server":{"command":"npx"}}}`), 0o644)
91+
a := New(dir, false)
92+
cfg := a.GetCurrentConfig()
93+
if _, ok := cfg["mcpServers"]; !ok {
94+
t.Error("expected mcpServers key")
95+
}
96+
}
97+
98+
func TestUpdateConfig_CursorDirMustExist(t *testing.T) {
99+
dir := t.TempDir()
100+
a := New(dir, false)
101+
// No .cursor dir: UpdateConfig should be a no-op (not an error)
102+
if err := a.UpdateConfig(map[string]interface{}{"mcpServers": map[string]interface{}{}}); err != nil {
103+
t.Errorf("expected no error when .cursor dir is absent: %v", err)
104+
}
105+
}
106+
107+
func TestUpdateConfig_CreatesMCPJSON(t *testing.T) {
108+
dir := t.TempDir()
109+
cursorDir := filepath.Join(dir, ".cursor")
110+
os.MkdirAll(cursorDir, 0o755)
111+
a := New(dir, false)
112+
err := a.UpdateConfig(map[string]interface{}{"mcpServers": map[string]interface{}{}})
113+
if err != nil {
114+
t.Fatalf("UpdateConfig: %v", err)
115+
}
116+
cfgPath := filepath.Join(cursorDir, "mcp.json")
117+
if _, err := os.Stat(cfgPath); os.IsNotExist(err) {
118+
t.Error("mcp.json should have been created")
119+
}
120+
}
121+
122+
func TestNew_MultipleInstances_Independent(t *testing.T) {
123+
a1 := New("/proj1", false)
124+
a2 := New("/proj2", false)
125+
if a1.ProjectRoot == a2.ProjectRoot {
126+
t.Error("distinct adapters should have distinct ProjectRoot values")
127+
}
128+
if a1.GetConfigPath() == a2.GetConfigPath() {
129+
t.Error("distinct adapters should have distinct config paths")
130+
}
131+
}
Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
package windsurf_test
2+
3+
import (
4+
"strings"
5+
"testing"
6+
7+
"github.com/githubnext/apm/internal/adapters/windsurf"
8+
)
9+
10+
func TestNew_Returns_NonNil(t *testing.T) {
11+
a := windsurf.New()
12+
if a == nil {
13+
t.Fatal("New() returned nil")
14+
}
15+
}
16+
17+
func TestGetConfigPath_NotEmpty(t *testing.T) {
18+
a := windsurf.New()
19+
p := a.GetConfigPath()
20+
if p == "" {
21+
t.Error("GetConfigPath() returned empty string")
22+
}
23+
}
24+
25+
func TestGetConfigPath_ContainsCodeium(t *testing.T) {
26+
a := windsurf.New()
27+
p := a.GetConfigPath()
28+
if !strings.Contains(p, ".codeium") {
29+
t.Errorf("GetConfigPath() should contain .codeium, got %q", p)
30+
}
31+
}
32+
33+
func TestGetConfigPath_ContainsWindsurfDir(t *testing.T) {
34+
a := windsurf.New()
35+
p := a.GetConfigPath()
36+
if !strings.Contains(p, "windsurf") {
37+
t.Errorf("GetConfigPath() should contain windsurf dir, got %q", p)
38+
}
39+
}
40+
41+
func TestGetConfigPath_EndsMCPConfig(t *testing.T) {
42+
a := windsurf.New()
43+
p := a.GetConfigPath()
44+
if !strings.HasSuffix(p, "mcp_config.json") {
45+
t.Errorf("GetConfigPath() should end with mcp_config.json, got %q", p)
46+
}
47+
}
48+
49+
func TestIsAvailable_AlwaysTrue(t *testing.T) {
50+
for i := 0; i < 3; i++ {
51+
a := windsurf.New()
52+
if !a.IsAvailable() {
53+
t.Error("IsAvailable() must always return true")
54+
}
55+
}
56+
}
57+
58+
func TestGetRuntimeName_IsWindsurf(t *testing.T) {
59+
a := windsurf.New()
60+
if a.GetRuntimeName() != "windsurf" {
61+
t.Errorf("GetRuntimeName() = %q, want windsurf", a.GetRuntimeName())
62+
}
63+
}
64+
65+
func TestClientLabel_Exact(t *testing.T) {
66+
a := windsurf.New()
67+
if a.ClientLabel != "Windsurf" {
68+
t.Errorf("ClientLabel = %q, want Windsurf", a.ClientLabel)
69+
}
70+
}
71+
72+
func TestMCPServersKey_CamelCase(t *testing.T) {
73+
a := windsurf.New()
74+
if a.MCPServersKey != "mcpServers" {
75+
t.Errorf("MCPServersKey = %q, want mcpServers", a.MCPServersKey)
76+
}
77+
}
78+
79+
func TestSupportsUserScope_True(t *testing.T) {
80+
a := windsurf.New()
81+
if !a.SupportsUserScope {
82+
t.Error("SupportsUserScope must be true")
83+
}
84+
}
85+
86+
func TestSupportsRuntimeEnvSubstitution_False(t *testing.T) {
87+
a := windsurf.New()
88+
if a.SupportsRuntimeEnvSubstitution {
89+
t.Error("SupportsRuntimeEnvSubstitution must be false")
90+
}
91+
}
92+
93+
func TestTargetName_Windsurf(t *testing.T) {
94+
a := windsurf.New()
95+
if a.TargetName != "windsurf" {
96+
t.Errorf("TargetName = %q, want windsurf", a.TargetName)
97+
}
98+
}
99+
100+
func TestGetRuntimeName_ConsistentWithTargetName(t *testing.T) {
101+
a := windsurf.New()
102+
if a.GetRuntimeName() != a.TargetName {
103+
t.Errorf("GetRuntimeName() %q != TargetName %q", a.GetRuntimeName(), a.TargetName)
104+
}
105+
}
106+
107+
func TestMultipleInstances_Independent(t *testing.T) {
108+
a1 := windsurf.New()
109+
a2 := windsurf.New()
110+
a1.ClientLabel = "Modified"
111+
if a2.ClientLabel == "Modified" {
112+
t.Error("instances should be independent")
113+
}
114+
}
Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
package cachepaths_test
2+
3+
import (
4+
"os"
5+
"path/filepath"
6+
"strings"
7+
"testing"
8+
9+
"github.com/githubnext/apm/internal/cache/cachepaths"
10+
)
11+
12+
func TestGetCacheRoot_APMCacheDirAbsolute(t *testing.T) {
13+
tmp := t.TempDir()
14+
t.Setenv("APM_CACHE_DIR", tmp)
15+
t.Setenv("APM_NO_CACHE", "")
16+
dir, err := cachepaths.GetCacheRoot(false)
17+
if err != nil {
18+
t.Fatalf("unexpected error: %v", err)
19+
}
20+
// Result should be absolute
21+
if !filepath.IsAbs(dir) {
22+
t.Errorf("expected absolute path, got %q", dir)
23+
}
24+
}
25+
26+
func TestGetCacheRoot_APMCacheDirCreated(t *testing.T) {
27+
tmp := t.TempDir()
28+
sub := filepath.Join(tmp, "apm-test-cache")
29+
t.Setenv("APM_CACHE_DIR", sub)
30+
t.Setenv("APM_NO_CACHE", "")
31+
_, err := cachepaths.GetCacheRoot(false)
32+
if err != nil {
33+
t.Fatalf("unexpected error: %v", err)
34+
}
35+
if _, statErr := os.Stat(sub); statErr != nil {
36+
t.Errorf("directory should be created: %v", statErr)
37+
}
38+
}
39+
40+
func TestGetCacheRoot_NoCacheParamTrue_IsTempDir(t *testing.T) {
41+
t.Setenv("APM_NO_CACHE", "")
42+
dir, err := cachepaths.GetCacheRoot(true)
43+
if err != nil {
44+
t.Fatalf("unexpected error: %v", err)
45+
}
46+
// Must be a real directory
47+
if info, err2 := os.Stat(dir); err2 != nil || !info.IsDir() {
48+
t.Errorf("result should be an existing directory: %v", err2)
49+
}
50+
}
51+
52+
func TestGetCacheRoot_DefaultReturnsDir(t *testing.T) {
53+
t.Setenv("APM_NO_CACHE", "")
54+
t.Setenv("APM_CACHE_DIR", "")
55+
dir, err := cachepaths.GetCacheRoot(false)
56+
if err != nil {
57+
t.Fatalf("unexpected error: %v", err)
58+
}
59+
if dir == "" {
60+
t.Error("default cache root must not be empty")
61+
}
62+
}
63+
64+
func TestGetCacheRoot_DefaultContainsApm(t *testing.T) {
65+
t.Setenv("APM_NO_CACHE", "")
66+
t.Setenv("APM_CACHE_DIR", "")
67+
dir, err := cachepaths.GetCacheRoot(false)
68+
if err != nil {
69+
t.Fatalf("unexpected error: %v", err)
70+
}
71+
if !strings.Contains(strings.ToLower(dir), "apm") {
72+
t.Errorf("default cache root should contain 'apm': %q", dir)
73+
}
74+
}
75+
76+
func TestConstants_ContainV1(t *testing.T) {
77+
for _, c := range []string{cachepaths.GitDBBucket, cachepaths.GitCheckoutsBucket, cachepaths.HTTPBucket} {
78+
if !strings.Contains(c, "_v1") {
79+
t.Errorf("bucket should contain _v1: %q", c)
80+
}
81+
}
82+
}
83+
84+
func TestConstants_DistinctValues(t *testing.T) {
85+
buckets := []string{cachepaths.GitDBBucket, cachepaths.GitCheckoutsBucket, cachepaths.HTTPBucket}
86+
seen := map[string]bool{}
87+
for _, b := range buckets {
88+
if seen[b] {
89+
t.Errorf("duplicate bucket: %q", b)
90+
}
91+
seen[b] = true
92+
}
93+
}
94+
95+
func TestGetCacheRoot_NoCacheEnvValues(t *testing.T) {
96+
for _, val := range []string{"1", "true", "yes"} {
97+
t.Run("APM_NO_CACHE="+val, func(t *testing.T) {
98+
t.Setenv("APM_NO_CACHE", val)
99+
dir, err := cachepaths.GetCacheRoot(false)
100+
if err != nil {
101+
t.Fatalf("unexpected error: %v", err)
102+
}
103+
if dir == "" {
104+
t.Error("expected non-empty dir")
105+
}
106+
})
107+
}
108+
}
109+
110+
func TestGetCacheRoot_NoCacheEnvOtherValues_NoTmp(t *testing.T) {
111+
// "false", "0", "no" should NOT trigger no-cache
112+
for _, val := range []string{"false", "0", "no"} {
113+
t.Run("APM_NO_CACHE="+val, func(t *testing.T) {
114+
t.Setenv("APM_NO_CACHE", val)
115+
t.Setenv("APM_CACHE_DIR", t.TempDir())
116+
dir, err := cachepaths.GetCacheRoot(false)
117+
if err != nil {
118+
t.Fatalf("unexpected error: %v", err)
119+
}
120+
if dir == "" {
121+
t.Error("expected non-empty dir")
122+
}
123+
})
124+
}
125+
}

0 commit comments

Comments
 (0)