| // |
| // 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 <angle_windowsstore.h> |
| |
| 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<WinRtClassicComMix>, |
| IAmInspectable > |
| { |
| }; |
| |
| MIDL_INTERFACE("3CBCFE7A-E000-4094-B2D2-B7C9A4D67A2C") |
| IAmUnknown : public IUnknown |
| { |
| }; |
| |
| class GenericIUnknown : public RuntimeClass < |
| RuntimeClassFlags<ClassicCom>, |
| IAmUnknown > |
| { |
| }; |
| |
| // Mock ICoreWindow |
| class MockCoreWindow : public ABI::Windows::UI::Core::ICoreWindow |
| { |
| public: |
| // IUnknown |
| STDMETHOD(QueryInterface)(REFIID riid, void** ppvObject) |
| { |
| *ppvObject = nullptr; |
| |
| if (IsEqualIID(IID_IUnknown, riid)) |
| { |
| *ppvObject = static_cast<IUnknown*>(this); |
| return S_OK; |
| } |
| |
| if (IsEqualIID(IID_IInspectable, riid)) |
| { |
| *ppvObject = static_cast<IInspectable*>(this); |
| return S_OK; |
| } |
| |
| if (IsEqualIID(IID_ICoreWindow, riid)) |
| { |
| *ppvObject = static_cast<ABI::Windows::UI::Core::ICoreWindow*>(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<HSTRING, IInspectable*>** propertyMap) |
| { |
| HRESULT result = S_OK; |
| ComPtr<IPropertySet> propertySet; |
| ComPtr<IActivationFactory> 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<IPropertyValueStatics> 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<IMap<HSTRING, IInspectable*>>& 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<IAmInspectable> notCoreWindow = Make<GenericIInspectable>(); |
| NativeWindow nativeWindow(notCoreWindow.Get()); |
| EXPECT_FALSE(nativeWindow.initialize()); |
| } |
| |
| TEST(NativeWindowTest, NativeWindowNotInspectable) |
| { |
| ComPtr<IAmUnknown> notIInspectable = Make<GenericIUnknown>(); |
| 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(nullptr, COINIT_MULTITHREADED)); |
| { |
| MockCoreWindow mockCoreWindow; |
| ComPtr<IMap<HSTRING, IInspectable*>> 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(nullptr, COINIT_MULTITHREADED)); |
| { |
| MockCoreWindow mockCoreWindow; |
| ComPtr<IMap<HSTRING, IInspectable*>> 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<std::pair<float, bool>> |
| { |
| }; |
| |
| 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(nullptr, COINIT_MULTITHREADED)); |
| { |
| MockCoreWindow mockCoreWindow; |
| ComPtr<IMap<HSTRING, IInspectable*>> propertySet; |
| ComPtr<IPropertyValueStatics> propertyValueStatics; |
| ComPtr<IPropertyValue> singleValue; |
| |
| // Create a simple property set |
| EXPECT_HRESULT_SUCCEEDED(CreatePropertyMap(&propertySet)); |
| EXPECT_HRESULT_SUCCEEDED(SetInspectablePropertyValue(propertySet, EGLNativeWindowTypeProperty, reinterpret_cast<IInspectable*>(&mockCoreWindow))); |
| |
| // Add a valid scale factor to the property set |
| EXPECT_HRESULT_SUCCEEDED(CreatePropertyValueStatics(propertyValueStatics.GetAddressOf())); |
| propertyValueStatics->CreateSingle(scale, reinterpret_cast<IInspectable**>(singleValue.GetAddressOf())); |
| EXPECT_HRESULT_SUCCEEDED(SetInspectablePropertyValue(propertySet, EGLRenderResolutionScaleProperty, reinterpret_cast<IInspectable*>(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<float, bool> 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<std::tuple<float, float, bool>> |
| { |
| }; |
| |
| 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(nullptr, COINIT_MULTITHREADED)); |
| { |
| MockCoreWindow mockCoreWindow; |
| ComPtr<IMap<HSTRING, IInspectable*>> propertySet; |
| ComPtr<IPropertyValueStatics> propertyValueStatics; |
| ComPtr<IPropertyValue> sizeValue; |
| |
| // Create a simple property set |
| EXPECT_HRESULT_SUCCEEDED(CreatePropertyMap(&propertySet)); |
| EXPECT_HRESULT_SUCCEEDED(SetInspectablePropertyValue(propertySet, EGLNativeWindowTypeProperty, reinterpret_cast<IInspectable*>(&mockCoreWindow))); |
| |
| // Add a valid size to the property set |
| EXPECT_HRESULT_SUCCEEDED(CreatePropertyValueStatics(propertyValueStatics.GetAddressOf())); |
| propertyValueStatics->CreateSize(renderSize, reinterpret_cast<IInspectable**>(sizeValue.GetAddressOf())); |
| EXPECT_HRESULT_SUCCEEDED(SetInspectablePropertyValue(propertySet, EGLRenderSurfaceSizeProperty, reinterpret_cast<IInspectable*>(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<float, float, bool> 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 |