| 1 | package main |
| 2 | |
| 3 | import ( |
| 4 | "go/ast" |
| 5 | "go/parser" |
| 6 | "go/token" |
| 7 | "os" |
| 8 | "path/filepath" |
| 9 | "strconv" |
| 10 | "testing" |
| 11 | |
| 12 | "golang.org/x/mod/modfile" |
| 13 | ) |
| 14 | |
| 15 | const ( |
| 16 | webview2ModulePath = "github.com/wailsapp/go-webview2" |
| 17 | webview2PatchPath = "./third_party/go-webview2" |
| 18 | ) |
| 19 | |
| 20 | func TestWebView2PatchWiring(t *testing.T) { |
| 21 | modData, err := os.ReadFile("go.mod") |
| 22 | if err != nil { |
| 23 | t.Fatal(err) |
| 24 | } |
| 25 | mod, err := modfile.Parse("go.mod", modData, nil) |
| 26 | if err != nil { |
| 27 | t.Fatal(err) |
| 28 | } |
| 29 | replaced := false |
| 30 | for _, directive := range mod.Replace { |
| 31 | if directive.Old.Path == webview2ModulePath && directive.New.Path == webview2PatchPath { |
| 32 | replaced = true |
| 33 | break |
| 34 | } |
| 35 | } |
| 36 | if !replaced { |
| 37 | t.Fatalf("%s must be replaced by %s", webview2ModulePath, webview2PatchPath) |
| 38 | } |
| 39 | |
| 40 | patchFile := filepath.Join("third_party", "go-webview2", "pkg", "edge", "chromium.go") |
| 41 | parsed, err := parser.ParseFile(token.NewFileSet(), patchFile, nil, 0) |
| 42 | if err != nil { |
| 43 | t.Fatal(err) |
| 44 | } |
| 45 | |
| 46 | policyEnabled := false |
| 47 | policyApplied := false |
| 48 | proxyIsolationArgDefined := false |
| 49 | proxyIsolationArgApplied := false |
| 50 | ast.Inspect(parsed, func(node ast.Node) bool { |
| 51 | switch value := node.(type) { |
| 52 | case *ast.ValueSpec: |
| 53 | if len(value.Names) == 1 && value.Names[0].Name == "shouldDetectMonitorScaleChanges" && len(value.Values) == 1 { |
| 54 | ident, ok := value.Values[0].(*ast.Ident) |
| 55 | policyEnabled = ok && ident.Name == "true" |
| 56 | } |
| 57 | if len(value.Names) == 1 && value.Names[0].Name == "reasonixNoProxyServerBrowserArg" && len(value.Values) == 1 { |
| 58 | literal, ok := value.Values[0].(*ast.BasicLit) |
| 59 | if ok { |
| 60 | unquoted, err := strconv.Unquote(literal.Value) |
| 61 | proxyIsolationArgDefined = err == nil && unquoted == "--no-proxy-server" |
| 62 | } |
| 63 | } |
| 64 | case *ast.CallExpr: |
| 65 | selector, ok := value.Fun.(*ast.SelectorExpr) |
| 66 | if !ok || selector.Sel.Name != "PutShouldDetectMonitorScaleChanges" || len(value.Args) != 1 { |
| 67 | break |
| 68 | } |
| 69 | ident, ok := value.Args[0].(*ast.Ident) |
| 70 | policyApplied = ok && ident.Name == "shouldDetectMonitorScaleChanges" |
| 71 | case *ast.CompositeLit: |
| 72 | ident, ok := value.Type.(*ast.Ident) |
| 73 | if !ok || ident.Name != "Chromium" { |
| 74 | break |
| 75 | } |
| 76 | for _, element := range value.Elts { |
| 77 | entry, ok := element.(*ast.KeyValueExpr) |
| 78 | if !ok { |
| 79 | continue |
| 80 | } |
| 81 | key, ok := entry.Key.(*ast.Ident) |
| 82 | if !ok || key.Name != "AdditionalBrowserArgs" { |
| 83 | continue |
| 84 | } |
| 85 | args, ok := entry.Value.(*ast.CompositeLit) |
| 86 | if !ok || len(args.Elts) != 1 { |
| 87 | continue |
| 88 | } |
| 89 | arg, ok := args.Elts[0].(*ast.Ident) |
| 90 | proxyIsolationArgApplied = ok && arg.Name == "reasonixNoProxyServerBrowserArg" |
| 91 | } |
| 92 | } |
| 93 | return true |
| 94 | }) |
| 95 | if !policyEnabled || !policyApplied { |
| 96 | t.Fatal("patched WebView2 must enable and apply automatic monitor-scale detection") |
| 97 | } |
| 98 | if !proxyIsolationArgDefined || !proxyIsolationArgApplied { |
| 99 | t.Fatal("patched WebView2 must pass --no-proxy-server to the browser process") |
| 100 | } |
| 101 | } |
| 102 |