Files
aego/editor/shell/recent_menu_test.go
sanspie a46347e2c6
ci-platforms / darwin arm64 smoke (push) Skipped
ci / build (amd64, linux, ubuntu-24.04) (push) Failing after 12m19s
ci-platforms / darwin amd64 smoke (push) Skipped
ci-platforms / windows amd64 smoke (push) Skipped
github-native / gitea-pending (push) Skipped
github-native / darwin amd64 native (push) Skipped
github-native / linux amd64 native (push) Skipped
github-native / windows amd64 native (push) Skipped
github-native / darwin arm64 native (push) Skipped
github-native / gitea-result (push) Skipped
ci / checks (push) Failing after 23m57s
ci / release (push) Skipped
GitHub / windows amd64 native GitHub-hosted native CI: failure
GitHub / darwin arm64 native GitHub-hosted native CI: failure
GitHub / darwin amd64 native GitHub-hosted native CI: failure
GitHub / linux amd64 native GitHub-hosted native CI: success
editor: add art studio and stage 12.5 workflows
2026-11-08 18:47:57 +03:00

144 lines
4.4 KiB
Go

package shell
import (
"fmt"
"os"
"path/filepath"
"strings"
"testing"
"aego/core/log"
"aego/core/mathx"
"aego/editor/core/command"
"aego/editor/core/context"
"aego/editor/core/document"
"aego/editor/shell/launcher"
"aego/engine"
"aego/engine/i18n"
"aego/platform/input"
"aego/project"
"aego/ui/core"
"aego/ui/widgets"
)
func TestRecentNamesDisambiguateProjects(t *testing.T) {
entries := []launcher.Entry{
{Name: "Game", Path: "/first/Game"},
{Name: "Game", Path: "/second/Game"},
{Name: "Other", Path: "/third/Other"},
}
names := recentNames(entries)
if names[0] == names[1] || !strings.Contains(names[0], entries[0].Path) || !strings.Contains(names[1], entries[1].Path) || names[2] != "Other" {
t.Fatalf("ambiguous recent names: %q", names)
}
}
func TestRecentElidedNamesStayDistinct(t *testing.T) {
ui := core.New(nil)
common := strings.Repeat("long-directory/", 20)
names := []string{"Game — /" + common + "first/" + common, "Game — /" + common + "second/" + common}
labels := recentMenuLabels(ui, names, 180)
if labels[0] == labels[1] {
t.Fatalf("elided paths are indistinguishable: %q", labels)
}
for _, label := range labels {
if ui.TextSize(label).X > 180 {
t.Fatalf("label does not fit: %q", label)
}
}
}
func TestRecentMenuSelectsDuplicateAndScrolledProjects(t *testing.T) {
for _, tc := range []struct {
name string
count int
selectIndex int
height float32
}{
{"second project with same name", 2, 1, 600},
{"last project after scrolling", launcher.MaxRecent, launcher.MaxRecent - 1, 240},
} {
t.Run(tc.name, func(t *testing.T) {
root := t.TempDir()
entries := make([]launcher.Entry, tc.count)
for i := range entries {
dir := filepath.Join(root, fmt.Sprintf("project-%02d", i))
if err := os.MkdirAll(dir, 0755); err != nil {
t.Fatal(err)
}
if err := os.WriteFile(filepath.Join(dir, project.FileName), nil, 0644); err != nil {
t.Fatal(err)
}
entries[i] = launcher.Entry{Path: dir, Name: "Shared"}
}
recentFile := filepath.Join(root, "recent")
if err := launcher.SaveRecent(recentFile, entries); err != nil {
t.Fatal(err)
}
e, err := engine.NewBuilder(engine.Config{Headless: true, ResRoot: t.TempDir(), UserRoot: t.TempDir()}).WithLogger(log.Nop()).Build()
if err != nil {
t.Fatal(err)
}
defer e.Close()
ui, in := core.New(nil), &input.State{}
var opened string
a := &App{
eng: e, ui: ui,
ctx: &context.Editor{Commands: command.New(), Docs: document.NewManager(document.Options{Root: root})},
opt: Options{Project: &project.Project{Root: root}, Recent: recentFile, Relaunch: func(target, _ string) error { opened = target; return nil }},
}
if err := a.registerProject(); err != nil {
t.Fatal(err)
}
step := func(at mathx.Vec2, down, up bool, wheel float32) {
in.BeginFrame()
in.ApplyMouseMove(at, mathx.Vec2{})
if down {
in.ApplyMouseDown(at, input.MouseLeft)
}
if up {
in.ApplyMouseUp(at, input.MouseLeft)
}
if wheel != 0 {
in.ApplyWheel(at, mathx.Vec2{Y: wheel})
}
ui.Begin(in, mathx.Vec2{X: 1000, Y: tc.height}, 1)
bar := widgets.BeginMenuBar(ui, mathx.Rect{W: 1000, H: 28})
if bar.Menu("File", 280) {
a.commandItems("File")
bar.EndMenu()
}
ui.End()
}
step(mathx.Vec2{X: 12, Y: 10}, true, false, 0)
step(mathx.Vec2{X: 12, Y: 10}, false, true, 0)
rowH := ui.Theme.RowHeight + ui.Theme.Spacing
parent := mathx.Vec2{X: 60, Y: 28 + ui.Theme.Padding + 2*rowH + ui.Theme.RowHeight/2}
step(parent, false, false, 0)
step(parent, false, false, 0)
subID := ui.ID("sub/" + i18n.Tr("editor.shell.open_recent", "Open Recent"))
if !ui.PopupOpen(subID) {
t.Fatal("hovering Open Recent did not open its submenu")
}
areaH := min(float32(tc.count)*rowH, max(rowH, tc.height-2*ui.Theme.Padding-4))
subY := 28 + 2*rowH
if subY+areaH+2*ui.Theme.Padding > tc.height {
subY = tc.height - areaH - 2*ui.Theme.Padding
}
at := mathx.Vec2{X: 320, Y: subY + ui.Theme.Padding + ui.Theme.RowHeight/2}
if tc.selectIndex >= 5 {
step(at, false, false, -100)
if a.recentScroll <= 0 {
t.Fatal("long recent-project list did not scroll")
}
}
at.Y += float32(tc.selectIndex)*rowH - a.recentScroll
step(at, true, false, 0)
step(at, false, true, 0)
if opened != entries[tc.selectIndex].Path {
t.Fatalf("selected %q, want %q", opened, entries[tc.selectIndex].Path)
}
})
}
}