blob: 8ac27884149e74a7dea6745a8847c84b9ba76fef [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 "core/loader/resource/CSSStyleSheetResource.h"
#include <memory>
#include "base/memory/scoped_refptr.h"
#include "core/css/CSSCrossfadeValue.h"
#include "core/css/CSSImageValue.h"
#include "core/css/CSSPrimitiveValue.h"
#include "core/css/CSSPropertyValue.h"
#include "core/css/CSSPropertyValueSet.h"
#include "core/css/CSSSelectorList.h"
#include "core/css/CSSStyleSheet.h"
#include "core/css/StyleRule.h"
#include "core/css/StyleSheetContents.h"
#include "core/css/parser/CSSParserContext.h"
#include "core/css/parser/CSSParserSelector.h"
#include "core/dom/Document.h"
#include "core/loader/resource/ImageResource.h"
#include "core/testing/DummyPageHolder.h"
#include "platform/heap/Handle.h"
#include "platform/heap/Heap.h"
#include "platform/loader/fetch/FetchContext.h"
#include "platform/loader/fetch/MemoryCache.h"
#include "platform/loader/fetch/ResourceFetcher.h"
#include "platform/loader/fetch/ResourceRequest.h"
#include "platform/loader/fetch/fetch_initiator_type_names.h"
#include "platform/testing/URLTestHelpers.h"
#include "platform/testing/UnitTestHelpers.h"
#include "platform/weborigin/KURL.h"
#include "platform/wtf/PtrUtil.h"
#include "platform/wtf/text/TextEncoding.h"
#include "platform/wtf/text/WTFString.h"
#include "public/platform/Platform.h"
#include "public/platform/WebURLResponse.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace blink {
class Document;
namespace {
class CSSStyleSheetResourceTest : public ::testing::Test {
protected:
CSSStyleSheetResourceTest() {
original_memory_cache_ =
ReplaceMemoryCacheForTesting(MemoryCache::Create());
page_ = DummyPageHolder::Create();
GetDocument().SetURL(KURL(NullURL(), "https://localhost/"));
}
~CSSStyleSheetResourceTest() override {
ReplaceMemoryCacheForTesting(original_memory_cache_.Release());
}
CSSStyleSheetResource* CreateAndSaveTestStyleSheetResource() {
const char kUrl[] = "https://localhost/style.css";
KURL css_url(NullURL(), kUrl);
CSSStyleSheetResource* css_resource =
CSSStyleSheetResource::CreateForTest(css_url, UTF8Encoding());
css_resource->ResponseReceived(
ResourceResponse(css_url, "style/css", 0, g_null_atom), nullptr);
css_resource->FinishForTest();
GetMemoryCache()->Add(css_resource);
return css_resource;
}
Document& GetDocument() { return page_->GetDocument(); }
Persistent<MemoryCache> original_memory_cache_;
std::unique_ptr<DummyPageHolder> page_;
};
TEST_F(CSSStyleSheetResourceTest, DuplicateResourceNotCached) {
const char kUrl[] = "https://localhost/style.css";
KURL image_url(NullURL(), kUrl);
KURL css_url(NullURL(), kUrl);
// 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(
ResourceResponse(css_url, "style/css", 0, g_null_atom), nullptr);
css_resource->FinishForTest();
CSSParserContext* parser_context = CSSParserContext::Create(
kHTMLStandardMode, SecureContextMode::kInsecureContext);
StyleSheetContents* contents = StyleSheetContents::Create(parser_context);
CSSStyleSheet* sheet = CSSStyleSheet::Create(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();
CSSParserContext* parser_context = CSSParserContext::Create(
kHTMLStandardMode, SecureContextMode::kInsecureContext);
StyleSheetContents* contents = StyleSheetContents::Create(parser_context);
CSSStyleSheet* sheet = CSSStyleSheet::Create(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();
CSSParserContext* parser_context = CSSParserContext::Create(
kHTMLStandardMode, SecureContextMode::kInsecureContext);
StyleSheetContents* contents = StyleSheetContents::Create(parser_context);
CSSStyleSheet* sheet = CSSStyleSheet::Create(contents, GetDocument());
ASSERT_TRUE(sheet);
contents->ParseString("@media { div { color: red; } }");
contents->NotifyLoadedSheet(css_resource);
contents->CheckLoaded();
EXPECT_TRUE(contents->IsCacheableForResource());
contents->EnsureRuleSet(MediaQueryEvaluator(), 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 = CSSStyleSheet::Create(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