| 1 | package main |
| 2 | |
| 3 | import ( |
| 4 | "context" |
| 5 | "os" |
| 6 | "path/filepath" |
| 7 | "testing" |
| 8 | |
| 9 | "github.com/wailsapp/wails/v2/pkg/options/linux" |
| 10 | ) |
| 11 | |
| 12 | func TestParseDesktopLaunchArgsStripsLegacySafeMode(t *testing.T) { |
| 13 | got := parseDesktopLaunchArgs([]string{"launch", "--detach", "--safe-mode", "--other"}) |
| 14 | if !got.LegacySafeModeArg { |
| 15 | t.Fatal("--safe-mode should still be recognized for stripping") |
| 16 | } |
| 17 | if parseDesktopLaunchArgs([]string{"--other"}).LegacySafeModeArg { |
| 18 | t.Fatal("unrelated argument must not set legacy safe-mode flag") |
| 19 | } |
| 20 | } |
| 21 | |
| 22 | func TestParseDesktopLaunchArgsRemoteWindow(t *testing.T) { |
| 23 | got := parseDesktopLaunchArgs([]string{ |
| 24 | "--other", |
| 25 | remoteWindowTicketArgPrefix + ".remote-window-123", |
| 26 | remoteWindowHostArgPrefix + "abcd1234", |
| 27 | remoteWindowOwnerArgPrefix + "0123456789abcdef0123456789abcdef", |
| 28 | remoteWindowParentArgPrefix + "4242", |
| 29 | }) |
| 30 | if got.RemoteWindowTicket != ".remote-window-123" { |
| 31 | t.Fatalf("RemoteWindowTicket = %q", got.RemoteWindowTicket) |
| 32 | } |
| 33 | if got.RemoteWindowHostKey != "abcd1234" { |
| 34 | t.Fatalf("RemoteWindowHostKey = %q", got.RemoteWindowHostKey) |
| 35 | } |
| 36 | if got.RemoteWindowOwnerID != "0123456789abcdef0123456789abcdef" { |
| 37 | t.Fatalf("RemoteWindowOwnerID = %q", got.RemoteWindowOwnerID) |
| 38 | } |
| 39 | if got.RemoteWindowParentPID != 4242 { |
| 40 | t.Fatalf("RemoteWindowParentPID = %d", got.RemoteWindowParentPID) |
| 41 | } |
| 42 | if got.LegacySafeModeArg { |
| 43 | t.Fatal("remote window args unexpectedly enabled legacy safe mode") |
| 44 | } |
| 45 | } |
| 46 | |
| 47 | // TestMain isolates user config/state/cache dirs for the whole package. Without |
| 48 | // this, tests that persist desktop state, sessions, cache, or CLI-style config |
| 49 | // can leak into the developer's real Reasonix directories. |
| 50 | func TestMain(m *testing.M) { |
| 51 | dir, err := os.MkdirTemp("", "reasonix-desktop-test") |
| 52 | if err != nil { |
| 53 | os.Exit(1) |
| 54 | } |
| 55 | os.Setenv("HOME", dir) |
| 56 | os.Setenv("REASONIX_CREDENTIALS_STORE", "file") |
| 57 | os.Setenv("USERPROFILE", dir) |
| 58 | os.Setenv("XDG_CONFIG_HOME", dir+"/config") |
| 59 | os.Setenv("REASONIX_STATE_HOME", dir+"/state") |
| 60 | os.Setenv("REASONIX_CACHE_HOME", dir+"/cache") |
| 61 | os.Setenv("AppData", dir) |
| 62 | // Neutralize the Wails runtime-event bridge for the whole test binary: |
| 63 | // outside a running Wails app, runtime.EventsEmit log.Fatals on the plain |
| 64 | // contexts tests use, killing the process from any emitting code path. |
| 65 | // Tests that assert on runtime events install their own capture through |
| 66 | // the per-instance runtimeEvents.emit hook, which takes precedence. |
| 67 | runtimeEventsEmitFallback = func(context.Context, string, ...interface{}) {} |
| 68 | code := m.Run() |
| 69 | os.RemoveAll(dir) |
| 70 | os.Exit(code) |
| 71 | } |
| 72 | |
| 73 | func TestWindowsWebview2GPUDisabled(t *testing.T) { |
| 74 | oldChannel := channel |
| 75 | t.Cleanup(func() { |
| 76 | channel = oldChannel |
| 77 | os.Unsetenv(disableWebview2GPUEnv) |
| 78 | }) |
| 79 | |
| 80 | tests := []struct { |
| 81 | name string |
| 82 | channel string |
| 83 | env string |
| 84 | want bool |
| 85 | }{ |
| 86 | {name: "stable default keeps gpu", channel: "stable", want: false}, |
| 87 | {name: "preview default disables gpu", channel: "preview", want: true}, |
| 88 | {name: "legacy canary default disables gpu", channel: "canary", want: true}, |
| 89 | {name: "env enables fallback", channel: "stable", env: "1", want: true}, |
| 90 | {name: "env disables canary fallback", channel: "canary", env: "0", want: false}, |
| 91 | {name: "truthy env", channel: "stable", env: "yes", want: true}, |
| 92 | {name: "falsey env", channel: "canary", env: "off", want: false}, |
| 93 | } |
| 94 | |
| 95 | for _, tt := range tests { |
| 96 | t.Run(tt.name, func(t *testing.T) { |
| 97 | channel = tt.channel |
| 98 | if tt.env == "" { |
| 99 | os.Unsetenv(disableWebview2GPUEnv) |
| 100 | } else { |
| 101 | os.Setenv(disableWebview2GPUEnv, tt.env) |
| 102 | } |
| 103 | if got := windowsWebview2GPUDisabled(); got != tt.want { |
| 104 | t.Fatalf("windowsWebview2GPUDisabled() = %v, want %v", got, tt.want) |
| 105 | } |
| 106 | }) |
| 107 | } |
| 108 | } |
| 109 | |
| 110 | func TestLinuxWebviewGpuPolicyDisablesGpuWithoutAccessibleRenderNode(t *testing.T) { |
| 111 | glob := filepath.Join(t.TempDir(), "renderD*") |
| 112 | |
| 113 | if got := linuxWebviewGpuPolicy(glob); got != linux.WebviewGpuPolicyNever { |
| 114 | t.Fatalf("linuxWebviewGpuPolicy() = %v, want %v", got, linux.WebviewGpuPolicyNever) |
| 115 | } |
| 116 | } |
| 117 | |
| 118 | func TestLinuxWebviewGpuPolicyDisablesGpuForInaccessibleRenderNode(t *testing.T) { |
| 119 | dir := t.TempDir() |
| 120 | if err := os.Mkdir(filepath.Join(dir, "renderD128"), 0o700); err != nil { |
| 121 | t.Fatal(err) |
| 122 | } |
| 123 | |
| 124 | if got := linuxWebviewGpuPolicy(filepath.Join(dir, "renderD*")); got != linux.WebviewGpuPolicyNever { |
| 125 | t.Fatalf("linuxWebviewGpuPolicy() = %v, want %v", got, linux.WebviewGpuPolicyNever) |
| 126 | } |
| 127 | } |
| 128 | |
| 129 | func TestLinuxWebviewGpuPolicyKeepsOnDemandWithAccessibleRenderNode(t *testing.T) { |
| 130 | dir := t.TempDir() |
| 131 | if err := os.WriteFile(filepath.Join(dir, "renderD128"), nil, 0o600); err != nil { |
| 132 | t.Fatal(err) |
| 133 | } |
| 134 | |
| 135 | if got := linuxWebviewGpuPolicy(filepath.Join(dir, "renderD*")); got != linux.WebviewGpuPolicyOnDemand { |
| 136 | t.Fatalf("linuxWebviewGpuPolicy() = %v, want %v", got, linux.WebviewGpuPolicyOnDemand) |
| 137 | } |
| 138 | } |
| 139 |