Skip to content

Commit a7fe46d

Browse files
committed
Regression test for ICoreWebView2Controller.MoveFocus related crash
See issue #27
1 parent 45d9086 commit a7fe46d

1 file changed

Lines changed: 74 additions & 0 deletions

File tree

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
#pragma warning disable CA1416 // Platform compatibility — guarded by runtime OS check inside each test
2+
3+
using System;
4+
using System.Runtime.InteropServices;
5+
using Avalonia.Controls.Win;
6+
using Avalonia.Controls.Win.WebView2;
7+
using Avalonia.Controls.Win.WebView2.Interop;
8+
using Xunit;
9+
10+
namespace Avalonia.Controls.WebView.Tests;
11+
12+
public class WebView2BaseAdapterTests
13+
{
14+
// Reproduces https://github.com/AvaloniaUI/Avalonia.Controls.WebView/issues/27
15+
// The controller exists but rejects MoveFocus with E_INVALIDARG during a
16+
// window-activation race (WM_ACTIVATE fires before async init completes).
17+
// This tests that the adapter's Focus method doesn't throw in this scenario, which would cause a crash at runtime.
18+
// NOTE: This is a regression test for a specific issue. We test the implementation by faking the behavior
19+
// of the controller, rather than using a real WebView2 instance, to avoid the complexity of reproducing the exact race
20+
// condition in a reliable way.
21+
[Fact]
22+
public void FocusShouldNotThrowWhenControllerThrowsEInvalidArg()
23+
{
24+
if (!OperatingSystem.IsWindows())
25+
{
26+
Assert.Skip("WebView2 adapter is Windows-only");
27+
}
28+
29+
var adapter = new TestableAdapter(new ThrowingFakeController());
30+
31+
adapter.Focus();
32+
}
33+
34+
private sealed class TestableAdapter(ICoreWebView2Controller controller)
35+
: WebView2BaseAdapter(controller)
36+
{
37+
public override IntPtr Handle => IntPtr.Zero;
38+
public override string? HandleDescriptor => null;
39+
}
40+
41+
private sealed class ThrowingFakeController : ICoreWebView2Controller
42+
{
43+
void ICoreWebView2Controller.MoveFocus(COREWEBVIEW2_MOVE_FOCUS_REASON reason)
44+
{
45+
// Marshal.GetExceptionForHR produces the exact ArgumentException with HResult
46+
// E_INVALIDARG that the source-generated COM interop layer throws at runtime.
47+
throw (ArgumentException)Marshal.GetExceptionForHR(unchecked((int)0x80070057))!;
48+
}
49+
50+
void ICoreWebView2Controller.Close() { }
51+
52+
int ICoreWebView2Controller.GetIsVisible() => throw new NotImplementedException();
53+
void ICoreWebView2Controller.SetIsVisible(int value) => throw new NotImplementedException();
54+
tagRECT ICoreWebView2Controller.GetBounds() => throw new NotImplementedException();
55+
void ICoreWebView2Controller.SetBounds(tagRECT value) => throw new NotImplementedException();
56+
double ICoreWebView2Controller.GetZoomFactor() => throw new NotImplementedException();
57+
void ICoreWebView2Controller.SetZoomFactor(double value) => throw new NotImplementedException();
58+
void ICoreWebView2Controller.add_ZoomFactorChanged(IntPtr eventHandler, out EventRegistrationToken token) => throw new NotImplementedException();
59+
void ICoreWebView2Controller.remove_ZoomFactorChanged(EventRegistrationToken token) => throw new NotImplementedException();
60+
void ICoreWebView2Controller.SetBoundsAndZoomFactor(tagRECT bounds, double zoomFactor) => throw new NotImplementedException();
61+
void ICoreWebView2Controller.add_MoveFocusRequested(ICoreWebView2MoveFocusRequestedEventHandler eventHandler, out EventRegistrationToken token) => throw new NotImplementedException();
62+
void ICoreWebView2Controller.remove_MoveFocusRequested(EventRegistrationToken token) => throw new NotImplementedException();
63+
void ICoreWebView2Controller.add_GotFocus(ICoreWebView2FocusChangedEventHandler eventHandler, out EventRegistrationToken token) => throw new NotImplementedException();
64+
void ICoreWebView2Controller.remove_GotFocus(EventRegistrationToken token) => throw new NotImplementedException();
65+
void ICoreWebView2Controller.add_LostFocus(ICoreWebView2FocusChangedEventHandler eventHandler, out EventRegistrationToken token) => throw new NotImplementedException();
66+
void ICoreWebView2Controller.remove_LostFocus(EventRegistrationToken token) => throw new NotImplementedException();
67+
void ICoreWebView2Controller.add_AcceleratorKeyPressed(IntPtr eventHandler, out EventRegistrationToken token) => throw new NotImplementedException();
68+
void ICoreWebView2Controller.remove_AcceleratorKeyPressed(EventRegistrationToken token) => throw new NotImplementedException();
69+
IntPtr ICoreWebView2Controller.GetParentWindow() => throw new NotImplementedException();
70+
void ICoreWebView2Controller.SetParentWindow(IntPtr value) => throw new NotImplementedException();
71+
void ICoreWebView2Controller.NotifyParentWindowPositionChanged() => throw new NotImplementedException();
72+
ICoreWebView2 ICoreWebView2Controller.GetCoreWebView2() => throw new NotImplementedException();
73+
}
74+
}

0 commit comments

Comments
 (0)