package browser import ( "context" "errors" "io/fs" "path/filepath" "reflect" "testing" "time" "chub/internal/domain" ) func TestBuildArgsUsesControlledArgumentsAndRejectsOverrides(t *testing.T) { profile := filepath.Join(t.TempDir(), "profile one") args, err := BuildArgs(domain.LaunchSpec{ Kind: domain.BrowserChrome, UserDataDir: profile, ProfileDirectory: "Default", TargetURL: "https://example.com/?a=1&b=2", ProxyServer: "HTTPS://Proxy.Local:8443", Headless: true, ExtraArgs: []string{"--window-size=1280,900"}, }) if err != nil { t.Fatalf("BuildArgs() error = %v", err) } want := []string{"--user-data-dir=" + filepath.Clean(profile), "--no-first-run", "--disable-default-apps", "--profile-directory=Default", "--headless=new", "--proxy-server=https://proxy.local:8443", "--window-size=1280,900", "https://example.com/?a=1&b=2"} if !reflect.DeepEqual(args, want) { t.Fatalf("args = %#v, want %#v", args, want) } for _, unsafe := range []string{"--user-data-dir=C:\\other", "--remote-debugging-port=9222", "not-a-flag"} { _, err := BuildArgs(domain.LaunchSpec{Kind: domain.BrowserEdge, UserDataDir: profile, TargetURL: "https://example.com", ExtraArgs: []string{unsafe}}) if !errors.Is(err, ErrUnsafeArgument) { t.Errorf("extra arg %q error = %v", unsafe, err) } } } func TestBuildArgsRejectsProxyCredentialsAndUnsupportedValues(t *testing.T) { base := domain.LaunchSpec{Kind: domain.BrowserChrome, UserDataDir: filepath.Join(t.TempDir(), "profile"), TargetURL: "https://example.com"} for _, proxy := range []string{"http://user@127.0.0.1:8080", "ftp://127.0.0.1:21", "http://127.0.0.1:70000", "http://127.0.0.1:8080/path"} { base.ProxyServer = proxy if _, err := BuildArgs(base); !errors.Is(err, domain.ErrInvalidLaunchSpec) { t.Errorf("proxy %q error = %v", proxy, err) } } } func TestDiscovererResolvesConfiguredAndStandardPaths(t *testing.T) { root := t.TempDir() chrome := filepath.Join(root, `Google\Chrome\Application\chrome.exe`) edge := filepath.Join(root, `Microsoft\Edge\Application\msedge.exe`) files := map[string]fs.FileInfo{chrome: fakeFileInfo{}, edge: fakeFileInfo{}} discoverer := &Discoverer{getenv: func(key string) string { if key == "PROGRAMFILES" { return root } return "" }, stat: func(path string) (fs.FileInfo, error) { info, ok := files[path] if !ok { return nil, fs.ErrNotExist } return info, nil }} for _, test := range []struct { kind domain.BrowserKind want string }{{domain.BrowserChrome, chrome}, {domain.BrowserEdge, edge}} { got, err := discoverer.Resolve(context.Background(), test.kind, "") if err != nil || got != test.want { t.Errorf("Resolve(%s) = %q, %v; want %q", test.kind, got, err, test.want) } } got, err := discoverer.Resolve(context.Background(), domain.BrowserChrome, chrome) if err != nil || got != chrome { t.Fatalf("configured Resolve() = %q, %v", got, err) } } type fakeFileInfo struct{} func (fakeFileInfo) Name() string { return "browser.exe" } func (fakeFileInfo) Size() int64 { return 1 } func (fakeFileInfo) Mode() fs.FileMode { return 0o755 } func (fakeFileInfo) ModTime() time.Time { return time.Time{} } func (fakeFileInfo) IsDir() bool { return false } func (fakeFileInfo) Sys() any { return nil }