| 1 | package main |
| 2 | |
| 3 | import ( |
| 4 | "fmt" |
| 5 | "os" |
| 6 | "path/filepath" |
| 7 | "testing" |
| 8 | |
| 9 | "reasonix/internal/pathidentity" |
| 10 | ) |
| 11 | |
| 12 | // Every sidebar read loads the projects file, and on Windows one resolution |
| 13 | // opens every component of the path, so the load must resolve each root a |
| 14 | // bounded number of times rather than once per pair of roots. |
| 15 | func TestLoadProjectsFileResolvesEachRootLinearly(t *testing.T) { |
| 16 | isolateDesktopUserDirs(t) |
| 17 | base := t.TempDir() |
| 18 | const projects = 24 |
| 19 | var file desktopProjectFile |
| 20 | for i := range projects { |
| 21 | root := filepath.Join(base, fmt.Sprintf("project-%02d", i)) |
| 22 | if err := os.MkdirAll(root, 0o755); err != nil { |
| 23 | t.Fatal(err) |
| 24 | } |
| 25 | file.Projects = append(file.Projects, desktopProject{Root: root, ManualTopicOrder: true, Topics: []string{"t"}}) |
| 26 | file.SidebarOrder = append(file.SidebarOrder, root) |
| 27 | if i%3 == 0 { |
| 28 | file.PinnedProjects = append(file.PinnedProjects, root) |
| 29 | } |
| 30 | } |
| 31 | alias := filepath.Join(base, "alias") |
| 32 | if err := os.Symlink(file.Projects[5].Root, alias); err != nil { |
| 33 | t.Skipf("symlink unavailable: %v", err) |
| 34 | } |
| 35 | file.Projects = append(file.Projects, desktopProject{Root: alias, Title: "Alias title"}) |
| 36 | if err := saveProjectsFile(file); err != nil { |
| 37 | t.Fatal(err) |
| 38 | } |
| 39 | |
| 40 | resolutions := 0 |
| 41 | original := resolveDesktopPathIdentity |
| 42 | resolveDesktopPathIdentity = func(path string, options pathidentity.Options) (pathidentity.Identity, error) { |
| 43 | resolutions++ |
| 44 | return original(path, options) |
| 45 | } |
| 46 | t.Cleanup(func() { resolveDesktopPathIdentity = original }) |
| 47 | |
| 48 | loaded := loadProjectsFile() |
| 49 | if len(loaded.Projects) != projects { |
| 50 | t.Fatalf("projects = %d, want %d with the alias folded into its target", len(loaded.Projects), projects) |
| 51 | } |
| 52 | if loaded.Projects[5].Title != "Alias title" { |
| 53 | t.Fatalf("alias metadata was not merged into its target: %+v", loaded.Projects[5]) |
| 54 | } |
| 55 | if len(loaded.SidebarOrder) != projects || len(loaded.PinnedProjects) != (projects+2)/3 { |
| 56 | t.Fatalf("sidebar order %d / pinned %d changed", len(loaded.SidebarOrder), len(loaded.PinnedProjects)) |
| 57 | } |
| 58 | if limit := 4 * (projects + 1); resolutions > limit { |
| 59 | t.Fatalf("loading %d projects resolved path identity %d times, want at most %d", projects, resolutions, limit) |
| 60 | } |
| 61 | } |
| 62 |