Skip to content

Commit

Permalink
Add various DOM and Web tests. (youtube#2001)
Browse files Browse the repository at this point in the history
Various additions to test coverage. This improves overall unit test coverage by 0.46%.

b/312288290
  • Loading branch information
jellefoks authored and Rongo-JL committed Dec 19, 2023
1 parent 7c4cc2b commit f09ca39
Show file tree
Hide file tree
Showing 20 changed files with 1,316 additions and 260 deletions.
1 change: 1 addition & 0 deletions cobalt/dom/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -385,6 +385,7 @@ target(gtest_target_type, "dom_test") {
"event_queue_test.cc",
"font_cache_test.cc",
"html_element_factory_test.cc",
"html_element_style_test.cc",
"html_element_test.cc",
"html_link_element_test.cc",
"intersection_observer_test.cc",
Expand Down
260 changes: 260 additions & 0 deletions cobalt/dom/html_element_style_test.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,260 @@
// Copyright 2015 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 <memory>
#include <string>

#include "base/bind.h"
#include "base/strings/stringprintf.h"
#include "cobalt/bindings/testing/utils.h"
#include "cobalt/dom/html_element.h"
#include "cobalt/dom/screen.h"
#include "cobalt/dom/testing/test_with_javascript.h"
#include "cobalt/network_bridge/net_poster.h"
#include "cobalt/script/testing/fake_script_value.h"
#include "cobalt/web/error_event.h"
#include "cobalt/web/message_event.h"
#include "cobalt/web/testing/mock_event_listener.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"

namespace cobalt {
namespace dom {

using script::testing::FakeScriptValue;

namespace {
std::string GetStyleName(::testing::TestParamInfo<const char*> info) {
return std::string(info.param);
}

std::string CamelCaseToPropertyName(const char* camel_case) {
std::string snake;
for (const char* input = camel_case; *input; ++input) {
if (*input >= 'A' && *input <= 'Z') {
snake.push_back('-');
snake.push_back(std::tolower(*input));
} else {
snake.push_back(*input);
}
}
return snake;
}

const char* longhand_styles[] = {"alignContent",
"alignItems",
"alignSelf",
"animationDelay",
"animationDirection",
"animationDuration",
"animationFillMode",
"animationIterationCount",
"animationName",
"animationTimingFunction",
"backgroundColor",
"backgroundImage",
"backgroundPosition",
"backgroundRepeat",
"backgroundSize",
"borderBottomColor",
"borderBottomLeftRadius",
"borderBottomRightRadius",
"borderBottomStyle",
"borderBottomWidth",
"borderLeftColor",
"borderLeftStyle",
"borderLeftWidth",
"borderRightColor",
"borderRightStyle",
"borderRightWidth",
"borderTopColor",
"borderTopLeftRadius",
"borderTopRightRadius",
"borderTopStyle",
"borderTopWidth",
"bottom",
"boxShadow",
"color",
"content",
"display",
"filter",
"flexBasis",
"flexDirection",
"flexGrow",
"flexShrink",
"flexWrap",
"fontFamily",
"fontSize",
"fontStyle",
"fontWeight",
"height",
"justifyContent",
"left",
"lineHeight",
"marginBottom",
"marginLeft",
"marginRight",
"marginTop",
"maxHeight",
"maxWidth",
"minHeight",
"minWidth",
"opacity",
"order",
"outlineColor",
"outlineStyle",
"outlineWidth",
"overflow",
"overflowWrap",
"paddingBottom",
"paddingLeft",
"paddingRight",
"paddingTop",
"pointerEvents",
"position",
"right",
"textAlign",
"textDecorationColor",
"textDecorationLine",
"textIndent",
"textOverflow",
"textShadow",
"textTransform",
"top",
"transform",
"transformOrigin",
"transitionDelay",
"transitionDuration",
"transitionProperty",
"transitionTimingFunction",
"verticalAlign",
"visibility",
"whiteSpace",
"width",
"zIndex"};

class HTMLElementStyleTestLongHandStyles
: public testing::TestWithJavaScriptBase,
public ::testing::TestWithParam<const char*> {};
} // namespace

TEST_P(HTMLElementStyleTestLongHandStyles, SetStyle) {
const char* style_attribute_name = GetParam();
std::string property_name = CamelCaseToPropertyName(style_attribute_name);
std::string script = base::StringPrintf(
R"(
var style_name = '%s';
var result = style_name;
var div = document.createElement('div');
div.style.%s = 'initial';
if (div.style.%s != 'initial') { result = 'Could not be set to \'initial\': \'' + div.style.%s + '\''; }
if (div.style.cssText != '%s: initial;') { result = 'cssText is not set to \'initial\': cssText \'' + div.style.cssText + '\''; }
div.style.%s = 'inherit';
if (div.style.%s != 'inherit') { result = 'Could not be set to \'inherit\': \'' + div.style.%s + '\''; }
if (div.style.cssText != '%s: inherit;') { result = 'cssText is not set to \'inherit\': cssText \'' + div.style.cssText + '\''; }
result
)",
style_attribute_name, style_attribute_name, style_attribute_name,
style_attribute_name, property_name.c_str(), style_attribute_name,
style_attribute_name, style_attribute_name, property_name.c_str());
std::string result;
EXPECT_TRUE(EvaluateScript(script, &result));
EXPECT_EQ(style_attribute_name, result) << script;
}

INSTANTIATE_TEST_CASE_P(HTMLElementStyleTest,
HTMLElementStyleTestLongHandStyles,
::testing::ValuesIn(longhand_styles), GetStyleName);

namespace {
const char* shorthand_simple_styles[] = {
"animation", "background", "border", "borderBottom", "borderLeft",
"borderRight", "borderTop", "flex", "font", "margin",
"outline", "padding", "textDecoration", "transition"};

class HTMLElementStyleTestShortHandStyles
: public testing::TestWithJavaScriptBase,
public ::testing::TestWithParam<const char*> {};
} // namespace

TEST_P(HTMLElementStyleTestShortHandStyles, SetStyle) {
const char* style_attribute_name = GetParam();
std::string property_name = CamelCaseToPropertyName(style_attribute_name);
std::string script = base::StringPrintf(
R"(
var style_name = '%s';
var result = style_name;
var div = document.createElement('div');
div.style.%s = 'initial';
if (!div.style.cssText.includes('initial')) { result = 'cssText does not contain \'initial\': cssText \'' + div.style.cssText + '\''; }
if (!div.style.cssText.includes('%s')) { result = 'cssText does not contain \'%s\': cssText \'' + div.style.cssText + '\''; }
div.style.%s = 'inherit';
if (!div.style.cssText.includes('inherit')) { result = 'cssText does not contain \'inherit\': cssText \'' + div.style.cssText + '\''; }
if (!div.style.cssText.includes('%s')) { result = 'cssText does not contain \'%s\': cssText \'' + div.style.cssText + '\''; }
result
)",
style_attribute_name, style_attribute_name, property_name.c_str(),
property_name.c_str(), style_attribute_name, property_name.c_str(),
property_name.c_str());
std::string result;
EXPECT_TRUE(EvaluateScript(script, &result));
EXPECT_EQ(style_attribute_name, result) << script;
}

INSTANTIATE_TEST_CASE_P(HTMLElementStyleTest,
HTMLElementStyleTestShortHandStyles,
::testing::ValuesIn(shorthand_simple_styles),
GetStyleName);

namespace {
const char* renamed_styles[] = {
"borderColor", // Shorthand for border[Top|Right|Bottom|Left]Color.
"borderRadius", // Shorthand for
// border[TopLeft|TopRight|BottomRight|BottomLeft]Radius.
"borderStyle", // Shorthand for border[Top|Right|Bottom|Left]Style.
"borderWidth", // Shorthand for border[Top|Right|Bottom|Left]Width.
"flexFlow", // Shorthand for flexDirection and flexWrap.
"wordWrap", // Alias for overflowWrap.
};

class HTMLElementStyleTestRenamedStyles
: public testing::TestWithJavaScriptBase,
public ::testing::TestWithParam<const char*> {};
} // namespace

TEST_P(HTMLElementStyleTestRenamedStyles, SetStyle) {
const char* style_attribute_name = GetParam();
std::string script = base::StringPrintf(
R"(
var style_name = '%s';
var result = style_name;
var div = document.createElement('div');
div.style.%s = 'initial';
if (!div.style.cssText.includes('initial')) { result = 'cssText does not contain \'initial\': cssText \'' + div.style.cssText + '\''; }
div.style.%s = 'inherit';
if (!div.style.cssText.includes('inherit')) { result = 'cssText does not contain \'inherit\': cssText \'' + div.style.cssText + '\''; }
result
)",
style_attribute_name, style_attribute_name, style_attribute_name);
std::string result;
EXPECT_TRUE(EvaluateScript(script, &result));
EXPECT_EQ(style_attribute_name, result) << script;
}

INSTANTIATE_TEST_CASE_P(HTMLElementStyleTest, HTMLElementStyleTestRenamedStyles,
::testing::ValuesIn(renamed_styles), GetStyleName);


} // namespace dom
} // namespace cobalt
11 changes: 7 additions & 4 deletions cobalt/dom/testing/test_with_javascript.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,10 +34,10 @@ namespace dom {
namespace testing {

// Helper class for running tests in a Window JavaScript context.
class TestWithJavaScript : public ::testing::Test {
class TestWithJavaScriptBase {
public:
TestWithJavaScript() { stub_window_.reset(new StubWindow()); }
~TestWithJavaScript() {
TestWithJavaScriptBase() { stub_window_.reset(new StubWindow()); }
virtual ~TestWithJavaScriptBase() {
stub_window_.reset();
EXPECT_TRUE(GlobalStats::GetInstance()->CheckNoLeaks());
}
Expand Down Expand Up @@ -94,14 +94,17 @@ class TestWithJavaScript : public ::testing::Test {
global_environment()->EnableEval();
global_environment()->SetReportEvalCallback(base::Closure());
return script::SourceCode::CreateSourceCode(
js_code, base::SourceLocation(__FILE__, __LINE__, 1));
js_code, base::SourceLocation(js_code.c_str(), 1, 1));
}

std::unique_ptr<StubWindow> stub_window_;
::testing::StrictMock<script::testing::MockExceptionState> exception_state_;
base::EventDispatcher event_dispatcher_;
};

class TestWithJavaScript : public TestWithJavaScriptBase,
public ::testing::Test {};

} // namespace testing
} // namespace dom
} // namespace cobalt
Expand Down
15 changes: 15 additions & 0 deletions cobalt/dom/window.h
Original file line number Diff line number Diff line change
Expand Up @@ -283,6 +283,21 @@ class Window : public web::WindowOrWorkerGlobalScope,
scoped_refptr<Storage> local_storage() const;
scoped_refptr<Storage> session_storage() const;

