blob: 851f356e326cf6bd135555022313c78fde08954a [file] [log] [blame]
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "third_party/blink/renderer/core/css/properties/css_property.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/blink/renderer/core/css/css_property_names.h"
#include "third_party/blink/renderer/core/css/css_test_helpers.h"
#include "third_party/blink/renderer/core/css/properties/css_property_instances.h"
#include "third_party/blink/renderer/core/css/properties/css_property_ref.h"
#include "third_party/blink/renderer/core/css/resolver/style_builder.h"
#include "third_party/blink/renderer/core/css/resolver/style_resolver_state.h"
#include "third_party/blink/renderer/core/css/scoped_css_value.h"
#include "third_party/blink/renderer/core/html/html_element.h"
#include "third_party/blink/renderer/core/style/computed_style.h"
#include "third_party/blink/renderer/core/style/data_equivalency.h"
#include "third_party/blink/renderer/core/testing/page_test_base.h"
namespace blink {
class CSSPropertyTest : public PageTestBase {
public:
const CSSValue* Parse(String name, String value) {
auto* set = css_test_helpers::ParseDeclarationBlock(name + ":" + value);
DCHECK(set);
if (set->PropertyCount() != 1)
return nullptr;
return &set->PropertyAt(0).Value();
}
scoped_refptr<ComputedStyle> ComputedStyleWithValue(
const CSSProperty& property,
const CSSValue& value) {
StyleResolverState state(GetDocument(), *GetDocument().body());
state.SetStyle(ComputedStyle::Create());
// The border-style needs to be non-hidden and non-none, otherwise
// the computed values of border-width properties are always zero.
//
// https://drafts.csswg.org/css-backgrounds-3/#the-border-width
state.Style()->SetBorderBottomStyle(EBorderStyle::kSolid);
state.Style()->SetBorderLeftStyle(EBorderStyle::kSolid);
state.Style()->SetBorderRightStyle(EBorderStyle::kSolid);
state.Style()->SetBorderTopStyle(EBorderStyle::kSolid);
StyleBuilder::ApplyProperty(property, state,
ScopedCSSValue(value, &GetDocument()));
return state.TakeStyle();
}
};
TEST_F(CSSPropertyTest, VisitedPropertiesAreNotWebExposed) {
for (CSSPropertyID property_id : CSSPropertyIDList()) {
const CSSProperty& property = CSSProperty::Get(property_id);
EXPECT_TRUE(!property.IsVisited() ||
!property.IsWebExposed(GetDocument().GetExecutionContext()));
}
}
TEST_F(CSSPropertyTest, GetVisitedPropertyOnlyReturnsVisitedProperties) {
for (CSSPropertyID property_id : CSSPropertyIDList()) {
const CSSProperty& property = CSSProperty::Get(property_id);
const CSSProperty* visited = property.GetVisitedProperty();
EXPECT_TRUE(!visited || visited->IsVisited());
}
}
TEST_F(CSSPropertyTest, GetUnvisitedPropertyFromVisited) {
for (CSSPropertyID property_id : CSSPropertyIDList()) {
const CSSProperty& property = CSSProperty::Get(property_id);
EXPECT_EQ(property.IsVisited(),
static_cast<bool>(property.GetUnvisitedProperty()));
}
}
TEST_F(CSSPropertyTest, InternalFontSizeDeltaNotWebExposed) {
ASSERT_FALSE(
CSSProperty::Get(CSSPropertyID::kInternalFontSizeDelta).IsWebExposed());
}
TEST_F(CSSPropertyTest, VisitedPropertiesCanParseValues) {
scoped_refptr<ComputedStyle> initial_style = ComputedStyle::Create();
// Count the number of 'visited' properties seen.
size_t num_visited = 0;
for (CSSPropertyID property_id : CSSPropertyIDList()) {
const CSSProperty& property = CSSProperty::Get(property_id);
const CSSProperty* visited = property.GetVisitedProperty();
if (!visited)
continue;
// Get any value compatible with 'property'. The initial value will do.
const CSSValue* initial_value = property.CSSValueFromComputedStyle(
*initial_style, nullptr /* layout_object */,
false /* allow_visited_style */);
ASSERT_TRUE(initial_value);
String css_text = initial_value->CssText();
// Parse the initial value using both the regular property, and the
// accompanying 'visited' property.
const CSSValue* parsed_regular_value = css_test_helpers::ParseLonghand(
GetDocument(), property, initial_value->CssText());
const CSSValue* parsed_visited_value = css_test_helpers::ParseLonghand(
GetDocument(), *visited, initial_value->CssText());
// The properties should have identical parsing behavior.
EXPECT_TRUE(DataEquivalent(parsed_regular_value, parsed_visited_value));
num_visited++;
}
// Verify that we have seen at least one visited property. If we didn't (and
// there is no bug), it means this test can be removed.
EXPECT_GT(num_visited, 0u);
}
TEST_F(CSSPropertyTest, Surrogates) {
EXPECT_EQ(&GetCSSPropertyWidth(),
GetCSSPropertyInlineSize().SurrogateFor(
TextDirection::kLtr, WritingMode::kHorizontalTb));
EXPECT_EQ(&GetCSSPropertyHeight(),
GetCSSPropertyInlineSize().SurrogateFor(TextDirection::kLtr,
WritingMode::kVerticalRl));
EXPECT_EQ(&GetCSSPropertyWritingMode(),
GetCSSPropertyWebkitWritingMode().SurrogateFor(
TextDirection::kLtr, WritingMode::kHorizontalTb));
EXPECT_FALSE(GetCSSPropertyWidth().SurrogateFor(TextDirection::kLtr,
WritingMode::kHorizontalTb));
}
TEST_F(CSSPropertyTest, PairsWithIdenticalValues) {
const CSSValue* border_radius = css_test_helpers::ParseLonghand(
GetDocument(), GetCSSPropertyBorderTopLeftRadius(), "1% 1%");
const CSSValue* perspective_origin = css_test_helpers::ParseLonghand(
GetDocument(), GetCSSPropertyPerspectiveOrigin(), "1% 1%");
// Border radius drops identical values
EXPECT_EQ("1%", border_radius->CssText());
// Perspective origin keeps identical values
EXPECT_EQ("1% 1%", perspective_origin->CssText());
// Therefore, the values are different
EXPECT_NE(*border_radius, *perspective_origin);
}
} // namespace blink