mirror of
https://github.com/Syngnat/GoNavi.git
synced 2026-06-08 07:29:44 +08:00
- 新增 ResetWebViewZoom RPC:从 ctx 反射拿 Wails 内部 *edge.Chromium,调 PutZoomFactor(1.0) 强制 WebView2 重算 D2D/DirectWrite 字体度量,完全不动窗口零动画
- 自动路径:maximised + restore + drift 时直接调 backend reset,告别 9848b8b2 之后字体偶发变大的取舍
- 手动路径:保留 Ctrl+Shift+0 快捷键作为兜底(优先 WebView2 reset,失败回退 toggle)
- 撤回上一版 CSS zoom nudge:实测在 WebView2 上不能修字体度量(度量缓存在 D2D 层不在 Chromium layout 层)
- 反射做了 3 层签名校验(frontend value / chromium 字段 / PutZoomFactor 方法签名),wails 升级破坏接口时返回 error 不让进程崩溃
- 新增 windows-only 反射逻辑测试 4 个、跨平台 RPC 行为测试 2 个、Ctrl+Shift+0 快捷键注册测试
88 lines
2.9 KiB
Go
88 lines
2.9 KiB
Go
//go:build windows
|
||
|
||
package app
|
||
|
||
import (
|
||
"context"
|
||
"strings"
|
||
"sync/atomic"
|
||
"testing"
|
||
)
|
||
|
||
// fakeChromium 模仿 *edge.Chromium 的接口:只需要 exported 的 PutZoomFactor(float64) 方法。
|
||
// 用于在不依赖真实 wails / WebView2 的情况下验证反射路径。
|
||
type fakeChromium struct {
|
||
called atomic.Int32
|
||
last atomic.Value // float64
|
||
}
|
||
|
||
func (f *fakeChromium) PutZoomFactor(factor float64) {
|
||
f.called.Add(1)
|
||
f.last.Store(factor)
|
||
}
|
||
|
||
// fakeFrontend 模仿 wails 的 internal/frontend/desktop/windows.Frontend:
|
||
// unexported 字段 chromium 是 *fakeChromium 类型(exported method PutZoomFactor)。
|
||
// 反射代码不依赖具体类型名,只检查 method signature。
|
||
type fakeFrontend struct {
|
||
chromium *fakeChromium
|
||
}
|
||
|
||
// 测试必须用 wails 一致的 string key "frontend" 作为 context.WithValue 的 key,
|
||
// 否则反射拿不到。go vet 会警告 string key,用本地 stringContextKey 帮助函数封装来抑制。
|
||
// 这层封装等价于直接传字符串字面量,行为完全一致。
|
||
func stringContextKey(key string) any {
|
||
type contextKeyAlias = string
|
||
return contextKeyAlias(key)
|
||
}
|
||
|
||
func TestResetWebViewZoomFactorCallsPutZoomFactor(t *testing.T) {
|
||
chromium := &fakeChromium{}
|
||
ctx := context.WithValue(context.Background(), stringContextKey("frontend"), &fakeFrontend{chromium: chromium})
|
||
|
||
if err := resetWebViewZoomFactor(ctx, 1.0); err != nil {
|
||
t.Fatalf("expected reset to succeed against fake frontend, got %v", err)
|
||
}
|
||
if got := chromium.called.Load(); got != 1 {
|
||
t.Fatalf("expected PutZoomFactor called exactly once, got %d", got)
|
||
}
|
||
if got, _ := chromium.last.Load().(float64); got != 1.0 {
|
||
t.Fatalf("expected factor 1.0, got %v", got)
|
||
}
|
||
}
|
||
|
||
func TestResetWebViewZoomFactorErrorsWhenChromiumFieldMissing(t *testing.T) {
|
||
type fakeFrontendWithoutChromium struct {
|
||
other string
|
||
}
|
||
ctx := context.WithValue(context.Background(), stringContextKey("frontend"), &fakeFrontendWithoutChromium{})
|
||
err := resetWebViewZoomFactor(ctx, 1.0)
|
||
if err == nil {
|
||
t.Fatal("expected error when chromium field is missing, got nil")
|
||
}
|
||
if !strings.Contains(err.Error(), "chromium") {
|
||
t.Fatalf("expected error to mention chromium, got %v", err)
|
||
}
|
||
}
|
||
|
||
func TestResetWebViewZoomFactorErrorsWhenChromiumNil(t *testing.T) {
|
||
ctx := context.WithValue(context.Background(), stringContextKey("frontend"), &fakeFrontend{chromium: nil})
|
||
err := resetWebViewZoomFactor(ctx, 1.0)
|
||
if err == nil {
|
||
t.Fatal("expected error when chromium is nil, got nil")
|
||
}
|
||
if !strings.Contains(err.Error(), "nil") {
|
||
t.Fatalf("expected error to mention nil, got %v", err)
|
||
}
|
||
}
|
||
|
||
func TestResetWebViewZoomFactorErrorsWhenFrontendMissing(t *testing.T) {
|
||
err := resetWebViewZoomFactor(context.Background(), 1.0)
|
||
if err == nil {
|
||
t.Fatal("expected error when frontend not in ctx, got nil")
|
||
}
|
||
if !strings.Contains(err.Error(), "frontend") {
|
||
t.Fatalf("expected error to mention frontend, got %v", err)
|
||
}
|
||
}
|