| // Copyright 2017 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include <memory> |
| |
| #include "base/bind.h" |
| #include "base/callback_helpers.h" |
| #include "base/memory/ref_counted.h" |
| #include "base/run_loop.h" |
| #include "base/test/task_environment.h" |
| #include "base/test/test_future.h" |
| #include "services/device/generic_sensor/absolute_orientation_euler_angles_fusion_algorithm_using_accelerometer_and_magnetometer.h" |
| #include "services/device/generic_sensor/fake_platform_sensor_and_provider.h" |
| #include "services/device/generic_sensor/generic_sensor_consts.h" |
| #include "services/device/generic_sensor/linear_acceleration_fusion_algorithm_using_accelerometer.h" |
| #include "services/device/generic_sensor/platform_sensor.h" |
| #include "services/device/generic_sensor/platform_sensor_fusion.h" |
| #include "services/device/generic_sensor/platform_sensor_fusion_algorithm.h" |
| #include "services/device/generic_sensor/platform_sensor_provider.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| |
| using ::testing::_; |
| using ::testing::Invoke; |
| using ::testing::Return; |
| |
| namespace device { |
| |
| using mojom::SensorType; |
| |
| namespace { |
| |
| void ExpectNoReadingChangedEvent(MockPlatformSensorClient* sensor_client, |
| mojom::SensorType sensor_type) { |
| base::RunLoop run_loop; |
| EXPECT_CALL(*sensor_client, OnSensorReadingChanged(sensor_type)).Times(0); |
| run_loop.RunUntilIdle(); |
| } |
| |
| void ExpectReadingChangedEvent(MockPlatformSensorClient* sensor_client, |
| mojom::SensorType sensor_type) { |
| base::RunLoop run_loop; |
| EXPECT_CALL(*sensor_client, OnSensorReadingChanged(sensor_type)) |
| .WillOnce(Invoke([&](SensorType) { run_loop.Quit(); })); |
| run_loop.Run(); |
| } |
| |
| // Attempts to add a new reading to the sensor owned by |sensor_client|, and |
| // asserts that it does not lead to OnSensorReadingChanged() being called (i.e. |
| // PlatformSensor's significance check has failed). |
| void AddNewReadingAndExpectNoReadingChangedEvent( |
| MockPlatformSensorClient* sensor_client, |
| const SensorReading& new_reading, |
| mojom::SensorType sensor_type) { |
| scoped_refptr<FakePlatformSensor> fake_sensor = |
| static_cast<FakePlatformSensor*>(sensor_client->sensor().get()); |
| fake_sensor->AddNewReading(new_reading); |
| ExpectNoReadingChangedEvent(sensor_client, sensor_type); |
| } |
| |
| // Add a new reading to the sensor owned by |sensor_client|, and expect reading |
| // change event. |
| void AddNewReadingAndExpectReadingChangedEvent( |
| MockPlatformSensorClient* sensor_client, |
| const SensorReading& new_reading, |
| mojom::SensorType sensor_type) { |
| scoped_refptr<FakePlatformSensor> fake_sensor = |
| static_cast<FakePlatformSensor*>(sensor_client->sensor().get()); |
| fake_sensor->AddNewReading(new_reading); |
| ExpectReadingChangedEvent(sensor_client, sensor_type); |
| } |
| |
| void FusionAlgorithmCopyLowLevelValues(const SensorReading& low_level_reading, |
| SensorReading* fused_reading) { |
| fused_reading->raw.values[0] = low_level_reading.raw.values[0]; |
| fused_reading->raw.values[1] = low_level_reading.raw.values[1]; |
| fused_reading->raw.values[2] = low_level_reading.raw.values[2]; |
| } |
| |
| void FusionAlgorithmSubtractEpsilonFromX(const SensorReading& low_level_reading, |
| SensorReading* fused_reading) { |
| fused_reading->raw.values[0] = low_level_reading.raw.values[0] - kEpsilon; |
| fused_reading->raw.values[1] = low_level_reading.raw.values[1]; |
| fused_reading->raw.values[2] = low_level_reading.raw.values[2]; |
| } |
| |
| // A PlatformSensorFusionAlgorithm whose fusion algorithm can be customized |
| // at runtime via set_fusion_function(). |
| class CustomizableFusionAlgorithm : public PlatformSensorFusionAlgorithm { |
| public: |
| using FusionFunction = |
| base::RepeatingCallback<void(const SensorReading& low_level_reading, |
| SensorReading* fused_reading)>; |
| static constexpr mojom::SensorType kLowLevelSensorType = |
| SensorType::ACCELEROMETER; |
| static constexpr mojom::SensorType kFusionSensorType = SensorType::GRAVITY; |
| |
| CustomizableFusionAlgorithm() |
| : PlatformSensorFusionAlgorithm(kFusionSensorType, |
| {kLowLevelSensorType}) {} |
| ~CustomizableFusionAlgorithm() override = default; |
| |
| bool GetFusedDataInternal(mojom::SensorType which_sensor_changed, |
| SensorReading* fused_reading) override { |
| EXPECT_EQ(which_sensor_changed, kLowLevelSensorType); |
| |
| SensorReading low_level_reading; |
| EXPECT_TRUE(fusion_sensor_->GetSourceReading(kLowLevelSensorType, |
| &low_level_reading)); |
| |
| fusion_function_.Run(low_level_reading, fused_reading); |
| return true; |
| } |
| |
| void set_fusion_function(FusionFunction fusion_function) { |
| fusion_function_ = std::move(fusion_function); |
| } |
| |
| private: |
| FusionFunction fusion_function_; |
| }; |
| |
| } // namespace |
| |
| class PlatformSensorFusionTest : public testing::Test { |
| public: |
| PlatformSensorFusionTest() { |
| provider_ = std::make_unique<FakePlatformSensorProvider>(); |
| } |
| |
| PlatformSensorFusionTest(const PlatformSensorFusionTest&) = delete; |
| PlatformSensorFusionTest& operator=(const PlatformSensorFusionTest&) = delete; |
| |
| protected: |
| void CreateAccelerometer() { |
| base::test::TestFuture<scoped_refptr<PlatformSensor>> future; |
| provider_->CreateSensor(SensorType::ACCELEROMETER, future.GetCallback()); |
| accelerometer_ = static_cast<FakePlatformSensor*>(future.Get().get()); |
| EXPECT_TRUE(accelerometer_); |
| EXPECT_EQ(SensorType::ACCELEROMETER, accelerometer_->GetType()); |
| } |
| |
| void CreateMagnetometer() { |
| base::test::TestFuture<scoped_refptr<PlatformSensor>> future; |
| provider_->CreateSensor(SensorType::MAGNETOMETER, future.GetCallback()); |
| magnetometer_ = static_cast<FakePlatformSensor*>(future.Get().get()); |
| EXPECT_TRUE(magnetometer_); |
| EXPECT_EQ(SensorType::MAGNETOMETER, magnetometer_->GetType()); |
| } |
| |
| void CreateLinearAccelerationFusionSensor() { |
| auto fusion_algorithm = |
| std::make_unique<LinearAccelerationFusionAlgorithmUsingAccelerometer>(); |
| CreateFusionSensor(std::move(fusion_algorithm)); |
| } |
| |
| void CreateAbsoluteOrientationEulerAnglesFusionSensor() { |
| auto fusion_algorithm = std::make_unique< |
| AbsoluteOrientationEulerAnglesFusionAlgorithmUsingAccelerometerAndMagnetometer>(); |
| CreateFusionSensor(std::move(fusion_algorithm)); |
| } |
| |
| void CreateFusionSensor( |
| std::unique_ptr<PlatformSensorFusionAlgorithm> fusion_algorithm) { |
| base::test::TestFuture<scoped_refptr<PlatformSensor>> future; |
| const SensorType type = fusion_algorithm->fused_type(); |
| PlatformSensorFusion::Create(provider_->GetSensorReadingBuffer(type), |
| provider_.get(), std::move(fusion_algorithm), |
| future.GetCallback()); |
| fusion_sensor_ = static_cast<PlatformSensorFusion*>(future.Get().get()); |
| } |
| |
| base::test::TaskEnvironment task_environment_; |
| std::unique_ptr<FakePlatformSensorProvider> provider_; |
| scoped_refptr<FakePlatformSensor> accelerometer_; |
| scoped_refptr<FakePlatformSensor> magnetometer_; |
| scoped_refptr<PlatformSensorFusion> fusion_sensor_; |
| }; |
| |
| // The following code tests creating a fusion sensor that needs one source |
| // sensor. |
| |
| TEST_F(PlatformSensorFusionTest, SourceSensorAlreadyExists) { |
| EXPECT_FALSE(provider_->GetSensor(SensorType::ACCELEROMETER)); |
| CreateAccelerometer(); |
| // Now the source sensor already exists. |
| EXPECT_TRUE(provider_->GetSensor(SensorType::ACCELEROMETER)); |
| |
| CreateLinearAccelerationFusionSensor(); |
| EXPECT_TRUE(fusion_sensor_); |
| EXPECT_EQ(SensorType::LINEAR_ACCELERATION, fusion_sensor_->GetType()); |
| } |
| |
| TEST_F(PlatformSensorFusionTest, SourceSensorWorksSeparately) { |
| CreateAccelerometer(); |
| EXPECT_TRUE(accelerometer_); |
| EXPECT_FALSE(accelerometer_->IsActiveForTesting()); |
| |
| auto client = std::make_unique<testing::NiceMock<MockPlatformSensorClient>>(); |
| accelerometer_->AddClient(client.get()); |
| accelerometer_->StartListening(client.get(), PlatformSensorConfiguration(10)); |
| EXPECT_TRUE(accelerometer_->IsActiveForTesting()); |
| |
| CreateLinearAccelerationFusionSensor(); |
| EXPECT_TRUE(fusion_sensor_); |
| EXPECT_EQ(SensorType::LINEAR_ACCELERATION, fusion_sensor_->GetType()); |
| EXPECT_FALSE(fusion_sensor_->IsActiveForTesting()); |
| |
| fusion_sensor_->AddClient(client.get()); |
| fusion_sensor_->StartListening(client.get(), PlatformSensorConfiguration(10)); |
| EXPECT_TRUE(fusion_sensor_->IsActiveForTesting()); |
| |
| fusion_sensor_->StopListening(client.get(), PlatformSensorConfiguration(10)); |
| EXPECT_FALSE(fusion_sensor_->IsActiveForTesting()); |
| |
| EXPECT_TRUE(accelerometer_->IsActiveForTesting()); |
| |
| accelerometer_->RemoveClient(client.get()); |
| EXPECT_FALSE(accelerometer_->IsActiveForTesting()); |
| |
| fusion_sensor_->RemoveClient(client.get()); |
| } |
| |
| namespace { |
| |
| void CheckConfigsCountForClient(const scoped_refptr<PlatformSensor>& sensor, |
| PlatformSensor::Client* client, |
| size_t expected_count) { |
| auto client_entry = sensor->GetConfigMapForTesting().find(client); |
| if (sensor->GetConfigMapForTesting().end() == client_entry) { |
| EXPECT_EQ(0u, expected_count); |
| return; |
| } |
| EXPECT_EQ(expected_count, client_entry->second.size()); |
| } |
| |
| } // namespace |
| |
| TEST_F(PlatformSensorFusionTest, SourceSensorDoesNotKeepOutdatedConfigs) { |
| CreateAccelerometer(); |
| EXPECT_TRUE(accelerometer_); |
| |
| CreateLinearAccelerationFusionSensor(); |
| EXPECT_TRUE(fusion_sensor_); |
| EXPECT_EQ(SensorType::LINEAR_ACCELERATION, fusion_sensor_->GetType()); |
| |
| auto client = std::make_unique<testing::NiceMock<MockPlatformSensorClient>>( |
| fusion_sensor_); |
| fusion_sensor_->StartListening(client.get(), PlatformSensorConfiguration(10)); |
| fusion_sensor_->StartListening(client.get(), PlatformSensorConfiguration(20)); |
| fusion_sensor_->StartListening(client.get(), PlatformSensorConfiguration(30)); |
| |
| EXPECT_EQ(1u, fusion_sensor_->GetConfigMapForTesting().size()); |
| EXPECT_EQ(1u, accelerometer_->GetConfigMapForTesting().size()); |
| |
| CheckConfigsCountForClient(fusion_sensor_, client.get(), 3u); |
| // Fusion sensor is a client for its sources, however it must keep only |
| // one active configuration for them at a time. |
| CheckConfigsCountForClient(accelerometer_, fusion_sensor_.get(), 1u); |
| |
| fusion_sensor_->StopListening(client.get(), PlatformSensorConfiguration(30)); |
| fusion_sensor_->StopListening(client.get(), PlatformSensorConfiguration(20)); |
| |
| CheckConfigsCountForClient(fusion_sensor_, client.get(), 1u); |
| CheckConfigsCountForClient(accelerometer_, fusion_sensor_.get(), 1u); |
| |
| fusion_sensor_->StopListening(client.get(), PlatformSensorConfiguration(10)); |
| |
| CheckConfigsCountForClient(fusion_sensor_, client.get(), 0u); |
| CheckConfigsCountForClient(accelerometer_, fusion_sensor_.get(), 0u); |
| } |
| |
| TEST_F(PlatformSensorFusionTest, AllSourceSensorsStoppedOnSingleSourceFailure) { |
| CreateAccelerometer(); |
| EXPECT_TRUE(accelerometer_); |
| |
| CreateMagnetometer(); |
| EXPECT_TRUE(magnetometer_); |
| // Magnetometer will be started after Accelerometer for the given |
| // sensor fusion algorithm. |
| ON_CALL(*magnetometer_, StartSensor(_)).WillByDefault(Return(false)); |
| |
| CreateAbsoluteOrientationEulerAnglesFusionSensor(); |
| EXPECT_TRUE(fusion_sensor_); |
| EXPECT_EQ(SensorType::ABSOLUTE_ORIENTATION_EULER_ANGLES, |
| fusion_sensor_->GetType()); |
| |
| auto client = std::make_unique<testing::NiceMock<MockPlatformSensorClient>>( |
| fusion_sensor_); |
| fusion_sensor_->StartListening(client.get(), PlatformSensorConfiguration(10)); |
| |
| EXPECT_FALSE(fusion_sensor_->IsActiveForTesting()); |
| EXPECT_FALSE(accelerometer_->IsActiveForTesting()); |
| EXPECT_FALSE(magnetometer_->IsActiveForTesting()); |
| } |
| |
| TEST_F(PlatformSensorFusionTest, SourceSensorNeedsToBeCreated) { |
| EXPECT_FALSE(provider_->GetSensor(SensorType::ACCELEROMETER)); |
| |
| CreateLinearAccelerationFusionSensor(); |
| EXPECT_TRUE(fusion_sensor_); |
| EXPECT_EQ(SensorType::LINEAR_ACCELERATION, fusion_sensor_->GetType()); |
| } |
| |
| TEST_F(PlatformSensorFusionTest, SourceSensorIsNotAvailable) { |
| // Accelerometer is not available. |
| ON_CALL(*provider_, DoCreateSensorInternal(SensorType::ACCELEROMETER, _, _)) |
| .WillByDefault( |
| Invoke([](mojom::SensorType, scoped_refptr<PlatformSensor>, |
| FakePlatformSensorProvider::CreateSensorCallback callback) { |
| std::move(callback).Run(nullptr); |
| })); |
| |
| CreateLinearAccelerationFusionSensor(); |
| EXPECT_FALSE(fusion_sensor_); |
| } |
| |
| // The following code tests creating a fusion sensor that needs two source |
| // sensors. |
| |
| TEST_F(PlatformSensorFusionTest, BothSourceSensorsAlreadyExist) { |
| EXPECT_FALSE(provider_->GetSensor(SensorType::ACCELEROMETER)); |
| CreateAccelerometer(); |
| EXPECT_TRUE(provider_->GetSensor(SensorType::ACCELEROMETER)); |
| |
| EXPECT_FALSE(provider_->GetSensor(SensorType::MAGNETOMETER)); |
| CreateMagnetometer(); |
| EXPECT_TRUE(provider_->GetSensor(SensorType::MAGNETOMETER)); |
| |
| CreateAbsoluteOrientationEulerAnglesFusionSensor(); |
| EXPECT_TRUE(fusion_sensor_); |
| EXPECT_EQ(SensorType::ABSOLUTE_ORIENTATION_EULER_ANGLES, |
| fusion_sensor_->GetType()); |
| } |
| |
| TEST_F(PlatformSensorFusionTest, BothSourceSensorsNeedToBeCreated) { |
| EXPECT_FALSE(provider_->GetSensor(SensorType::ACCELEROMETER)); |
| EXPECT_FALSE(provider_->GetSensor(SensorType::MAGNETOMETER)); |
| |
| CreateAbsoluteOrientationEulerAnglesFusionSensor(); |
| EXPECT_TRUE(fusion_sensor_); |
| EXPECT_EQ(SensorType::ABSOLUTE_ORIENTATION_EULER_ANGLES, |
| fusion_sensor_->GetType()); |
| } |
| |
| TEST_F(PlatformSensorFusionTest, BothSourceSensorsAreNotAvailable) { |
| // Failure. |
| ON_CALL(*provider_, DoCreateSensorInternal(_, _, _)) |
| .WillByDefault( |
| Invoke([](mojom::SensorType, scoped_refptr<PlatformSensor>, |
| FakePlatformSensorProvider::CreateSensorCallback callback) { |
| std::move(callback).Run(nullptr); |
| })); |
| |
| CreateAbsoluteOrientationEulerAnglesFusionSensor(); |
| EXPECT_FALSE(fusion_sensor_); |
| } |
| |
| TEST_F(PlatformSensorFusionTest, |
| OneSourceSensorAlreadyExistsTheOtherSourceSensorNeedsToBeCreated) { |
| EXPECT_FALSE(provider_->GetSensor(SensorType::ACCELEROMETER)); |
| CreateAccelerometer(); |
| EXPECT_TRUE(provider_->GetSensor(SensorType::ACCELEROMETER)); |
| EXPECT_FALSE(provider_->GetSensor(SensorType::MAGNETOMETER)); |
| |
| CreateAbsoluteOrientationEulerAnglesFusionSensor(); |
| EXPECT_TRUE(fusion_sensor_); |
| EXPECT_EQ(SensorType::ABSOLUTE_ORIENTATION_EULER_ANGLES, |
| fusion_sensor_->GetType()); |
| } |
| |
| TEST_F(PlatformSensorFusionTest, |
| OneSourceSensorAlreadyExistsTheOtherSourceSensorIsNotAvailable) { |
| EXPECT_FALSE(provider_->GetSensor(SensorType::ACCELEROMETER)); |
| CreateAccelerometer(); |
| EXPECT_TRUE(provider_->GetSensor(SensorType::ACCELEROMETER)); |
| |
| // Magnetometer is not available. |
| ON_CALL(*provider_, DoCreateSensorInternal(SensorType::MAGNETOMETER, _, _)) |
| .WillByDefault( |
| Invoke([](mojom::SensorType, scoped_refptr<PlatformSensor>, |
| FakePlatformSensorProvider::CreateSensorCallback callback) { |
| std::move(callback).Run(nullptr); |
| })); |
| |
| CreateAbsoluteOrientationEulerAnglesFusionSensor(); |
| EXPECT_FALSE(fusion_sensor_); |
| } |
| |
| TEST_F(PlatformSensorFusionTest, |
| OneSourceSensorNeedsToBeCreatedTheOtherSourceSensorIsNotAvailable) { |
| EXPECT_FALSE(provider_->GetSensor(SensorType::ACCELEROMETER)); |
| // Magnetometer is not available. |
| ON_CALL(*provider_, DoCreateSensorInternal(SensorType::MAGNETOMETER, _, _)) |
| .WillByDefault( |
| Invoke([](mojom::SensorType, scoped_refptr<PlatformSensor>, |
| FakePlatformSensorProvider::CreateSensorCallback callback) { |
| std::move(callback).Run(nullptr); |
| })); |
| |
| CreateAbsoluteOrientationEulerAnglesFusionSensor(); |
| EXPECT_FALSE(fusion_sensor_); |
| } |
| |
| TEST_F(PlatformSensorFusionTest, |
| FusionSensorMaximumSupportedFrequencyIsTheMaximumOfItsSourceSensors) { |
| EXPECT_FALSE(provider_->GetSensor(SensorType::ACCELEROMETER)); |
| CreateAccelerometer(); |
| scoped_refptr<PlatformSensor> accelerometer = |
| provider_->GetSensor(SensorType::ACCELEROMETER); |
| EXPECT_TRUE(accelerometer); |
| static_cast<FakePlatformSensor*>(accelerometer.get()) |
| ->set_maximum_supported_frequency(30.0); |
| |
| EXPECT_FALSE(provider_->GetSensor(SensorType::MAGNETOMETER)); |
| CreateMagnetometer(); |
| scoped_refptr<PlatformSensor> magnetometer = |
| provider_->GetSensor(SensorType::MAGNETOMETER); |
| EXPECT_TRUE(magnetometer); |
| static_cast<FakePlatformSensor*>(magnetometer.get()) |
| ->set_maximum_supported_frequency(20.0); |
| |
| CreateAbsoluteOrientationEulerAnglesFusionSensor(); |
| EXPECT_TRUE(fusion_sensor_); |
| EXPECT_EQ(SensorType::ABSOLUTE_ORIENTATION_EULER_ANGLES, |
| fusion_sensor_->GetType()); |
| EXPECT_EQ(30.0, fusion_sensor_->GetMaximumSupportedFrequency()); |
| auto client = std::make_unique<testing::NiceMock<MockPlatformSensorClient>>( |
| fusion_sensor_); |
| EXPECT_TRUE(fusion_sensor_->StartListening( |
| client.get(), PlatformSensorConfiguration(30.0))); |
| } |
| |
| TEST_F(PlatformSensorFusionTest, FusionIsSignificantlyDifferent) { |
| // Due to inaccuracy of calculations between doubles, difference between two |
| // input values has to be bigger than the threshold value used in |
| // significantly different check. |
| CreateLinearAccelerationFusionSensor(); |
| const auto* const fusion_algorithm = fusion_sensor_->fusion_algorithm(); |
| |
| const double kValueToFlipThreshold = fusion_algorithm->threshold() + kEpsilon; |
| const double kValueNotToFlipThreshold = |
| fusion_algorithm->threshold() - kEpsilon; |
| SensorReading reading1; |
| SensorReading reading2; |
| // Made up test values. |
| reading1.accel.x = reading2.accel.x = 0.1; |
| reading1.accel.y = reading2.accel.y = 0.5; |
| reading1.accel.z = reading2.accel.z = 10.0; |
| |
| // Compared values are same. |
| // reading1: 0.1, 0.5, 10.0 |
| // reading2: 0.1, 0.5, 10.0 |
| EXPECT_FALSE(fusion_sensor_->IsSignificantlyDifferent( |
| reading1, reading2, fusion_sensor_->GetType())); |
| |
| // Compared values do not significantly differ from each other. |
| // reading1: 0.1, 0.5, 10.0 |
| // reading2: 0.1, 0.5, 10.00001 |
| reading2.accel.z = reading2.accel.z + kValueNotToFlipThreshold; |
| EXPECT_FALSE(fusion_sensor_->IsSignificantlyDifferent( |
| reading1, reading2, fusion_sensor_->GetType())); |
| |
| // Compared values significantly differ from each other. |
| // reading1: 0.1, 0.5, 10.0 |
| // reading2: 0.1, 0.5, 10.11001 |
| reading2.accel.z = reading2.accel.z + kValueToFlipThreshold; |
| EXPECT_TRUE(fusion_sensor_->IsSignificantlyDifferent( |
| reading1, reading2, fusion_sensor_->GetType())); |
| } |
| |
| TEST_F(PlatformSensorFusionTest, OnSensorReadingChanged) { |
| // Accelerometer is selected as low-level sensor. |
| CreateAccelerometer(); |
| EXPECT_TRUE(accelerometer_); |
| auto client_low_level_ = |
| std::make_unique<testing::NiceMock<MockPlatformSensorClient>>( |
| accelerometer_); |
| |
| CreateFusionSensor(std::make_unique<CustomizableFusionAlgorithm>()); |
| ASSERT_TRUE(fusion_sensor_); |
| auto* fusion_algorithm = static_cast<CustomizableFusionAlgorithm*>( |
| fusion_sensor_->fusion_algorithm()); |
| EXPECT_EQ(CustomizableFusionAlgorithm::kFusionSensorType, |
| fusion_sensor_->GetType()); |
| |
| auto client_fusion = |
| std::make_unique<testing::NiceMock<MockPlatformSensorClient>>( |
| fusion_sensor_); |
| fusion_sensor_->StartListening(client_fusion.get(), |
| PlatformSensorConfiguration(10)); |
| |
| // Made up test values. |
| const double kTestValueX = 0.6; |
| const double kTestValueY = 0.9; |
| const double kTestValueZ = 1.1; |
| const double kValueToFlipThreshold = fusion_algorithm->threshold() + kEpsilon; |
| const double kValueToFlipThresholdRounded = fusion_algorithm->threshold(); |
| |
| struct TestSensorReading { |
| const struct { |
| double x; |
| double y; |
| double z; |
| } input, expected; |
| const bool expect_reading_changed_event; |
| }; |
| |
| const struct { |
| TestSensorReading low_level; |
| TestSensorReading fusion; |
| CustomizableFusionAlgorithm::FusionFunction fusion_function; |
| } kTestSteps[] = { |
| // Test set 1 |
| // Triggers low-level and fusion reading as initial sensor |
| // values are zero. |
| {// Low-level sensor |
| {{kTestValueX, kTestValueY, kTestValueZ}, |
| {kTestValueX, kTestValueY, kTestValueZ}, |
| true}, |
| // Fusion sensor |
| {{kTestValueX, kTestValueY, kTestValueZ}, |
| {kTestValueX, kTestValueY, kTestValueZ}, |
| true}, |
| base::BindRepeating(&FusionAlgorithmCopyLowLevelValues)}, |
| |
| // Test set 2 |
| // Doesn't trigger low-level reading event as rounded value is same as |
| // earlier. Because of that fusion sensor event is not either triggered. |
| {// Low-level sensor |
| {{kTestValueX + kEpsilon, kTestValueY, kTestValueZ}, |
| {kTestValueX, kTestValueY, kTestValueZ}, |
| false}, |
| // Fusion sensor |
| {{kTestValueX, kTestValueY, kTestValueZ}, |
| {kTestValueX, kTestValueY, kTestValueZ}, |
| false}, |
| base::BindRepeating(&FusionAlgorithmSubtractEpsilonFromX)}, |
| |
| // Test set 3 |
| // In current code as fusion sensor values are rounded before |
| // PlatformSensorFusionAlgorithm::IsReadingSignificantlyDifferent() call |
| // the difference between values must much bigger than threshold value. |
| {// Low-level sensor |
| {{kTestValueX + kValueToFlipThreshold, kTestValueY, kTestValueZ}, |
| {kTestValueX + kValueToFlipThresholdRounded, kTestValueY, kTestValueZ}, |
| true}, |
| // Fusion sensor |
| {{kTestValueX + kValueToFlipThreshold, kTestValueY, kTestValueZ}, |
| {kTestValueX + kValueToFlipThresholdRounded, kTestValueY, kTestValueZ}, |
| true}, |
| base::BindRepeating(&FusionAlgorithmCopyLowLevelValues)}, |
| }; |
| |
| for (const auto& test_step : kTestSteps) { |
| fusion_algorithm->set_fusion_function(test_step.fusion_function); |
| |
| // First add low-level sensor readings. |
| SensorReading reading; |
| reading.accel.x = test_step.low_level.input.x; |
| reading.accel.y = test_step.low_level.input.y; |
| reading.accel.z = test_step.low_level.input.z; |
| |
| // Code checks if PlatformSensor::OnSensorReadingChanged() is called |
| // or not called as expected. |
| if (test_step.low_level.expect_reading_changed_event) { |
| AddNewReadingAndExpectReadingChangedEvent( |
| client_low_level_.get(), reading, |
| CustomizableFusionAlgorithm::kLowLevelSensorType); |
| } else { |
| AddNewReadingAndExpectNoReadingChangedEvent( |
| client_low_level_.get(), reading, |
| CustomizableFusionAlgorithm::kLowLevelSensorType); |
| } |
| |
| if (test_step.fusion.expect_reading_changed_event) { |
| ExpectReadingChangedEvent(client_fusion.get(), |
| CustomizableFusionAlgorithm::kFusionSensorType); |
| } else { |
| ExpectNoReadingChangedEvent( |
| client_fusion.get(), CustomizableFusionAlgorithm::kFusionSensorType); |
| } |
| |
| // Once new values are added, we can check that low-level sensors and |
| // fusion sensor have correct values. |
| // Check rounded low-level sensor values. |
| EXPECT_TRUE(accelerometer_->GetLatestReading(&reading)); |
| EXPECT_DOUBLE_EQ(test_step.low_level.expected.x, reading.accel.x); |
| EXPECT_DOUBLE_EQ(test_step.low_level.expected.y, reading.accel.y); |
| EXPECT_DOUBLE_EQ(test_step.low_level.expected.z, reading.accel.z); |
| |
| // Check raw low-level sensor values. |
| EXPECT_TRUE(accelerometer_->GetLatestRawReading(&reading)); |
| EXPECT_DOUBLE_EQ(test_step.low_level.input.x, reading.accel.x); |
| EXPECT_DOUBLE_EQ(test_step.low_level.input.y, reading.accel.y); |
| EXPECT_DOUBLE_EQ(test_step.low_level.input.z, reading.accel.z); |
| |
| // Check rounded fusion sensor values. |
| EXPECT_TRUE(fusion_sensor_->GetLatestReading(&reading)); |
| EXPECT_DOUBLE_EQ(test_step.fusion.expected.x, reading.accel.x); |
| EXPECT_DOUBLE_EQ(test_step.fusion.expected.y, reading.accel.y); |
| EXPECT_DOUBLE_EQ(test_step.fusion.expected.z, reading.accel.z); |
| |
| // Check raw fusion sensor values. |
| EXPECT_TRUE(fusion_sensor_->GetLatestRawReading(&reading)); |
| EXPECT_DOUBLE_EQ(test_step.fusion.input.x, reading.accel.x); |
| EXPECT_DOUBLE_EQ(test_step.fusion.input.y, reading.accel.y); |
| EXPECT_DOUBLE_EQ(test_step.fusion.input.z, reading.accel.z); |
| } |
| } |
| |
| } // namespace device |