blob: 35842b079d18595dfd1e04a32bc396e91c955594 [file] [log] [blame]
// 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