mirror of
https://github.com/moonD4rk/HackBrowserData.git
synced 2026-06-02 19:41:36 +02:00
feat: support MSIX/UWP browsers on Windows (Arc, DuckDuckGo) (#563)
* chore: remove redundant separator comments in browser_test.go
This commit is contained in:
@@ -50,6 +50,8 @@ func pickFromConfigs(configs []types.BrowserConfig, opts PickOptions) ([]Browser
|
|||||||
// it's harmless (DPAPI reads Local State per-profile, D-Bus is stateless).
|
// it's harmless (DPAPI reads Local State per-profile, D-Bus is stateless).
|
||||||
retriever := keyretriever.DefaultRetriever(opts.KeychainPassword)
|
retriever := keyretriever.DefaultRetriever(opts.KeychainPassword)
|
||||||
|
|
||||||
|
configs = resolveGlobs(configs)
|
||||||
|
|
||||||
var browsers []Browser
|
var browsers []Browser
|
||||||
for _, cfg := range configs {
|
for _, cfg := range configs {
|
||||||
if name != "all" && cfg.Key != name {
|
if name != "all" && cfg.Key != name {
|
||||||
@@ -94,6 +96,34 @@ type retrieverSetter interface {
|
|||||||
SetRetriever(keyretriever.KeyRetriever)
|
SetRetriever(keyretriever.KeyRetriever)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// resolveGlobs expands glob patterns in browser configs' UserDataDir.
|
||||||
|
// This supports MSIX/UWP browsers on Windows whose package directories
|
||||||
|
// contain a dynamic publisher hash suffix (e.g., "TheBrowserCompany.Arc_*").
|
||||||
|
//
|
||||||
|
// For literal paths (no glob metacharacters), Glob returns the path itself
|
||||||
|
// when it exists, so the config passes through unchanged. When a path does
|
||||||
|
// not exist and contains no metacharacters, Glob returns nil and the
|
||||||
|
// original config is preserved — the main loop handles "not found" as usual.
|
||||||
|
//
|
||||||
|
// When a glob matches multiple directories, the config is duplicated so
|
||||||
|
// each resolved path is treated as a separate browser data directory.
|
||||||
|
func resolveGlobs(configs []types.BrowserConfig) []types.BrowserConfig {
|
||||||
|
var out []types.BrowserConfig
|
||||||
|
for _, cfg := range configs {
|
||||||
|
matches, _ := filepath.Glob(cfg.UserDataDir)
|
||||||
|
if len(matches) == 0 {
|
||||||
|
out = append(out, cfg)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
for _, dir := range matches {
|
||||||
|
c := cfg
|
||||||
|
c.UserDataDir = dir
|
||||||
|
out = append(out, c)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
// newBrowsers dispatches to the correct engine based on BrowserKind
|
// newBrowsers dispatches to the correct engine based on BrowserKind
|
||||||
// and converts engine-specific types to the Browser interface.
|
// and converts engine-specific types to the Browser interface.
|
||||||
func newBrowsers(cfg types.BrowserConfig) ([]Browser, error) {
|
func newBrowsers(cfg types.BrowserConfig) ([]Browser, error) {
|
||||||
|
|||||||
+264
-133
@@ -25,57 +25,33 @@ func TestListBrowsers(t *testing.T) {
|
|||||||
assert.True(t, sort.StringsAreSorted(list))
|
assert.True(t, sort.StringsAreSorted(list))
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestPickFromConfigs_NameFilter(t *testing.T) {
|
type pickTest struct {
|
||||||
dir := t.TempDir()
|
name string
|
||||||
mkFile(t, dir, "Default", "Preferences")
|
configs []types.BrowserConfig
|
||||||
mkFile(t, dir, "Default", "Login Data")
|
opts PickOptions
|
||||||
mkFile(t, dir, "Default", "History")
|
wantNames []string
|
||||||
|
wantProfiles []string
|
||||||
configs := []types.BrowserConfig{
|
}
|
||||||
{Key: "chrome", Name: "Chrome", Kind: types.Chromium, UserDataDir: dir},
|
|
||||||
{Key: "edge", Name: "Edge", Kind: types.Chromium, UserDataDir: dir},
|
|
||||||
}
|
|
||||||
|
|
||||||
tests := []struct {
|
|
||||||
name string
|
|
||||||
pickName string
|
|
||||||
wantNames []string
|
|
||||||
wantProfiles []string
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
name: "exact match",
|
|
||||||
pickName: "chrome",
|
|
||||||
wantNames: []string{"Chrome"},
|
|
||||||
wantProfiles: []string{"Default"},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "case insensitive",
|
|
||||||
pickName: "Chrome",
|
|
||||||
wantNames: []string{"Chrome"},
|
|
||||||
wantProfiles: []string{"Default"},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "all returns both",
|
|
||||||
pickName: "all",
|
|
||||||
wantNames: []string{"Chrome", "Edge"},
|
|
||||||
wantProfiles: []string{"Default", "Default"},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "unknown returns empty",
|
|
||||||
pickName: "safari",
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
|
func runPickTests(t *testing.T, tests []pickTest) {
|
||||||
|
t.Helper()
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
browsers, err := pickFromConfigs(configs, PickOptions{Name: tt.pickName})
|
browsers, err := pickFromConfigs(tt.configs, tt.opts)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
assertBrowsers(t, browsers, tt.wantNames, tt.wantProfiles)
|
assertBrowsers(t, browsers, tt.wantNames, tt.wantProfiles)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestPickFromConfigs_BrowserKind(t *testing.T) {
|
func TestPickFromConfigs(t *testing.T) {
|
||||||
|
// --- fixtures: single-profile chromium (for name filter tests) ---
|
||||||
|
singleDir := t.TempDir()
|
||||||
|
mkFile(t, singleDir, "Default", "Preferences")
|
||||||
|
mkFile(t, singleDir, "Default", "Login Data")
|
||||||
|
mkFile(t, singleDir, "Default", "History")
|
||||||
|
|
||||||
|
// --- fixtures: multi-profile chromium ---
|
||||||
chromeDir := t.TempDir()
|
chromeDir := t.TempDir()
|
||||||
mkFile(t, chromeDir, "Default", "Preferences")
|
mkFile(t, chromeDir, "Default", "Preferences")
|
||||||
mkFile(t, chromeDir, "Default", "Login Data")
|
mkFile(t, chromeDir, "Default", "Login Data")
|
||||||
@@ -84,128 +60,287 @@ func TestPickFromConfigs_BrowserKind(t *testing.T) {
|
|||||||
mkFile(t, chromeDir, "Profile 1", "Login Data")
|
mkFile(t, chromeDir, "Profile 1", "Login Data")
|
||||||
mkFile(t, chromeDir, "Profile 1", "History")
|
mkFile(t, chromeDir, "Profile 1", "History")
|
||||||
|
|
||||||
|
// --- fixtures: firefox ---
|
||||||
firefoxDir := t.TempDir()
|
firefoxDir := t.TempDir()
|
||||||
mkFile(t, firefoxDir, "abc123.default-release", "logins.json")
|
mkFile(t, firefoxDir, "abc123.default-release", "logins.json")
|
||||||
mkFile(t, firefoxDir, "abc123.default-release", "places.sqlite")
|
mkFile(t, firefoxDir, "abc123.default-release", "places.sqlite")
|
||||||
|
|
||||||
|
// --- fixtures: yandex ---
|
||||||
yandexDir := t.TempDir()
|
yandexDir := t.TempDir()
|
||||||
mkFile(t, yandexDir, "Default", "Preferences")
|
mkFile(t, yandexDir, "Default", "Preferences")
|
||||||
mkFile(t, yandexDir, "Default", "Ya Passman Data")
|
mkFile(t, yandexDir, "Default", "Ya Passman Data")
|
||||||
mkFile(t, yandexDir, "Default", "History")
|
mkFile(t, yandexDir, "Default", "History")
|
||||||
|
|
||||||
|
// --- fixtures: glob (MSIX-like package directories) ---
|
||||||
|
globBase := t.TempDir()
|
||||||
|
mkFile(t, globBase, "App.Browser_abc123", "UserData", "Default", "Preferences")
|
||||||
|
mkFile(t, globBase, "App.Browser_abc123", "UserData", "Default", "History")
|
||||||
|
mkFile(t, globBase, "App.Browser_def456", "UserData", "Default", "Preferences")
|
||||||
|
mkFile(t, globBase, "App.Browser_def456", "UserData", "Default", "History")
|
||||||
|
mkFile(t, globBase, "Solo.Browser_xyz789", "UserData", "Default", "Preferences")
|
||||||
|
mkFile(t, globBase, "Solo.Browser_xyz789", "UserData", "Default", "History")
|
||||||
|
|
||||||
|
nameFilterConfigs := []types.BrowserConfig{
|
||||||
|
{Key: "chrome", Name: "Chrome", Kind: types.Chromium, UserDataDir: singleDir},
|
||||||
|
{Key: "edge", Name: "Edge", Kind: types.Chromium, UserDataDir: singleDir},
|
||||||
|
}
|
||||||
|
|
||||||
|
t.Run("NameFilter", func(t *testing.T) {
|
||||||
|
runPickTests(t, []pickTest{
|
||||||
|
{
|
||||||
|
name: "exact match",
|
||||||
|
configs: nameFilterConfigs,
|
||||||
|
opts: PickOptions{Name: "chrome"},
|
||||||
|
wantNames: []string{"Chrome"},
|
||||||
|
wantProfiles: []string{"Default"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "case insensitive",
|
||||||
|
configs: nameFilterConfigs,
|
||||||
|
opts: PickOptions{Name: "Chrome"},
|
||||||
|
wantNames: []string{"Chrome"},
|
||||||
|
wantProfiles: []string{"Default"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "all returns both",
|
||||||
|
configs: nameFilterConfigs,
|
||||||
|
opts: PickOptions{Name: "all"},
|
||||||
|
wantNames: []string{"Chrome", "Edge"},
|
||||||
|
wantProfiles: []string{"Default", "Default"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "unknown returns empty",
|
||||||
|
configs: nameFilterConfigs,
|
||||||
|
opts: PickOptions{Name: "safari"},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("BrowserKind", func(t *testing.T) {
|
||||||
|
runPickTests(t, []pickTest{
|
||||||
|
{
|
||||||
|
name: "chromium multi-profile",
|
||||||
|
configs: []types.BrowserConfig{
|
||||||
|
{Key: "chrome", Name: "Chrome", Kind: types.Chromium, UserDataDir: chromeDir},
|
||||||
|
},
|
||||||
|
opts: PickOptions{Name: "all"},
|
||||||
|
wantNames: []string{"Chrome", "Chrome"},
|
||||||
|
wantProfiles: []string{"Default", "Profile 1"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "firefox random dir",
|
||||||
|
configs: []types.BrowserConfig{
|
||||||
|
{Key: "firefox", Name: "Firefox", Kind: types.Firefox, UserDataDir: firefoxDir},
|
||||||
|
},
|
||||||
|
opts: PickOptions{Name: "all"},
|
||||||
|
wantNames: []string{"Firefox"},
|
||||||
|
wantProfiles: []string{"abc123.default-release"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "yandex variant",
|
||||||
|
configs: []types.BrowserConfig{
|
||||||
|
{Key: "yandex", Name: "Yandex", Kind: types.ChromiumYandex, UserDataDir: yandexDir},
|
||||||
|
},
|
||||||
|
opts: PickOptions{Name: "all"},
|
||||||
|
wantNames: []string{"Yandex"},
|
||||||
|
wantProfiles: []string{"Default"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "nonexistent dir",
|
||||||
|
configs: []types.BrowserConfig{
|
||||||
|
{Key: "chrome", Name: "Chrome", Kind: types.Chromium, UserDataDir: "/nonexistent"},
|
||||||
|
},
|
||||||
|
opts: PickOptions{Name: "all"},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("ProfilePath", func(t *testing.T) {
|
||||||
|
runPickTests(t, []pickTest{
|
||||||
|
{
|
||||||
|
name: "chromium uses path directly",
|
||||||
|
configs: []types.BrowserConfig{
|
||||||
|
{Key: "chrome", Name: "Chrome", Kind: types.Chromium, UserDataDir: "/wrong"},
|
||||||
|
},
|
||||||
|
opts: PickOptions{Name: "chrome", ProfilePath: filepath.Join(chromeDir, "Default")},
|
||||||
|
wantNames: []string{"Chrome"},
|
||||||
|
wantProfiles: []string{"Default"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "firefox uses parent dir",
|
||||||
|
configs: []types.BrowserConfig{
|
||||||
|
{Key: "firefox", Name: "Firefox", Kind: types.Firefox, UserDataDir: "/wrong"},
|
||||||
|
},
|
||||||
|
opts: PickOptions{Name: "firefox", ProfilePath: filepath.Join(firefoxDir, "abc123.default-release")},
|
||||||
|
wantNames: []string{"Firefox"},
|
||||||
|
wantProfiles: []string{"abc123.default-release"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "ignored when name is all",
|
||||||
|
configs: []types.BrowserConfig{
|
||||||
|
{Key: "chrome", Name: "Chrome", Kind: types.Chromium, UserDataDir: chromeDir},
|
||||||
|
},
|
||||||
|
opts: PickOptions{Name: "all", ProfilePath: "/some/override"},
|
||||||
|
wantNames: []string{"Chrome", "Chrome"},
|
||||||
|
wantProfiles: []string{"Default", "Profile 1"},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("Glob", func(t *testing.T) {
|
||||||
|
runPickTests(t, []pickTest{
|
||||||
|
{
|
||||||
|
name: "single match",
|
||||||
|
configs: []types.BrowserConfig{
|
||||||
|
{Key: "solo", Name: "Solo", Kind: types.Chromium, UserDataDir: filepath.Join(globBase, "Solo.Browser_*", "UserData")},
|
||||||
|
},
|
||||||
|
opts: PickOptions{Name: "all"},
|
||||||
|
wantNames: []string{"Solo"},
|
||||||
|
wantProfiles: []string{"Default"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "multiple matches",
|
||||||
|
configs: []types.BrowserConfig{
|
||||||
|
{Key: "arc", Name: "Arc", Kind: types.Chromium, UserDataDir: filepath.Join(globBase, "App.Browser_*", "UserData")},
|
||||||
|
},
|
||||||
|
opts: PickOptions{Name: "all"},
|
||||||
|
wantNames: []string{"Arc", "Arc"},
|
||||||
|
wantProfiles: []string{"Default", "Default"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "no match",
|
||||||
|
configs: []types.BrowserConfig{
|
||||||
|
{Key: "missing", Name: "Missing", Kind: types.Chromium, UserDataDir: filepath.Join(globBase, "NoSuch_*", "UserData")},
|
||||||
|
},
|
||||||
|
opts: PickOptions{Name: "all"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "mixed with literal",
|
||||||
|
configs: []types.BrowserConfig{
|
||||||
|
{Key: "chrome", Name: "Chrome", Kind: types.Chromium, UserDataDir: singleDir},
|
||||||
|
{Key: "arc", Name: "Arc", Kind: types.Chromium, UserDataDir: filepath.Join(globBase, "Solo.Browser_*", "UserData")},
|
||||||
|
},
|
||||||
|
opts: PickOptions{Name: "all"},
|
||||||
|
wantNames: []string{"Arc", "Chrome"},
|
||||||
|
wantProfiles: []string{"Default", "Default"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "with name filter",
|
||||||
|
configs: []types.BrowserConfig{
|
||||||
|
{Key: "chrome", Name: "Chrome", Kind: types.Chromium, UserDataDir: singleDir},
|
||||||
|
{Key: "arc", Name: "Arc", Kind: types.Chromium, UserDataDir: filepath.Join(globBase, "App.Browser_*", "UserData")},
|
||||||
|
},
|
||||||
|
opts: PickOptions{Name: "arc"},
|
||||||
|
wantNames: []string{"Arc", "Arc"},
|
||||||
|
wantProfiles: []string{"Default", "Default"},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestResolveGlobs(t *testing.T) {
|
||||||
|
// Create directories for glob matching:
|
||||||
|
// base/
|
||||||
|
// ├── App.Browser_abc123/UserData/ (match 1)
|
||||||
|
// ├── App.Browser_def456/UserData/ (match 2)
|
||||||
|
// └── ExactBrowser/UserData/ (literal path)
|
||||||
|
base := t.TempDir()
|
||||||
|
require.NoError(t, os.MkdirAll(filepath.Join(base, "App.Browser_abc123", "UserData"), 0o755))
|
||||||
|
require.NoError(t, os.MkdirAll(filepath.Join(base, "App.Browser_def456", "UserData"), 0o755))
|
||||||
|
require.NoError(t, os.MkdirAll(filepath.Join(base, "ExactBrowser", "UserData"), 0o755))
|
||||||
|
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
name string
|
name string
|
||||||
configs []types.BrowserConfig
|
configs []types.BrowserConfig
|
||||||
wantNames []string
|
wantDirs []string // expected UserDataDir values after resolution
|
||||||
wantProfiles []string
|
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
name: "chromium multi-profile",
|
name: "literal path exists",
|
||||||
configs: []types.BrowserConfig{
|
configs: []types.BrowserConfig{
|
||||||
{Key: "chrome", Name: "Chrome", Kind: types.Chromium, UserDataDir: chromeDir},
|
{Key: "exact", UserDataDir: filepath.Join(base, "ExactBrowser", "UserData")},
|
||||||
},
|
},
|
||||||
wantNames: []string{"Chrome", "Chrome"},
|
wantDirs: []string{filepath.Join(base, "ExactBrowser", "UserData")},
|
||||||
wantProfiles: []string{"Default", "Profile 1"},
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "firefox random dir",
|
name: "literal path not exists preserved",
|
||||||
configs: []types.BrowserConfig{
|
configs: []types.BrowserConfig{
|
||||||
{Key: "firefox", Name: "Firefox", Kind: types.Firefox, UserDataDir: firefoxDir},
|
{Key: "missing", UserDataDir: filepath.Join(base, "NoSuchBrowser", "UserData")},
|
||||||
},
|
},
|
||||||
wantNames: []string{"Firefox"},
|
wantDirs: []string{filepath.Join(base, "NoSuchBrowser", "UserData")},
|
||||||
wantProfiles: []string{"abc123.default-release"},
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "yandex variant",
|
name: "glob single match",
|
||||||
configs: []types.BrowserConfig{
|
configs: []types.BrowserConfig{
|
||||||
{Key: "yandex", Name: "Yandex", Kind: types.ChromiumYandex, UserDataDir: yandexDir},
|
{Key: "single", UserDataDir: filepath.Join(base, "ExactBrow*", "UserData")},
|
||||||
},
|
},
|
||||||
wantNames: []string{"Yandex"},
|
wantDirs: []string{filepath.Join(base, "ExactBrowser", "UserData")},
|
||||||
wantProfiles: []string{"Default"},
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "nonexistent dir",
|
name: "glob multiple matches",
|
||||||
configs: []types.BrowserConfig{
|
configs: []types.BrowserConfig{
|
||||||
{Key: "chrome", Name: "Chrome", Kind: types.Chromium, UserDataDir: "/nonexistent"},
|
{Key: "multi", UserDataDir: filepath.Join(base, "App.Browser_*", "UserData")},
|
||||||
},
|
},
|
||||||
|
wantDirs: []string{
|
||||||
|
filepath.Join(base, "App.Browser_abc123", "UserData"),
|
||||||
|
filepath.Join(base, "App.Browser_def456", "UserData"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "glob no match preserved",
|
||||||
|
configs: []types.BrowserConfig{
|
||||||
|
{Key: "nomatch", UserDataDir: filepath.Join(base, "NoSuch_*", "UserData")},
|
||||||
|
},
|
||||||
|
wantDirs: []string{filepath.Join(base, "NoSuch_*", "UserData")},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "mixed literal and glob",
|
||||||
|
configs: []types.BrowserConfig{
|
||||||
|
{Key: "chrome", UserDataDir: filepath.Join(base, "ExactBrowser", "UserData")},
|
||||||
|
{Key: "arc", UserDataDir: filepath.Join(base, "App.Browser_*", "UserData")},
|
||||||
|
},
|
||||||
|
wantDirs: []string{
|
||||||
|
filepath.Join(base, "ExactBrowser", "UserData"),
|
||||||
|
filepath.Join(base, "App.Browser_abc123", "UserData"),
|
||||||
|
filepath.Join(base, "App.Browser_def456", "UserData"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "empty input",
|
||||||
|
configs: nil,
|
||||||
|
wantDirs: nil,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
browsers, err := pickFromConfigs(tt.configs, PickOptions{Name: "all"})
|
got := resolveGlobs(tt.configs)
|
||||||
require.NoError(t, err)
|
|
||||||
assertBrowsers(t, browsers, tt.wantNames, tt.wantProfiles)
|
var gotDirs []string
|
||||||
|
for _, cfg := range got {
|
||||||
|
gotDirs = append(gotDirs, cfg.UserDataDir)
|
||||||
|
}
|
||||||
|
sort.Strings(gotDirs)
|
||||||
|
sort.Strings(tt.wantDirs)
|
||||||
|
assert.Equal(t, tt.wantDirs, gotDirs)
|
||||||
|
|
||||||
|
// Verify non-UserDataDir fields are preserved.
|
||||||
|
for _, cfg := range got {
|
||||||
|
found := false
|
||||||
|
for _, orig := range tt.configs {
|
||||||
|
if cfg.Key != orig.Key {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
found = true
|
||||||
|
assert.Equal(t, orig.Name, cfg.Name)
|
||||||
|
assert.Equal(t, orig.Kind, cfg.Kind)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
assert.True(t, found, "unexpected key %q in output", cfg.Key)
|
||||||
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestPickFromConfigs_ProfilePath(t *testing.T) {
|
|
||||||
chromeDir := t.TempDir()
|
|
||||||
mkFile(t, chromeDir, "Default", "Preferences")
|
|
||||||
mkFile(t, chromeDir, "Default", "Login Data")
|
|
||||||
mkFile(t, chromeDir, "Default", "History")
|
|
||||||
mkFile(t, chromeDir, "Profile 1", "Preferences")
|
|
||||||
mkFile(t, chromeDir, "Profile 1", "Login Data")
|
|
||||||
mkFile(t, chromeDir, "Profile 1", "History")
|
|
||||||
|
|
||||||
firefoxDir := t.TempDir()
|
|
||||||
mkFile(t, firefoxDir, "abc123.default-release", "logins.json")
|
|
||||||
mkFile(t, firefoxDir, "abc123.default-release", "places.sqlite")
|
|
||||||
|
|
||||||
tests := []struct {
|
|
||||||
name string
|
|
||||||
configs []types.BrowserConfig
|
|
||||||
pickName string
|
|
||||||
profilePath string
|
|
||||||
wantNames []string
|
|
||||||
wantProfiles []string
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
name: "chromium uses path directly",
|
|
||||||
configs: []types.BrowserConfig{
|
|
||||||
{Key: "chrome", Name: "Chrome", Kind: types.Chromium, UserDataDir: "/wrong"},
|
|
||||||
},
|
|
||||||
pickName: "chrome",
|
|
||||||
profilePath: filepath.Join(chromeDir, "Default"),
|
|
||||||
wantNames: []string{"Chrome"},
|
|
||||||
wantProfiles: []string{"Default"},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "firefox uses parent dir",
|
|
||||||
configs: []types.BrowserConfig{
|
|
||||||
{Key: "firefox", Name: "Firefox", Kind: types.Firefox, UserDataDir: "/wrong"},
|
|
||||||
},
|
|
||||||
pickName: "firefox",
|
|
||||||
profilePath: filepath.Join(firefoxDir, "abc123.default-release"),
|
|
||||||
wantNames: []string{"Firefox"},
|
|
||||||
wantProfiles: []string{"abc123.default-release"},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "ignored when name is all",
|
|
||||||
configs: []types.BrowserConfig{
|
|
||||||
{Key: "chrome", Name: "Chrome", Kind: types.Chromium, UserDataDir: chromeDir},
|
|
||||||
},
|
|
||||||
pickName: "all",
|
|
||||||
profilePath: "/some/override",
|
|
||||||
wantNames: []string{"Chrome", "Chrome"},
|
|
||||||
wantProfiles: []string{"Default", "Profile 1"},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, tt := range tests {
|
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
|
||||||
browsers, err := pickFromConfigs(tt.configs, PickOptions{Name: tt.pickName, ProfilePath: tt.profilePath})
|
|
||||||
require.NoError(t, err)
|
|
||||||
assertBrowsers(t, browsers, tt.wantNames, tt.wantProfiles)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
|
||||||
// newBrowsers dispatcher
|
|
||||||
// ---------------------------------------------------------------------------
|
|
||||||
|
|
||||||
func TestNewBrowsersDispatch(t *testing.T) {
|
func TestNewBrowsersDispatch(t *testing.T) {
|
||||||
chromiumDir := t.TempDir()
|
chromiumDir := t.TempDir()
|
||||||
mkFile(t, chromiumDir, "Default", "Preferences")
|
mkFile(t, chromiumDir, "Default", "Preferences")
|
||||||
@@ -267,10 +402,6 @@ func TestNewBrowsersDispatch(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
|
||||||
// Helpers
|
|
||||||
// ---------------------------------------------------------------------------
|
|
||||||
|
|
||||||
// assertBrowsers verifies browser names and profiles match expectations (order-independent).
|
// assertBrowsers verifies browser names and profiles match expectations (order-independent).
|
||||||
func assertBrowsers(t *testing.T, browsers []Browser, wantNames, wantProfiles []string) {
|
func assertBrowsers(t *testing.T, browsers []Browser, wantNames, wantProfiles []string) {
|
||||||
t.Helper()
|
t.Helper()
|
||||||
|
|||||||
@@ -98,6 +98,18 @@ func platformBrowsers() []types.BrowserConfig {
|
|||||||
Kind: types.Chromium,
|
Kind: types.Chromium,
|
||||||
UserDataDir: homeDir + "/AppData/Local/Sogou/SogouExplorer/User Data",
|
UserDataDir: homeDir + "/AppData/Local/Sogou/SogouExplorer/User Data",
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
Key: "arc",
|
||||||
|
Name: arcName,
|
||||||
|
Kind: types.Chromium,
|
||||||
|
UserDataDir: homeDir + "/AppData/Local/Packages/TheBrowserCompany.Arc_*/LocalCache/Local/Arc/User Data",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Key: "duckduckgo",
|
||||||
|
Name: duckduckgoName,
|
||||||
|
Kind: types.Chromium,
|
||||||
|
UserDataDir: homeDir + "/AppData/Local/Packages/DuckDuckGo.DesktopBrowser_*/LocalState/EBWebView",
|
||||||
|
},
|
||||||
{
|
{
|
||||||
Key: "firefox",
|
Key: "firefox",
|
||||||
Name: firefoxName,
|
Name: firefoxName,
|
||||||
|
|||||||
@@ -25,4 +25,5 @@ const (
|
|||||||
dcName = "DC"
|
dcName = "DC"
|
||||||
sogouName = "Sogou"
|
sogouName = "Sogou"
|
||||||
arcName = "Arc"
|
arcName = "Arc"
|
||||||
|
duckduckgoName = "DuckDuckGo"
|
||||||
)
|
)
|
||||||
|
|||||||
Reference in New Issue
Block a user