910e62b5创建于 1月15日历史提交
// Copyright 2018 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "content/common/input/actions_parser.h"

#include <utility>

#include "base/json/json_reader.h"
#include "base/test/fuzztest_support.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/fuzztest/src/fuzztest/fuzztest.h"

namespace content {

TEST(ActionsParserTest, ParseMousePointerActionSequence) {
  std::optional<base::Value> value = base::JSONReader::Read(
      R"JSON( [{"source": "mouse", "id": 0,
                "actions": [{"name": "pointerDown", "x": 2, "y": 3,
                             "button": 0},
                            {"name": "pointerUp", "x": 2, "y": 3,
                             "button": 0}]}] )JSON",
      base::JSON_PARSE_CHROMIUM_EXTENSIONS);

  ActionsParser actions_parser(std::move(value.value()));
  EXPECT_TRUE(actions_parser.Parse());
  SyntheticPointerActionListParams action_list_params =
      actions_parser.pointer_action_params();
  EXPECT_EQ(content::mojom::GestureSourceType::kMouseInput,
            action_list_params.gesture_source_type);
  EXPECT_EQ(2U, action_list_params.params.size());
  EXPECT_EQ(1U, action_list_params.params[0].size());
  EXPECT_EQ(SyntheticPointerActionParams::PointerActionType::PRESS,
            action_list_params.params[0][0].pointer_action_type());
  EXPECT_EQ(gfx::PointF(2, 3), action_list_params.params[0][0].position());
  EXPECT_EQ(SyntheticPointerActionParams::Button::LEFT,
            action_list_params.params[0][0].button());
  EXPECT_EQ(SyntheticPointerActionParams::PointerActionType::RELEASE,
            action_list_params.params[1][0].pointer_action_type());
}

TEST(ActionsParserTest, ParseTouchPointerActionSequence1) {
  std::optional<base::Value> value = base::JSONReader::Read(
      R"JSON( [{"source": "touch", "id": 1,
                "actions": [{"name": "pointerDown", "x": 3, "y": 5},
                            {"name": "pointerMove", "x": 30, "y": 30},
                            {"name": "pointerUp" } ]},
               {"source": "touch", "id": 2,
                "actions": [{"name": "pointerDown", "x": 10, "y": 10},
                            {"name": "pointerMove", "x": 50, "y": 50},
                            {"name": "pointerUp" } ]}] )JSON",
      base::JSON_PARSE_CHROMIUM_EXTENSIONS);

  ActionsParser actions_parser(std::move(value.value()));
  EXPECT_TRUE(actions_parser.Parse());
  SyntheticPointerActionListParams action_list_params =
      actions_parser.pointer_action_params();
  EXPECT_EQ(content::mojom::GestureSourceType::kTouchInput,
            action_list_params.gesture_source_type);
  EXPECT_EQ(3U, action_list_params.params.size());
  EXPECT_EQ(2U, action_list_params.params[0].size());
  EXPECT_EQ(SyntheticPointerActionParams::PointerActionType::PRESS,
            action_list_params.params[0][0].pointer_action_type());
  EXPECT_EQ(gfx::PointF(3, 5), action_list_params.params[0][0].position());
  EXPECT_EQ(0U, action_list_params.params[0][0].pointer_id());
  EXPECT_EQ(SyntheticPointerActionParams::PointerActionType::PRESS,
            action_list_params.params[0][1].pointer_action_type());
  EXPECT_EQ(gfx::PointF(10, 10), action_list_params.params[0][1].position());
  EXPECT_EQ(1U, action_list_params.params[0][1].pointer_id());
}

