// // Copyright (c) 2014 The ANGLE Project Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // #include "gmock/gmock.h" #include "gtest/gtest.h" // WINAPI_FAMILY is required to be defined as WINAPI_FAMILY_PC_APP // to ensure that the proper defines are set when including additional // headers which rely on Windows Store specific configuration. // This would normally be defined already but this unittest exe is compiled // as a desktop application which results in WINAPI_FAMILY being // set to WINAPI_FAMILY_DESKTOP_APP #undef WINAPI_FAMILY #define WINAPI_FAMILY WINAPI_FAMILY_PC_APP #include "libANGLE/renderer/d3d/d3d11/NativeWindow.h" #include using namespace rx; using namespace ABI::Windows::ApplicationModel::Core; using namespace ABI::Windows::Foundation; using namespace ABI::Windows::Foundation::Collections; using namespace ABI::Windows::UI::Core; using namespace ABI::Windows::System; namespace { // Mock Generic interfaces which are NOT ICoreWindow or // IPropertySet MIDL_INTERFACE("A4D67D0A-0E7F-4DF7-918B-7A1395413AF2") IAmInspectable : public IInspectable { }; class GenericIInspectable : public RuntimeClass < RuntimeClassFlags, IAmInspectable > { }; MIDL_INTERFACE("3CBCFE7A-E000-4094-B2D2-B7C9A4D67A2C") IAmUnknown : public IUnknown { }; class GenericIUnknown : public RuntimeClass < RuntimeClassFlags, IAmUnknown > { }; // Mock ICoreWindow class MockCoreWindow : public ABI::Windows::UI::Core::ICoreWindow { public: // IUnknown STDMETHOD(QueryInterface)(REFIID riid, void** ppvObject) { *ppvObject = NULL; if (IsEqualIID(IID_IUnknown, riid)) { *ppvObject = static_cast(this); return S_OK; } if (IsEqualIID(IID_IInspectable, riid)) { *ppvObject = static_cast(this); return S_OK; } if (IsEqualIID(IID_ICoreWindow, riid)) { *ppvObject = static_cast(this); return S_OK; } return E_NOINTERFACE; } STDMETHOD_(ULONG, AddRef)(){ return 1; } STDMETHOD_(ULONG, Release)(){ return 1; } // IInspectable MOCK_METHOD2_WITH_CALLTYPE(STDMETHODCALLTYPE, GetIids, HRESULT(ULONG *, IID**)); MOCK_METHOD1_WITH_CALLTYPE(STDMETHODCALLTYPE, GetRuntimeClassName, HRESULT(HSTRING *)); MOCK_METHOD1_WITH_CALLTYPE(STDMETHODCALLTYPE, GetTrustLevel, HRESULT(TrustLevel *)); // ICoreWindow MOCK_METHOD1_WITH_CALLTYPE(STDMETHODCALLTYPE, get_AutomationHostProvider, HRESULT(IInspectable **)); MOCK_METHOD1_WITH_CALLTYPE(STDMETHODCALLTYPE, get_Bounds, HRESULT(Rect *)); MOCK_METHOD1_WITH_CALLTYPE(STDMETHODCALLTYPE, get_CustomProperties, HRESULT(IPropertySet **)); MOCK_METHOD1_WITH_CALLTYPE(STDMETHODCALLTYPE, get_Dispatcher, HRESULT(ICoreDispatcher **)); MOCK_METHOD1_WITH_CALLTYPE(STDMETHODCALLTYPE, get_FlowDirection, HRESULT(CoreWindowFlowDirection *)); MOCK_METHOD1_WITH_CALLTYPE(STDMETHODCALLTYPE, put_FlowDirection, HRESULT(CoreWindowFlowDirection)); MOCK_METHOD1_WITH_CALLTYPE(STDMETHODCALLTYPE, get_IsInputEnabled, HRESULT(boolean *)); MOCK_METHOD1_WITH_CALLTYPE(STDMETHODCALLTYPE, put_IsInputEnabled, HRESULT(boolean)); MOCK_METHOD1_WITH_CALLTYPE(STDMETHODCALLTYPE, get_PointerCursor, HRESULT(ICoreCursor**)); MOCK_METHOD1_WITH_CALLTYPE(STDMETHODCALLTYPE, put_PointerCursor, HRESULT(ICoreCursor*)); MOCK_METHOD1_WITH_CALLTYPE(STDMETHODCALLTYPE, get_PointerPosition, HRESULT(Point*)); MOCK_METHOD1_WITH_CALLTYPE(STDMETHODCALLTYPE, get_Visible, HRESULT(boolean *)); MOCK_METHOD0_WITH_CALLTYPE(STDMETHODCALLTYPE, Activate, HRESULT()); MOCK_METHOD0_WITH_CALLTYPE(STDMETHODCALLTYPE, Close , HRESULT()); MOCK_METHOD2_WITH_CALLTYPE(STDMETHODCALLTYPE, GetAsyncKeyState, HRESULT(ABI::Windows::System::VirtualKey, ABI::Windows::UI::Core::CoreVirtualKeyStates*)); MOCK_METHOD2_WITH_CALLTYPE(STDMETHODCALLTYPE, GetKeyState, HRESULT(ABI::Windows::System::VirtualKey, ABI::Windows::UI::Core::CoreVirtualKeyStates*)); MOCK_METHOD0_WITH_CALLTYPE(STDMETHODCALLTYPE, ReleasePointerCapture, HRESULT()); MOCK_METHOD0_WITH_CALLTYPE(STDMETHODCALLTYPE, SetPointerCapture, HRESULT()); MOCK_METHOD2_WITH_CALLTYPE(STDMETHODCALLTYPE, add_Activated, HRESULT(__FITypedEventHandler_2_Windows__CUI__CCore__CCoreWindow_Windows__CUI__CCore__CWindowActivatedEventArgs*, EventRegistrationToken *)); MOCK_METHOD1_WITH_CALLTYPE(STDMETHODCALLTYPE, remove_Activated, HRESULT(EventRegistrationToken)); MOCK_METHOD2_WITH_CALLTYPE(STDMETHODCALLTYPE, add_AutomationProviderRequested, HRESULT(__FITypedEventHandler_2_Windows__CUI__CCore__CCoreWindow_Windows__CUI__CCore__CAutomationProviderRequestedEventArgs*, EventRegistrationToken *)); MOCK_METHOD1_WITH_CALLTYPE(STDMETHODCALLTYPE, remove_AutomationProviderRequested, HRESULT(EventRegistrationToken)); MOCK_METHOD2_WITH_CALLTYPE(STDMETHODCALLTYPE, add_CharacterReceived, HRESULT(__FITypedEventHandler_2_Windows__CUI__CCore__CCoreWindow_Windows__CUI__CCore__CCharacterReceivedEventArgs*, EventRegistrationToken *)); MOCK_METHOD1_WITH_CALLTYPE(STDMETHODCALLTYPE, remove_CharacterReceived, HRESULT(EventRegistrationToken)); MOCK_METHOD2_WITH_CALLTYPE(STDMETHODCALLTYPE, add_Closed, HRESULT(__FITypedEventHandler_2_Windows__CUI__CCore__CCoreWindow_Windows__CUI__CCore__CCoreWindowEventArgs*, EventRegistrationToken *)); MOCK_METHOD1_WITH_CALLTYPE(STDMETHODCALLTYPE, remove_Closed, HRESULT(EventRegistrationToken)); MOCK_METHOD2_WITH_CALLTYPE(STDMETHODCALLTYPE, add_InputEnabled, HRESULT(__FITypedEventHandler_2_Windows__CUI__CCore__CCoreWindow_Windows__CUI__CCore__CInputEnabledEventArgs*, EventRegistrationToken *)); MOCK_METHOD1_WITH_CALLTYPE(STDMETHODCALLTYPE, remove_InputEnabled, HRESULT(EventRegistrationToken)); MOCK_METHOD2_WITH_CALLTYPE(STDMETHODCALLTYPE, add_KeyDown, HRESULT(__FITypedEventHandler_2_Windows__CUI__CCore__CCoreWindow_Windows__CUI__CCore__CKeyEventArgs*, EventRegistrationToken *)); MOCK_METHOD1_WITH_CALLTYPE(STDMETHODCALLTYPE, remove_KeyDown, HRESULT(EventRegistrationToken)); MOCK_METHOD2_WITH_CALLTYPE(STDMETHODCALLTYPE, add_KeyUp, HRESULT(__FITypedEventHandler_2_Windows__CUI__CCore__CCoreWindow_Windows__CUI__CCore__CKeyEventArgs*, EventRegistrationToken *)); MOCK_METHOD1_WITH_CALLTYPE(STDMETHODCALLTYPE, remove_KeyUp, HRESULT(EventRegistrationToken)); MOCK_METHOD2_WITH_CALLTYPE(STDMETHODCALLTYPE, add_PointerCaptureLost, HRESULT(__FITypedEventHandler_2_Windows__CUI__CCore__CCoreWindow_Windows__CUI__CCore__CPointerEventArgs*, EventRegistrationToken *)); MOCK_METHOD1_WITH_CALLTYPE(STDMETHODCALLTYPE, remove_PointerCaptureLost, HRESULT(EventRegistrationToken)); MOCK_METHOD2_WITH_CALLTYPE(STDMETHODCALLTYPE, add_PointerEntered, HRESULT(__FITypedEventHandler_2_Windows__CUI__CCore__CCoreWindow_Windows__CUI__CCore__CPointerEventArgs*, EventRegistrationToken *)); MOCK_METHOD1_WITH_CALLTYPE(STDMETHODCALLTYPE, remove_PointerEntered, HRESULT(EventRegistrationToken)); MOCK_METHOD2_WITH_CALLTYPE(STDMETHODCALLTYPE, add_PointerExited, HRESULT(__FITypedEventHandler_2_Windows__CUI__CCore__CCoreWindow_Windows__CUI__CCore__CPointerEventArgs*, EventRegistrationToken *)); MOCK_METHOD1_WITH_CALLTYPE(STDMETHODCALLTYPE, remove_PointerExited, HRESULT(EventRegistrationToken)); MOCK_METHOD2_WITH_CALLTYPE(STDMETHODCALLTYPE, add_PointerMoved, HRESULT(__FITypedEventHandler_2_Windows__CUI__CCore__CCoreWindow_Windows__CUI__CCore__CPointerEventArgs*, EventRegistrationToken *)); MOCK_METHOD1_WITH_CALLTYPE(STDMETHODCALLTYPE, remove_PointerMoved, HRESULT(EventRegistrationToken)); MOCK_METHOD2_WITH_CALLTYPE(STDMETHODCALLTYPE, add_PointerPressed, HRESULT(__FITypedEventHandler_2_Windows__CUI__CCore__CCoreWindow_Windows__CUI__CCore__CPointerEventArgs*, EventRegistrationToken *)); MOCK_METHOD1_WITH_CALLTYPE(STDMETHODCALLTYPE, remove_PointerPressed, HRESULT(EventRegistrationToken)); MOCK_METHOD2_WITH_CALLTYPE(STDMETHODCALLTYPE, add_PointerReleased, HRESULT(__FITypedEventHandler_2_Windows__CUI__CCore__CCoreWindow_Windows__CUI__CCore__CPointerEventArgs*, EventRegistrationToken *)); MOCK_METHOD1_WITH_CALLTYPE(STDMETHODCALLTYPE, remove_PointerReleased, HRESULT(EventRegistrationToken)); MOCK_METHOD2_WITH_CALLTYPE(STDMETHODCALLTYPE, add_TouchHitTesting, HRESULT(__FITypedEventHandler_2_Windows__CUI__CCore__CCoreWindow_Windows__CUI__CCore__CTouchHitTestingEventArgs*, EventRegistrationToken *)); MOCK_METHOD1_WITH_CALLTYPE(STDMETHODCALLTYPE, remove_TouchHitTesting, HRESULT(EventRegistrationToken)); MOCK_METHOD2_WITH_CALLTYPE(STDMETHODCALLTYPE, add_PointerWheelChanged, HRESULT(__FITypedEventHandler_2_Windows__CUI__CCore__CCoreWindow_Windows__CUI__CCore__CPointerEventArgs*, EventRegistrationToken *)); MOCK_METHOD1_WITH_CALLTYPE(STDMETHODCALLTYPE, remove_PointerWheelChanged, HRESULT(EventRegistrationToken)); MOCK_METHOD2_WITH_CALLTYPE(STDMETHODCALLTYPE, add_SizeChanged, HRESULT(__FITypedEventHandler_2_Windows__CUI__CCore__CCoreWindow_Windows__CUI__CCore__CWindowSizeChangedEventArgs*, EventRegistrationToken *)); MOCK_METHOD1_WITH_CALLTYPE(STDMETHODCALLTYPE, remove_SizeChanged, HRESULT(EventRegistrationToken)); MOCK_METHOD2_WITH_CALLTYPE(STDMETHODCALLTYPE, add_VisibilityChanged, HRESULT(__FITypedEventHandler_2_Windows__CUI__CCore__CCoreWindow_Windows__CUI__CCore__CVisibilityChangedEventArgs*, EventRegistrationToken *)); MOCK_METHOD1_WITH_CALLTYPE(STDMETHODCALLTYPE, remove_VisibilityChanged, HRESULT(EventRegistrationToken)); }; HRESULT CreatePropertyMap(IMap** propertyMap) { HRESULT result = S_OK; ComPtr propertySet; ComPtr propertySetFactory; result = GetActivationFactory(HStringReference(RuntimeClass_Windows_Foundation_Collections_PropertySet).Get(), &propertySetFactory); EXPECT_HRESULT_SUCCEEDED(result); result = propertySetFactory->ActivateInstance(&propertySet); EXPECT_HRESULT_SUCCEEDED(result); result = propertySet.CopyTo(propertyMap); EXPECT_HRESULT_SUCCEEDED(result); return result; } HRESULT CreatePropertyValueStatics(IPropertyValueStatics** propertyStatics) { ComPtr propertyValueStatics; HRESULT result = GetActivationFactory(HStringReference(RuntimeClass_Windows_Foundation_PropertyValue).Get(), &propertyValueStatics); EXPECT_HRESULT_SUCCEEDED(result); result = propertyValueStatics.CopyTo(propertyStatics); EXPECT_HRESULT_SUCCEEDED(result); return result; } HRESULT SetInspectablePropertyValue(const ComPtr>& propertyMap, const wchar_t* propertyName, IInspectable* inspectable) { boolean propertyReplaced = false; return propertyMap->Insert(HStringReference(propertyName).Get(), inspectable, &propertyReplaced); } void expectNativeWindowInitCalls(MockCoreWindow &coreWindow, bool expectBounds) { if (expectBounds) { EXPECT_CALL(coreWindow, get_Bounds(testing::_)).Times(1); } EXPECT_CALL(coreWindow, add_SizeChanged(testing::_, testing::_)).Times(1); EXPECT_CALL(coreWindow, remove_SizeChanged(testing::_)).Times(1); } TEST(NativeWindowTest, NativeWindowNull) { NativeWindow nativeWindow(nullptr); EXPECT_FALSE(nativeWindow.initialize()); } TEST(NativeWindowTest, NativeWindowBadInspectable) { ComPtr notCoreWindow = Make(); NativeWindow nativeWindow(notCoreWindow.Get()); EXPECT_FALSE(nativeWindow.initialize()); } TEST(NativeWindowTest, NativeWindowNotInspectable) { ComPtr notIInspectable = Make(); NativeWindow nativeWindow((IInspectable*)notIInspectable.Get()); EXPECT_FALSE(nativeWindow.initialize()); } TEST(NativeWindowTest, NativeWindowValidCoreWindow) { MockCoreWindow mockCoreWindow; expectNativeWindowInitCalls(mockCoreWindow, true); NativeWindow nativeWindow(&mockCoreWindow); EXPECT_TRUE(nativeWindow.initialize()); } TEST(NativeWindowTest, NativeWindowValidCoreWindowInPropertySet) { // COM is required to be initialized for creation of the property set EXPECT_HRESULT_SUCCEEDED(CoInitializeEx(NULL, COINIT_MULTITHREADED)); { MockCoreWindow mockCoreWindow; ComPtr> propertySet; // Add the CoreWindow to the property set EXPECT_HRESULT_SUCCEEDED(CreatePropertyMap(&propertySet)); EXPECT_HRESULT_SUCCEEDED(SetInspectablePropertyValue(propertySet, EGLNativeWindowTypeProperty, &mockCoreWindow)); expectNativeWindowInitCalls(mockCoreWindow, true); NativeWindow nativeWindow(propertySet.Get()); EXPECT_TRUE(nativeWindow.initialize()); } CoUninitialize(); } TEST(NativeWindowTest, NativeWindowMissingCoreWindowInPropertySet) { // COM is required to be initialized for creation of the property set EXPECT_HRESULT_SUCCEEDED(CoInitializeEx(NULL, COINIT_MULTITHREADED)); { MockCoreWindow mockCoreWindow; ComPtr> propertySet; EXPECT_HRESULT_SUCCEEDED(CreatePropertyMap(&propertySet)); NativeWindow nativeWindow(propertySet.Get()); EXPECT_FALSE(nativeWindow.initialize()); } CoUninitialize(); } // Tests that the scale property works as expected in a property set with a SwapChainPanel class CoreWindowScaleTest : public testing::TestWithParam> { }; TEST_P(CoreWindowScaleTest, ValidateScale) { float scale = GetParam().first; bool expectedResult = GetParam().second; // COM is required to be initialized for creation of the property set EXPECT_HRESULT_SUCCEEDED(CoInitializeEx(NULL, COINIT_MULTITHREADED)); { MockCoreWindow mockCoreWindow; ComPtr> propertySet; ComPtr propertyValueStatics; ComPtr singleValue; // Create a simple property set EXPECT_HRESULT_SUCCEEDED(CreatePropertyMap(&propertySet)); EXPECT_HRESULT_SUCCEEDED(SetInspectablePropertyValue(propertySet, EGLNativeWindowTypeProperty, reinterpret_cast(&mockCoreWindow))); // Add a valid scale factor to the property set EXPECT_HRESULT_SUCCEEDED(CreatePropertyValueStatics(propertyValueStatics.GetAddressOf())); propertyValueStatics->CreateSingle(scale, reinterpret_cast(singleValue.GetAddressOf())); EXPECT_HRESULT_SUCCEEDED(SetInspectablePropertyValue(propertySet, EGLRenderResolutionScaleProperty, reinterpret_cast(singleValue.Get()))); // Check native window init status and calls to the mock swapchainpanel NativeWindow nativeWindow(propertySet.Get()); if (expectedResult) { expectNativeWindowInitCalls(mockCoreWindow, true); } EXPECT_EQ(nativeWindow.initialize(), expectedResult); } CoUninitialize(); } typedef std::pair scaleValidPair; static const scaleValidPair scales[] = { scaleValidPair(1.0f, true), scaleValidPair(0.5f, true), scaleValidPair(0.0f, false), scaleValidPair(0.01f, true), scaleValidPair(2.00f, true) }; INSTANTIATE_TEST_CASE_P(NativeWindowTest, CoreWindowScaleTest, testing::ValuesIn(scales)); // Tests that the size property works as expected in a property set with a SwapChainPanel class CoreWindowSizeTest : public testing::TestWithParam> { }; TEST_P(CoreWindowSizeTest, ValidateSize) { Size renderSize = { std::get<0>(GetParam()), std::get<1>(GetParam()) }; bool expectedResult = std::get<2>(GetParam()); // COM is required to be initialized for creation of the property set EXPECT_HRESULT_SUCCEEDED(CoInitializeEx(NULL, COINIT_MULTITHREADED)); { MockCoreWindow mockCoreWindow; ComPtr> propertySet; ComPtr propertyValueStatics; ComPtr sizeValue; // Create a simple property set EXPECT_HRESULT_SUCCEEDED(CreatePropertyMap(&propertySet)); EXPECT_HRESULT_SUCCEEDED(SetInspectablePropertyValue(propertySet, EGLNativeWindowTypeProperty, reinterpret_cast(&mockCoreWindow))); // Add a valid size to the property set EXPECT_HRESULT_SUCCEEDED(CreatePropertyValueStatics(propertyValueStatics.GetAddressOf())); propertyValueStatics->CreateSize(renderSize, reinterpret_cast(sizeValue.GetAddressOf())); EXPECT_HRESULT_SUCCEEDED(SetInspectablePropertyValue(propertySet, EGLRenderSurfaceSizeProperty, reinterpret_cast(sizeValue.Get()))); // Check native window init status and calls to the mock swapchainpanel NativeWindow nativeWindow(propertySet.Get()); if (expectedResult) { expectNativeWindowInitCalls(mockCoreWindow, false); } EXPECT_EQ(nativeWindow.initialize(), expectedResult); } CoUninitialize(); } typedef std::tuple sizeValidPair; static const sizeValidPair sizes[] = { sizeValidPair( 800, 480, true), sizeValidPair( 0, 480, false), sizeValidPair( 800, 0, false), sizeValidPair( 0, 0, false) }; INSTANTIATE_TEST_CASE_P(NativeWindowTest, CoreWindowSizeTest, testing::ValuesIn(sizes)); } // namespace