package main import ( "path/filepath" "testing" ) func TestInferLaunchKind(t *testing.T) { cases := []struct { name, exe, cmdline, want string }{ {"node.exe", `C:\nodejs\node.exe`, "node vite dev", "node"}, {"mysqld.exe", `C:\mysql\bin\mysqld.exe`, "mysqld --console", "mysql"}, {"redis-server", "/usr/bin/redis-server", "redis-server *:6379", "redis"}, {"nginx.exe", `C:\nginx\nginx.exe`, "nginx", "nginx"}, {"java.exe", `C:\jdk\bin\java.exe`, "java -jar app.jar", "java"}, {"python.exe", `C:\py\python.exe`, "uvicorn main:app", "python"}, {"php-cgi.exe", `C:\php\php-cgi.exe`, "", "php"}, {"dotnet.exe", `C:\dotnet\dotnet.exe`, "dotnet run", "dotnet"}, {"main.exe", `C:\Temp\go-build\__debug_bin.exe`, "", "go"}, {"svchost.exe", `C:\Windows\svchost.exe`, "-k netsvcs", "other"}, } for _, c := range cases { if got := inferLaunchKind(c.name, c.exe, c.cmdline); got != c.want { t.Errorf("inferLaunchKind(%q)=%q want %q", c.name, got, c.want) } } } func TestLaunchCmdSuggest(t *testing.T) { a := &App{} if s := a.LaunchCmdSuggest("node"); len(s.Start) == 0 { t.Fatal("node suggestions empty") } if s := a.LaunchCmdSuggest("mysql"); len(s.Stop) == 0 { t.Fatal("mysql stop suggestions empty") } if s := a.LaunchCmdSuggest("unknown-kind"); len(s.Start) != 0 || len(s.Stop) != 0 { t.Fatal("unknown kind should be empty") } } func TestLaunchAppCRUD(t *testing.T) { s, e := OpenStore(filepath.Join(t.TempDir(), "lp.db")) if e != nil { t.Fatal(e) } defer s.db.Close() if _, e := s.SaveLaunchApp(LaunchApp{Name: " "}); e == nil { t.Fatal("blank name accepted") } app, e := s.SaveLaunchApp(LaunchApp{Name: "demo-api", Port: 8080, Dir: t.TempDir(), StartCmd: "npm run dev"}) if e != nil || app.ID == 0 || app.Kind != "other" { t.Fatalf("create: %#v %v", app, e) } app.Kind, app.StopCmd = "node", "npx kill-port 8080" app2, e := s.SaveLaunchApp(app) if e != nil || app2.Kind != "node" || app2.StopCmd != "npx kill-port 8080" { t.Fatalf("update: %#v %v", app2, e) } if e := s.setLaunchPID(app.ID, 4321); e != nil { t.Fatal(e) } got, e := s.GetLaunchApp(app.ID) if e != nil || got.LastPID != 4321 { t.Fatalf("get: %#v %v", got, e) } lst, e := s.ListLaunchApps() if e != nil || len(lst) != 1 { t.Fatalf("list: %d %v", len(lst), e) } if e := s.DeleteLaunchApp(app.ID); e != nil { t.Fatal(e) } if lst, _ = s.ListLaunchApps(); len(lst) != 0 { t.Fatalf("after delete: %d", len(lst)) } } // TestScanListenPorts 冒烟:真机上应能扫出至少 0 个监听进程且不报错。 func TestScanListenPorts(t *testing.T) { m, e := scanListenPorts() if e != nil { t.Fatalf("scan failed: %v", e) } for pid, ports := range m { if pid <= 0 || len(ports) == 0 { t.Fatalf("bad entry pid=%d ports=%v", pid, ports) } } t.Logf("scanned %d listening processes", len(m)) }