123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339 |
- // Copyright 2018 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 "components/ui_devtools/css_agent.h"
- #include "base/strings/string_number_conversions.h"
- #include "base/strings/string_util.h"
- #include "base/test/task_environment.h"
- #include "components/ui_devtools/agent_util.h"
- #include "components/ui_devtools/dom_agent.h"
- #include "components/ui_devtools/ui_devtools_unittest_utils.h"
- #include "components/ui_devtools/ui_element.h"
- #include "testing/gtest/include/gtest/gtest.h"
- namespace ui_devtools {
- class FakeUIElement : public UIElement {
- public:
- FakeUIElement(UIElementDelegate* ui_element_delegate)
- : UIElement(UIElementType::ROOT, ui_element_delegate, nullptr) {}
- ~FakeUIElement() override {}
- void GetBounds(gfx::Rect* bounds) const override { *bounds = bounds_; }
- void SetBounds(const gfx::Rect& bounds) override { bounds_ = bounds; }
- void GetVisible(bool* visible) const override { *visible = visible_; }
- void SetVisible(bool visible) override { visible_ = visible; }
- std::vector<std::string> GetAttributes() const override { return {}; }
- std::pair<gfx::NativeWindow, gfx::Rect> GetNodeWindowAndScreenBounds()
- const override {
- return {};
- }
- bool visible() const { return visible_; }
- gfx::Rect bounds() const { return bounds_; }
- void AddSource(std::string path, int line) {
- UIElement::AddSource(path, line);
- }
- private:
- gfx::Rect bounds_;
- bool visible_ = false;
- };
- class FakeDOMAgent : public DOMAgent {
- public:
- void OnUIElementAdded(UIElement* parent, UIElement* child) override {
- // nullptr root short circuits everything but adding |child|
- // to the node ID map, which is all we need here.
- DOMAgent::OnUIElementAdded(nullptr, child);
- }
- std::unique_ptr<protocol::DOM::Node> BuildTreeForUIElement(
- UIElement* root) override {
- return BuildDomNodeFromUIElement(root);
- }
- std::vector<UIElement*> CreateChildrenForRoot() override { return {}; }
- };
- class CSSAgentTest : public testing::Test {
- public:
- void SetUp() override {
- testing::Test::SetUp();
- frontend_channel_ = std::make_unique<FakeFrontendChannel>();
- uber_dispatcher_ =
- std::make_unique<protocol::UberDispatcher>(frontend_channel_.get());
- dom_agent_ = std::make_unique<FakeDOMAgent>();
- dom_agent_->Init(uber_dispatcher_.get());
- css_agent_ = std::make_unique<CSSAgent>(dom_agent_.get());
- css_agent_->Init(uber_dispatcher_.get());
- css_agent_->enable();
- element_ = std::make_unique<FakeUIElement>(dom_agent_.get());
- element()->SetBaseStylesheetId(0);
- dom_agent_->OnUIElementAdded(nullptr, element_.get());
- }
- void TearDown() override {
- css_agent_.reset();
- dom_agent_.reset();
- uber_dispatcher_.reset();
- frontend_channel_.reset();
- element_.reset();
- testing::Test::TearDown();
- }
- std::string BuildStylesheetUId(int node_id, int stylesheet_id) {
- return base::NumberToString(node_id) + "_" +
- base::NumberToString(stylesheet_id);
- }
- protected:
- base::test::TaskEnvironment task_environment_;
- using StyleArray = protocol::Array<protocol::CSS::CSSStyle>;
- std::pair<bool, std::unique_ptr<StyleArray>>
- SetStyle(const std::string& style_text, int node_id, int stylesheet_id = 0) {
- auto edits = std::make_unique<
- protocol::Array<protocol::CSS::StyleDeclarationEdit>>();
- auto edit = protocol::CSS::StyleDeclarationEdit::create()
- .setStyleSheetId(BuildStylesheetUId(node_id, stylesheet_id))
- .setRange(protocol::CSS::SourceRange::create()
- .setStartLine(0)
- .setStartColumn(0)
- .setEndLine(0)
- .setEndColumn(0)
- .build())
- .setText(style_text)
- .build();
- edits->emplace_back(std::move(edit));
- std::unique_ptr<StyleArray> output;
- auto response = css_agent_->setStyleTexts(std::move(edits), &output);
- return {response.IsSuccess(), std::move(output)};
- }
- std::string GetValueForProperty(protocol::CSS::CSSStyle* style,
- const std::string& property_name) {
- for (const auto& property : *(style->getCssProperties())) {
- if (property->getName() == property_name) {
- return property->getValue();
- }
- }
- return std::string();
- }
- int GetStyleSheetChangedCount(std::string stylesheet_id) {
- return frontend_channel_->CountProtocolNotificationMessage(
- "{\"method\":\"CSS.styleSheetChanged\",\"params\":{"
- "\"styleSheetId\":\"" +
- stylesheet_id + "\"}}");
- }
- std::pair<bool, std::string> GetSourceForElement() {
- std::string output;
- auto response = css_agent_->getStyleSheetText(
- BuildStylesheetUId(element()->node_id(), 0), &output);
- return {response.IsSuccess(), output};
- }
- CSSAgent* css_agent() { return css_agent_.get(); }
- DOMAgent* dom_agent() { return dom_agent_.get(); }
- FakeUIElement* element() { return element_.get(); }
- private:
- std::unique_ptr<CSSAgent> css_agent_;
- std::unique_ptr<DOMAgent> dom_agent_;
- std::unique_ptr<FakeFrontendChannel> frontend_channel_;
- std::unique_ptr<protocol::UberDispatcher> uber_dispatcher_;
- std::unique_ptr<FakeUIElement> element_;
- };
- TEST_F(CSSAgentTest, UnrecognizedNodeFails) {
- EXPECT_FALSE(SetStyle("x : 25", 42).first);
- }
- TEST_F(CSSAgentTest, UnrecognizedKeyFails) {
- element()->SetVisible(true);
- element()->SetBounds(gfx::Rect(1, 2, 3, 4));
- auto result = SetStyle("nonsense : 3.14", element()->node_id());
- EXPECT_FALSE(result.first);
- EXPECT_FALSE(result.second);
- // Ensure element didn't change.
- EXPECT_TRUE(element()->visible());
- EXPECT_EQ(element()->bounds(), gfx::Rect(1, 2, 3, 4));
- }
- TEST_F(CSSAgentTest, UnrecognizedValueFails) {
- element()->SetVisible(true);
- element()->SetBounds(gfx::Rect(1, 2, 3, 4));
- auto result = SetStyle("visibility : banana", element()->node_id());
- EXPECT_FALSE(result.first);
- EXPECT_FALSE(result.second);
- // Ensure element didn't change.
- EXPECT_TRUE(element()->visible());
- EXPECT_EQ(element()->bounds(), gfx::Rect(1, 2, 3, 4));
- }
- TEST_F(CSSAgentTest, BadInputsFail) {
- element()->SetVisible(true);
- element()->SetBounds(gfx::Rect(1, 2, 3, 4));
- // Input with no property name.
- auto result = SetStyle(": 1;", element()->node_id());
- EXPECT_FALSE(result.first);
- EXPECT_FALSE(result.second);
- // Ensure element didn't change.
- EXPECT_TRUE(element()->visible());
- EXPECT_EQ(element()->bounds(), gfx::Rect(1, 2, 3, 4));
- // Input with no property value.
- result = SetStyle("visibility:", element()->node_id());
- EXPECT_FALSE(result.first);
- EXPECT_FALSE(result.second);
- // Ensure element didn't change.
- EXPECT_TRUE(element()->visible());
- EXPECT_EQ(element()->bounds(), gfx::Rect(1, 2, 3, 4));
- // Blank input.
- result = SetStyle(":", element()->node_id());
- EXPECT_FALSE(result.first);
- EXPECT_FALSE(result.second);
- // Ensure element didn't change.
- EXPECT_TRUE(element()->visible());
- EXPECT_EQ(element()->bounds(), gfx::Rect(1, 2, 3, 4));
- }
- TEST_F(CSSAgentTest, SettingVisibility) {
- element()->SetVisible(false);
- DCHECK(!element()->visible());
- auto result = SetStyle("visibility: 1", element()->node_id());
- EXPECT_TRUE(result.first);
- EXPECT_TRUE(element()->visible());
- EXPECT_EQ(result.second->size(), 1U);
- std::unique_ptr<protocol::CSS::CSSStyle>& style = result.second->at(0);
- EXPECT_EQ(style->getStyleSheetId("default"),
- base::NumberToString(element()->node_id()) + "_0");
- EXPECT_EQ(GetValueForProperty(style.get(), "visibility"), "true");
- }
- TEST_F(CSSAgentTest, SettingX) {
- DCHECK_EQ(element()->bounds().x(), 0);
- auto result = SetStyle("x: 500", element()->node_id());
- EXPECT_TRUE(result.first);
- EXPECT_EQ(element()->bounds().x(), 500);
- EXPECT_EQ(result.second->size(), 1U);
- std::unique_ptr<protocol::CSS::CSSStyle>& style = result.second->at(0);
- EXPECT_EQ(style->getStyleSheetId("default"),
- base::NumberToString(element()->node_id()) + "_0");
- EXPECT_EQ(GetValueForProperty(style.get(), "x"), "500");
- }
- TEST_F(CSSAgentTest, SettingY) {
- DCHECK_EQ(element()->bounds().y(), 0);
- auto result = SetStyle("y: 100", element()->node_id());
- EXPECT_TRUE(result.first);
- EXPECT_EQ(element()->bounds().y(), 100);
- EXPECT_EQ(result.second->size(), 1U);
- std::unique_ptr<protocol::CSS::CSSStyle>& style = result.second->at(0);
- EXPECT_EQ(style->getStyleSheetId("default"),
- base::NumberToString(element()->node_id()) + "_0");
- EXPECT_EQ(GetValueForProperty(style.get(), "y"), "100");
- }
- TEST_F(CSSAgentTest, SettingWidth) {
- DCHECK_EQ(element()->bounds().width(), 0);
- auto result = SetStyle("width: 20", element()->node_id());
- EXPECT_TRUE(result.first);
- EXPECT_EQ(element()->bounds().width(), 20);
- EXPECT_EQ(result.second->size(), 1U);
- std::unique_ptr<protocol::CSS::CSSStyle>& style = result.second->at(0);
- EXPECT_EQ(style->getStyleSheetId("default"),
- base::NumberToString(element()->node_id()) + "_0");
- EXPECT_EQ(GetValueForProperty(style.get(), "width"), "20");
- }
- TEST_F(CSSAgentTest, SettingHeight) {
- DCHECK_EQ(element()->bounds().height(), 0);
- auto result = SetStyle("height: 30", element()->node_id());
- EXPECT_TRUE(result.first);
- EXPECT_EQ(element()->bounds().height(), 30);
- EXPECT_EQ(result.second->size(), 1U);
- std::unique_ptr<protocol::CSS::CSSStyle>& style = result.second->at(0);
- EXPECT_EQ(style->getStyleSheetId("default"),
- base::NumberToString(element()->node_id()) + "_0");
- EXPECT_EQ(GetValueForProperty(style.get(), "height"), "30");
- }
- TEST_F(CSSAgentTest, SettingAll) {
- DCHECK(element()->bounds() == gfx::Rect());
- element()->SetVisible(true);
- DCHECK(element()->visible());
- // Throw in odd whitespace while we're at it.
- std::string new_text(
- "\ny: 25; width: 50; visibility:0; height: 30;\nx: 9000;\n\n");
- auto result = SetStyle(new_text, element()->node_id());
- EXPECT_TRUE(result.first);
- EXPECT_EQ(element()->bounds(), gfx::Rect(9000, 25, 50, 30));
- EXPECT_FALSE(element()->visible());
- EXPECT_EQ(result.second->size(), 1U);
- std::unique_ptr<protocol::CSS::CSSStyle>& style = result.second->at(0);
- EXPECT_EQ(style->getStyleSheetId("default"),
- base::NumberToString(element()->node_id()) + "_0");
- EXPECT_EQ(GetValueForProperty(style.get(), "x"), "9000");
- EXPECT_EQ(GetValueForProperty(style.get(), "y"), "25");
- EXPECT_EQ(GetValueForProperty(style.get(), "width"), "50");
- EXPECT_EQ(GetValueForProperty(style.get(), "height"), "30");
- EXPECT_EQ(GetValueForProperty(style.get(), "visibility"), "false");
- }
- TEST_F(CSSAgentTest, UpdateOnBoundsChange) {
- FakeUIElement another_element(dom_agent());
- another_element.SetBaseStylesheetId(0);
- std::string element_stylesheet_id =
- BuildStylesheetUId(element()->node_id(), 0);
- std::string another_element_stylesheet_id =
- BuildStylesheetUId(another_element.node_id(), 0);
- EXPECT_EQ(0, GetStyleSheetChangedCount(element_stylesheet_id));
- EXPECT_EQ(0, GetStyleSheetChangedCount(another_element_stylesheet_id));
- css_agent()->OnElementBoundsChanged(element());
- EXPECT_EQ(1, GetStyleSheetChangedCount(element_stylesheet_id));
- EXPECT_EQ(0, GetStyleSheetChangedCount(another_element_stylesheet_id));
- css_agent()->OnElementBoundsChanged(&another_element);
- EXPECT_EQ(1, GetStyleSheetChangedCount(element_stylesheet_id));
- EXPECT_EQ(1, GetStyleSheetChangedCount(another_element_stylesheet_id));
- css_agent()->OnElementBoundsChanged(&another_element);
- EXPECT_EQ(1, GetStyleSheetChangedCount(element_stylesheet_id));
- EXPECT_EQ(2, GetStyleSheetChangedCount(another_element_stylesheet_id));
- }
- TEST_F(CSSAgentTest, GetSource) {
- // Tests CSSAgent::getStyleSheetText() with one source file.
- std::string file = "components/test/data/ui_devtools/test_file.cc";
- element()->AddSource(file, 0);
- auto result = GetSourceForElement();
- // Ensure that test_file.cc was read in correctly.
- EXPECT_TRUE(result.first);
- EXPECT_NE(std::string::npos,
- result.second.find("This file is for testing GetSource."));
- }
- TEST_F(CSSAgentTest, BadPathFails) {
- element()->AddSource("not/a/real/path", 0);
- auto result = GetSourceForElement();
- EXPECT_FALSE(result.first);
- EXPECT_EQ(result.second, "");
- }
- } // namespace ui_devtools
|