TEST(ActionsParserTest, ParseTouchPointerActionSequenceWithoutId) {
  std::optional<base::Value> value = base::JSONReader::Read(
      R"JSON( [{"source": "touch", "id": 0,
                "actions": [{"name": "pointerDown", "x": 3, "y": 5},
                            {"name": "pointerMove", "x": 30, "y": 30},
                            {"name": "pointerUp" } ]},
               {"source": "touch", "id": 1,
                "actions": [{"name": "pointerDown", "x": 10, "y": 10},
                            {"name": "pointerMove", "x": 50, "y": 50},
                            {"name": "pointerUp" } ]}] )JSON",
      base::JSON_PARSE_CHROMIUM_EXTENSIONS);

  ActionsParser actions_parser(std::move(value.value()));
  EXPECT_TRUE(actions_parser.Parse());
  SyntheticPointerActionListParams action_list_params =
      actions_parser.pointer_action_params();
  EXPECT_EQ(content::mojom::GestureSourceType::kTouchInput,
            action_list_params.gesture_source_type);
  EXPECT_EQ(3U, action_list_params.params.size());
  EXPECT_EQ(2U, action_list_params.params[0].size());
  EXPECT_EQ(SyntheticPointerActionParams::PointerActionType::PRESS,
            action_list_params.params[0][0].pointer_action_type());
  EXPECT_EQ(gfx::PointF(3, 5), action_list_params.params[0][0].position());
  EXPECT_EQ(0U, action_list_params.params[0][0].pointer_id());
  EXPECT_EQ(SyntheticPointerActionParams::PointerActionType::PRESS,
            action_list_params.params[0][1].pointer_action_type());
  EXPECT_EQ(gfx::PointF(10, 10), action_list_params.params[0][1].position());
  EXPECT_EQ(1U, action_list_params.params[0][1].pointer_id());
}

TEST(ActionsParserTest, ParseMousePointerActionSequenceNoSource) {
  std::optional<base::Value> value = base::JSONReader::Read(
      R"JSON( [{"id": 0,
                "actions": [{"name": "pointerDown", "x": 2, "y": 3,
                             "button": 0},
                            {"name": "pointerUp", "x": 2, "y": 3,
                             "button": 0}]}] )JSON",
      base::JSON_PARSE_CHROMIUM_EXTENSIONS);

  ActionsParser actions_parser(std::move(value.value()));
  EXPECT_FALSE(actions_parser.Parse());
  EXPECT_EQ("source type is not defined or not a string",
            actions_parser.error_message());
}

TEST(ActionsParserTest, ParseMousePointerActionSequenceNoAction) {
  std::optional<base::Value> value =
      base::JSONReader::Read(R"JSON( [{"source": "mouse", "id": 0}] )JSON",
                             base::JSON_PARSE_CHROMIUM_EXTENSIONS);

  ActionsParser actions_parser(std::move(value.value()));
  EXPECT_FALSE(actions_parser.Parse());
  EXPECT_EQ("action_sequence[0].actions is not defined or not a list",
            actions_parser.error_message());
}

TEST(ActionsParserTest, ParseMousePointerActionSequenceUnsupportedButton) {
  std::optional<base::Value> value = base::JSONReader::Read(
      R"JSON( [{"source": "mouse", "id": 0,
                "actions": [{"name": "pointerDown", "x": 2, "y": 3,
                             "button": -1},
                            {"name": "pointerUp", "x": 2, "y": 3,
                             "button": 0}]}] )JSON",
      base::JSON_PARSE_CHROMIUM_EXTENSIONS);

  ActionsParser actions_parser(std::move(value.value()));
  EXPECT_FALSE(actions_parser.Parse());
  EXPECT_EQ("actions[0].actions.button is an unsupported button",
            actions_parser.error_message());
}

TEST(ActionsParserTest, ParseTouchPointerActionSequenceMultiSource) {
  std::optional<base::Value> value = base::JSONReader::Read(
      R"JSON( [{"source": "touch", "id": 1,
                "actions": [{"name": "pointerDown", "x": 3, "y": 5},
                            {"name": "pointerMove", "x": 30, "y": 30},
                            {"name": "pointerUp" } ]},
               {"source": "mouse", "id": 2,
                "actions": [{"name": "pointerDown", "x": 10, "y": 10},
                            {"name": "pointerMove", "x": 50, "y": 50},
                            {"name": "pointerUp" } ]}] )JSON",
      base::JSON_PARSE_CHROMIUM_EXTENSIONS);

  ActionsParser actions_parser(std::move(value.value()));
  EXPECT_FALSE(actions_parser.Parse());
  EXPECT_EQ("currently multiple input types are not not supported",
            actions_parser.error_message());
}

