blob: f558a840c2f91bc827b99e8080276da2a228e575 [file] [log] [blame]
// Copyright 2016 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/loader/resource/css_style_sheet_resource.h"
#include "base/memory/scoped_refptr.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/blink/public/platform/platform.h"
#include "third_party/blink/public/platform/scheduler/test/renderer_scheduler_test_support.h"
#include "third_party/blink/public/platform/web_url_response.h"
#include "third_party/blink/renderer/core/css/css_crossfade_value.h"
#include "third_party/blink/renderer/core/css/css_image_value.h"
#include "third_party/blink/renderer/core/css/css_primitive_value.h"
#include "third_party/blink/renderer/core/css/css_property_value.h"
#include "third_party/blink/renderer/core/css/css_property_value_set.h"
#include "third_party/blink/renderer/core/css/css_selector_list.h"
#include "third_party/blink/renderer/core/css/css_style_sheet.h"
#include "third_party/blink/renderer/core/css/parser/css_parser_context.h"
#include "third_party/blink/renderer/core/css/parser/css_parser_selector.h"
#include "third_party/blink/renderer/core/css/style_rule.h"
#include "third_party/blink/renderer/core/css/style_sheet_contents.h"
#include "third_party/blink/renderer/core/dom/document.h"
#include "third_party/blink/renderer/core/loader/resource/image_resource.h"
#include "third_party/blink/renderer/core/testing/page_test_base.h"
#include "third_party/blink/renderer/platform/heap/handle.h"
#include "third_party/blink/renderer/platform/heap/heap.h"
#include "third_party/blink/renderer/platform/loader/fetch/fetch_context.h"
#include "third_party/blink/renderer/platform/loader/fetch/fetch_initiator_type_names.h"
#include "third_party/blink/renderer/platform/loader/fetch/memory_cache.h"
#include "third_party/blink/renderer/platform/loader/fetch/resource_fetcher.h"
#include "third_party/blink/renderer/platform/loader/fetch/resource_request.h"
#include "third_party/blink/renderer/platform/testing/unit_test_helpers.h"
#include "third_party/blink/renderer/platform/testing/url_test_helpers.h"
#include "third_party/blink/renderer/platform/weborigin/kurl.h"
#include "third_party/blink/renderer/platform/wtf/text/text_encoding.h"
#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
namespace blink {
class Document;
namespace {
class CSSStyleSheetResourceTest : public PageTestBase {
protected:
CSSStyleSheetResourceTest() {
original_memory_cache_ =
ReplaceMemoryCacheForTesting(MakeGarbageCollected<MemoryCache>(
blink::scheduler::GetSingleThreadTaskRunnerForTesting()));
}
~CSSStyleSheetResourceTest() override {
ReplaceMemoryCacheForTesting(original_memory_cache_.Release());
}
void SetUp() override {
PageTestBase::SetUp(IntSize());
GetDocument().SetURL(KURL("https://localhost/"));
}
CSSStyleSheetResource* CreateAndSaveTestStyleSheetResource() {
const char kUrl[] = "https://localhost/style.css";
const KURL css_url(kUrl);
ResourceResponse response(css_url);
response.SetMimeType("style/css");
CSSStyleSheetResource* css_resource =
CSSStyleSheetResource::CreateForTest(css_url, UTF8Encoding());
css_resource->ResponseReceived(response);
css_resource->FinishForTest();
GetMemoryCache()->Add(css_resource);
return css_resource;
}
Persistent<MemoryCache> original_memory_cache_;
};
TEST_F(CSSStyleSheetResourceTest, DuplicateResourceNotCached) {
const char kUrl[] = "https://localhost/style.css";
const KURL image_url(kUrl);
const KURL css_url(kUrl);
ResourceResponse response(css_url);
response.SetMimeType("style/css");
// Emulate using <img> to do async stylesheet preloads.
Resource* image_resource = ImageResource::CreateForTest(image_url);
ASSERT_TRUE(image_resource);
GetMemoryCache()->Add(image_resource);
ASSERT_TRUE(GetMemoryCache()->Contains(image_resource));
CSSStyleSheetResource* css_resource =
CSSStyleSheetResource::CreateForTest(css_url, UTF8Encoding());
css_resource->ResponseReceived(response);
css_resource->FinishForTest();
auto* parser_context = MakeGarbageCollected<CSSParserContext>(
kHTMLStandardMode, SecureContextMode::kInsecureContext);
auto* contents = MakeGarbageCollected<StyleSheetContents>(parser_context);
auto* sheet = MakeGarbageCollected<CSSStyleSheet>(contents, GetDocument());
EXPECT_TRUE(sheet);
contents->CheckLoaded();
css_resource->SaveParsedStyleSheet(contents);
// Verify that the cache will have a mapping for |imageResource| at |url|.
// The underlying |contents| for the stylesheet resource must have a
// matching reference status.
EXPECT_TRUE(GetMemoryCache()->Contains(image_resource));
EXPECT_FALSE(GetMemoryCache()->Contains(css_resource));
EXPECT_FALSE(contents->IsReferencedFromResource());
EXPECT_FALSE(css_resource->CreateParsedStyleSheetFromCache(parser_context));
}
TEST_F(CSSStyleSheetResourceTest, CreateFromCacheRestoresOriginalSheet) {
CSSStyleSheetResource* css_resource = CreateAndSaveTestStyleSheetResource();
auto* parser_context = MakeGarbageCollected<CSSParserContext>(
kHTMLStandardMode, SecureContextMode::kInsecureContext);
auto* contents = MakeGarbageCollected<StyleSheetContents>(parser_context);
auto* sheet = MakeGarbageCollected<CSSStyleSheet>(contents, GetDocument());
ASSERT_TRUE(sheet);
contents->ParseString("div { color: red; }");
contents->NotifyLoadedSheet(css_resource);
contents->CheckLoaded();
EXPECT_TRUE(contents->IsCacheableForResource());
css_resource->SaveParsedStyleSheet(contents);
EXPECT_TRUE(GetMemoryCache()->Contains(css_resource));
EXPECT_TRUE(contents->IsReferencedFromResource());
StyleSheetContents* parsed_stylesheet =
css_resource->CreateParsedStyleSheetFromCache(parser_context);
ASSERT_EQ(contents, parsed_stylesheet);
}
TEST_F(CSSStyleSheetResourceTest,
CreateFromCacheWithMediaQueriesCopiesOriginalSheet) {
CSSStyleSheetResource* css_resource = CreateAndSaveTestStyleSheetResource();
auto* parser_context = MakeGarbageCollected<CSSParserContext>(
kHTMLStandardMode, SecureContextMode::kInsecureContext);
auto* contents = MakeGarbageCollected<StyleSheetContents>(parser_context);
auto* sheet = MakeGarbageCollected<CSSStyleSheet>(contents, GetDocument());
ASSERT_TRUE(sheet);
contents->ParseString("@media { div { color: red; } }");
contents->NotifyLoadedSheet(css_resource);
contents->CheckLoaded();
EXPECT_TRUE(contents->IsCacheableForResource());
contents->EnsureRuleSet(MediaQueryEvaluator(GetDocument().GetFrame()),
kRuleHasNoSpecialState);
EXPECT_TRUE(contents->HasRuleSet());
css_resource->SaveParsedStyleSheet(contents);
EXPECT_TRUE(GetMemoryCache()->Contains(css_resource));
EXPECT_TRUE(contents->IsReferencedFromResource());
StyleSheetContents* parsed_stylesheet =
css_resource->CreateParsedStyleSheetFromCache(parser_context);
ASSERT_TRUE(parsed_stylesheet);
sheet->ClearOwnerNode();
sheet = MakeGarbageCollected<CSSStyleSheet>(parsed_stylesheet, GetDocument());
ASSERT_TRUE(sheet);
EXPECT_TRUE(contents->HasSingleOwnerDocument());
EXPECT_EQ(0U, contents->ClientSize());
EXPECT_TRUE(contents->IsReferencedFromResource());
EXPECT_TRUE(contents->HasRuleSet());
EXPECT_TRUE(parsed_stylesheet->HasSingleOwnerDocument());
EXPECT_TRUE(parsed_stylesheet->HasOneClient());
EXPECT_FALSE(parsed_stylesheet->IsReferencedFromResource());
EXPECT_FALSE(parsed_stylesheet->HasRuleSet());
}
} // namespace
} // namespace blink