| // Copyright 2015 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 "ios/web/webui/crw_web_ui_page_builder.h" |
| |
| #import <Foundation/Foundation.h> |
| |
| #include "base/logging.h" |
| #import "base/mac/scoped_nsobject.h" |
| #include "base/strings/sys_string_conversions.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| #include "testing/gtest_mac.h" |
| #include "testing/platform_test.h" |
| #include "url/gurl.h" |
| |
| namespace { |
| |
| // HTML page template. |
| NSString* const kPageTemplate = @"<html><head>%@</head></html>"; |
| |
| // URL for BuildSimplePage. |
| const char* kSimplePageUrl("http://simplepage"); |
| // URL for BuildPageWithJSSubresource. |
| const char* kJsPageUrl("http://javascriptpage"); |
| // URL for BuildPageWithCSSSubresource. |
| const char* kCssPageUrl("http://csspage"); |
| // URL for BuildPageWithMultipleSubresources. |
| const char* kMultipleResourcesPageUrl("http://multipleresourcespage"); |
| // URL for BuildPageWithCSSNestedSubresources. |
| const char* kCssImportPageUrl("http://csspagewithimport"); |
| // URL for BuildPageWithRelativeSubresource. |
| const char* kCssRelativePageUrl("http://css/csspage.html"); |
| // URL for BuildPageWithWebUIJS. |
| const char* kCoreJsPageUrl("http://corejs"); |
| |
| // URL for JS resource. |
| const char* kJsResourceUrl("http://javascriptpage/resources/javascript.js"); |
| // URL for CSS resource. |
| const char* kCssResourceUrl("http://csspage/resources/stylesheet.css"); |
| // URL for CSS resource with import. |
| const char* kCssImportResourceUrl("http://csspage/resources/import.css"); |
| // Chrome URL for messaging JavaScript. |
| const char* kCoreJsResourceUrl("chrome://resources/js/ios/web_ui.js"); |
| // String for relative resource URL. |
| const char* kRelativeCssString("myresource.css"); |
| |
| // Template for JS tag with URL. |
| NSString* const kJsTagTemplate = @"<script src=\"%@\"></script>"; |
| // Template for inlined JS tag. |
| NSString* const kJsInlinedTemplate = @"<script>%@</script>"; |
| // Template for CSS tag with URL. |
| NSString* const kCssTagTemplate = @"<link rel=\"stylesheet\" href=\"%@\">"; |
| // Template for inlined CSS tag. |
| NSString* const kCssInlinedTemplate = @"<style>%@</style>"; |
| // Template for CSS with import statement. |
| NSString* const kCssImportTemplate = @"@import url(%@); b {diplay:block;}"; |
| |
| // Content for JS resource. |
| NSString* const kJsContent = @"console.log('This is JavaScript');"; |
| // Content for CSS resource. |
| NSString* const kCssContent = @"html {height:100%;}"; |
| // Content for relative CSS resource. |
| NSString* const kRelativeCssContent = @"mytag {someprop:1}"; |
| // Dummy content for WebUI messaging JavaScript. |
| NSString* kCoreJsContent = @"console.log('messaging javascript');"; |
| |
| // Returns HTML string containing tag formed with tag_template and content. |
| NSString* PageForTagTemplateAndContent(NSString* tag_template, |
| NSString* content) { |
| NSString* tag = [NSString stringWithFormat:tag_template, content]; |
| return [NSString stringWithFormat:kPageTemplate, tag]; |
| } |
| |
| } // namespace |
| |
| // Mock subclass of CRWWebUIPageBuilder for testing. |
| @interface MockCRWWebUIPageBuilder : CRWWebUIPageBuilder |
| // Stub out webUIJavaScript method so resource bundle access is not needed. |
| - (NSString*)webUIJavaScript; |
| @end |
| |
| @implementation MockCRWWebUIPageBuilder |
| - (NSString*)webUIJavaScript { |
| return kCoreJsContent; |
| } |
| @end |
| |
| // Mock CRWWebUIPageBuilderDelegate to serve responses for resource requests. |
| @interface MockPageBuilderDelegate : NSObject<CRWWebUIPageBuilderDelegate> |
| // Returns HTML page containing tag formed from tagTemplate and URL. |
| - (NSString*)pageWithTagTemplate:(NSString*)tagTemplate URL:(const char*)URL; |
| // Returns resource string for resourceURL. |
| - (NSString*)resourceForURL:(const GURL&)resourceURL; |
| @end |
| |
| @implementation MockPageBuilderDelegate |
| |
| - (void)webUIPageBuilder:(CRWWebUIPageBuilder*)webUIPageBuilder |
| fetchResourceWithURL:(const GURL&)resourceURL |
| completionHandler:(web::WebUIDelegateCompletion)completionHandler { |
| completionHandler([self resourceForURL:resourceURL], resourceURL); |
| } |
| |
| - (NSString*)resourceForURL:(const GURL&)resourceURL { |
| // Resource for BuildSimplePage. |
| if (resourceURL == GURL(kSimplePageUrl)) |
| return [NSString stringWithFormat:kPageTemplate, @""]; |
| // Resources for BuildPageWithJSSubresource. |
| if (resourceURL == GURL(kJsPageUrl)) |
| return [self pageWithTagTemplate:kJsTagTemplate URL:kJsResourceUrl]; |
| if (resourceURL == GURL(kJsResourceUrl)) |
| return kJsContent; |
| // Resources for BuildPageWithCSSSubresource. |
| if (resourceURL == GURL(kCssPageUrl)) |
| return [self pageWithTagTemplate:kCssTagTemplate URL:kCssResourceUrl]; |
| if (resourceURL == GURL(kCssResourceUrl)) |
| return kCssContent; |
| // Resource for BuildPageWithMultipleSubresources. |
| if (resourceURL == GURL(kMultipleResourcesPageUrl)) { |
| NSString* JSTag = |
| [NSString stringWithFormat:kJsTagTemplate, |
| base::SysUTF8ToNSString(kJsResourceUrl)]; |
| NSString* CSSTag = |
| [NSString stringWithFormat:kCssTagTemplate, |
| base::SysUTF8ToNSString(kCssResourceUrl)]; |
| NSString* CoreJSTag = |
| [NSString stringWithFormat:kJsTagTemplate, |
| base::SysUTF8ToNSString(kCoreJsResourceUrl)]; |
| NSString* tags = [[JSTag stringByAppendingString:CSSTag] |
| stringByAppendingString:CoreJSTag]; |
| return [NSString stringWithFormat:kPageTemplate, tags]; |
| } |
| // Resources for BuildPageWithCSSNestedSubresource. |
| if (resourceURL == GURL(kCssImportPageUrl)) { |
| return [self pageWithTagTemplate:kCssTagTemplate URL:kCssImportResourceUrl]; |
| } |
| if (resourceURL == GURL(kCssImportResourceUrl)) { |
| return [NSString stringWithFormat:kCssImportTemplate, |
| base::SysUTF8ToNSString(kCssResourceUrl)]; |
| } |
| // Resources for BuildPageWithRelativeSubresource. |
| GURL relativePageURL(kCssRelativePageUrl); |
| GURL cssRelativeResourceURL = relativePageURL.Resolve(kRelativeCssString); |
| if (resourceURL == relativePageURL) { |
| return [self pageWithTagTemplate:kCssTagTemplate URL:kRelativeCssString]; |
| } |
| if (resourceURL == cssRelativeResourceURL) |
| return kRelativeCssContent; |
| // Resource for BuildPageWithWebUIJS. |
| if (resourceURL == GURL(kCoreJsPageUrl)) |
| return [self pageWithTagTemplate:kJsTagTemplate URL:kCoreJsResourceUrl]; |
| |
| NOTREACHED(); |
| return nil; |
| } |
| |
| - (NSString*)pageWithTagTemplate:(NSString*)tagTemplate URL:(const char*)URL { |
| NSString* URLString = base::SysUTF8ToNSString(URL); |
| NSString* tag = [NSString stringWithFormat:tagTemplate, URLString]; |
| return [NSString stringWithFormat:kPageTemplate, tag]; |
| } |
| |
| @end |
| |
| namespace web { |
| |
| class CRWWebUIPageBuilderTest : public PlatformTest { |
| protected: |
| void SetUp() override { |
| PlatformTest::SetUp(); |
| delegate_.reset([[MockPageBuilderDelegate alloc] init]); |
| web_ui_page_builder_.reset( |
| [[MockCRWWebUIPageBuilder alloc] initWithDelegate:delegate_]); |
| } |
| // CRWWebUIPageBuilder for testing. |
| base::scoped_nsobject<MockCRWWebUIPageBuilder> web_ui_page_builder_; |
| // Delegate for test CRWWebUIPageBuilder. |
| base::scoped_nsobject<MockPageBuilderDelegate> delegate_; |
| }; |
| |
| // Tests that a page without imports is passed to completion handler unchanged. |
| TEST_F(CRWWebUIPageBuilderTest, BuildSimplePage) { |
| NSString* simple_page_html = [NSString stringWithFormat:kPageTemplate, @""]; |
| [web_ui_page_builder_ buildWebUIPageForURL:GURL(kSimplePageUrl) |
| completionHandler:^(NSString* result) { |
| EXPECT_NSEQ(simple_page_html, result); |
| }]; |
| } |
| |
| // Tests that a page with a JavaScript subresource is passed to the completion |
| // handler with the resource inlined properly, i.e. <script |
| // src="http://somejs.js"></script> becomes <script>some javascript;</script>. |
| TEST_F(CRWWebUIPageBuilderTest, BuildPageWithJSSubresource) { |
| NSString* js_page_html = |
| PageForTagTemplateAndContent(kJsInlinedTemplate, kJsContent); |
| web::WebUIPageCompletion completionHandler = ^(NSString* result) { |
| EXPECT_NSEQ(js_page_html, result); |
| }; |
| [web_ui_page_builder_ buildWebUIPageForURL:GURL(kJsPageUrl) |
| completionHandler:completionHandler]; |
| } |
| |
| // Tests that a page with a CSS subresource is passed to the completion handler |
| // with the resource inlined properly, i.e. <link rel="stylesheet" |
| // href="http://somecss.css"/> becomes <style>some css</style>. |
| TEST_F(CRWWebUIPageBuilderTest, BuildPageWithCSSSubresource) { |
| NSString* css_page_html = |
| PageForTagTemplateAndContent(kCssInlinedTemplate, kCssContent); |
| [web_ui_page_builder_ buildWebUIPageForURL:GURL(kCssPageUrl) |
| completionHandler:^(NSString* result) { |
| EXPECT_NSEQ(css_page_html, result); |
| }]; |
| } |
| |
| TEST_F(CRWWebUIPageBuilderTest, BuildPageWithMultipleSubresources) { |
| NSString* js_tag = [NSString stringWithFormat:kJsInlinedTemplate, kJsContent]; |
| NSString* css_tag = |
| [NSString stringWithFormat:kCssInlinedTemplate, kCssContent]; |
| NSString* core_js_tag = |
| [NSString stringWithFormat:kJsInlinedTemplate, kCoreJsContent]; |
| NSString* tags = [[js_tag stringByAppendingString:css_tag] |
| stringByAppendingString:core_js_tag]; |
| NSString* multiple_resources_html = |
| [NSString stringWithFormat:kPageTemplate, tags]; |
| [web_ui_page_builder_ buildWebUIPageForURL:GURL(kMultipleResourcesPageUrl) |
| completionHandler:^(NSString* result) { |
| EXPECT_NSEQ(multiple_resources_html, result); |
| }]; |
| } |
| |
| // Tests that a page with a CSS subresource that contains an @import statement |
| // for another CSS subresource is passed to the completion handler with the |
| // resource inlined properly, i.e. if somecss.css from above has the statement |
| // @import url(morecss.css), the original tag becomes <style>contents of |
| // morecss</style><style>some css</style>. |
| TEST_F(CRWWebUIPageBuilderTest, BuildPageWithCSSNestedSubresource) { |
| NSString* css_inlined_tag = |
| [NSString stringWithFormat:kCssInlinedTemplate, kCssContent]; |
| NSString* css_inlined_content = |
| [NSString stringWithFormat:kCssImportTemplate, |
| base::SysUTF8ToNSString(kCssResourceUrl)]; |
| NSString* css_import_inlined_tag = |
| [NSString stringWithFormat:kCssInlinedTemplate, css_inlined_content]; |
| NSString* tags = |
| [css_inlined_tag stringByAppendingString:css_import_inlined_tag]; |
| NSString* css_import_page_html = |
| [NSString stringWithFormat:kPageTemplate, tags]; |
| [web_ui_page_builder_ buildWebUIPageForURL:GURL(kCssImportPageUrl) |
| completionHandler:^(NSString* result) { |
| EXPECT_NSEQ(css_import_page_html, result); |
| }]; |
| } |
| |
| // Tests that a page with a relative subresource is properly resolved. |
| TEST_F(CRWWebUIPageBuilderTest, BuildPageWithRelativeSubresource) { |
| NSString* css_page_html = |
| PageForTagTemplateAndContent(kCssInlinedTemplate, kRelativeCssContent); |
| [web_ui_page_builder_ buildWebUIPageForURL:GURL(kCssRelativePageUrl) |
| completionHandler:^(NSString* result) { |
| EXPECT_NSEQ(css_page_html, result); |
| }]; |
| } |
| |
| // Tests that the JavaScript for connecting WebUI messaging to web controller |
| // messaging is properly inlined. |
| TEST_F(CRWWebUIPageBuilderTest, BuildPageWithWebUIJS) { |
| NSString* core_js_html = |
| PageForTagTemplateAndContent(kJsInlinedTemplate, kCoreJsContent); |
| [web_ui_page_builder_ buildWebUIPageForURL:GURL(kCoreJsPageUrl) |
| completionHandler:^(NSString* result) { |
| EXPECT_NSEQ(core_js_html, result); |
| }]; |
| } |
| |
| } // namespace web |