// Web API: WindowEventHandlers (implements)
const EventListenerScriptValue* onhashchange() {
return GetAttributeEventListener(base::Tokens::hashchange());
}
void set_onhashchange(const EventListenerScriptValue& event_listener) {
SetAttributeEventListener(base::Tokens::hashchange(), event_listener);
}

const EventListenerScriptValue* onunload() {
return GetAttributeEventListener(base::Tokens::unload());
}
void set_onunload(const EventListenerScriptValue& event_listener) {
SetAttributeEventListener(base::Tokens::unload(), event_listener);
}

// Access to the Performance API (partial interface)
// https://dvcs.w3.org/hg/webperf/raw-file/tip/specs/NavigationTiming/Overview.html#sec-window.performance-attribute
const scoped_refptr<Performance>& performance() const;
Expand Down
3 changes: 3 additions & 0 deletions cobalt/dom/window_event_handlers.idl
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,10 @@

[NoInterfaceObject] interface WindowEventHandlers {
attribute EventHandler onbeforeunload;
attribute EventHandler onhashchange;
attribute EventHandler onlanguagechange;
attribute EventHandler onmessage;
attribute EventHandler onmessageerror;
attribute EventHandler onoffline;
attribute EventHandler ononline;
attribute EventHandler onrejectionhandled;
Expand Down
Loading

0 comments on commit f09ca39

Please sign in to comment.