| // Copyright 2019 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "ui/base/prediction/linear_predictor.h" |
| |
| #include "testing/gtest/include/gtest/gtest.h" |
| #include "ui/base/prediction/input_predictor_unittest_helpers.h" |
| #include "ui/base/ui_base_features.h" |
| |
| namespace ui { |
| namespace test { |
| |
| class LinearPredictorFirstOrderTest : public InputPredictorTest { |
| public: |
| explicit LinearPredictorFirstOrderTest() {} |
| |
| LinearPredictorFirstOrderTest(const LinearPredictorFirstOrderTest&) = delete; |
| LinearPredictorFirstOrderTest& operator=( |
| const LinearPredictorFirstOrderTest&) = delete; |
| |
| void SetUp() override { |
| predictor_ = std::make_unique<LinearPredictor>( |
| LinearPredictor::EquationOrder::kFirstOrder); |
| } |
| }; |
| |
| class LinearPredictorSecondOrderTest : public InputPredictorTest { |
| public: |
| explicit LinearPredictorSecondOrderTest() {} |
| |
| LinearPredictorSecondOrderTest(const LinearPredictorSecondOrderTest&) = |
| delete; |
| LinearPredictorSecondOrderTest& operator=( |
| const LinearPredictorSecondOrderTest&) = delete; |
| |
| void SetUp() override { |
| predictor_ = std::make_unique<LinearPredictor>( |
| LinearPredictor::EquationOrder::kSecondOrder); |
| } |
| }; |
| |
| // Test if the output name of the predictor is taking account of the |
| // equation order |
| TEST_F(LinearPredictorFirstOrderTest, GetName) { |
| EXPECT_EQ(predictor_->GetName(), features::kPredictorNameLinearFirst); |
| } |
| |
| // Test if the output name of the predictor is taking account of the |
| // equation order |
| TEST_F(LinearPredictorSecondOrderTest, GetName) { |
| EXPECT_EQ(predictor_->GetName(), features::kPredictorNameLinearSecond); |
| } |
| |
| // Test that the number of events required to compute a prediction is correct |
| TEST_F(LinearPredictorFirstOrderTest, ShouldHavePrediction) { |
| LinearPredictor predictor(LinearPredictor::EquationOrder::kFirstOrder); |
| size_t n = static_cast<size_t>(LinearPredictor::EquationOrder::kFirstOrder); |
| for (size_t i = 0; i < n; i++) { |
| EXPECT_FALSE(predictor.HasPrediction()); |
| predictor.Update(InputPredictor::InputData()); |
| } |
| EXPECT_TRUE(predictor.HasPrediction()); |
| predictor.Reset(); |
| EXPECT_FALSE(predictor.HasPrediction()); |
| } |
| |
| // Test that the number of events required to compute a prediction is correct |
| TEST_F(LinearPredictorSecondOrderTest, ShouldHavePrediction) { |
| LinearPredictor predictor(LinearPredictor::EquationOrder::kSecondOrder); |
| size_t n1 = static_cast<size_t>(LinearPredictor::EquationOrder::kFirstOrder); |
| size_t n2 = static_cast<size_t>(LinearPredictor::EquationOrder::kSecondOrder); |
| for (size_t i = 0; i < n2; i++) { |
| if (i < n1) |
| EXPECT_FALSE(predictor.HasPrediction()); |
| else |
| EXPECT_TRUE(predictor.HasPrediction()); |
| predictor.Update(InputPredictor::InputData()); |
| } |
| EXPECT_TRUE(predictor.HasPrediction()); |
| predictor.Reset(); |
| EXPECT_FALSE(predictor.HasPrediction()); |
| } |
| |
| TEST_F(LinearPredictorFirstOrderTest, PredictedValue) { |
| std::vector<double> x = {10, 20}; |
| std::vector<double> y = {5, 25}; |
| std::vector<double> t = {17, 33}; |
| // Compensating 23 ms |
| // 1st order prediction at 33 + 23 = 56 ms |
| |
| std::vector<double> pred_ts = {56}; |
| std::vector<double> pred_x = {34.37}; |
| std::vector<double> pred_y = {53.75}; |
| ValidatePredictor(x, y, t, pred_ts, pred_x, pred_y); |
| } |
| |
| TEST_F(LinearPredictorSecondOrderTest, PredictedValue) { |
| std::vector<double> x = {0, 10, 20}; |
| std::vector<double> y = {0, 5, 25}; |
| std::vector<double> t = {0, 17, 33}; |
| // Compensating 23 ms in both results |
| // 1st order prediction at 17 + 23 = 40 ms |
| // 2nd order prediction at 33 + 23 = 56 ms |
| std::vector<double> pred_ts = {40, 56}; |
| std::vector<double> pred_x = {23.52, 34.98}; |
| std::vector<double> pred_y = {11.76, 69.55}; |
| ValidatePredictor(x, y, t, pred_ts, pred_x, pred_y); |
| } |
| |
| // Test constant position and constant velocity |
| TEST_F(LinearPredictorSecondOrderTest, ConstantPositionAndVelocity) { |
| std::vector<double> x = {10, 10, 10, 10, 10}; // constant position |
| std::vector<double> y = {0, 5, 10, 15, 20}; // constant velocity |
| std::vector<double> t = {0, 7, 14, 21, 28}; // regular interval |
| // since velocity is constant, acceleration should be 0 which simplifies |
| // computations |
| // Compensating 10 ms in all results |
| std::vector<double> pred_ts = {17, 24, 31, 38}; |
| std::vector<double> pred_x = {10, 10, 10, 10}; |
| std::vector<double> pred_y = {12.14, 17.14, 22.14, 27.14}; |
| ValidatePredictor(x, y, t, pred_ts, pred_x, pred_y); |
| } |
| |
| // Test time interval in first order |
| TEST_F(LinearPredictorFirstOrderTest, TimeInterval) { |
| EXPECT_EQ(predictor_->TimeInterval(), kExpectedDefaultTimeInterval); |
| std::vector<double> x = {10, 20}; |
| std::vector<double> y = {5, 25}; |
| std::vector<double> t = {17, 33}; |
| size_t n = static_cast<size_t>(LinearPredictor::EquationOrder::kFirstOrder); |
| for (size_t i = 0; i < n; i++) { |
| predictor_->Update({gfx::PointF(x[i], y[i]), FromMilliseconds(t[i])}); |
| } |
| EXPECT_EQ(predictor_->TimeInterval(), base::Milliseconds(t[1] - t[0])); |
| } |
| |
| // Test time interval in second order |
| TEST_F(LinearPredictorSecondOrderTest, TimeInterval) { |
| EXPECT_EQ(predictor_->TimeInterval(), kExpectedDefaultTimeInterval); |
| std::vector<double> x = {0, 10, 20}; |
| std::vector<double> y = {0, 5, 25}; |
| std::vector<double> t = {0, 17, 33}; |
| size_t n = static_cast<size_t>(LinearPredictor::EquationOrder::kSecondOrder); |
| for (size_t i = 0; i < n; i++) { |
| predictor_->Update({gfx::PointF(x[i], y[i]), FromMilliseconds(t[i])}); |
| } |
| EXPECT_EQ(predictor_->TimeInterval(), base::Milliseconds((t[2] - t[0]) / 2)); |
| } |
| |
| } // namespace test |
| } // namespace ui |