| // Copyright (c) 2012 The Chromium 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 <Objbase.h> |
| |
| #include <algorithm> |
| #include <cmath> |
| |
| #include "base/compiler_specific.h" |
| #include "base/logging.h" |
| #include "base/memory/scoped_ptr.h" |
| #include "base/message_loop/message_loop.h" |
| #include "base/time/time.h" |
| #include "content/browser/geolocation/win7_location_api_win.h" |
| #include "content/public/common/geoposition.h" |
| #include "testing/gmock/include/gmock/gmock.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| |
| using testing::_; |
| using testing::AtLeast; |
| using testing::DoDefault; |
| using testing::Invoke; |
| using testing::NiceMock; |
| using testing::Return; |
| |
| namespace content { |
| |
| class MockLatLongReport : public ILatLongReport { |
| public: |
| MockLatLongReport() : ref_count_(1) { |
| ON_CALL(*this, GetAltitude(_)) |
| .WillByDefault(Invoke(this, &MockLatLongReport::GetAltitudeValid)); |
| ON_CALL(*this, GetAltitudeError(_)) |
| .WillByDefault(Invoke(this, |
| &MockLatLongReport::GetAltitudeErrorValid)); |
| ON_CALL(*this, GetErrorRadius(_)) |
| .WillByDefault(Invoke(this, &MockLatLongReport::GetErrorRadiusValid)); |
| ON_CALL(*this, GetLatitude(_)) |
| .WillByDefault(Invoke(this, &MockLatLongReport::GetLatitudeValid)); |
| ON_CALL(*this, GetLongitude(_)) |
| .WillByDefault(Invoke(this, &MockLatLongReport::GetLongitudeValid)); |
| ON_CALL(*this, GetValue(_, _)) |
| .WillByDefault(Invoke(this, &MockLatLongReport::GetValueValid)); |
| ON_CALL(*this, Release()) |
| .WillByDefault(Invoke(this, &MockLatLongReport::ReleaseInternal)); |
| ON_CALL(*this, AddRef()) |
| .WillByDefault(Invoke(this, &MockLatLongReport::AddRefInternal)); |
| } |
| |
| // ILatLongReport |
| MOCK_METHOD1_WITH_CALLTYPE(STDMETHODCALLTYPE, |
| GetAltitude, |
| HRESULT(DOUBLE*)); |
| MOCK_METHOD1_WITH_CALLTYPE(STDMETHODCALLTYPE, |
| GetAltitudeError, |
| HRESULT(DOUBLE*)); |
| MOCK_METHOD1_WITH_CALLTYPE(STDMETHODCALLTYPE, |
| GetErrorRadius, |
| HRESULT(DOUBLE*)); |
| MOCK_METHOD1_WITH_CALLTYPE(STDMETHODCALLTYPE, |
| GetLatitude, |
| HRESULT(DOUBLE*)); |
| MOCK_METHOD1_WITH_CALLTYPE(STDMETHODCALLTYPE, |
| GetLongitude, |
| HRESULT(DOUBLE*)); |
| // ILocationReport |
| MOCK_METHOD1_WITH_CALLTYPE(STDMETHODCALLTYPE, |
| GetSensorID, |
| HRESULT(SENSOR_ID*)); |
| MOCK_METHOD1_WITH_CALLTYPE(STDMETHODCALLTYPE, |
| GetTimestamp, |
| HRESULT(SYSTEMTIME*)); |
| MOCK_METHOD2_WITH_CALLTYPE(STDMETHODCALLTYPE, |
| GetValue, |
| HRESULT(REFPROPERTYKEY, PROPVARIANT*)); |
| // IUnknown |
| MOCK_METHOD2_WITH_CALLTYPE(STDMETHODCALLTYPE, |
| QueryInterface, |
| HRESULT(REFIID, void**)); |
| MOCK_METHOD0_WITH_CALLTYPE(STDMETHODCALLTYPE, |
| AddRef, |
| ULONG()); |
| MOCK_METHOD0_WITH_CALLTYPE(STDMETHODCALLTYPE, |
| Release, |
| ULONG()); |
| |
| HRESULT GetAltitudeValid(DOUBLE* altitude) { |
| *altitude = 20.5; |
| return S_OK; |
| } |
| HRESULT GetAltitudeErrorValid(DOUBLE* altitude_error) { |
| *altitude_error = 10.0; |
| return S_OK; |
| } |
| HRESULT GetErrorRadiusValid(DOUBLE* error) { |
| *error = 5.0; |
| return S_OK; |
| } |
| HRESULT GetLatitudeValid(DOUBLE* latitude) { |
| *latitude = 51.0; |
| return S_OK; |
| } |
| HRESULT GetLongitudeValid(DOUBLE* longitude) { |
| *longitude = -0.1; |
| return S_OK; |
| } |
| HRESULT GetValueValid(REFPROPERTYKEY prop_key, PROPVARIANT* prop) { |
| prop->dblVal = 10.0; |
| return S_OK; |
| } |
| |
| private: |
| ~MockLatLongReport() {} |
| |
| ULONG AddRefInternal() { |
| return InterlockedIncrement(&ref_count_); |
| } |
| ULONG ReleaseInternal() { |
| LONG new_ref_count = InterlockedDecrement(&ref_count_); |
| if (0 == new_ref_count) |
| delete this; |
| return new_ref_count; |
| } |
| |
| LONG ref_count_; |
| }; |
| |
| class MockReport : public ILocationReport { |
| public: |
| MockReport() : ref_count_(1) { |
| mock_lat_long_report_ = |
| new MockLatLongReport(); |
| ON_CALL(*this, QueryInterface(_, _)) |
| .WillByDefault(Invoke(this, &MockReport::QueryInterfaceValid)); |
| ON_CALL(*this, Release()) |
| .WillByDefault(Invoke(this, &MockReport::ReleaseInternal)); |
| ON_CALL(*this, AddRef()) |
| .WillByDefault(Invoke(this, &MockReport::AddRefInternal)); |
| } |
| |
| // ILocationReport |
| MOCK_METHOD1_WITH_CALLTYPE(STDMETHODCALLTYPE, |
| GetSensorID, |
| HRESULT(SENSOR_ID*)); |
| MOCK_METHOD1_WITH_CALLTYPE(STDMETHODCALLTYPE, |
| GetTimestamp, |
| HRESULT(SYSTEMTIME*)); |
| MOCK_METHOD2_WITH_CALLTYPE(STDMETHODCALLTYPE, |
| GetValue, |
| HRESULT(REFPROPERTYKEY, PROPVARIANT*)); |
| // IUnknown |
| MOCK_METHOD2_WITH_CALLTYPE(STDMETHODCALLTYPE, |
| QueryInterface, |
| HRESULT(REFIID, void**)); |
| MOCK_METHOD0_WITH_CALLTYPE(STDMETHODCALLTYPE, |
| AddRef, |
| ULONG()); |
| MOCK_METHOD0_WITH_CALLTYPE(STDMETHODCALLTYPE, |
| Release, |
| ULONG()); |
| |
| MockLatLongReport* mock_lat_long_report_; |
| |
| private: |
| ~MockReport() { |
| mock_lat_long_report_->Release(); |
| } |
| |
| ULONG AddRefInternal() { |
| return InterlockedIncrement(&ref_count_); |
| } |
| ULONG ReleaseInternal() { |
| LONG new_ref_count = InterlockedDecrement(&ref_count_); |
| if (0 == new_ref_count) |
| delete this; |
| return new_ref_count; |
| } |
| HRESULT QueryInterfaceValid(REFIID id, void** report) { |
| EXPECT_TRUE(id == IID_ILatLongReport); |
| *report = reinterpret_cast<ILatLongReport*>(mock_lat_long_report_); |
| mock_lat_long_report_->AddRef(); |
| return S_OK; |
| } |
| |
| LONG ref_count_; |
| }; |
| |
| class MockLocation : public ILocation { |
| public: |
| MockLocation() : ref_count_(1) { |
| mock_report_ = new MockReport(); |
| ON_CALL(*this, SetDesiredAccuracy(_, _)) |
| .WillByDefault(Return(S_OK)); |
| ON_CALL(*this, GetReport(_, _)) |
| .WillByDefault(Invoke(this, &MockLocation::GetReportValid)); |
| ON_CALL(*this, RequestPermissions(_, _, _, _)) |
| .WillByDefault(Return(S_OK)); |
| ON_CALL(*this, AddRef()) |
| .WillByDefault(Invoke(this, &MockLocation::AddRefInternal)); |
| ON_CALL(*this, Release()) |
| .WillByDefault(Invoke(this, &MockLocation::ReleaseInternal)); |
| } |
| |
| // ILocation |
| MOCK_METHOD2_WITH_CALLTYPE(STDMETHODCALLTYPE, |
| GetDesiredAccuracy, |
| HRESULT(REFIID, LOCATION_DESIRED_ACCURACY*)); |
| MOCK_METHOD2_WITH_CALLTYPE(STDMETHODCALLTYPE, |
| GetReport, |
| HRESULT(REFIID, ILocationReport**)); |
| MOCK_METHOD2_WITH_CALLTYPE(STDMETHODCALLTYPE, |
| GetReportInterval, |
| HRESULT(REFIID, DWORD*)); |
| MOCK_METHOD2_WITH_CALLTYPE(STDMETHODCALLTYPE, |
| GetReportStatus, |
| HRESULT(REFIID, LOCATION_REPORT_STATUS*)); |
| MOCK_METHOD4_WITH_CALLTYPE(STDMETHODCALLTYPE, |
| RequestPermissions, |
| HRESULT(HWND, IID*, ULONG, BOOL)); |
| MOCK_METHOD3_WITH_CALLTYPE(STDMETHODCALLTYPE, |
| RegisterForReport, |
| HRESULT(ILocationEvents*, REFIID, DWORD)); |
| MOCK_METHOD2_WITH_CALLTYPE(STDMETHODCALLTYPE, |
| SetDesiredAccuracy, |
| HRESULT(REFIID, LOCATION_DESIRED_ACCURACY)); |
| MOCK_METHOD2_WITH_CALLTYPE(STDMETHODCALLTYPE, |
| SetReportInterval, |
| HRESULT(REFIID, DWORD)); |
| MOCK_METHOD1_WITH_CALLTYPE(STDMETHODCALLTYPE, |
| UnregisterForReport, |
| HRESULT(REFIID)); |
| // IUnknown |
| MOCK_METHOD2_WITH_CALLTYPE(STDMETHODCALLTYPE, |
| QueryInterface, |
| HRESULT(REFIID, void**)); |
| MOCK_METHOD0_WITH_CALLTYPE(STDMETHODCALLTYPE, |
| AddRef, |
| ULONG()); |
| MOCK_METHOD0_WITH_CALLTYPE(STDMETHODCALLTYPE, |
| Release, |
| ULONG()); |
| |
| MockReport* mock_report_; |
| |
| protected: |
| ~MockLocation() { |
| mock_report_->Release(); |
| } |
| |
| private: |
| HRESULT GetReportValid(REFIID report_type, |
| ILocationReport** location_report) { |
| *location_report = reinterpret_cast<ILocationReport*>(mock_report_); |
| mock_report_->AddRef(); |
| return S_OK; |
| } |
| ULONG AddRefInternal() { |
| return InterlockedIncrement(&ref_count_); |
| } |
| ULONG ReleaseInternal() { |
| LONG new_ref_count = InterlockedDecrement(&ref_count_); |
| if (0 == new_ref_count) |
| delete this; |
| return new_ref_count; |
| } |
| |
| LONG ref_count_; |
| }; |
| |
| |
| HRESULT __stdcall MockPropVariantToDoubleFunction(REFPROPVARIANT propvarIn, |
| DOUBLE *pdblRet) { |
| CHECK_EQ(10.0, propvarIn.dblVal); |
| *pdblRet = 10.0; |
| return S_OK; |
| } |
| |
| // TODO(allanwoj): Either make mock classes into NiceMock classes |
| // or check every mock method call. |
| class GeolocationApiWin7Tests : public testing::Test { |
| public: |
| GeolocationApiWin7Tests() { |
| } |
| virtual void SetUp() { |
| api_.reset(CreateMock()); |
| report_ = locator_->mock_report_; |
| lat_long_report_ = report_->mock_lat_long_report_; |
| } |
| virtual void TearDown() { |
| locator_->Release(); |
| api_.reset(); |
| } |
| ~GeolocationApiWin7Tests() { |
| } |
| protected: |
| Win7LocationApi* CreateMock() { |
| NiceMock<MockLocation>* locator = new NiceMock<MockLocation>(); |
| locator_ = locator; |
| return Win7LocationApi::CreateForTesting(&MockPropVariantToDoubleFunction, |
| locator); |
| } |
| |
| scoped_ptr<Win7LocationApi> api_; |
| MockLatLongReport* lat_long_report_; |
| NiceMock<MockLocation>* locator_; |
| MockReport* report_; |
| }; |
| |
| TEST_F(GeolocationApiWin7Tests, PermissionDenied) { |
| EXPECT_CALL(*locator_, GetReport(_, _)) |
| .Times(AtLeast(1)) |
| .WillRepeatedly(Return(E_ACCESSDENIED)); |
| Geoposition position; |
| api_->GetPosition(&position); |
| EXPECT_EQ(Geoposition::ERROR_CODE_PERMISSION_DENIED, |
| position.error_code); |
| } |
| |
| TEST_F(GeolocationApiWin7Tests, GetValidPosition) { |
| EXPECT_CALL(*locator_, GetReport(_, _)) |
| .Times(AtLeast(1)); |
| Geoposition position; |
| api_->GetPosition(&position); |
| EXPECT_TRUE(position.Validate()); |
| } |
| |
| TEST_F(GeolocationApiWin7Tests, GetInvalidPosition) { |
| EXPECT_CALL(*lat_long_report_, GetLatitude(_)) |
| .Times(AtLeast(1)) |
| .WillRepeatedly(Return(HRESULT_FROM_WIN32(ERROR_NO_DATA))); |
| EXPECT_CALL(*locator_, GetReport(_, _)) |
| .Times(AtLeast(1)); |
| Geoposition position; |
| api_->GetPosition(&position); |
| EXPECT_FALSE(position.Validate()); |
| } |
| |
| } // namespace content |