TEST(ActionsParserTest, ParseTouchPointerActionSequenceMultiMouse) {
  std::optional<base::Value> value = base::JSONReader::Read(
      R"JSON( [{"source": "mouse", "id": 1,
                "actions": [{"name": "pointerDown", "x": 3, "y": 5},
                            {"name": "pointerMove", "x": 30, "y": 30},
                            {"name": "pointerUp" } ]},
               {"source": "mouse", "id": 2,
                "actions": [{"name": "pointerDown", "x": 10, "y": 10},
                            {"name": "pointerMove", "x": 50, "y": 50},
                            {"name": "pointerUp" } ]}] )JSON",
      base::JSON_PARSE_CHROMIUM_EXTENSIONS);

  ActionsParser actions_parser(std::move(value.value()));
  EXPECT_FALSE(actions_parser.Parse());
  EXPECT_EQ(
      "for source type of mouse and pen, we only support one device in one "
      "sequence",
      actions_parser.error_message());
}

TEST(ActionsParserTest, ParsePointerActionSequenceInvalidKey) {
  std::optional<base::Value> value = base::JSONReader::Read(
      R"JSON( [{"source": "mouse", "id": 0,
                "actions": [{"name": "pointerDown", "x": 3, "y": 5,
                             "keys": "Ctrl"} ]}] )JSON",
      base::JSON_PARSE_CHROMIUM_EXTENSIONS);

  ActionsParser actions_parser(std::move(value.value()));
  EXPECT_FALSE(actions_parser.Parse());
  EXPECT_EQ("actions[0].actions.key is not a valid key",
            actions_parser.error_message());
}

TEST(ActionsParserTest, ParsePointerActionSequenceEmptyActionList) {
  std::optional<base::Value> value = base::JSONReader::Read(
      R"JSON( [{"source": "mouse", "id": 0,
                "actions": []}] )JSON",
      base::JSON_PARSE_CHROMIUM_EXTENSIONS);

  ActionsParser actions_parser(std::move(value.value()));
  EXPECT_FALSE(actions_parser.Parse());
  EXPECT_EQ("action_sequence[0].actions is an empty list",
            actions_parser.error_message());
}

TEST(ActionsParserTest, ParsePointerActionSequenceInvalidPointerType) {
  std::optional<base::Value> value = base::JSONReader::Read(
      R"JSON( [{"source": "wheel", "id": 0,
                "actions": [{"name": "pointerDown", "x": 3, "y": 5,
                             "keys": "Ctrl"} ]}] )JSON",
      base::JSON_PARSE_CHROMIUM_EXTENSIONS);

  ActionsParser actions_parser(std::move(value.value()));
  EXPECT_FALSE(actions_parser.Parse());
  EXPECT_EQ("source type wheel is an unsupported input type",
            actions_parser.error_message());
}

void ParsesJSONCorrectly(base::Value value) {
  content::ActionsParser parser(std::move(value));
  std::ignore = parser.Parse();
}

FUZZ_TEST(ActionsParserFuzzTest, ParsesJSONCorrectly)
    .WithSeeds({
        *base::JSONReader::Read(R"JSON([{
          "source":"mouse",
          "id":0,
          "actions":[
             { "name":"pointerDown" , "x":2 , "y":3 , "button":0 } ,
             { "name":"pointerUp"   , "x":2 , "y":3 , "button":0 }
          ]
        }])JSON",
                                base::JSON_PARSE_CHROMIUM_EXTENSIONS),
        *base::JSONReader::Read(R"JSON([{
          "source":"touch",
          "id":1,
          "actions":[
             { "name":"pointerDown" , "x":3  , "y":5 }  ,
             { "name":"pointerMove" , "x":30 , "y":30 } ,
             { "name":"pointerUp" }
          ]
        },{
          "source":"touch",
          "id":2,
          "actions":[
             { "name":"pointerDown" , "x":10 , "y":10 } ,
             { "name":"pointerMove" , "x":50 , "y":50 } ,
             { "name":"pointerUp" }
          ]
        }])JSON",
                                base::JSON_PARSE_CHROMIUM_EXTENSIONS),
    });

}  // namespace content