blob: d510f2cfd3f0546d0da16889227de541f3b184c4 [file] [log] [blame]
// Copyright 2014 The Cobalt Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "cobalt/css_parser/parser.h"
#include <cmath>
#include <memory>
#include <string>
#include <vector>
#include "base/bind.h"
#include "base/strings/stringprintf.h"
#include "cobalt/cssom/active_pseudo_class.h"
#include "cobalt/cssom/after_pseudo_element.h"
#include "cobalt/cssom/attribute_selector.h"
#include "cobalt/cssom/before_pseudo_element.h"
#include "cobalt/cssom/child_combinator.h"
#include "cobalt/cssom/class_selector.h"
#include "cobalt/cssom/cobalt_ui_nav_focus_transform_function.h"
#include "cobalt/cssom/cobalt_ui_nav_spotlight_transform_function.h"
#include "cobalt/cssom/complex_selector.h"
#include "cobalt/cssom/compound_selector.h"
#include "cobalt/cssom/css_declared_style_data.h"
#include "cobalt/cssom/css_font_face_declaration_data.h"
#include "cobalt/cssom/css_font_face_rule.h"
#include "cobalt/cssom/css_keyframe_rule.h"
#include "cobalt/cssom/css_keyframes_rule.h"
#include "cobalt/cssom/css_rule_list.h"
#include "cobalt/cssom/css_style_rule.h"
#include "cobalt/cssom/css_style_sheet.h"
#include "cobalt/cssom/descendant_combinator.h"
#include "cobalt/cssom/empty_pseudo_class.h"
#include "cobalt/cssom/filter_function_list_value.h"
#include "cobalt/cssom/focus_pseudo_class.h"
#include "cobalt/cssom/following_sibling_combinator.h"
#include "cobalt/cssom/font_style_value.h"
#include "cobalt/cssom/font_weight_value.h"
#include "cobalt/cssom/hover_pseudo_class.h"
#include "cobalt/cssom/id_selector.h"
#include "cobalt/cssom/integer_value.h"
#include "cobalt/cssom/keyword_value.h"
#include "cobalt/cssom/length_value.h"
#include "cobalt/cssom/linear_gradient_value.h"
#include "cobalt/cssom/local_src_value.h"
#include "cobalt/cssom/map_to_mesh_function.h"
#include "cobalt/cssom/matrix_function.h"
#include "cobalt/cssom/media_list.h"
#include "cobalt/cssom/media_query.h"
#include "cobalt/cssom/next_sibling_combinator.h"
#include "cobalt/cssom/not_pseudo_class.h"
#include "cobalt/cssom/number_value.h"
#include "cobalt/cssom/percentage_value.h"
#include "cobalt/cssom/property_definitions.h"
#include "cobalt/cssom/property_key_list_value.h"
#include "cobalt/cssom/property_list_value.h"
#include "cobalt/cssom/property_value_visitor.h"
#include "cobalt/cssom/radial_gradient_value.h"
#include "cobalt/cssom/rgba_color_value.h"
#include "cobalt/cssom/rotate_function.h"
#include "cobalt/cssom/scale_function.h"
#include "cobalt/cssom/shadow_value.h"
#include "cobalt/cssom/simple_selector.h"
#include "cobalt/cssom/string_value.h"
#include "cobalt/cssom/time_list_value.h"
#include "cobalt/cssom/timing_function.h"
#include "cobalt/cssom/timing_function_list_value.h"
#include "cobalt/cssom/transform_function_list_value.h"
#include "cobalt/cssom/translate_function.h"
#include "cobalt/cssom/type_selector.h"
#include "cobalt/cssom/unicode_range_value.h"
#include "cobalt/cssom/universal_selector.h"
#include "cobalt/cssom/url_src_value.h"
#include "cobalt/cssom/url_value.h"
#include "cobalt/cssom/viewport_size.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
using cobalt::cssom::ViewportSize;
using testing::_;
using testing::AtLeast;
namespace cobalt {
namespace css_parser {
constexpr cssom::TransformFunction::Trait kTraitIsDynamic =
cssom::TransformFunction::Trait::kTraitIsDynamic;
constexpr cssom::TransformFunction::Trait kTraitUsesRelativeUnits =
cssom::TransformFunction::Trait::kTraitUsesRelativeUnits;
constexpr cssom::TransformFunction::Trait kTraitUsesUiNavFocus =
cssom::TransformFunction::Trait::kTraitUsesUiNavFocus;
class MockParserObserver {
public:
MOCK_METHOD1(OnWarning, void(const std::string& message));
MOCK_METHOD1(OnError, void(const std::string& message));
};
class ParserTestBase : public ::testing::Test {
public:
explicit ParserTestBase(Parser::SupportsMapToMeshFlag supports_map_to_mesh);
~ParserTestBase() override {}
protected:
::testing::StrictMock<MockParserObserver> parser_observer_;
Parser parser_;
const base::SourceLocation source_location_;
};
ParserTestBase::ParserTestBase(
Parser::SupportsMapToMeshFlag supports_map_to_mesh)
: parser_(base::Bind(&MockParserObserver::OnWarning,
base::Unretained(&parser_observer_)),
base::Bind(&MockParserObserver::OnError,
base::Unretained(&parser_observer_)),
Parser::kShort, supports_map_to_mesh),
source_location_("[object ParserTest]", 1, 1) {}
class ParserTest : public ParserTestBase {
public:
ParserTest() : ParserTestBase(Parser::kSupportsMapToMesh) {}
};
class ParserNoMapToMeshTest : public ParserTestBase {
public:
ParserNoMapToMeshTest() : ParserTestBase(Parser::kDoesNotSupportMapToMesh) {}
};
// TODO: Test every reduction that has semantic action.
TEST_F(ParserTest, ParsesEmptyInput) {
scoped_refptr<cssom::CSSStyleSheet> style_sheet =
parser_.ParseStyleSheet("", source_location_);
ASSERT_TRUE(style_sheet);
EXPECT_EQ(0, style_sheet->css_rules_same_origin()->length());
}
TEST_F(ParserTest, HandlesInvalidAtRuleEndsWithSemicolons) {
EXPECT_CALL(
parser_observer_,
OnWarning(
"[object ParserTest]:1:1: warning: invalid rule @casino-royale"));
scoped_refptr<cssom::CSSStyleSheet> style_sheet =
parser_.ParseStyleSheet("@casino-royale;", source_location_);
ASSERT_TRUE(style_sheet);
EXPECT_EQ(0, style_sheet->css_rules_same_origin()->length());
}
TEST_F(ParserTest, HandlesInvalidAtRuleWithoutSemicolonsAtTheEndOfFile) {
EXPECT_CALL(
parser_observer_,
OnWarning(
"[object ParserTest]:1:1: warning: invalid rule @casino-royale"));
scoped_refptr<cssom::CSSStyleSheet> style_sheet =
parser_.ParseStyleSheet("@casino-royale", source_location_);
ASSERT_TRUE(style_sheet);
EXPECT_EQ(0, style_sheet->css_rules_same_origin()->length());
}
TEST_F(ParserTest, HandlesInvalidAtRuleWithNoMatchingEndBrace) {
EXPECT_CALL(
parser_observer_,
OnWarning(
"[object ParserTest]:1:1: warning: invalid rule @casino-royale"));
scoped_refptr<cssom::CSSStyleSheet> style_sheet =
parser_.ParseStyleSheet("@casino-royale }", source_location_);
ASSERT_TRUE(style_sheet);
EXPECT_EQ(0, style_sheet->css_rules_same_origin()->length());
}
TEST_F(ParserTest, ComputesErrorLocationOnFirstLine) {
EXPECT_CALL(
parser_observer_,
OnError("[object ParserTest]:10:18: error: unrecoverable syntax error"));
scoped_refptr<cssom::CSSStyleSheet> style_sheet = parser_.ParseStyleSheet(
"cucumber", base::SourceLocation("[object ParserTest]", 10, 10));
ASSERT_TRUE(style_sheet);
EXPECT_EQ(0, style_sheet->css_rules_same_origin()->length());
}
TEST_F(ParserTest, ComputesErrorLocationOnSecondLine) {
EXPECT_CALL(
parser_observer_,
OnError("[object ParserTest]:11:9: error: unrecoverable syntax error"));
scoped_refptr<cssom::CSSStyleSheet> style_sheet = parser_.ParseStyleSheet(
"\n"
"cucumber",
base::SourceLocation("[object ParserTest]", 10, 10));
ASSERT_TRUE(style_sheet);
EXPECT_EQ(0, style_sheet->css_rules_same_origin()->length());
}
TEST_F(ParserTest, IgnoresSgmlCommentDelimiters) {
scoped_refptr<cssom::CSSStyleSheet> style_sheet =
parser_.ParseStyleSheet("<!-- body {} -->", source_location_);
ASSERT_TRUE(style_sheet);
EXPECT_EQ(1, style_sheet->css_rules_same_origin()->length());
}
TEST_F(ParserTest, RecoversFromInvalidAtToken) {
EXPECT_CALL(
parser_observer_,
OnWarning(
"[object ParserTest]:1:9: warning: invalid rule @cobalt-magic"));
scoped_refptr<cssom::CSSStyleSheet> style_sheet = parser_.ParseStyleSheet(
"body {} @cobalt-magic; div {}", source_location_);
ASSERT_TRUE(style_sheet);
EXPECT_EQ(2, style_sheet->css_rules_same_origin()->length());
}
TEST_F(ParserTest, RecoversFromInvalidRuleWhichEndsWithSemicolon) {
EXPECT_CALL(
parser_observer_,
OnWarning("[object ParserTest]:1:9: warning: invalid rule @charset"));
scoped_refptr<cssom::CSSStyleSheet> style_sheet = parser_.ParseStyleSheet(
"body {} @charset 'utf-8'; div {}", source_location_);
ASSERT_TRUE(style_sheet);
EXPECT_EQ(2, style_sheet->css_rules_same_origin()->length());
}
TEST_F(ParserTest, RecoversFromInvalidRuleWhichEndsWithBlock) {
EXPECT_CALL(
parser_observer_,
OnWarning("[object ParserTest]:1:9: warning: invalid qualified rule"));
scoped_refptr<cssom::CSSStyleSheet> style_sheet =
parser_.ParseStyleSheet("body {} !important {} div {}", source_location_);
ASSERT_TRUE(style_sheet);
EXPECT_EQ(2, style_sheet->css_rules_same_origin()->length());
}
TEST_F(ParserTest, SemicolonsDonotEndQualifiedRules) {
EXPECT_CALL(
parser_observer_,
OnWarning("[object ParserTest]:1:1: warning: invalid qualified rule"));
scoped_refptr<cssom::CSSStyleSheet> style_sheet =
parser_.ParseStyleSheet("foo; bar {} div {}", source_location_);
ASSERT_TRUE(style_sheet);
EXPECT_EQ(1, style_sheet->css_rules_same_origin()->length());
}
TEST_F(ParserTest, ParsesAttributeSelectorNoValue) {
scoped_refptr<cssom::CSSStyleSheet> style_sheet =
parser_.ParseStyleSheet("[attr] {}", source_location_);
ASSERT_EQ(1, style_sheet->css_rules_same_origin()->length());
ASSERT_EQ(cssom::CSSRule::kStyleRule,
style_sheet->css_rules_same_origin()->Item(0)->type());
cssom::CSSStyleRule* style_rule = static_cast<cssom::CSSStyleRule*>(
style_sheet->css_rules_same_origin()->Item(0).get());
ASSERT_EQ(1, style_rule->selectors().size());
cssom::ComplexSelector* complex_selector =
dynamic_cast<cssom::ComplexSelector*>(
const_cast<cssom::Selector*>(style_rule->selectors()[0].get()));
ASSERT_TRUE(complex_selector);
cssom::CompoundSelector* compound_selector =
complex_selector->first_selector();
ASSERT_TRUE(compound_selector);
ASSERT_EQ(1, compound_selector->simple_selectors().size());
cssom::AttributeSelector* attribute_selector =
dynamic_cast<cssom::AttributeSelector*>(
const_cast<cssom::SimpleSelector*>(
compound_selector->simple_selectors()[0].get()));
ASSERT_TRUE(attribute_selector);
EXPECT_EQ("attr", attribute_selector->attribute_name());
}
TEST_F(ParserTest, ParsesAttributeSelectorValueWithQuotes) {
scoped_refptr<cssom::CSSStyleSheet> style_sheet =
parser_.ParseStyleSheet("[attr=\"value\"] {}", source_location_);
ASSERT_EQ(1, style_sheet->css_rules_same_origin()->length());
ASSERT_EQ(cssom::CSSRule::kStyleRule,
style_sheet->css_rules_same_origin()->Item(0)->type());
cssom::CSSStyleRule* style_rule = static_cast<cssom::CSSStyleRule*>(
style_sheet->css_rules_same_origin()->Item(0).get());
ASSERT_EQ(1, style_rule->selectors().size());
cssom::ComplexSelector* complex_selector =
dynamic_cast<cssom::ComplexSelector*>(
const_cast<cssom::Selector*>(style_rule->selectors()[0].get()));
ASSERT_TRUE(complex_selector);
cssom::CompoundSelector* compound_selector =
complex_selector->first_selector();
ASSERT_TRUE(compound_selector);
ASSERT_EQ(1, compound_selector->simple_selectors().size());
cssom::AttributeSelector* attribute_selector =
dynamic_cast<cssom::AttributeSelector*>(
const_cast<cssom::SimpleSelector*>(
compound_selector->simple_selectors()[0].get()));
ASSERT_TRUE(attribute_selector);
EXPECT_EQ("attr", attribute_selector->attribute_name());
EXPECT_EQ("value", attribute_selector->attribute_value());
}
TEST_F(ParserTest, ParsesAttributeSelectorValueWithoutQuotes) {
scoped_refptr<cssom::CSSStyleSheet> style_sheet =
parser_.ParseStyleSheet("[attr=value] {}", source_location_);
ASSERT_EQ(1, style_sheet->css_rules_same_origin()->length());
ASSERT_EQ(cssom::CSSRule::kStyleRule,
style_sheet->css_rules_same_origin()->Item(0)->type());
cssom::CSSStyleRule* style_rule = static_cast<cssom::CSSStyleRule*>(
style_sheet->css_rules_same_origin()->Item(0).get());
ASSERT_EQ(1, style_rule->selectors().size());
cssom::ComplexSelector* complex_selector =
dynamic_cast<cssom::ComplexSelector*>(
const_cast<cssom::Selector*>(style_rule->selectors()[0].get()));
ASSERT_TRUE(complex_selector);
cssom::CompoundSelector* compound_selector =
complex_selector->first_selector();
ASSERT_TRUE(compound_selector);
ASSERT_EQ(1, compound_selector->simple_selectors().size());
cssom::AttributeSelector* attribute_selector =
dynamic_cast<cssom::AttributeSelector*>(
const_cast<cssom::SimpleSelector*>(
compound_selector->simple_selectors()[0].get()));
ASSERT_TRUE(attribute_selector);
EXPECT_EQ("attr", attribute_selector->attribute_name());
EXPECT_EQ("value", attribute_selector->attribute_value());
}
TEST_F(ParserTest, ParsesClassSelector) {
scoped_refptr<cssom::CSSStyleSheet> style_sheet =
parser_.ParseStyleSheet(".my-class {}", source_location_);
ASSERT_EQ(1, style_sheet->css_rules_same_origin()->length());
ASSERT_EQ(cssom::CSSRule::kStyleRule,
style_sheet->css_rules_same_origin()->Item(0)->type());
cssom::CSSStyleRule* style_rule = static_cast<cssom::CSSStyleRule*>(
style_sheet->css_rules_same_origin()->Item(0).get());
ASSERT_EQ(1, style_rule->selectors().size());
cssom::ComplexSelector* complex_selector =
dynamic_cast<cssom::ComplexSelector*>(
const_cast<cssom::Selector*>(style_rule->selectors()[0].get()));
ASSERT_TRUE(complex_selector);
cssom::CompoundSelector* compound_selector =
complex_selector->first_selector();
ASSERT_TRUE(compound_selector);
ASSERT_EQ(1, compound_selector->simple_selectors().size());
cssom::ClassSelector* class_selector =
dynamic_cast<cssom::ClassSelector*>(const_cast<cssom::SimpleSelector*>(
compound_selector->simple_selectors()[0].get()));
ASSERT_TRUE(class_selector);
EXPECT_EQ("my-class", class_selector->class_name());
}
TEST_F(ParserTest, ParsesPropertyKeyAsClassSelector) {
for (int i = 0; i < 1 + cssom::kMaxEveryPropertyKey; i++) {
cssom::PropertyKey property_key = static_cast<cssom::PropertyKey>(i);
std::string property_name = cssom::GetPropertyName(property_key);
std::string declaration =
base::StringPrintf(".%s {}", property_name.c_str());
scoped_refptr<cssom::CSSStyleSheet> style_sheet =
parser_.ParseStyleSheet(declaration, source_location_);
ASSERT_EQ(1, style_sheet->css_rules_same_origin()->length());
ASSERT_EQ(cssom::CSSRule::kStyleRule,
style_sheet->css_rules_same_origin()->Item(0)->type());
cssom::CSSStyleRule* style_rule = static_cast<cssom::CSSStyleRule*>(
style_sheet->css_rules_same_origin()->Item(0).get());
ASSERT_EQ(1, style_rule->selectors().size());
cssom::ComplexSelector* complex_selector =
dynamic_cast<cssom::ComplexSelector*>(
const_cast<cssom::Selector*>(style_rule->selectors()[0].get()));
ASSERT_TRUE(complex_selector);
cssom::CompoundSelector* compound_selector =
complex_selector->first_selector();
ASSERT_TRUE(compound_selector);
ASSERT_EQ(1, compound_selector->simple_selectors().size());
cssom::ClassSelector* class_selector =
dynamic_cast<cssom::ClassSelector*>(const_cast<cssom::SimpleSelector*>(
compound_selector->simple_selectors()[0].get()));
ASSERT_TRUE(class_selector);
EXPECT_EQ(property_name, class_selector->class_name());
}
}
TEST_F(ParserTest, ParsesKeywordAsClassSelector) {
for (int i = 0; i < 1 + cssom::KeywordValue::kMaxKeywordValue; i++) {
cssom::KeywordValue::Value keyword_value =
static_cast<cssom::KeywordValue::Value>(i);
std::string keyword_name = cssom::KeywordValue::GetName(keyword_value);
std::string declaration =
base::StringPrintf(".%s {}", keyword_name.c_str());
scoped_refptr<cssom::CSSStyleSheet> style_sheet =
parser_.ParseStyleSheet(declaration, source_location_);
ASSERT_EQ(1, style_sheet->css_rules_same_origin()->length());
ASSERT_EQ(cssom::CSSRule::kStyleRule,
style_sheet->css_rules_same_origin()->Item(0)->type());
cssom::CSSStyleRule* style_rule = static_cast<cssom::CSSStyleRule*>(
style_sheet->css_rules_same_origin()->Item(0).get());
ASSERT_EQ(1, style_rule->selectors().size());
cssom::ComplexSelector* complex_selector =
dynamic_cast<cssom::ComplexSelector*>(
const_cast<cssom::Selector*>(style_rule->selectors()[0].get()));
ASSERT_TRUE(complex_selector);
cssom::CompoundSelector* compound_selector =
complex_selector->first_selector();
ASSERT_TRUE(compound_selector);
ASSERT_EQ(1, compound_selector->simple_selectors().size());
cssom::ClassSelector* class_selector =
dynamic_cast<cssom::ClassSelector*>(const_cast<cssom::SimpleSelector*>(
compound_selector->simple_selectors()[0].get()));
ASSERT_TRUE(class_selector);
EXPECT_EQ(keyword_name, class_selector->class_name());
}
}
TEST_F(ParserTest, ParsesAfterPseudoElementCSS2) {
scoped_refptr<cssom::CSSStyleSheet> style_sheet =
parser_.ParseStyleSheet(":after {}", source_location_);
ASSERT_EQ(1, style_sheet->css_rules_same_origin()->length());
ASSERT_EQ(cssom::CSSRule::kStyleRule,
style_sheet->css_rules_same_origin()->Item(0)->type());
cssom::CSSStyleRule* style_rule = static_cast<cssom::CSSStyleRule*>(
style_sheet->css_rules_same_origin()->Item(0).get());
ASSERT_EQ(1, style_rule->selectors().size());
cssom::ComplexSelector* complex_selector =
dynamic_cast<cssom::ComplexSelector*>(
const_cast<cssom::Selector*>(style_rule->selectors()[0].get()));
ASSERT_TRUE(complex_selector);
cssom::CompoundSelector* compound_selector =
complex_selector->first_selector();
ASSERT_TRUE(compound_selector);
ASSERT_EQ(1, compound_selector->simple_selectors().size());
cssom::AfterPseudoElement* after_pseudo_element =
dynamic_cast<cssom::AfterPseudoElement*>(
const_cast<cssom::SimpleSelector*>(
compound_selector->simple_selectors()[0].get()));
ASSERT_TRUE(after_pseudo_element);
}
TEST_F(ParserTest, ParsesAfterPseudoElementCSS3) {
scoped_refptr<cssom::CSSStyleSheet> style_sheet =
parser_.ParseStyleSheet("::after {}", source_location_);
ASSERT_EQ(1, style_sheet->css_rules_same_origin()->length());
ASSERT_EQ(cssom::CSSRule::kStyleRule,
style_sheet->css_rules_same_origin()->Item(0)->type());
cssom::CSSStyleRule* style_rule = static_cast<cssom::CSSStyleRule*>(
style_sheet->css_rules_same_origin()->Item(0).get());
ASSERT_EQ(1, style_rule->selectors().size());
cssom::ComplexSelector* complex_selector =
dynamic_cast<cssom::ComplexSelector*>(
const_cast<cssom::Selector*>(style_rule->selectors()[0].get()));
ASSERT_TRUE(complex_selector);
cssom::CompoundSelector* compound_selector =
complex_selector->first_selector();
ASSERT_TRUE(compound_selector);
ASSERT_EQ(1, compound_selector->simple_selectors().size());
cssom::AfterPseudoElement* after_pseudo_element =
dynamic_cast<cssom::AfterPseudoElement*>(
const_cast<cssom::SimpleSelector*>(
compound_selector->simple_selectors()[0].get()));
ASSERT_TRUE(after_pseudo_element);
}
TEST_F(ParserTest, ParsesBeforePseudoElementCSS2) {
scoped_refptr<cssom::CSSStyleSheet> style_sheet =
parser_.ParseStyleSheet(":before {}", source_location_);
ASSERT_EQ(1, style_sheet->css_rules_same_origin()->length());
ASSERT_EQ(cssom::CSSRule::kStyleRule,
style_sheet->css_rules_same_origin()->Item(0)->type());
cssom::CSSStyleRule* style_rule = static_cast<cssom::CSSStyleRule*>(
style_sheet->css_rules_same_origin()->Item(0).get());
ASSERT_EQ(1, style_rule->selectors().size());
cssom::ComplexSelector* complex_selector =
dynamic_cast<cssom::ComplexSelector*>(
const_cast<cssom::Selector*>(style_rule->selectors()[0].get()));
ASSERT_TRUE(complex_selector);
cssom::CompoundSelector* compound_selector =
complex_selector->first_selector();
ASSERT_TRUE(compound_selector);
ASSERT_EQ(1, compound_selector->simple_selectors().size());
cssom::BeforePseudoElement* before_pseudo_element =
dynamic_cast<cssom::BeforePseudoElement*>(
const_cast<cssom::SimpleSelector*>(
compound_selector->simple_selectors()[0].get()));
ASSERT_TRUE(before_pseudo_element);
}
TEST_F(ParserTest, ParsesBeforePseudoElementCSS3) {
scoped_refptr<cssom::CSSStyleSheet> style_sheet =
parser_.ParseStyleSheet("::before {}", source_location_);
ASSERT_EQ(1, style_sheet->css_rules_same_origin()->length());
ASSERT_EQ(cssom::CSSRule::kStyleRule,
style_sheet->css_rules_same_origin()->Item(0)->type());
cssom::CSSStyleRule* style_rule = static_cast<cssom::CSSStyleRule*>(
style_sheet->css_rules_same_origin()->Item(0).get());
ASSERT_EQ(1, style_rule->selectors().size());
cssom::ComplexSelector* complex_selector =
dynamic_cast<cssom::ComplexSelector*>(
const_cast<cssom::Selector*>(style_rule->selectors()[0].get()));
ASSERT_TRUE(complex_selector);
cssom::CompoundSelector* compound_selector =
complex_selector->first_selector();
ASSERT_TRUE(compound_selector);
ASSERT_EQ(1, compound_selector->simple_selectors().size());
cssom::BeforePseudoElement* before_pseudo_element =
dynamic_cast<cssom::BeforePseudoElement*>(
const_cast<cssom::SimpleSelector*>(
compound_selector->simple_selectors()[0].get()));
ASSERT_TRUE(before_pseudo_element);
}
TEST_F(ParserTest, ParsesActivePseudoClass) {
scoped_refptr<cssom::CSSStyleSheet> style_sheet =
parser_.ParseStyleSheet(":active {}", source_location_);
ASSERT_EQ(1, style_sheet->css_rules_same_origin()->length());
ASSERT_EQ(cssom::CSSRule::kStyleRule,
style_sheet->css_rules_same_origin()->Item(0)->type());
cssom::CSSStyleRule* style_rule = static_cast<cssom::CSSStyleRule*>(
style_sheet->css_rules_same_origin()->Item(0).get());
ASSERT_EQ(1, style_rule->selectors().size());
cssom::ComplexSelector* complex_selector =
dynamic_cast<cssom::ComplexSelector*>(
const_cast<cssom::Selector*>(style_rule->selectors()[0].get()));
ASSERT_TRUE(complex_selector);
cssom::CompoundSelector* compound_selector =
complex_selector->first_selector();
ASSERT_TRUE(compound_selector);
ASSERT_EQ(1, compound_selector->simple_selectors().size());
cssom::ActivePseudoClass* active_pseudo_class =
dynamic_cast<cssom::ActivePseudoClass*>(
const_cast<cssom::SimpleSelector*>(
compound_selector->simple_selectors()[0].get()));
ASSERT_TRUE(active_pseudo_class);
}
TEST_F(ParserTest, ParsesEmptyPseudoClass) {
scoped_refptr<cssom::CSSStyleSheet> style_sheet =
parser_.ParseStyleSheet(":empty {}", source_location_);
ASSERT_EQ(1, style_sheet->css_rules_same_origin()->length());
ASSERT_EQ(cssom::CSSRule::kStyleRule,
style_sheet->css_rules_same_origin()->Item(0)->type());
cssom::CSSStyleRule* style_rule = static_cast<cssom::CSSStyleRule*>(
style_sheet->css_rules_same_origin()->Item(0).get());
ASSERT_EQ(1, style_rule->selectors().size());
cssom::ComplexSelector* complex_selector =
dynamic_cast<cssom::ComplexSelector*>(
const_cast<cssom::Selector*>(style_rule->selectors()[0].get()));
ASSERT_TRUE(complex_selector);
cssom::CompoundSelector* compound_selector =
complex_selector->first_selector();
ASSERT_TRUE(compound_selector);
ASSERT_EQ(1, compound_selector->simple_selectors().size());
cssom::EmptyPseudoClass* empty_pseudo_class =
dynamic_cast<cssom::EmptyPseudoClass*>(const_cast<cssom::SimpleSelector*>(
compound_selector->simple_selectors()[0].get()));
ASSERT_TRUE(empty_pseudo_class);
}
TEST_F(ParserTest, ParsesFocusPseudoClass) {
scoped_refptr<cssom::CSSStyleSheet> style_sheet =
parser_.ParseStyleSheet(":focus {}", source_location_);
ASSERT_EQ(1, style_sheet->css_rules_same_origin()->length());
ASSERT_EQ(cssom::CSSRule::kStyleRule,
style_sheet->css_rules_same_origin()->Item(0)->type());
cssom::CSSStyleRule* style_rule = static_cast<cssom::CSSStyleRule*>(
style_sheet->css_rules_same_origin()->Item(0).get());
ASSERT_EQ(1, style_rule->selectors().size());
cssom::ComplexSelector* complex_selector =
dynamic_cast<cssom::ComplexSelector*>(
const_cast<cssom::Selector*>(style_rule->selectors()[0].get()));
ASSERT_TRUE(complex_selector);
cssom::CompoundSelector* compound_selector =
complex_selector->first_selector();
ASSERT_TRUE(compound_selector);
ASSERT_EQ(1, compound_selector->simple_selectors().size());
cssom::FocusPseudoClass* focus_pseudo_class =
dynamic_cast<cssom::FocusPseudoClass*>(const_cast<cssom::SimpleSelector*>(
compound_selector->simple_selectors()[0].get()));
ASSERT_TRUE(focus_pseudo_class);
}
TEST_F(ParserTest, ParsesHoverPseudoClass) {
scoped_refptr<cssom::CSSStyleSheet> style_sheet =
parser_.ParseStyleSheet(":hover {}", source_location_);
ASSERT_EQ(1, style_sheet->css_rules_same_origin()->length());
ASSERT_EQ(cssom::CSSRule::kStyleRule,
style_sheet->css_rules_same_origin()->Item(0)->type());
cssom::CSSStyleRule* style_rule = static_cast<cssom::CSSStyleRule*>(
style_sheet->css_rules_same_origin()->Item(0).get());
ASSERT_EQ(1, style_rule->selectors().size());
cssom::ComplexSelector* complex_selector =
dynamic_cast<cssom::ComplexSelector*>(
const_cast<cssom::Selector*>(style_rule->selectors()[0].get()));
ASSERT_TRUE(complex_selector);
cssom::CompoundSelector* compound_selector =
complex_selector->first_selector();
ASSERT_TRUE(compound_selector);
ASSERT_EQ(1, compound_selector->simple_selectors().size());
cssom::HoverPseudoClass* hover_pseudo_class =
dynamic_cast<cssom::HoverPseudoClass*>(const_cast<cssom::SimpleSelector*>(
compound_selector->simple_selectors()[0].get()));
ASSERT_TRUE(hover_pseudo_class);
}
TEST_F(ParserTest, ParsesNotPseudoClass) {
scoped_refptr<cssom::CSSStyleSheet> style_sheet =
parser_.ParseStyleSheet(":not(div.my-class) {}", source_location_);
ASSERT_EQ(1, style_sheet->css_rules_same_origin()->length());
ASSERT_EQ(cssom::CSSRule::kStyleRule,
style_sheet->css_rules_same_origin()->Item(0)->type());
cssom::CSSStyleRule* style_rule = static_cast<cssom::CSSStyleRule*>(
style_sheet->css_rules_same_origin()->Item(0).get());
ASSERT_EQ(1, style_rule->selectors().size());
cssom::ComplexSelector* complex_selector =
dynamic_cast<cssom::ComplexSelector*>(
const_cast<cssom::Selector*>(style_rule->selectors()[0].get()));
ASSERT_TRUE(complex_selector);
cssom::CompoundSelector* compound_selector =
complex_selector->first_selector();
ASSERT_TRUE(compound_selector);
ASSERT_EQ(1, compound_selector->simple_selectors().size());
cssom::NotPseudoClass* not_pseudo_class =
dynamic_cast<cssom::NotPseudoClass*>(const_cast<cssom::SimpleSelector*>(
compound_selector->simple_selectors()[0].get()));
ASSERT_TRUE(not_pseudo_class);
// Check the selector within :not pseudo class.
cssom::CompoundSelector* not_compound_selector = not_pseudo_class->selector();
ASSERT_TRUE(not_compound_selector);
ASSERT_EQ(2, not_compound_selector->simple_selectors().size());
cssom::TypeSelector* type_selector =
dynamic_cast<cssom::TypeSelector*>(const_cast<cssom::SimpleSelector*>(
not_compound_selector->simple_selectors()[0].get()));
ASSERT_TRUE(type_selector);
EXPECT_EQ("div", type_selector->element_name());
cssom::ClassSelector* class_selector =
dynamic_cast<cssom::ClassSelector*>(const_cast<cssom::SimpleSelector*>(
not_compound_selector->simple_selectors()[1].get()));
ASSERT_TRUE(class_selector);
EXPECT_EQ("my-class", class_selector->class_name());
}
TEST_F(ParserTest, ParsesNotPseudoClassShouldNotTakeEmptyParameter) {
EXPECT_CALL(parser_observer_,
OnWarning("[object ParserTest]:1:1: warning: unsupported "
"selector within :not()"));
scoped_refptr<cssom::CSSStyleSheet> style_sheet =
parser_.ParseStyleSheet(":not() {}", source_location_);
EXPECT_EQ(0, style_sheet->css_rules_same_origin()->length());
}
TEST_F(ParserTest, ParsesNotPseudoClassShouldNotTakeComplexSelector) {
EXPECT_CALL(parser_observer_,
OnWarning("[object ParserTest]:1:1: warning: unsupported "
"selector within :not()"));
scoped_refptr<cssom::CSSStyleSheet> style_sheet =
parser_.ParseStyleSheet(":not(div span) {}", source_location_);
EXPECT_EQ(0, style_sheet->css_rules_same_origin()->length());
}
TEST_F(ParserTest, ParsesIdSelector) {
scoped_refptr<cssom::CSSStyleSheet> style_sheet =
parser_.ParseStyleSheet("#my-id {}", source_location_);
ASSERT_EQ(1, style_sheet->css_rules_same_origin()->length());
ASSERT_EQ(cssom::CSSRule::kStyleRule,
style_sheet->css_rules_same_origin()->Item(0)->type());
cssom::CSSStyleRule* style_rule = static_cast<cssom::CSSStyleRule*>(
style_sheet->css_rules_same_origin()->Item(0).get());
ASSERT_EQ(1, style_rule->selectors().size());
cssom::ComplexSelector* complex_selector =
dynamic_cast<cssom::ComplexSelector*>(
const_cast<cssom::Selector*>(style_rule->selectors()[0].get()));
ASSERT_TRUE(complex_selector);
cssom::CompoundSelector* compound_selector =
complex_selector->first_selector();
ASSERT_TRUE(compound_selector);
ASSERT_EQ(1, compound_selector->simple_selectors().size());
cssom::IdSelector* id_selector =
dynamic_cast<cssom::IdSelector*>(const_cast<cssom::SimpleSelector*>(
compound_selector->simple_selectors()[0].get()));
ASSERT_TRUE(id_selector);
EXPECT_EQ("my-id", id_selector->id());
}
TEST_F(ParserTest, ParsesTypeSelector) {
scoped_refptr<cssom::CSSStyleSheet> style_sheet =
parser_.ParseStyleSheet("div {}", source_location_);
ASSERT_EQ(1, style_sheet->css_rules_same_origin()->length());
ASSERT_EQ(cssom::CSSRule::kStyleRule,
style_sheet->css_rules_same_origin()->Item(0)->type());
cssom::CSSStyleRule* style_rule = static_cast<cssom::CSSStyleRule*>(
style_sheet->css_rules_same_origin()->Item(0).get());
ASSERT_EQ(1, style_rule->selectors().size());
cssom::ComplexSelector* complex_selector =
dynamic_cast<cssom::ComplexSelector*>(
const_cast<cssom::Selector*>(style_rule->selectors()[0].get()));
ASSERT_TRUE(complex_selector);
cssom::CompoundSelector* compound_selector =
complex_selector->first_selector();
ASSERT_TRUE(compound_selector);
ASSERT_EQ(1, compound_selector->simple_selectors().size());
cssom::TypeSelector* type_selector =
dynamic_cast<cssom::TypeSelector*>(const_cast<cssom::SimpleSelector*>(
compound_selector->simple_selectors()[0].get()));
ASSERT_TRUE(type_selector);
EXPECT_EQ("div", type_selector->element_name());
}
TEST_F(ParserTest, ParsesUniversalSelector) {
scoped_refptr<cssom::CSSStyleSheet> style_sheet =
parser_.ParseStyleSheet("* {}", source_location_);
ASSERT_EQ(1, style_sheet->css_rules_same_origin()->length());
ASSERT_EQ(cssom::CSSRule::kStyleRule,
style_sheet->css_rules_same_origin()->Item(0)->type());
cssom::CSSStyleRule* style_rule = static_cast<cssom::CSSStyleRule*>(
style_sheet->css_rules_same_origin()->Item(0).get());
ASSERT_EQ(1, style_rule->selectors().size());
cssom::ComplexSelector* complex_selector =
dynamic_cast<cssom::ComplexSelector*>(
const_cast<cssom::Selector*>(style_rule->selectors()[0].get()));
ASSERT_TRUE(complex_selector);
cssom::CompoundSelector* compound_selector =
complex_selector->first_selector();
ASSERT_TRUE(compound_selector);
ASSERT_EQ(1, compound_selector->simple_selectors().size());
cssom::UniversalSelector* universal_selector =
dynamic_cast<cssom::UniversalSelector*>(
const_cast<cssom::SimpleSelector*>(
compound_selector->simple_selectors()[0].get()));
ASSERT_TRUE(universal_selector);
}
TEST_F(ParserTest, ParsesCompoundSelector) {
scoped_refptr<cssom::CSSStyleSheet> style_sheet =
parser_.ParseStyleSheet("div.my-class {}", source_location_);
ASSERT_EQ(1, style_sheet->css_rules_same_origin()->length());
ASSERT_EQ(cssom::CSSRule::kStyleRule,
style_sheet->css_rules_same_origin()->Item(0)->type());
cssom::CSSStyleRule* style_rule = static_cast<cssom::CSSStyleRule*>(
style_sheet->css_rules_same_origin()->Item(0).get());
ASSERT_EQ(1, style_rule->selectors().size());
cssom::ComplexSelector* complex_selector =
dynamic_cast<cssom::ComplexSelector*>(
const_cast<cssom::Selector*>(style_rule->selectors()[0].get()));
ASSERT_TRUE(complex_selector);
cssom::CompoundSelector* compound_selector =
complex_selector->first_selector();
ASSERT_TRUE(compound_selector);
ASSERT_EQ(2, compound_selector->simple_selectors().size());
cssom::TypeSelector* type_selector =
dynamic_cast<cssom::TypeSelector*>(const_cast<cssom::SimpleSelector*>(
compound_selector->simple_selectors()[0].get()));
ASSERT_TRUE(type_selector);
EXPECT_EQ("div", type_selector->element_name());
cssom::ClassSelector* class_selector =
dynamic_cast<cssom::ClassSelector*>(const_cast<cssom::SimpleSelector*>(
compound_selector->simple_selectors()[1].get()));
ASSERT_TRUE(class_selector);
EXPECT_EQ("my-class", class_selector->class_name());
}
TEST_F(ParserTest, ParsesComplexSelectorDescendantCombinator) {
scoped_refptr<cssom::CSSStyleSheet> style_sheet =
parser_.ParseStyleSheet("div div {}", source_location_);
ASSERT_EQ(1, style_sheet->css_rules_same_origin()->length());
ASSERT_EQ(cssom::CSSRule::kStyleRule,
style_sheet->css_rules_same_origin()->Item(0)->type());
cssom::CSSStyleRule* style_rule = static_cast<cssom::CSSStyleRule*>(
style_sheet->css_rules_same_origin()->Item(0).get());
ASSERT_EQ(1, style_rule->selectors().size());
cssom::ComplexSelector* complex_selector =
dynamic_cast<cssom::ComplexSelector*>(
const_cast<cssom::Selector*>(style_rule->selectors()[0].get()));
ASSERT_TRUE(complex_selector);
ASSERT_TRUE(complex_selector->first_selector());
cssom::CompoundSelector* selector = complex_selector->first_selector();
ASSERT_TRUE(selector->right_combinator());
EXPECT_EQ(cssom::kDescendantCombinator,
selector->right_combinator()->GetCombinatorType());
}
TEST_F(ParserTest, ParsesComplexSelectorFollowingSiblingCombinator) {
scoped_refptr<cssom::CSSStyleSheet> style_sheet =
parser_.ParseStyleSheet("div ~ div {}", source_location_);
ASSERT_EQ(1, style_sheet->css_rules_same_origin()->length());
ASSERT_EQ(cssom::CSSRule::kStyleRule,
style_sheet->css_rules_same_origin()->Item(0)->type());
cssom::CSSStyleRule* style_rule = static_cast<cssom::CSSStyleRule*>(
style_sheet->css_rules_same_origin()->Item(0).get());
ASSERT_EQ(1, style_rule->selectors().size());
cssom::ComplexSelector* complex_selector =
dynamic_cast<cssom::ComplexSelector*>(
const_cast<cssom::Selector*>(style_rule->selectors()[0].get()));
ASSERT_TRUE(complex_selector);
ASSERT_TRUE(complex_selector->first_selector());
cssom::CompoundSelector* selector = complex_selector->first_selector();
ASSERT_TRUE(selector->right_combinator());
EXPECT_EQ(cssom::kFollowingSiblingCombinator,
selector->right_combinator()->GetCombinatorType());
}
TEST_F(ParserTest, ParsesComplexSelectorChildCombinator) {
scoped_refptr<cssom::CSSStyleSheet> style_sheet =
parser_.ParseStyleSheet("div > div {}", source_location_);
ASSERT_EQ(1, style_sheet->css_rules_same_origin()->length());
ASSERT_EQ(cssom::CSSRule::kStyleRule,
style_sheet->css_rules_same_origin()->Item(0)->type());
cssom::CSSStyleRule* style_rule = static_cast<cssom::CSSStyleRule*>(
style_sheet->css_rules_same_origin()->Item(0).get());
ASSERT_EQ(1, style_rule->selectors().size());
cssom::ComplexSelector* complex_selector =
dynamic_cast<cssom::ComplexSelector*>(
const_cast<cssom::Selector*>(style_rule->selectors()[0].get()));
ASSERT_TRUE(complex_selector);
ASSERT_TRUE(complex_selector->first_selector());
cssom::CompoundSelector* selector = complex_selector->first_selector();
ASSERT_TRUE(selector->right_combinator());
EXPECT_EQ(cssom::kChildCombinator,
selector->right_combinator()->GetCombinatorType());
}
TEST_F(ParserTest, ParsesComplexSelectorNextSiblingCombinator) {
scoped_refptr<cssom::CSSStyleSheet> style_sheet =
parser_.ParseStyleSheet("div + div {}", source_location_);
ASSERT_EQ(1, style_sheet->css_rules_same_origin()->length());
ASSERT_EQ(cssom::CSSRule::kStyleRule,
style_sheet->css_rules_same_origin()->Item(0)->type());
cssom::CSSStyleRule* style_rule = static_cast<cssom::CSSStyleRule*>(
style_sheet->css_rules_same_origin()->Item(0).get());
ASSERT_EQ(1, style_rule->selectors().size());
cssom::ComplexSelector* complex_selector =
dynamic_cast<cssom::ComplexSelector*>(
const_cast<cssom::Selector*>(style_rule->selectors()[0].get()));
ASSERT_TRUE(complex_selector);
ASSERT_TRUE(complex_selector->first_selector());
cssom::CompoundSelector* selector = complex_selector->first_selector();
ASSERT_TRUE(selector->right_combinator());
EXPECT_EQ(cssom::kNextSiblingCombinator,
selector->right_combinator()->GetCombinatorType());
}
TEST_F(ParserTest, ParsesDeclarationListWithTrailingSemicolon) {
scoped_refptr<cssom::CSSDeclaredStyleData> style =
parser_.ParseStyleDeclarationList(
"color: #0047ab; /* Cobalt blue */\n"
"font-size: 100px;\n",
source_location_);
ASSERT_TRUE(style->IsDeclared(cssom::kColorProperty));
EXPECT_TRUE(style->GetPropertyValue(cssom::kColorProperty));
ASSERT_TRUE(style->IsDeclared(cssom::kFontSizeProperty));
EXPECT_TRUE(style->GetPropertyValue(cssom::kFontSizeProperty));
}
TEST_F(ParserTest, ParsesDeclarationListWithoutTrailingSemicolon) {
scoped_refptr<cssom::CSSDeclaredStyleData> style =
parser_.ParseStyleDeclarationList(
"color: #0047ab;\n"
"font-size: 100px\n",
source_location_);
ASSERT_TRUE(style->IsDeclared(cssom::kColorProperty));
EXPECT_TRUE(style->GetPropertyValue(cssom::kColorProperty));
ASSERT_TRUE(style->IsDeclared(cssom::kFontSizeProperty));
EXPECT_TRUE(style->GetPropertyValue(cssom::kFontSizeProperty));
}
TEST_F(ParserTest, ParsesDeclarationListWithEmptyDeclaration) {
scoped_refptr<cssom::CSSDeclaredStyleData> style =
parser_.ParseStyleDeclarationList(
"color: #0047ab;\n"
";\n"
"font-size: 100px;\n",
source_location_);
ASSERT_TRUE(style->IsDeclared(cssom::kColorProperty));
EXPECT_TRUE(style->GetPropertyValue(cssom::kColorProperty));
ASSERT_TRUE(style->IsDeclared(cssom::kFontSizeProperty));
EXPECT_TRUE(style->GetPropertyValue(cssom::kFontSizeProperty));
}
TEST_F(ParserTest, RecoversFromInvalidPropertyDeclaration) {
EXPECT_CALL(
parser_observer_,
OnWarning("[object ParserTest]:2:1: warning: invalid declaration"));
scoped_refptr<cssom::CSSDeclaredStyleData> style =
parser_.ParseStyleDeclarationList(
"color: #0047ab;\n"
"1px;\n"
"font-size: 100px;\n",
source_location_);
ASSERT_TRUE(style->IsDeclared(cssom::kColorProperty));
EXPECT_TRUE(style->GetPropertyValue(cssom::kColorProperty));
ASSERT_TRUE(style->IsDeclared(cssom::kFontSizeProperty));
EXPECT_TRUE(style->GetPropertyValue(cssom::kFontSizeProperty));
}
TEST_F(ParserTest, HandlesUnsupportedPropertyInStyleDeclarationList) {
EXPECT_CALL(
parser_observer_,
OnWarning(
"[object ParserTest]:1:1: warning: unsupported style property: src"));
scoped_refptr<cssom::CSSDeclaredStyleData> style =
parser_.ParseStyleDeclarationList("src: initial;", source_location_);
EXPECT_EQ(style->length(), 0);
}
TEST_F(ParserTest,
HandlesUnsupportedPropertyInStyleDeclarationListWithSupportedProperty) {
EXPECT_CALL(parser_observer_,
OnWarning("[object ParserTest]:1:1: warning: unsupported style "
"property: unicode-range"));
scoped_refptr<cssom::CSSDeclaredStyleData> style =
parser_.ParseStyleDeclarationList("width: 100px; unicode-range: U+100;",
source_location_);
EXPECT_EQ(style->length(), 1);
ASSERT_TRUE(style->IsDeclared(cssom::kWidthProperty));
scoped_refptr<cssom::LengthValue> width = dynamic_cast<cssom::LengthValue*>(
style->GetPropertyValue(cssom::kWidthProperty).get());
ASSERT_TRUE(width);
EXPECT_EQ(100, width->value());
EXPECT_EQ(cssom::kPixelsUnit, width->unit());
}
TEST_F(ParserTest, SilentlyIgnoresNonWebKitProperties) {
scoped_refptr<cssom::CSSDeclaredStyleData> style =
parser_.ParseStyleDeclarationList(
"-moz-transform: scale(2);\n"
"-ms-transform: scale(2);\n"
"-o-transform: scale(2);\n"
"transform: scale(2);\n",
source_location_);
ASSERT_TRUE(style->IsDeclared(cssom::kTransformProperty));
EXPECT_TRUE(style->GetPropertyValue(cssom::kTransformProperty));
}
TEST_F(ParserTest, WarnsAboutInvalidDeclaration) {
EXPECT_CALL(
parser_observer_,
OnWarning("[object ParserTest]:1:1: warning: unsupported property pony"));
scoped_refptr<cssom::CSSDeclaredStyleData> style =
parser_.ParseStyleDeclarationList(
"pony: rainbowdash;\n"
"color: #9edbf9;\n",
source_location_);
ASSERT_TRUE(style->IsDeclared(cssom::kColorProperty));
scoped_refptr<cssom::RGBAColorValue> color =
dynamic_cast<cssom::RGBAColorValue*>(
style->GetPropertyValue(cssom::kColorProperty).get());
ASSERT_TRUE(color);
EXPECT_EQ(0x9edbf9ff, color->value());
}
TEST_F(ParserTest, WarnsAboutInvalidDeclarationAtTheEndOfBlock) {
EXPECT_CALL(parser_observer_, OnWarning("[object ParserTest]:1:10: warning: "
"unsupported property hallelujah"));
scoped_refptr<cssom::CSSStyleSheet> style_sheet = parser_.ParseStyleSheet(
":empty { hallelujah: rainbowdash }", source_location_);
}
TEST_F(ParserTest, WarnsAboutInvalidPropertyValues) {
EXPECT_CALL(
parser_observer_,
OnWarning("[object ParserTest]:1:19: warning: unsupported value"));
scoped_refptr<cssom::CSSDeclaredStyleData> style =
parser_.ParseStyleDeclarationList(
"background-color: morning haze over Paris;\n"
"color: #fff;\n",
source_location_);
ASSERT_FALSE(style->IsDeclared(cssom::kBackgroundColorProperty));
EXPECT_FALSE(style->GetPropertyValue(cssom::kBackgroundColorProperty));
ASSERT_TRUE(style->IsDeclared(cssom::kColorProperty));
EXPECT_TRUE(style->GetPropertyValue(cssom::kColorProperty));
}
TEST_F(ParserTest, WarnsAboutInvalidAtRule) {
EXPECT_CALL(
parser_observer_,
OnWarning("[object ParserTest]:1:1: warning: invalid rule @wuli-style"));
scoped_refptr<cssom::CSSStyleSheet> style_sheet = parser_.ParseStyleSheet(
"@wuli-style winners-list {"
" from ["
" opacity: 0.6;"
" ]"
" to ["
" opacity: 0.8;"
" ]"
"}\n"
"#my-id {} \n",
source_location_);
EXPECT_EQ(1, style_sheet->css_rules_same_origin()->length());
EXPECT_EQ(cssom::CSSRule::kStyleRule,
style_sheet->css_rules_same_origin()->Item(0)->type());
}
TEST_F(ParserTest, WarnsAboutInvalidAtRuleCurlyBraceInsideOfAnotherBlock) {
EXPECT_CALL(
parser_observer_,
OnWarning("[object ParserTest]:1:1: warning: invalid rule @foo-style"));
scoped_refptr<cssom::CSSStyleSheet> style_sheet = parser_.ParseStyleSheet(
"@foo-style winners-list {"
" from ["
" opacity: 0.6; }"
" ]"
" to ["
" opacity: 0.8;"
" ]"
"}\n"
"#my-id {} \n",
source_location_);
EXPECT_EQ(1, style_sheet->css_rules_same_origin()->length());
EXPECT_EQ(cssom::CSSRule::kStyleRule,
style_sheet->css_rules_same_origin()->Item(0)->type());
}
TEST_F(ParserTest, StyleSheetEndsWhileRuleIsStillOpen) {
scoped_refptr<cssom::CSSStyleSheet> style_sheet = parser_.ParseStyleSheet(
"@keyframes foo3 {"
" from {"
" opacity: 0.6;"
" }"
" to {"
" opacity: 0.8;",
source_location_);
ASSERT_TRUE(style_sheet);
EXPECT_EQ(1, style_sheet->css_rules_same_origin()->length());
cssom::CSSKeyframesRule* keyframes_rule =
dynamic_cast<cssom::CSSKeyframesRule*>(
style_sheet->css_rules_same_origin()->Item(0).get());
ASSERT_TRUE(keyframes_rule);
EXPECT_EQ("foo3", keyframes_rule->name());
ASSERT_EQ(2, keyframes_rule->css_rules()->length());
}
TEST_F(ParserTest, StyleSheetEndsWhileUnrecognizedAtRuleIsStillOpen) {
EXPECT_CALL(
parser_observer_,
OnWarning(
"[object ParserTest]:1:1: warning: invalid rule @user-defined"));
scoped_refptr<cssom::CSSStyleSheet> style_sheet =
parser_.ParseStyleSheet("@user-defined { abc[", source_location_);
}
TEST_F(ParserTest, StyleSheetEndsWhileDeclarationIsStillOpen) {
scoped_refptr<cssom::CSSDeclaredStyleData> style =
parser_.ParseStyleDeclarationList("background-color: inherit",
source_location_);
ASSERT_TRUE(style->IsDeclared(cssom::kBackgroundColorProperty));
EXPECT_EQ(cssom::KeywordValue::GetInherit(),
style->GetPropertyValue(cssom::kBackgroundColorProperty));
}
TEST_F(ParserTest, StyleSheetEndsWhileUrlIsStillOpen) {
scoped_refptr<cssom::CSSDeclaredStyleData> style =
parser_.ParseStyleDeclarationList("background-image: url(foo.png",
source_location_);
ASSERT_TRUE(style->IsDeclared(cssom::kBackgroundImageProperty));
scoped_refptr<cssom::PropertyListValue> background_image_list =
dynamic_cast<cssom::PropertyListValue*>(
style->GetPropertyValue(cssom::kBackgroundImageProperty).get());
ASSERT_TRUE(background_image_list);
EXPECT_EQ(1, background_image_list->value().size());
scoped_refptr<cssom::URLValue> url_value =
dynamic_cast<cssom::URLValue*>(background_image_list->value()[0].get());
EXPECT_EQ("foo.png", url_value->value());
}
TEST_F(ParserTest, StyleSheetEndsWhileFunctionIsStillOpen) {
scoped_refptr<cssom::CSSDeclaredStyleData> style =
parser_.ParseStyleDeclarationList("transform: translateX(20%",
source_location_);
ASSERT_TRUE(style->IsDeclared(cssom::kTransformProperty));
scoped_refptr<cssom::TransformFunctionListValue> transform_list =
dynamic_cast<cssom::TransformFunctionListValue*>(
style->GetPropertyValue(cssom::kTransformProperty).get());
ASSERT_TRUE(transform_list);
EXPECT_FALSE(transform_list->value().HasTrait(kTraitIsDynamic));
EXPECT_FALSE(transform_list->value().HasTrait(kTraitUsesRelativeUnits));
EXPECT_FALSE(transform_list->value().HasTrait(kTraitUsesUiNavFocus));
ASSERT_EQ(1, transform_list->value().size());
const cssom::TranslateFunction* translate_function =
dynamic_cast<const cssom::TranslateFunction*>(
transform_list->value()[0].get());
ASSERT_TRUE(translate_function);
ASSERT_EQ(cssom::TranslateFunction::kPercentage,
translate_function->offset_type());
scoped_refptr<cssom::PercentageValue> offset =
translate_function->offset_as_percentage();
EXPECT_FLOAT_EQ(0.2f, offset->value());
EXPECT_EQ(cssom::TranslateFunction::kXAxis, translate_function->axis());
}
// Test that the keywords supported for a property are parsed into a
// corresponding KeywordValue, FontStyleValue, or FontWeightValue.
TEST_F(ParserTest, ParsesLonghandPropertyKeywords) {
// List of longhand properties and keywords that are parsed to a KeywordValue,
// FontStyleValue, or FontWeightValue that is not computed further during
// parsing. Each longhand property in the enum cssom::PropertyKey has to
// appear here once, in the same order as the enum.
// clang-format off
const char* longhand_property_keywords[] = {
"align-content",
"inherit", "initial", "flex-start", "flex-end", "center", "space-between",
"space-around", "stretch", nullptr,
"align-items",
"inherit", "initial", "flex-start", "flex-end", "center", "baseline",
"stretch", nullptr,
"align-self",
"inherit", "initial", "auto", "flex-start", "flex-end", "center",
"baseline", "stretch", nullptr,
"animation-delay",
"inherit", "initial", nullptr,
"animation-direction",
"inherit", "initial", nullptr,
"animation-duration",
"inherit", "initial", nullptr,
"animation-fill-mode",
"inherit", "initial", nullptr,
"animation-iteration-count",
"inherit", "initial", nullptr,
"animation-name",
"inherit", "initial", nullptr,
"animation-timing-function",
"inherit", "initial", nullptr,
"background-color",
"inherit", "initial", nullptr,
"background-image",
"inherit", "initial", nullptr,
"background-position",
"inherit", "initial", nullptr,
"background-repeat",
"inherit", "initial", nullptr,
"background-size",
"inherit", "initial", "cover", "contain", nullptr,
"border-bottom-color",
"inherit", "initial", nullptr,
"border-bottom-left-radius",
"inherit", "initial", nullptr,
"border-bottom-right-radius",
"inherit", "initial", nullptr,
"border-bottom-style",
"inherit", "initial", "none", "hidden", "solid", nullptr,
"border-bottom-width",
"inherit", "initial", nullptr,
"border-left-color",
"inherit", "initial", nullptr,
"border-left-style",
"inherit", "initial", "none", "hidden", "solid", nullptr,
"border-left-width",
"inherit", "initial", nullptr,
"border-right-color",
"inherit", "initial", nullptr,
"border-right-style",
"inherit", "initial", "none", "hidden", "solid", nullptr,
"border-right-width",
"inherit", "initial", nullptr,
"border-top-color",
"inherit", "initial", nullptr,
"border-top-left-radius",
"inherit", "initial", nullptr,
"border-top-right-radius",
"inherit", "initial", nullptr,
"border-top-style",
"inherit", "initial", "none", "hidden", "solid", nullptr,
"border-top-width",
"inherit", "initial", nullptr,
"bottom",
"inherit", "initial", "auto", nullptr,
"box-shadow",
"inherit", "initial", "none", nullptr,
"color",
"inherit", "initial", nullptr,
"content",
"inherit", "initial", "none", "normal", nullptr,
"display",
"inherit", "initial", "block", "flex", "inline", "inline-block",
"inline-flex", "none", nullptr,
"filter",
"inherit", "initial", "none", nullptr,
"flex-basis",
"inherit", "initial", "auto", "content", nullptr,
"flex-direction",
"inherit", "initial", "row", "row-reverse", "column", "column-reverse",
nullptr,
"flex-grow",
"inherit", "initial", nullptr,
"flex-shrink",
"inherit", "initial", nullptr,
"flex-wrap",
"inherit", "initial", "nowrap", "wrap", "wrap-reverse", nullptr,
"font-family",
"inherit", "initial", nullptr,
"font-size",
"inherit", "initial", nullptr,
"font-style",
"inherit", "initial", "normal", "italic", "oblique", nullptr,
"font-weight",
"inherit", "initial", "bold", nullptr,
"height",
"inherit", "initial", "auto", nullptr,
"intersection-observer-root-margin",
nullptr,
"justify-content",
"inherit", "initial", "flex-start", "flex-end", "center", "space-between",
"space-around", nullptr,
"left",
"inherit", "initial", "auto", nullptr,
"line-height",
"inherit", "initial", "normal", nullptr,
"margin-bottom",
"inherit", "initial", "auto", nullptr,
"margin-left",
"inherit", "initial", "auto", nullptr,
"margin-right",
"inherit", "initial", "auto", nullptr,
"margin-top",
"inherit", "initial", "auto", nullptr,
"max-height",
"inherit", "initial", "none", nullptr,
"max-width",
"inherit", "initial", "none", nullptr,
"min-height",
"inherit", "initial", nullptr,
"min-width",
"inherit", "initial", nullptr,
"opacity",
"inherit", "initial", nullptr,
"order",
"inherit", "initial", nullptr,
"outline-color",
"inherit", "initial", nullptr,
"outline-style",
"inherit", "initial", "solid", "hidden", nullptr,
"outline-width",
"inherit", "initial", nullptr,
"overflow",
"inherit", "initial", "auto", "hidden", "scroll", "visible", nullptr,
"overflow-wrap",
"inherit", "initial", "break-word", "normal", nullptr,
"padding-bottom",
"inherit", "initial", nullptr,
"padding-left",
"inherit", "initial", nullptr,
"padding-right",
"inherit", "initial", nullptr,
"padding-top",
"inherit", "initial", nullptr,
"pointer-events",
"inherit", "initial", "auto", "none", nullptr,
"position",
"inherit", "initial", "static", "relative", "absolute", nullptr,
"right",
"inherit", "initial", "auto", nullptr,
"text-align",
"inherit", "initial", "start", "end", "left", "center", "right", nullptr,
"text-decoration-color",
"inherit", "initial", nullptr,
"text-decoration-line",
"inherit", "initial", "none", "line-through", nullptr,
"text-indent",
"inherit", "initial", nullptr,
"text-overflow",
"inherit", "initial", "clip", "ellipsis", nullptr,
"text-shadow",
"inherit", "initial", "none", nullptr,
"text-transform",
"inherit", "initial", "none", "uppercase", nullptr,
"top",
"inherit", "initial", "auto", nullptr,
"transform-origin",
"inherit", "initial", nullptr,
"transform",
"inherit", "initial", "none", nullptr,
"transition-delay",
"inherit", "initial", nullptr,
"transition-duration",
"inherit", "initial", nullptr,
"transition-property",
"inherit", "initial", nullptr,
"transition-timing-function",
"inherit", "initial", nullptr,
"vertical-align",
"inherit", "initial", "baseline", "bottom", "middle", "top", nullptr,
"visibility",
"inherit", "initial", "collapse", "hidden", "visible", nullptr,
"white-space",
"inherit", "initial", "normal", "nowrap", "pre", "pre-line", "pre-wrap",
nullptr,
"width",
"inherit", "initial", "auto", nullptr,
"z-index",
"inherit", "initial", "auto", nullptr,
nullptr,
};
// clang-format on
// Helper class to check if a PropertyValue is a KeywordValue, FontStyleValue,
// or FontWeightValue.
class KeywordProvider : public cssom::NotReachedPropertyValueVisitor {
public:
KeywordProvider() : is_keyword_(false) {}
bool is_keyword() { return is_keyword_; }
void VisitKeyword(cssom::KeywordValue* keyword) override {
is_keyword_ = true;
}
void VisitFontStyle(cssom::FontStyleValue* font_style) override {
is_keyword_ = true;
}
void VisitFontWeight(cssom::FontWeightValue* font_weight_value) override {
is_keyword_ = true;
}
private:
bool is_keyword_;
DISALLOW_COPY_AND_ASSIGN(KeywordProvider);
};
const char** property_keyword = longhand_property_keywords;
for (int i = 0; i <= cssom::kMaxLonghandPropertyKey;
++i, ++property_keyword) {
const char* property(*property_keyword);
cssom::PropertyKey property_key(static_cast<cssom::PropertyKey>(i));
ASSERT_NE(property, nullptr);
for (++property_keyword; *property_keyword; ++property_keyword) {
const char* keyword = *property_keyword;
std::string declaration =
base::StringPrintf("%s: %s;", property, keyword);
scoped_refptr<cssom::CSSDeclaredStyleData> style =
parser_.ParseStyleDeclarationList(declaration, source_location_);
ASSERT_TRUE(style->IsDeclared(property_key));
scoped_refptr<cssom::PropertyValue> property_value =
style->GetPropertyValue(property_key);
EXPECT_EQ(keyword, property_value->ToString());
KeywordProvider keyword_provider;
property_value->Accept(&keyword_provider);
EXPECT_EQ(true, keyword_provider.is_keyword());
}
}
}
// Test that shorthand properties are parsed into corresponding KeywordValues
// for the expanded properties for values 'inherit' and 'initial'.
TEST_F(ParserTest, ParsesShorthandPropertyInitialAndInherit) {
const char* shorthand_property_keywords[] = {
"inherit", "initial", nullptr,
};
// Helper class to check if a PropertyValue is a KeywordValue.
class KeywordProvider : public cssom::NotReachedPropertyValueVisitor {
public:
KeywordProvider() : is_keyword_(false) {}
bool is_keyword() { return is_keyword_; }
void VisitKeyword(cssom::KeywordValue* keyword) override {
is_keyword_ = true;
}
// Returns true if the property key is a longhand property with a keyword
// value, or is a shorthand property for which all longhand properties have
// keyword values, where all keywords serialize to the given keyword;
static void VerifyIsLongHandKeywordValue(
const scoped_refptr<cssom::CSSDeclaredStyleData>& style,
cssom::PropertyKey property_key, const char* keyword) {
if (!IsShorthandProperty(property_key)) {
// Test that the shorthand property is set and has a keyword value that
// serializes to the keyword name.
ASSERT_TRUE(style->IsDeclared(property_key));
scoped_refptr<cssom::PropertyValue> property_value =
style->GetPropertyValue(property_key);
EXPECT_EQ(keyword, property_value->ToString());
KeywordProvider keyword_provider;
property_value->Accept(&keyword_provider);
EXPECT_EQ(true, keyword_provider.is_keyword());
return;
}
for (auto expanded_property :
cssom::ExpandShorthandProperty(property_key)) {
// Recurse for the longhand properties that this shorthand expands to.
VerifyIsLongHandKeywordValue(style, expanded_property, keyword);
}
}
private:
bool is_keyword_;
DISALLOW_COPY_AND_ASSIGN(KeywordProvider);
};
for (int i = cssom::kFirstShorthandPropertyKey;
i <= cssom::kMaxShorthandPropertyKey; ++i) {
cssom::PropertyKey property_key(static_cast<cssom::PropertyKey>(i));
const char* property = cssom::GetPropertyName(property_key);
ASSERT_NE(property, nullptr);
for (const char** property_keyword = shorthand_property_keywords;
*property_keyword; ++property_keyword) {
const char* keyword = *property_keyword;
std::string declaration =
base::StringPrintf("%s: %s;", property, keyword);
scoped_refptr<cssom::CSSDeclaredStyleData> style =
parser_.ParseStyleDeclarationList(declaration, source_location_);
KeywordProvider::VerifyIsLongHandKeywordValue(style, property_key,
keyword);
}
}
}
TEST_F(ParserTest, ParsesBackgroundWithOnlyColor) {
scoped_refptr<cssom::CSSDeclaredStyleData> style =
parser_.ParseStyleDeclarationList("background: rgba(0, 0, 0, .8);",
source_location_);
ASSERT_TRUE(style->IsDeclared(cssom::kBackgroundColorProperty));
scoped_refptr<cssom::RGBAColorValue> background_color =
dynamic_cast<cssom::RGBAColorValue*>(
style->GetPropertyValue(cssom::kBackgroundColorProperty).get());
ASSERT_TRUE(background_color);
EXPECT_EQ(0x000000cc, background_color->value());
}
TEST_F(ParserTest, ParsesBackgroundWithOnlyRepeat) {
scoped_refptr<cssom::CSSDeclaredStyleData> style =
parser_.ParseStyleDeclarationList("background: no-repeat;",
source_location_);
ASSERT_TRUE(style->IsDeclared(cssom::kBackgroundRepeatProperty));
scoped_refptr<cssom::PropertyListValue> background_repeat_list =
dynamic_cast<cssom::PropertyListValue*>(
style->GetPropertyValue(cssom::kBackgroundRepeatProperty).get());
ASSERT_TRUE(background_repeat_list);
EXPECT_EQ(2, background_repeat_list->value().size());
EXPECT_EQ(cssom::KeywordValue::GetNoRepeat(),
background_repeat_list->value()[0]);
EXPECT_EQ(cssom::KeywordValue::GetNoRepeat(),
background_repeat_list->value()[1]);
}
TEST_F(ParserTest, ParsesBackgroundWithColorAndURL) {
scoped_refptr<cssom::CSSDeclaredStyleData> style =
parser_.ParseStyleDeclarationList(
"background: url(foo.png) rgba(0, 0, 0, .8);", source_location_);
ASSERT_TRUE(style->IsDeclared(cssom::kBackgroundColorProperty));
scoped_refptr<cssom::RGBAColorValue> background_color =
dynamic_cast<cssom::RGBAColorValue*>(
style->GetPropertyValue(cssom::kBackgroundColorProperty).get());
ASSERT_TRUE(background_color);
EXPECT_EQ(0x000000cc, background_color->value());
ASSERT_TRUE(style->IsDeclared(cssom::kBackgroundImageProperty));
scoped_refptr<cssom::PropertyListValue> background_image_list =
dynamic_cast<cssom::PropertyListValue*>(
style->GetPropertyValue(cssom::kBackgroundImageProperty).get());
ASSERT_TRUE(background_image_list);
EXPECT_EQ(1, background_image_list->value().size());
scoped_refptr<cssom::URLValue> url_value =
dynamic_cast<cssom::URLValue*>(background_image_list->value()[0].get());
EXPECT_EQ("foo.png", url_value->value());
}
TEST_F(ParserTest, ParsesBackgroundWithColorAndURLInDifferentOrder) {
scoped_refptr<cssom::CSSDeclaredStyleData> style =
parser_.ParseStyleDeclarationList(
"background: rgba(0, 0, 0, .8) url(foo.png);", source_location_);
ASSERT_TRUE(style->IsDeclared(cssom::kBackgroundColorProperty));
scoped_refptr<cssom::RGBAColorValue> background_color =
dynamic_cast<cssom::RGBAColorValue*>(
style->GetPropertyValue(cssom::kBackgroundColorProperty).get());
ASSERT_TRUE(background_color);
EXPECT_EQ(0x000000cc, background_color->value());
ASSERT_TRUE(style->IsDeclared(cssom::kBackgroundImageProperty));
scoped_refptr<cssom::PropertyListValue> background_image_list =
dynamic_cast<cssom::PropertyListValue*>(
style->GetPropertyValue(cssom::kBackgroundImageProperty).get());
ASSERT_TRUE(background_image_list);
EXPECT_EQ(1, background_image_list->value().size());
scoped_refptr<cssom::URLValue> url_value =
dynamic_cast<cssom::URLValue*>(background_image_list->value()[0].get());
EXPECT_EQ("foo.png", url_value->value());
}
TEST_F(ParserTest, ParsesBackgroundWithColorAndPosition) {
scoped_refptr<cssom::CSSDeclaredStyleData> style =
parser_.ParseStyleDeclarationList(
"background: rgba(0, 0, 0, .8) 70px 45%;", source_location_);
ASSERT_TRUE(style->IsDeclared(cssom::kBackgroundColorProperty));
scoped_refptr<cssom::RGBAColorValue> background_color =
dynamic_cast<cssom::RGBAColorValue*>(
style->GetPropertyValue(cssom::kBackgroundColorProperty).get());
ASSERT_TRUE(background_color);
EXPECT_EQ(0x000000cc, background_color->value());
ASSERT_TRUE(style->IsDeclared(cssom::kBackgroundPositionProperty));
scoped_refptr<cssom::PropertyListValue> background_position_list =
dynamic_cast<cssom::PropertyListValue*>(
style->GetPropertyValue(cssom::kBackgroundPositionProperty).get());
ASSERT_TRUE(background_position_list);
scoped_refptr<cssom::LengthValue> length_value_left =
dynamic_cast<cssom::LengthValue*>(
background_position_list->value()[0].get());
EXPECT_FLOAT_EQ(70, length_value_left->value());
EXPECT_EQ(cssom::kPixelsUnit, length_value_left->unit());
scoped_refptr<cssom::PercentageValue> percentage_value_right =
dynamic_cast<cssom::PercentageValue*>(
background_position_list->value()[1].get());
EXPECT_FLOAT_EQ(0.45f, percentage_value_right->value());
}
TEST_F(ParserTest, ParsesBackgroundWithColorAndPositionInDifferentOrder) {
scoped_refptr<cssom::CSSDeclaredStyleData> style =
parser_.ParseStyleDeclarationList(
"background: 70px 45% rgba(0, 0, 0, .8);", source_location_);
ASSERT_TRUE(style->IsDeclared(cssom::kBackgroundPositionProperty));
scoped_refptr<cssom::PropertyListValue> background_position_list =
dynamic_cast<cssom::PropertyListValue*>(
style->GetPropertyValue(cssom::kBackgroundPositionProperty).get());
ASSERT_TRUE(background_position_list);
scoped_refptr<cssom::LengthValue> length_value_left =
dynamic_cast<cssom::LengthValue*>(
background_position_list->value()[0].get());
EXPECT_FLOAT_EQ(70, length_value_left->value());
EXPECT_EQ(cssom::kPixelsUnit, length_value_left->unit());
scoped_refptr<cssom::PercentageValue> percentage_value_right =
dynamic_cast<cssom::PercentageValue*>(
background_position_list->value()[1].get());
EXPECT_FLOAT_EQ(0.45f, percentage_value_right->value());
ASSERT_TRUE(style->IsDeclared(cssom::kBackgroundColorProperty));
scoped_refptr<cssom::RGBAColorValue> background_color =
dynamic_cast<cssom::RGBAColorValue*>(
style->GetPropertyValue(cssom::kBackgroundColorProperty).get());
ASSERT_TRUE(background_color);
EXPECT_EQ(0x000000cc, background_color->value());
}
TEST_F(ParserTest, ParsesBackgroundWithURLPositionAndSize) {
scoped_refptr<cssom::CSSDeclaredStyleData> style =
parser_.ParseStyleDeclarationList(
"background: url(foo.png) center / 50px 80px;", source_location_);
ASSERT_TRUE(style->IsDeclared(cssom::kBackgroundImageProperty));
scoped_refptr<cssom::PropertyListValue> background_image_list =
dynamic_cast<cssom::PropertyListValue*>(
style->GetPropertyValue(cssom::kBackgroundImageProperty).get());
ASSERT_TRUE(background_image_list);
EXPECT_EQ(1, background_image_list->value().size());
scoped_refptr<cssom::URLValue> url_value =
dynamic_cast<cssom::URLValue*>(background_image_list->value()[0].get());
EXPECT_EQ("foo.png", url_value->value());
ASSERT_TRUE(style->IsDeclared(cssom::kBackgroundPositionProperty));
scoped_refptr<cssom::PropertyListValue> background_position_list =
dynamic_cast<cssom::PropertyListValue*>(
style->GetPropertyValue(cssom::kBackgroundPositionProperty).get());
ASSERT_TRUE(background_position_list);
EXPECT_EQ(1, background_position_list->value().size());
EXPECT_EQ(cssom::KeywordValue::GetCenter(),
background_position_list->value()[0]);
ASSERT_TRUE(style->IsDeclared(cssom::kBackgroundSizeProperty));
scoped_refptr<cssom::PropertyListValue> background_size_list =
dynamic_cast<cssom::PropertyListValue*>(
style->GetPropertyValue(cssom::kBackgroundSizeProperty).get());
ASSERT_TRUE(background_size_list);
scoped_refptr<cssom::LengthValue> size_value_left =
dynamic_cast<cssom::LengthValue*>(background_size_list->value()[0].get());
EXPECT_FLOAT_EQ(50, size_value_left->value());
EXPECT_EQ(cssom::kPixelsUnit, size_value_left->unit());
scoped_refptr<cssom::LengthValue> size_value_right =
dynamic_cast<cssom::LengthValue*>(background_size_list->value()[1].get());
EXPECT_FLOAT_EQ(80, size_value_right->value());
EXPECT_EQ(cssom::kPixelsUnit, size_value_right->unit());
}
TEST_F(ParserTest, ParsesBackgroundWithURLPositionAndSizeInDifferentOrder) {
scoped_refptr<cssom::CSSDeclaredStyleData> style =
parser_.ParseStyleDeclarationList(
"background: center/50px 80px url(foo.png);", source_location_);
ASSERT_TRUE(style->IsDeclared(cssom::kBackgroundImageProperty));
scoped_refptr<cssom::PropertyListValue> background_image_list =
dynamic_cast<cssom::PropertyListValue*>(
style->GetPropertyValue(cssom::kBackgroundImageProperty).get());
ASSERT_TRUE(background_image_list);
EXPECT_EQ(1, background_image_list->value().size());
scoped_refptr<cssom::URLValue> url_value =
dynamic_cast<cssom::URLValue*>(background_image_list->value()[0].get());
EXPECT_EQ("foo.png", url_value->value());
ASSERT_TRUE(style->IsDeclared(cssom::kBackgroundPositionProperty));
scoped_refptr<cssom::PropertyListValue> background_position_list =
dynamic_cast<cssom::PropertyListValue*>(
style->GetPropertyValue(cssom::kBackgroundPositionProperty).get());
ASSERT_TRUE(background_position_list);
EXPECT_EQ(1, background_position_list->value().size());
EXPECT_EQ(cssom::KeywordValue::GetCenter(),
background_position_list->value()[0]);
ASSERT_TRUE(style->IsDeclared(cssom::kBackgroundSizeProperty));
scoped_refptr<cssom::PropertyListValue> background_size_list =
dynamic_cast<cssom::PropertyListValue*>(
style->GetPropertyValue(cssom::kBackgroundSizeProperty).get());
ASSERT_TRUE(background_size_list);
scoped_refptr<cssom::LengthValue> size_value_left =
dynamic_cast<cssom::LengthValue*>(background_size_list->value()[0].get());
EXPECT_FLOAT_EQ(50, size_value_left->value());
EXPECT_EQ(cssom::kPixelsUnit, size_value_left->unit());
scoped_refptr<cssom::LengthValue> size_value_right =
dynamic_cast<cssom::LengthValue*>(background_size_list->value()[1].get());
EXPECT_FLOAT_EQ(80, size_value_right->value());
EXPECT_EQ(cssom::kPixelsUnit, size_value_right->unit());
}
TEST_F(ParserTest, ParsesBackgroundWithURLNoRepeat) {
scoped_refptr<cssom::CSSDeclaredStyleData> style =
parser_.ParseStyleDeclarationList("background: url(foo.png) no-repeat",
source_location_);
ASSERT_TRUE(style->IsDeclared(cssom::kBackgroundImageProperty));
scoped_refptr<cssom::PropertyListValue> background_image_list =
dynamic_cast<cssom::PropertyListValue*>(
style->GetPropertyValue(cssom::kBackgroundImageProperty).get());
ASSERT_TRUE(background_image_list);
EXPECT_EQ(1, background_image_list->value().size());
scoped_refptr<cssom::URLValue> url_value =
dynamic_cast<cssom::URLValue*>(background_image_list->value()[0].get());
EXPECT_EQ("foo.png", url_value->value());
ASSERT_TRUE(style->IsDeclared(cssom::kBackgroundRepeatProperty));
scoped_refptr<cssom::PropertyListValue> background_repeat =
dynamic_cast<cssom::PropertyListValue*>(
style->GetPropertyValue(cssom::kBackgroundRepeatProperty).get());
ASSERT_TRUE(background_repeat);
EXPECT_EQ(cssom::KeywordValue::GetNoRepeat(), background_repeat->value()[0]);
EXPECT_EQ(cssom::KeywordValue::GetNoRepeat(), background_repeat->value()[1]);
}
TEST_F(ParserTest, ParsesBackgroundWithNoRepeatAndColor) {
scoped_refptr<cssom::CSSDeclaredStyleData> style =
parser_.ParseStyleDeclarationList(
"background: no-repeat rgba(0, 0, 0, .8);", source_location_);
ASSERT_TRUE(style->IsDeclared(cssom::kBackgroundRepeatProperty));
scoped_refptr<cssom::PropertyListValue> background_repeat =
dynamic_cast<cssom::PropertyListValue*>(
style->GetPropertyValue(cssom::kBackgroundRepeatProperty).get());
ASSERT_TRUE(background_repeat);
EXPECT_EQ(cssom::KeywordValue::GetNoRepeat(), background_repeat->value()[0]);
EXPECT_EQ(cssom::KeywordValue::GetNoRepeat(), background_repeat->value()[1]);
ASSERT_TRUE(style->IsDeclared(cssom::kBackgroundColorProperty));
scoped_refptr<cssom::RGBAColorValue> background_color =
dynamic_cast<cssom::RGBAColorValue*>(
style->GetPropertyValue(cssom::kBackgroundColorProperty).get());
ASSERT_TRUE(background_color);
EXPECT_EQ(0x000000cc, background_color->value());
}
TEST_F(ParserTest, ParsesBackgroundWithBackgroundRepeatProperty) {
scoped_refptr<cssom::CSSDeclaredStyleData> style =
parser_.ParseStyleDeclarationList(
"background: url(foo.png); background-repeat: no-repeat;",
source_location_);
ASSERT_TRUE(style->IsDeclared(cssom::kBackgroundImageProperty));
scoped_refptr<cssom::PropertyListValue> background_image_list =
dynamic_cast<cssom::PropertyListValue*>(
style->GetPropertyValue(cssom::kBackgroundImageProperty).get());
ASSERT_TRUE(background_image_list);
EXPECT_EQ(1, background_image_list->value().size());
scoped_refptr<cssom::URLValue> url_value =
dynamic_cast<cssom::URLValue*>(background_image_list->value()[0].get());
EXPECT_EQ("foo.png", url_value->value());
ASSERT_TRUE(style->IsDeclared(cssom::kBackgroundRepeatProperty));
scoped_refptr<cssom::PropertyListValue> background_repeat =
dynamic_cast<cssom::PropertyListValue*>(
style->GetPropertyValue(cssom::kBackgroundRepeatProperty).get());
ASSERT_TRUE(background_repeat);
}
TEST_F(ParserTest, ParsesBackgroundWithURLNoRepeatAndPosition) {
scoped_refptr<cssom::CSSDeclaredStyleData> style =
parser_.ParseStyleDeclarationList(
"background: url(foo.png) center no-repeat", source_location_);
ASSERT_TRUE(style->IsDeclared(cssom::kBackgroundImageProperty));
scoped_refptr<cssom::PropertyListValue> background_image_list =
dynamic_cast<cssom::PropertyListValue*>(
style->GetPropertyValue(cssom::kBackgroundImageProperty).get());
ASSERT_TRUE(background_image_list);
EXPECT_EQ(1, background_image_list->value().size());
scoped_refptr<cssom::URLValue> url_value =
dynamic_cast<cssom::URLValue*>(background_image_list->value()[0].get());
EXPECT_EQ("foo.png", url_value->value());
ASSERT_TRUE(style->IsDeclared(cssom::kBackgroundPositionProperty));
scoped_refptr<cssom::PropertyListValue> background_position_list =
dynamic_cast<cssom::PropertyListValue*>(
style->GetPropertyValue(cssom::kBackgroundPositionProperty).get());
ASSERT_TRUE(background_position_list);
EXPECT_EQ(1, background_position_list->value().size());
EXPECT_EQ(cssom::KeywordValue::GetCenter(),
background_position_list->value()[0]);
ASSERT_TRUE(style->IsDeclared(cssom::kBackgroundRepeatProperty));
scoped_refptr<cssom::PropertyListValue> background_repeat =
dynamic_cast<cssom::PropertyListValue*>(
style->GetPropertyValue(cssom::kBackgroundRepeatProperty).get());
ASSERT_TRUE(background_repeat);
EXPECT_EQ(cssom::KeywordValue::GetNoRepeat(), background_repeat->value()[0]);
EXPECT_EQ(cssom::KeywordValue::GetNoRepeat(), background_repeat->value()[1]);
}
TEST_F(ParserTest, ParsesBackgroundWithNoRepeatAndCenter) {
scoped_refptr<cssom::CSSDeclaredStyleData> style =
parser_.ParseStyleDeclarationList("background: no-repeat center",
source_location_);
ASSERT_TRUE(style->IsDeclared(cssom::kBackgroundPositionProperty));
scoped_refptr<cssom::PropertyListValue> background_position_list =
dynamic_cast<cssom::PropertyListValue*>(
style->GetPropertyValue(cssom::kBackgroundPositionProperty).get());
ASSERT_TRUE(background_position_list);
EXPECT_EQ(1, background_position_list->value().size());
EXPECT_EQ(cssom::KeywordValue::GetCenter(),
background_position_list->value()[0]);
ASSERT_TRUE(style->IsDeclared(cssom::kBackgroundRepeatProperty));
scoped_refptr<cssom::PropertyListValue> background_repeat =
dynamic_cast<cssom::PropertyListValue*>(
style->GetPropertyValue(cssom::kBackgroundRepeatProperty).get());
ASSERT_TRUE(background_repeat);
EXPECT_EQ(cssom::KeywordValue::GetNoRepeat(), background_repeat->value()[0]);
EXPECT_EQ(cssom::KeywordValue::GetNoRepeat(), background_repeat->value()[1]);
}
TEST_F(ParserTest, ParsesBackgroundWithNone) {
scoped_refptr<cssom::CSSDeclaredStyleData> style =
parser_.ParseStyleDeclarationList("background: none;", source_location_);
ASSERT_TRUE(style->IsDeclared(cssom::kBackgroundImageProperty));
scoped_refptr<cssom::PropertyListValue> background_image_list =
dynamic_cast<cssom::PropertyListValue*>(
style->GetPropertyValue(cssom::kBackgroundImageProperty).get());
ASSERT_TRUE(background_image_list);
EXPECT_EQ(1, background_image_list->value().size());
EXPECT_EQ(cssom::KeywordValue::GetNone(), background_image_list->value()[0]);
}
TEST_F(ParserTest, ParsesBackgroundWithTransparent) {
scoped_refptr<cssom::CSSDeclaredStyleData> style =
parser_.ParseStyleDeclarationList("background: transparent;",
source_location_);
ASSERT_TRUE(style->IsDeclared(cssom::kBackgroundColorProperty));
scoped_refptr<cssom::RGBAColorValue> background_color =
dynamic_cast<cssom::RGBAColorValue*>(
style->GetPropertyValue(cssom::kBackgroundColorProperty).get());
ASSERT_TRUE(background_color);
EXPECT_EQ(0x00000000, background_color->value());
}
TEST_F(ParserTest, InvalidBackgroundWithTwoPositions) {
EXPECT_CALL(parser_observer_,
OnError("[object ParserTest]:1:11: error: background-position or "
"background-repeat declared twice in background."));
scoped_refptr<cssom::CSSDeclaredStyleData> style =
parser_.ParseStyleDeclarationList(
"background: 0 0 rgba(255,255,255,.1) 100%", source_location_);
EXPECT_FALSE(style->GetPropertyValue(cssom::kBackgroundColorProperty));
EXPECT_FALSE(style->GetPropertyValue(cssom::kBackgroundImageProperty));
EXPECT_FALSE(style->GetPropertyValue(cssom::kBackgroundPositionProperty));
EXPECT_FALSE(style->GetPropertyValue(cssom::kBackgroundRepeatProperty));
EXPECT_FALSE(style->GetPropertyValue(cssom::kBackgroundSizeProperty));
}
TEST_F(ParserTest, InvalidBackgroundWithTwoColors) {
EXPECT_CALL(parser_observer_,
OnError("[object ParserTest]:1:38: error: background-color value "
"declared twice in background."));
scoped_refptr<cssom::CSSDeclaredStyleData> style =
parser_.ParseStyleDeclarationList(
"background: 0 0 rgba(255,255,255,.1) rgba(255,255,255,.1)",
source_location_);
EXPECT_FALSE(style->GetPropertyValue(cssom::kBackgroundColorProperty));
EXPECT_FALSE(style->GetPropertyValue(cssom::kBackgroundImageProperty));
EXPECT_FALSE(style->GetPropertyValue(cssom::kBackgroundPositionProperty));
EXPECT_FALSE(style->GetPropertyValue(cssom::kBackgroundRepeatProperty));
EXPECT_FALSE(style->GetPropertyValue(cssom::kBackgroundSizeProperty));
}
TEST_F(ParserTest, InvalidBackgroundWithTwoImages) {
EXPECT_CALL(parser_observer_,
OnError("[object ParserTest]:1:26: error: background-image value "
"declared twice in background."));
scoped_refptr<cssom::CSSDeclaredStyleData> style =
parser_.ParseStyleDeclarationList("background: url(foo.png) url(bar.png)",
source_location_);
EXPECT_FALSE(style->GetPropertyValue(cssom::kBackgroundColorProperty));
EXPECT_FALSE(style->GetPropertyValue(cssom::kBackgroundImageProperty));
EXPECT_FALSE(style->GetPropertyValue(cssom::kBackgroundPositionProperty));
EXPECT_FALSE(style->GetPropertyValue(cssom::kBackgroundRepeatProperty));
EXPECT_FALSE(style->GetPropertyValue(cssom::kBackgroundSizeProperty));
}
TEST_F(ParserTest, InvalidBackgroundWithTwoPositionsAndTwoColors) {
EXPECT_CALL(parser_observer_,
OnError("[object ParserTest]:1:11: error: background-position or "
"background-repeat declared twice in background."));
scoped_refptr<cssom::CSSDeclaredStyleData> style =
parser_.ParseStyleDeclarationList(
"background: 0 0 rgba(255,255,255,.1) 100% rgba(255,255,255,.1) 100%",
source_location_);
EXPECT_FALSE(style->GetPropertyValue(cssom::kBackgroundColorProperty));
EXPECT_FALSE(style->GetPropertyValue(cssom::kBackgroundImageProperty));
EXPECT_FALSE(style->GetPropertyValue(cssom::kBackgroundPositionProperty));
EXPECT_FALSE(style->GetPropertyValue(cssom::kBackgroundRepeatProperty));
EXPECT_FALSE(style->GetPropertyValue(cssom::kBackgroundSizeProperty));
}
TEST_F(ParserTest, LinearGradientWithOneColorStopIsError) {
EXPECT_CALL(
parser_observer_,
OnWarning("[object ParserTest]:1:11: warning: unsupported value"));
scoped_refptr<cssom::CSSDeclaredStyleData> style =
parser_.ParseStyleDeclarationList(
"background: linear-gradient(to right, rgba(0,0,0,0.9));",
source_location_);
EXPECT_EQ(GetPropertyInitialValue(cssom::kBackgroundImageProperty),
style->GetPropertyValue(cssom::kBackgroundImageProperty));
}
TEST_F(ParserTest, LinearGradientWithInvalidColorStopIsError) {
EXPECT_CALL(
parser_observer_,
OnWarning("[object ParserTest]:1:11: warning: unsupported value"));
scoped_refptr<cssom::CSSDeclaredStyleData> style =
parser_.ParseStyleDeclarationList(
"background: linear-gradient(#0123456789abcde 0%));",
source_location_);
EXPECT_EQ(GetPropertyInitialValue(cssom::kBackgroundImageProperty),
style->GetPropertyValue(cssom::kBackgroundImageProperty));
}
TEST_F(ParserTest, RadialGradientWithOneColorStopIsError) {
EXPECT_CALL(
parser_observer_,
OnWarning("[object ParserTest]:1:11: warning: unsupported value"));
scoped_refptr<cssom::CSSDeclaredStyleData> style =
parser_.ParseStyleDeclarationList(
"background: radial-gradient(closest-corner, rgba(0,0,0,0.9));",
source_location_);
EXPECT_EQ(GetPropertyInitialValue(cssom::kBackgroundImageProperty),
style->GetPropertyValue(cssom::kBackgroundImageProperty));
}
TEST_F(ParserTest, ParsesBackgroundWithLinearGradient) {
scoped_refptr<cssom::CSSDeclaredStyleData> style =
parser_.ParseStyleDeclarationList(
"background: linear-gradient(rgba(0,0,0,0.56), rgba(0,0,0,0.9));",
source_location_);
ASSERT_TRUE(style->IsDeclared(cssom::kBackgroundImageProperty));
scoped_refptr<cssom::PropertyListValue> background_image_list =
dynamic_cast<cssom::PropertyListValue*>(
style->GetPropertyValue(cssom::kBackgroundImageProperty).get());
ASSERT_TRUE(background_image_list);
EXPECT_EQ(1, background_image_list->value().size());
scoped_refptr<cssom::LinearGradientValue> linear_gradient_value =
dynamic_cast<cssom::LinearGradientValue*>(
background_image_list->value()[0].get());
EXPECT_FALSE(linear_gradient_value->angle_in_radians());
EXPECT_EQ(cssom::LinearGradientValue::kBottom,
*linear_gradient_value->side_or_corner());
const cssom::ColorStopList& color_stop_list_value =
linear_gradient_value->color_stop_list();
EXPECT_EQ(2, color_stop_list_value.size());
float color_list[2] = {0x0000008E, 0x000000E5};
for (size_t i = 0; i < color_stop_list_value.size(); ++i) {
const cssom::ColorStop* color_stop_value = color_stop_list_value[i].get();
scoped_refptr<cssom::RGBAColorValue> color = color_stop_value->rgba();
ASSERT_TRUE(color);
EXPECT_EQ(color_list[i], color->value());
EXPECT_FALSE(color_stop_value->position());
}
}
TEST_F(ParserTest, ParsesBackgroundWithLinearGradientContainsTransparent) {
scoped_refptr<cssom::CSSDeclaredStyleData> style =
parser_.ParseStyleDeclarationList(
"background: linear-gradient(to bottom, rgba(0,0,0,0.56), "
"rgba(0,0,0,0.9), transparent);",
source_location_);
ASSERT_TRUE(style->IsDeclared(cssom::kBackgroundImageProperty));
scoped_refptr<cssom::PropertyListValue> background_image_list =
dynamic_cast<cssom::PropertyListValue*>(
style->GetPropertyValue(cssom::kBackgroundImageProperty).get());
ASSERT_TRUE(background_image_list);
EXPECT_EQ(1, background_image_list->value().size());
scoped_refptr<cssom::LinearGradientValue> linear_gradient_value =
dynamic_cast<cssom::LinearGradientValue*>(
background_image_list->value()[0].get());
EXPECT_FALSE(linear_gradient_value->angle_in_radians());
EXPECT_EQ(cssom::LinearGradientValue::kBottom,
*linear_gradient_value->side_or_corner());
const cssom::ColorStopList& color_stop_list_value =
linear_gradient_value->color_stop_list();
EXPECT_EQ(3, color_stop_list_value.size());
float color_list[3] = {0x0000008E, 0x000000E5, 0x00000000};
for (size_t i = 0; i < color_stop_list_value.size(); ++i) {
const cssom::ColorStop* color_stop_value = color_stop_list_value[i].get();
scoped_refptr<cssom::RGBAColorValue> color = color_stop_value->rgba();
ASSERT_TRUE(color);
EXPECT_EQ(color_list[i], color->value());
EXPECT_FALSE(color_stop_value->position());
}
}
TEST_F(ParserTest, ParsesBackgroundWithRadialGradient) {
scoped_refptr<cssom::CSSDeclaredStyleData> style =
parser_.ParseStyleDeclarationList(
"background: radial-gradient(closest-corner, "
"rgba(0,0,0,0.56), rgba(0,0,0,0.9));",
source_location_);
ASSERT_TRUE(style->IsDeclared(cssom::kBackgroundImageProperty));
scoped_refptr<cssom::PropertyListValue> background_image_list =
dynamic_cast<cssom::PropertyListValue*>(
style->GetPropertyValue(cssom::kBackgroundImageProperty).get());
ASSERT_TRUE(background_image_list);
EXPECT_EQ(1, background_image_list->value().size());
scoped_refptr<cssom::RadialGradientValue> radial_gradient_value =
dynamic_cast<cssom::RadialGradientValue*>(
background_image_list->value()[0].get());
EXPECT_EQ(cssom::RadialGradientValue::kEllipse,
radial_gradient_value->shape());
EXPECT_EQ(cssom::RadialGradientValue::kClosestCorner,
radial_gradient_value->size_keyword());
EXPECT_FALSE(radial_gradient_value->size_value());
scoped_refptr<cssom::PropertyListValue> position =
radial_gradient_value->position();
EXPECT_FALSE(position);
const cssom::ColorStopList& color_stop_list_value =
radial_gradient_value->color_stop_list();
EXPECT_EQ(2, color_stop_list_value.size());
float color_list[2] = {0x0000008E, 0x000000E5};
for (size_t i = 0; i < color_stop_list_value.size(); ++i) {
const cssom::ColorStop* color_stop_value = color_stop_list_value[i].get();
scoped_refptr<cssom::RGBAColorValue> color = color_stop_value->rgba();
ASSERT_TRUE(color);
EXPECT_EQ(color_list[i], color->value());
EXPECT_FALSE(color_stop_value->position());
}
}
TEST_F(ParserTest, ParsesBackgroundColor) {
scoped_refptr<cssom::CSSDeclaredStyleData> style =
parser_.ParseStyleDeclarationList("background-color: #fff;",
source_location_);
ASSERT_TRUE(style->IsDeclared(cssom::kBackgroundColorProperty));
scoped_refptr<cssom::RGBAColorValue> background_color =
dynamic_cast<cssom::RGBAColorValue*>(
style->GetPropertyValue(cssom::kBackgroundColorProperty).get());
ASSERT_TRUE(background_color);
EXPECT_EQ(0xffffffff, background_color->value());
}
TEST_F(ParserTest, ParsesBackgroundColorWithKeywordAqua) {
scoped_refptr<cssom::CSSDeclaredStyleData> style =
parser_.ParseStyleDeclarationList("background-color: aqua;",
source_location_);
ASSERT_TRUE(style->IsDeclared(cssom::kBackgroundColorProperty));
scoped_refptr<cssom::RGBAColorValue> background_color =
dynamic_cast<cssom::RGBAColorValue*>(
style->GetPropertyValue(cssom::kBackgroundColorProperty).get());
ASSERT_TRUE(background_color);
EXPECT_EQ(0x00FFFFFF, background_color->value());
}
TEST_F(ParserTest, ParsesBackgroundColorWithKeywordBlack) {
scoped_refptr<cssom::CSSDeclaredStyleData> style =
parser_.ParseStyleDeclarationList("background-color: black;",
source_location_);
ASSERT_TRUE(style->IsDeclared(cssom::kBackgroundColorProperty));
scoped_refptr<cssom::RGBAColorValue> background_color =
dynamic_cast<cssom::RGBAColorValue*>(
style->GetPropertyValue(cssom::kBackgroundColorProperty).get());
ASSERT_TRUE(background_color);
EXPECT_EQ(0x000000FF, background_color->value());
}
TEST_F(ParserTest, ParsesBackgroundColorWithKeywordBlue) {
scoped_refptr<cssom::CSSDeclaredStyleData> style =
parser_.ParseStyleDeclarationList("background-color: blue;",
source_location_);
ASSERT_TRUE(style->IsDeclared(cssom::kBackgroundColorProperty));
scoped_refptr<cssom::RGBAColorValue> background_color =
dynamic_cast<cssom::RGBAColorValue*>(
style->GetPropertyValue(cssom::kBackgroundColorProperty).get());
ASSERT_TRUE(background_color);
EXPECT_EQ(0x0000FFFF, background_color->value());
}
TEST_F(ParserTest, ParsesBackgroundColorWithKeywordFuchsia) {
scoped_refptr<cssom::CSSDeclaredStyleData> style =
parser_.ParseStyleDeclarationList("background-color: fuchsia;",
source_location_);
ASSERT_TRUE(style->IsDeclared(cssom::kBackgroundColorProperty));
scoped_refptr<cssom::RGBAColorValue> background_color =
dynamic_cast<cssom::RGBAColorValue*>(
style->GetPropertyValue(cssom::kBackgroundColorProperty).get());
ASSERT_TRUE(background_color);
EXPECT_EQ(0xFF00FFFF, background_color->value());
}
TEST_F(ParserTest, ParsesBackgroundColorWithKeywordGray) {
scoped_refptr<cssom::CSSDeclaredStyleData> style =
parser_.ParseStyleDeclarationList("background-color: gray;",
source_location_);
ASSERT_TRUE(style->IsDeclared(cssom::kBackgroundColorProperty));
scoped_refptr<cssom::RGBAColorValue> background_color =
dynamic_cast<cssom::RGBAColorValue*>(
style->GetPropertyValue(cssom::kBackgroundColorProperty).get());
ASSERT_TRUE(background_color);
EXPECT_EQ(0x808080FF, background_color->value());
}
TEST_F(ParserTest, ParsesBackgroundColorWithKeywordGreen) {
scoped_refptr<cssom::CSSDeclaredStyleData> style =
parser_.ParseStyleDeclarationList("background-color: green;",
source_location_);
ASSERT_TRUE(style->IsDeclared(cssom::kBackgroundColorProperty));
scoped_refptr<cssom::RGBAColorValue> background_color =
dynamic_cast<cssom::RGBAColorValue*>(
style->GetPropertyValue(cssom::kBackgroundColorProperty).get());
ASSERT_TRUE(background_color);
EXPECT_EQ(0x008000FF, background_color->value());
}
TEST_F(ParserTest, ParsesBackgroundColorWithKeywordLime) {
scoped_refptr<cssom::CSSDeclaredStyleData> style =
parser_.ParseStyleDeclarationList("background-color: lime;",
source_location_);
ASSERT_TRUE(style->IsDeclared(cssom::kBackgroundColorProperty));
scoped_refptr<cssom::RGBAColorValue> background_color =
dynamic_cast<cssom::RGBAColorValue*>(
style->GetPropertyValue(cssom::kBackgroundColorProperty).get());
ASSERT_TRUE(background_color);
EXPECT_EQ(0x00FF00FF, background_color->value());
}
TEST_F(ParserTest, ParsesBackgroundColorWithKeywordMaroon) {
scoped_refptr<cssom::CSSDeclaredStyleData> style =
parser_.ParseStyleDeclarationList("background-color: maroon;",
source_location_);
ASSERT_TRUE(style->IsDeclared(cssom::kBackgroundColorProperty));
scoped_refptr<cssom::RGBAColorValue> background_color =
dynamic_cast<cssom::RGBAColorValue*>(
style->GetPropertyValue(cssom::kBackgroundColorProperty).get());
ASSERT_TRUE(background_color);
EXPECT_EQ(0x800000FF, background_color->value());
}
TEST_F(ParserTest, ParsesBackgroundColorWithKeywordNavy) {
scoped_refptr<cssom::CSSDeclaredStyleData> style =
parser_.ParseStyleDeclarationList("background-color: navy;",
source_location_);
ASSERT_TRUE(style->IsDeclared(cssom::kBackgroundColorProperty));
scoped_refptr<cssom::RGBAColorValue> background_color =
dynamic_cast<cssom::RGBAColorValue*>(
style->GetPropertyValue(cssom::kBackgroundColorProperty).get());
ASSERT_TRUE(background_color);
EXPECT_EQ(0x000080FF, background_color->value());
}
TEST_F(ParserTest, ParsesBackgroundColorWithKeywordOlive) {
scoped_refptr<cssom::CSSDeclaredStyleData> style =
parser_.ParseStyleDeclarationList("background-color: olive;",
source_location_);
ASSERT_TRUE(style->IsDeclared(cssom::kBackgroundColorProperty));
scoped_refptr<cssom::RGBAColorValue> background_color =
dynamic_cast<cssom::RGBAColorValue*>(
style->GetPropertyValue(cssom::kBackgroundColorProperty).get());
ASSERT_TRUE(background_color);
EXPECT_EQ(0x808000FF, background_color->value());
}
TEST_F(ParserTest, ParsesBackgroundColorWithKeywordPurple) {
scoped_refptr<cssom::CSSDeclaredStyleData> style =
parser_.ParseStyleDeclarationList("background-color: purple;",
source_location_);
ASSERT_TRUE(style->IsDeclared(cssom::kBackgroundColorProperty));
scoped_refptr<cssom::RGBAColorValue> background_color =
dynamic_cast<cssom::RGBAColorValue*>(
style->GetPropertyValue(cssom::kBackgroundColorProperty).get());
ASSERT_TRUE(background_color);
EXPECT_EQ(0x800080FF, background_color->value());
}
TEST_F(ParserTest, ParsesBackgroundColorWithKeywordRed) {
scoped_refptr<cssom::CSSDeclaredStyleData> style =
parser_.ParseStyleDeclarationList("background-color: red;",
source_location_);
ASSERT_TRUE(style->IsDeclared(cssom::kBackgroundColorProperty));
scoped_refptr<cssom::RGBAColorValue> background_color =
dynamic_cast<cssom::RGBAColorValue*>(
style->GetPropertyValue(cssom::kBackgroundColorProperty).get());
ASSERT_TRUE(background_color);
EXPECT_EQ(0xFF0000FF, background_color->value());
}
TEST_F(ParserTest, ParsesBackgroundColorWithKeywordSilver) {
scoped_refptr<cssom::CSSDeclaredStyleData> style =
parser_.ParseStyleDeclarationList("background-color: silver;",
source_location_);
ASSERT_TRUE(style->IsDeclared(cssom::kBackgroundColorProperty));
scoped_refptr<cssom::RGBAColorValue> background_color =
dynamic_cast<cssom::RGBAColorValue*>(
style->GetPropertyValue(cssom::kBackgroundColorProperty).get());
ASSERT_TRUE(background_color);
EXPECT_EQ(0xC0C0C0FF, background_color->value());
}
TEST_F(ParserTest, ParsesBackgroundColorWithKeywordTeal) {
scoped_refptr<cssom::CSSDeclaredStyleData> style =
parser_.ParseStyleDeclarationList("background-color: teal;",
source_location_);
ASSERT_TRUE(style->IsDeclared(cssom::kBackgroundColorProperty));
scoped_refptr<cssom::RGBAColorValue> background_color =
dynamic_cast<cssom::RGBAColorValue*>(
style->GetPropertyValue(cssom::kBackgroundColorProperty).get());
ASSERT_TRUE(background_color);
EXPECT_EQ(0x008080FF, background_color->value());
}
TEST_F(ParserTest, ParsesBackgroundColorWithKeywordTransparent) {
scoped_refptr<cssom::CSSDeclaredStyleData> style =
parser_.ParseStyleDeclarationList("background-color: transparent;",
source_location_);
ASSERT_TRUE(style->IsDeclared(cssom::kBackgroundColorProperty));
scoped_refptr<cssom::RGBAColorValue> background_color =
dynamic_cast<cssom::RGBAColorValue*>(
style->GetPropertyValue(cssom::kBackgroundColorProperty).get());
ASSERT_TRUE(background_color);
EXPECT_EQ(0x00000000, background_color->value());
}
TEST_F(ParserTest, ParsesBackgroundColorWithKeywordWhite) {
scoped_refptr<cssom::CSSDeclaredStyleData> style =
parser_.ParseStyleDeclarationList("background-color: white;",
source_location_);
ASSERT_TRUE(style->IsDeclared(cssom::kBackgroundColorProperty));
scoped_refptr<cssom::RGBAColorValue> background_color =
dynamic_cast<cssom::RGBAColorValue*>(
style->GetPropertyValue(cssom::kBackgroundColorProperty).get());
ASSERT_TRUE(background_color);
EXPECT_EQ(0xFFFFFFFF, background_color->value());
}
TEST_F(ParserTest, ParsesBackgroundColorWithKeywordYellow) {
scoped_refptr<cssom::CSSDeclaredStyleData> style =
parser_.ParseStyleDeclarationList("background-color: yellow;",
source_location_);
ASSERT_TRUE(style->IsDeclared(cssom::kBackgroundColorProperty));
scoped_refptr<cssom::RGBAColorValue> background_color =
dynamic_cast<cssom::RGBAColorValue*>(
style->GetPropertyValue(cssom::kBackgroundColorProperty).get());
ASSERT_TRUE(background_color);
EXPECT_EQ(0xFFFF00FF, background_color->value());
}
TEST_F(ParserTest, ParsesBackgroundImageNone) {
scoped_refptr<cssom::CSSDeclaredStyleData> style =
parser_.ParseStyleDeclarationList("background-image: none;",
source_location_);
ASSERT_TRUE(style->IsDeclared(cssom::kBackgroundImageProperty));
scoped_refptr<cssom::PropertyListValue> background_image_list =
dynamic_cast<cssom::PropertyListValue*>(
style->GetPropertyValue(cssom::kBackgroundImageProperty).get());
ASSERT_TRUE(background_image_list);
EXPECT_EQ(1, background_image_list->value().size());
EXPECT_EQ(cssom::KeywordValue::GetNone(), background_image_list->value()[0]);
}
TEST_F(ParserTest, ParsesSingleBackgroundImageURL) {
scoped_refptr<cssom::CSSDeclaredStyleData> style =
parser_.ParseStyleDeclarationList("background-image: url(foo.png);",
source_location_);
ASSERT_TRUE(style->IsDeclared(cssom::kBackgroundImageProperty));
scoped_refptr<cssom::PropertyListValue> background_image_list =
dynamic_cast<cssom::PropertyListValue*>(
style->GetPropertyValue(cssom::kBackgroundImageProperty).get());
ASSERT_TRUE(background_image_list);
EXPECT_EQ(1, background_image_list->value().size());
scoped_refptr<cssom::URLValue> url_value =
dynamic_cast<cssom::URLValue*>(background_image_list->value()[0].get());
EXPECT_EQ("foo.png", url_value->value());
}
TEST_F(ParserTest, ParsesMultipleBackgroundImageURLs) {
scoped_refptr<cssom::CSSDeclaredStyleData> style =
parser_.ParseStyleDeclarationList(
"background-image: url(foo.png), url(bar.jpg), url(baz.png);",
source_location_);
ASSERT_TRUE(style->IsDeclared(cssom::kBackgroundImageProperty));
scoped_refptr<cssom::PropertyListValue> background_image_list =
dynamic_cast<cssom::PropertyListValue*>(
style->GetPropertyValue(cssom::kBackgroundImageProperty).get());
ASSERT_TRUE(background_image_list);
EXPECT_EQ(3, background_image_list->value().size());
scoped_refptr<cssom::URLValue> url_value_1 =
dynamic_cast<cssom::URLValue*>(background_image_list->value()[0].get());
EXPECT_EQ("foo.png", url_value_1->value());
scoped_refptr<cssom::URLValue> url_value_2 =
dynamic_cast<cssom::URLValue*>(background_image_list->value()[1].get());
EXPECT_EQ("bar.jpg", url_value_2->value());
scoped_refptr<cssom::URLValue> url_value_3 =
dynamic_cast<cssom::URLValue*>(background_image_list->value()[2].get());
EXPECT_EQ("baz.png", url_value_3->value());
}
TEST_F(ParserTest, ParsesMultipleBackgroundImagesWithNone) {
scoped_refptr<cssom::CSSDeclaredStyleData> style =
parser_.ParseStyleDeclarationList(
"background-image: url(foo.png), none, url(baz.png);",
source_location_);
ASSERT_TRUE(style->IsDeclared(cssom::kBackgroundImageProperty));
scoped_refptr<cssom::PropertyListValue> background_image_list =
dynamic_cast<cssom::PropertyListValue*>(
style->GetPropertyValue(cssom::kBackgroundImageProperty).get());
ASSERT_TRUE(background_image_list);
EXPECT_EQ(3, background_image_list->value().size());
scoped_refptr<cssom::URLValue> url_value_1 =
dynamic_cast<cssom::URLValue*>(background_image_list->value()[0].get());
EXPECT_EQ("foo.png", url_value_1->value());
EXPECT_EQ(cssom::KeywordValue::GetNone(), background_image_list->value()[1]);
scoped_refptr<cssom::URLValue> url_value_3 =
dynamic_cast<cssom::URLValue*>(background_image_list->value()[2].get());
EXPECT_EQ("baz.png", url_value_3->value());
}
TEST_F(ParserTest, ParsesBackgroundImageLinearGradientWithDirection) {
scoped_refptr<cssom::CSSDeclaredStyleData> style =
parser_.ParseStyleDeclarationList(
"background-image: linear-gradient(180deg, rgba(34, 34, 34, 0) 50px,"
"rgba(34, 34, 34, 0) 100px);",
source_location_);
ASSERT_TRUE(style->IsDeclared(cssom::kBackgroundImageProperty));
scoped_refptr<cssom::PropertyListValue> background_image_list =
dynamic_cast<cssom::PropertyListValue*>(
style->GetPropertyValue(cssom::kBackgroundImageProperty).get());
ASSERT_TRUE(background_image_list);
EXPECT_EQ(1, background_image_list->value().size());
scoped_refptr<cssom::LinearGradientValue> linear_gradient_value =
dynamic_cast<cssom::LinearGradientValue*>(
background_image_list->value()[0].get());
EXPECT_FLOAT_EQ(static_cast<float>(M_PI),
*linear_gradient_value->angle_in_radians());
EXPECT_FALSE(linear_gradient_value->side_or_corner());
const cssom::ColorStopList& color_stop_list_value =
linear_gradient_value->color_stop_list();
EXPECT_EQ(2, color_stop_list_value.size());
float percentage_list[2] = {50.0f, 100.0f};
for (size_t i = 0; i < color_stop_list_value.size(); ++i) {
const cssom::ColorStop* color_stop_value = color_stop_list_value[i].get();
scoped_refptr<cssom::RGBAColorValue> color = color_stop_value->rgba();
ASSERT_TRUE(color);
EXPECT_EQ(0x22222200, color->value());
scoped_refptr<cssom::LengthValue> position =
dynamic_cast<cssom::LengthValue*>(color_stop_value->position().get());
EXPECT_FLOAT_EQ(percentage_list[i], position->value());
EXPECT_EQ(cssom::kPixelsUnit, position->unit());
}
}
TEST_F(ParserTest, ParsesBackgroundImageLinearGradientWithoutDirection) {
scoped_refptr<cssom::CSSDeclaredStyleData> style =
parser_.ParseStyleDeclarationList(
"background-image: linear-gradient(rgba(34, 34, 34, 0),"
"rgba(34, 34, 34, 0) 60%);",
source_location_);
ASSERT_TRUE(style->IsDeclared(cssom::kBackgroundImageProperty));
scoped_refptr<cssom::PropertyListValue> background_image_list =
dynamic_cast<cssom::PropertyListValue*>(
style->GetPropertyValue(cssom::kBackgroundImageProperty).get());
ASSERT_TRUE(background_image_list);
EXPECT_EQ(1, background_image_list->value().size());
scoped_refptr<cssom::LinearGradientValue> linear_gradient_value =
dynamic_cast<cssom::LinearGradientValue*>(
background_image_list->value()[0].get());
EXPECT_FALSE(linear_gradient_value->angle_in_radians());
EXPECT_EQ(cssom::LinearGradientValue::kBottom,
*linear_gradient_value->side_or_corner());
const cssom::ColorStopList& color_stop_list_value =
linear_gradient_value->color_stop_list();
EXPECT_EQ(2, color_stop_list_value.size());
for (size_t i = 0; i < color_stop_list_value.size(); ++i) {
const cssom::ColorStop* color_stop_value = color_stop_list_value[i].get();
scoped_refptr<cssom::RGBAColorValue> color = color_stop_value->rgba();
ASSERT_TRUE(color);
EXPECT_EQ(0x22222200, color->value());
if (i == 0) {
EXPECT_FALSE(color_stop_value->position());
} else {
scoped_refptr<cssom::PercentageValue> position =
dynamic_cast<cssom::PercentageValue*>(
color_stop_value->position().get());
EXPECT_FLOAT_EQ(0.6f, position->value());
}
}
}
TEST_F(ParserTest, ParsesBackgroundImageLinearGradientAndURL