| /* |
| * Copyright 2014 Google Inc. |
| * |
| * 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. |
| */ |
| |
| // Author: stevensr@google.com (Ryan Stevens) |
| |
| #include "net/instaweb/rewriter/public/mobilize_rewrite_filter.h" |
| |
| #include "base/logging.h" |
| #include "net/instaweb/public/global_constants.h" |
| #include "net/instaweb/rewriter/public/rewrite_driver.h" |
| #include "net/instaweb/rewriter/public/rewrite_options.h" |
| #include "net/instaweb/rewriter/public/rewrite_test_base.h" |
| #include "net/instaweb/rewriter/public/server_context.h" |
| #include "pagespeed/kernel/base/gtest.h" |
| #include "pagespeed/kernel/base/mock_message_handler.h" |
| #include "pagespeed/kernel/base/scoped_ptr.h" |
| #include "pagespeed/kernel/base/statistics.h" |
| #include "pagespeed/kernel/base/stdio_file_system.h" |
| #include "pagespeed/kernel/base/string.h" |
| #include "pagespeed/kernel/base/string_util.h" |
| #include "pagespeed/kernel/html/html_element.h" |
| #include "pagespeed/kernel/html/html_node.h" |
| #include "pagespeed/kernel/html/html_parse_test_base.h" |
| #include "pagespeed/kernel/html/html_writer_filter.h" |
| #include "pagespeed/kernel/http/content_type.h" |
| #include "pagespeed/kernel/http/user_agent_matcher_test_base.h" |
| |
| namespace net_instaweb { |
| |
| namespace { |
| |
| const char kTestDataDir[] = "/net/instaweb/rewriter/testdata/"; |
| const char kOriginal[] = "mobilize_test.html"; |
| const char kRewritten[] = "mobilize_test_output.html"; |
| const char kPhoneNumber[] = "16175551212"; |
| const int64 kConversionId = 42; |
| const char kPhoneConversionLabel[] = "HelloWorld"; |
| const char kMobBeaconUrl[] = "/beacon"; |
| |
| GoogleString Styles(bool layout_mode) { |
| return StrCat( |
| "<link rel=\"stylesheet\" href=\"/psajs/mobilize_css.0.css\">", |
| (layout_mode |
| ? "<link rel=\"stylesheet\" href=\"/psajs/mobilize_layout_css.0.css\">" |
| : "")); |
| } |
| |
| GoogleString HeadAndViewport(bool layout_mode) { |
| return StrCat( |
| "<meta itemprop=\"telephone\" content=\"", kPhoneNumber, "\"/>", |
| (layout_mode ? ("<meta name='viewport' content='width=device-width'/>" |
| "<script src=\"/psajs/mobilize_xhr.0.js\"></script>") |
| : "")); |
| } |
| |
| } // namespace |
| |
| // Base class for doing our tests. Can access MobilizeRewriteFilter's private |
| // API. |
| class MobilizeRewriteFilterTest : public RewriteTestBase { |
| protected: |
| MobilizeRewriteFilterTest() {} |
| |
| void CheckExpected(const GoogleString& expected) { |
| PrepareWrite(); |
| EXPECT_STREQ(expected, output_buffer_); |
| } |
| |
| virtual void SetUp() { |
| RewriteTestBase::SetUp(); |
| options()->ClearSignatureForTesting(); |
| options()->set_mob_always(true); |
| options()->set_mob_phone_number(kPhoneNumber); |
| options()->set_mob_conversion_id(kConversionId); |
| options()->set_mob_phone_conversion_label(kPhoneConversionLabel); |
| options()->set_mob_beacon_url(kMobBeaconUrl); |
| options()->set_mob_layout(LayoutMode()); |
| options()->set_mob_nav(true); |
| server_context()->ComputeSignature(options()); |
| SetHtmlMimetype(); // Don't wrap scripts in <![CDATA[ ]]> |
| |
| filter_.reset(new MobilizeRewriteFilter(rewrite_driver())); |
| } |
| |
| virtual void TearDown() { |
| RewriteTestBase::TearDown(); |
| } |
| |
| virtual bool LayoutMode() const { return true; } |
| virtual bool AddBody() const { return false; } |
| virtual bool AddHtmlTags() const { return false; } |
| |
| void CheckVariable(const char* name, int value) { |
| Variable* var = rewrite_driver()->statistics()->FindVariable(name); |
| if (var == NULL) { |
| CHECK(false) << "Checked for a variable that doesn't exit."; |
| } else { |
| EXPECT_EQ(value, var->Get()) << name; |
| } |
| } |
| |
| // Wrappers for MobilizeRewriteFilter private API. |
| void FilterAddStyle(HtmlElement* element) { |
| filter_->AddStyle(element); |
| } |
| MobileRole::Level FilterGetMobileRole(HtmlElement* element) { |
| return filter_->GetMobileRole(element); |
| } |
| void FilterSetAddedProgress(bool added) { |
| filter_->added_progress_ = added; |
| } |
| |
| GoogleString ScriptsAtEndOfBody(StringPiece bg_color, |
| StringPiece fg_color) const { |
| return StrCat( |
| "<script src=\"/psajs/mobilize.0.js\"></script>" |
| "<script>window.psDebugMode=false;window.psNavMode=true;" |
| "window.psLabeledMode=false;window.psConfigMode=false;" |
| "window.psLayoutMode=", |
| BoolToString(LayoutMode()), |
| ";window.psStaticJs=false;" |
| "window.psDeviceType='mobile';", |
| "window.psConversionId='", Integer64ToString(kConversionId), |
| "';window.psPhoneNumber='", kPhoneNumber, |
| "';window.psPhoneConversionLabel='", kPhoneConversionLabel, |
| "';window.psMobBackgroundColor=", bg_color, |
| ";window.psMobForegroundColor=", fg_color, ";window.psMobBeaconUrl='", |
| kMobBeaconUrl, "';psStartMobilization();</script>"); |
| } |
| GoogleString ScriptsAtEndOfBody() const { |
| return ScriptsAtEndOfBody("null", "null"); |
| } |
| |
| GoogleString Spacer() const { |
| return "<header id=\"psmob-header-bar\" class=\"psmob-hide\"></header>" |
| "<div id=\"psmob-spacer\"></div>"; |
| } |
| |
| GoogleString Scrim() const { |
| return |
| "<div id=\"ps-progress-scrim\" class=\"psProgressScrim\">" |
| "<a href=\"javascript:psRemoveProgressBar();\"" |
| " id=\"ps-progress-remove\" id=\"ps-progress-show-log\">" |
| "Remove Progress Bar (doesn't stop mobilization)</a><br>" |
| "<a href=\"javascript:psSetDebugMode();\">" |
| "Show Debug Log In Progress Bar</a>" |
| "<div class=\"psProgressBar\">" |
| "<span id=\"ps-progress-span\" class=\"psProgressSpan\"></span></div>" |
| "<pre id=\"ps-progress-log\" class=\"psProgressLog\"/></div>"; |
| } |
| |
| scoped_ptr<MobilizeRewriteFilter> filter_; |
| |
| private: |
| void PrepareWrite() { |
| SetupWriter(); |
| html_parse()->ApplyFilter(html_writer_filter_.get()); |
| } |
| |
| DISALLOW_COPY_AND_ASSIGN(MobilizeRewriteFilterTest); |
| }; |
| |
| namespace { |
| |
| // For testing private functions in isolation. |
| class MobilizeRewriteUnitTest : public MobilizeRewriteFilterTest { |
| protected: |
| MobilizeRewriteUnitTest() {} |
| |
| virtual void SetUp() { |
| MobilizeRewriteFilterTest::SetUp(); |
| static const char kUrl[] = "http://mob.rewrite.test/test.html"; |
| ASSERT_TRUE(html_parse()->StartParse(kUrl)); |
| } |
| |
| virtual void TearDown() { |
| html_parse()->FinishParse(); |
| MobilizeRewriteFilterTest::TearDown(); |
| } |
| |
| private: |
| DISALLOW_COPY_AND_ASSIGN(MobilizeRewriteUnitTest); |
| }; |
| |
| TEST_F(MobilizeRewriteUnitTest, AddStyle) { |
| HtmlElement* head = html_parse()->NewElement(NULL, HtmlName::kHead); |
| html_parse()->InsertNodeBeforeCurrent(head); |
| HtmlCharactersNode* content = html_parse()->NewCharactersNode(head, "123"); |
| html_parse()->AppendChild(head, content); |
| CheckExpected("<head>123</head>"); |
| FilterAddStyle(head); |
| CheckExpected(StrCat("<head>123", Styles(LayoutMode()), "</head>")); |
| } |
| |
| TEST_F(MobilizeRewriteUnitTest, MobileRoleAttribute) { |
| HtmlElement* div = html_parse()->NewElement(NULL, HtmlName::kDiv); |
| html_parse()->AddAttribute(div, "data-mobile-role", "navigational"); |
| // Add the new node to the parse tree so it will be deleted. |
| html_parse()->InsertNodeBeforeCurrent(div); |
| EXPECT_EQ(MobileRole::kNavigational, |
| FilterGetMobileRole(div)); |
| } |
| |
| TEST_F(MobilizeRewriteUnitTest, InvalidMobileRoleAttribute) { |
| HtmlElement* div = html_parse()->NewElement(NULL, HtmlName::kDiv); |
| html_parse()->AddAttribute(div, "data-mobile-role", "garbage"); |
| // Add the new node to the parse tree so it will be deleted. |
| html_parse()->InsertNodeBeforeCurrent(div); |
| EXPECT_EQ(MobileRole::kInvalid, |
| FilterGetMobileRole(div)); |
| } |
| |
| TEST_F(MobilizeRewriteUnitTest, KeeperMobileRoleAttribute) { |
| HtmlElement* script = html_parse()->NewElement(NULL, HtmlName::kScript); |
| // Add the new node to the parse tree so it will be deleted. |
| html_parse()->InsertNodeBeforeCurrent(script); |
| EXPECT_EQ(MobileRole::kKeeper, |
| FilterGetMobileRole(script)); |
| } |
| |
| class MobilizeRewriteFunctionalTest : public MobilizeRewriteFilterTest { |
| protected: |
| MobilizeRewriteFunctionalTest() {} |
| |
| virtual void SetUp() { |
| MobilizeRewriteFilterTest::SetUp(); |
| rewrite_driver()->AppendUnownedPreRenderFilter(filter_.get()); |
| // By default we *don't* add the progress bar scrim. This explicitly gets |
| // overridden in subclasses. |
| FilterSetAddedProgress(true); |
| SetCurrentUserAgent( |
| UserAgentMatcherTestBase::kAndroidChrome21UserAgent); |
| } |
| |
| void HeadTest(const char* name, |
| StringPiece original_head, StringPiece expected_mid_head, |
| int deleted_elements, int keeper_blocks) { |
| GoogleString original = |
| StrCat("<head>\n", original_head, "\n</head>", Body()); |
| GoogleString expected = |
| StrCat("<head>", HeadAndViewport(LayoutMode()), "\n", expected_mid_head, |
| "\n", Styles(LayoutMode()), "</head>", ExpectedBody()); |
| ValidateExpected(name, original, expected); |
| CheckVariable(MobilizeRewriteFilter::kPagesMobilized, 1); |
| CheckVariable(MobilizeRewriteFilter::kKeeperBlocks, keeper_blocks); |
| CheckVariable(MobilizeRewriteFilter::kHeaderBlocks, 0); |
| CheckVariable(MobilizeRewriteFilter::kNavigationalBlocks, 0); |
| CheckVariable(MobilizeRewriteFilter::kContentBlocks, 0); |
| CheckVariable(MobilizeRewriteFilter::kMarginalBlocks, 0); |
| CheckVariable(MobilizeRewriteFilter::kDeletedElements, deleted_elements); |
| } |
| |
| void BodyTest(const char* name, |
| StringPiece original_body, StringPiece expected_mid_body) { |
| // TODO(jmaessen): We should inject a head in these cases, possibly by |
| // requiring AddHeadFilter to run. We should also deal with the complete |
| // absence of a body tag. |
| GoogleString original = |
| StrCat("\n<body>\n", original_body, "\n</body>\n"); |
| GoogleString expected = |
| StrCat("\n<body>", Spacer(), "\n", expected_mid_body, "\n", |
| ScriptsAtEndOfBody(), "</body>\n"); |
| ValidateExpected(name, original, expected); |
| CheckVariable(MobilizeRewriteFilter::kPagesMobilized, 1); |
| } |
| |
| void BodyUnchanged(const char* name, StringPiece body) { |
| BodyTest(name, body, body); |
| } |
| |
| void KeeperTagsTest(const char* name, GoogleString keeper) { |
| BodyUnchanged(name, keeper); |
| CheckVariable(MobilizeRewriteFilter::kKeeperBlocks, 1); |
| CheckVariable(MobilizeRewriteFilter::kHeaderBlocks, 0); |
| CheckVariable(MobilizeRewriteFilter::kNavigationalBlocks, 0); |
| CheckVariable(MobilizeRewriteFilter::kContentBlocks, 0); |
| CheckVariable(MobilizeRewriteFilter::kMarginalBlocks, 0); |
| CheckVariable(MobilizeRewriteFilter::kDeletedElements, 0); |
| } |
| |
| void TwoBodysTest(const char* name, |
| StringPiece first_body, StringPiece second_body) { |
| GoogleString original = |
| StrCat("\n<body>\n", first_body, |
| "\n</body>\n<body>\n", second_body, "\n</body>\n"); |
| GoogleString expected = |
| StrCat("\n<body>", Spacer(), "\n", first_body, "\n</body>\n<body>\n", |
| second_body, "\n", ScriptsAtEndOfBody(), "</body>\n"); |
| ValidateExpected(name, original, expected); |
| CheckVariable(MobilizeRewriteFilter::kPagesMobilized, 1); |
| } |
| |
| GoogleString Body() const { |
| return "\n<body>\nhello, world!\n</body>\n"; |
| } |
| |
| GoogleString ExpectedBody() const { |
| return StrCat("\n<body>", Spacer(), "\nhello, world!\n", |
| ScriptsAtEndOfBody(), "</body>\n"); |
| } |
| |
| GoogleString ExpectedBody(StringPiece bg_color, StringPiece fg_color) const { |
| return StrCat("\n<body>", Spacer(), "\nhello, world!\n", |
| ScriptsAtEndOfBody(bg_color, fg_color), "</body>\n"); |
| } |
| |
| private: |
| DISALLOW_COPY_AND_ASSIGN(MobilizeRewriteFunctionalTest); |
| }; |
| |
| TEST_F(MobilizeRewriteFunctionalTest, AddStyleAndViewport) { |
| HeadTest("add_style_and_viewport", "", "", 0, 0); |
| } |
| |
| TEST_F(MobilizeRewriteFunctionalTest, RemoveExistingViewport) { |
| HeadTest("remove_existing_viewport", |
| "<meta name='viewport' content='value' />", "", 1, 0); |
| } |
| |
| TEST_F(MobilizeRewriteFunctionalTest, RemoveExistingViewportThatMatches) { |
| HeadTest("remove_existing_viewport", |
| "<meta name='viewport' content='width=device-width'/>", "", 1, 0); |
| } |
| |
| TEST_F(MobilizeRewriteFunctionalTest, HeadUnmodified) { |
| const char kHeadTags[] = |
| "<meta name='keywords' content='cool,stuff'/>" |
| "<style>abcd</style>"; |
| HeadTest("head_unmodified", kHeadTags, kHeadTags, 0, 1); |
| } |
| |
| TEST_F(MobilizeRewriteFunctionalTest, HeadLinksUnmodified) { |
| const char kLink[] = |
| "<link rel='stylesheet' type='text/css' href='theme.css'>"; |
| HeadTest("head_unmodified", kLink, kLink, 0, 1); |
| } |
| |
| TEST_F(MobilizeRewriteFunctionalTest, EmptyBody) { |
| GoogleString expected = StrCat("<body>", Spacer(), ScriptsAtEndOfBody(), |
| "</body>"); |
| ValidateExpected("empty_body", |
| "<body></body>", expected); |
| CheckVariable(MobilizeRewriteFilter::kPagesMobilized, 1); |
| CheckVariable(MobilizeRewriteFilter::kKeeperBlocks, 0); |
| CheckVariable(MobilizeRewriteFilter::kHeaderBlocks, 0); |
| CheckVariable(MobilizeRewriteFilter::kNavigationalBlocks, 0); |
| CheckVariable(MobilizeRewriteFilter::kContentBlocks, 0); |
| CheckVariable(MobilizeRewriteFilter::kMarginalBlocks, 0); |
| CheckVariable(MobilizeRewriteFilter::kDeletedElements, 0); |
| } |
| |
| TEST_F(MobilizeRewriteFunctionalTest, EmptyBodyWithProgress) { |
| FilterSetAddedProgress(false); |
| GoogleString expected = StrCat( |
| "<body>", |
| Spacer(), |
| "<div id=\"ps-progress-scrim\" class=\"psProgressScrim\">" |
| "<a href=\"javascript:psRemoveProgressBar();\" id=\"ps-progress-remove\"" |
| " id=\"ps-progress-show-log\">Remove Progress Bar" |
| " (doesn't stop mobilization)</a><br>" |
| "<a href=\"javascript:psSetDebugMode();\">" |
| "Show Debug Log In Progress Bar</a>" |
| "<div class=\"psProgressBar\">" |
| "<span id=\"ps-progress-span\" class=\"psProgressSpan\"></span>" |
| "</div><pre id=\"ps-progress-log\" class=\"psProgressLog\"/></div>", |
| ScriptsAtEndOfBody(), "</body>"); |
| ValidateExpected("empty_body_with_progress", |
| "<body></body>", expected); |
| CheckVariable(MobilizeRewriteFilter::kPagesMobilized, 1); |
| CheckVariable(MobilizeRewriteFilter::kKeeperBlocks, 0); |
| CheckVariable(MobilizeRewriteFilter::kHeaderBlocks, 0); |
| CheckVariable(MobilizeRewriteFilter::kNavigationalBlocks, 0); |
| CheckVariable(MobilizeRewriteFilter::kContentBlocks, 0); |
| CheckVariable(MobilizeRewriteFilter::kMarginalBlocks, 0); |
| CheckVariable(MobilizeRewriteFilter::kDeletedElements, 0); |
| } |
| |
| TEST_F(MobilizeRewriteFunctionalTest, MapTagsUnmodified) { |
| KeeperTagsTest("map_tags_unmodified", |
| "<map name='planetmap'><area shape='rect'" |
| " coords='0,0,82,126' alt='Sun'></map>"); |
| } |
| |
| TEST_F(MobilizeRewriteFunctionalTest, ScriptTagsUnmodified) { |
| KeeperTagsTest("script_tags_unmodified", |
| "<script>document.getElementById('demo')." |
| "innerHTML = 'Hello JavaScript!';</script>"); |
| } |
| |
| TEST_F(MobilizeRewriteFunctionalTest, StyleTagsUnmodified) { |
| KeeperTagsTest("style_tags_unmodified", |
| "<style>* { foo: bar; }</style>"); |
| } |
| |
| TEST_F(MobilizeRewriteFunctionalTest, UnknownMobileRole) { |
| // Its probably OK if the behavior resulting from having a weird |
| // data-mobile-role value is unexpected, as long as it doesn't crash. |
| BodyUnchanged( |
| "unknown_mobile_role", |
| "<div data-mobile-role='garbage'><a>123</a></div>"); |
| CheckVariable(MobilizeRewriteFilter::kKeeperBlocks, 0); |
| CheckVariable(MobilizeRewriteFilter::kHeaderBlocks, 0); |
| CheckVariable(MobilizeRewriteFilter::kNavigationalBlocks, 0); |
| CheckVariable(MobilizeRewriteFilter::kContentBlocks, 0); |
| CheckVariable(MobilizeRewriteFilter::kMarginalBlocks, 0); |
| CheckVariable(MobilizeRewriteFilter::kDeletedElements, 0); |
| } |
| |
| TEST_F(MobilizeRewriteFunctionalTest, MultipleHeads) { |
| // Check we only add the style and viewport tag once. |
| const char kRestOfHeads[] = "</head><head></head>"; |
| GoogleString original = StrCat("<head>", kRestOfHeads); |
| GoogleString expected = |
| StrCat("<head>", HeadAndViewport(LayoutMode()), Styles(LayoutMode()), |
| kRestOfHeads, ScriptsAtEndOfBody()); |
| ValidateExpected("multiple_heads", original, expected); |
| CheckVariable(MobilizeRewriteFilter::kPagesMobilized, 1); |
| CheckVariable(MobilizeRewriteFilter::kKeeperBlocks, 0); |
| CheckVariable(MobilizeRewriteFilter::kHeaderBlocks, 0); |
| CheckVariable(MobilizeRewriteFilter::kNavigationalBlocks, 0); |
| CheckVariable(MobilizeRewriteFilter::kContentBlocks, 0); |
| CheckVariable(MobilizeRewriteFilter::kMarginalBlocks, 0); |
| CheckVariable(MobilizeRewriteFilter::kDeletedElements, 0); |
| } |
| |
| TEST_F(MobilizeRewriteFunctionalTest, MultipleBodys) { |
| // Each body should be handled as its own unit. |
| TwoBodysTest("multiple_bodys", "", ""); |
| CheckVariable(MobilizeRewriteFilter::kKeeperBlocks, 0); |
| CheckVariable(MobilizeRewriteFilter::kHeaderBlocks, 0); |
| CheckVariable(MobilizeRewriteFilter::kNavigationalBlocks, 0); |
| CheckVariable(MobilizeRewriteFilter::kContentBlocks, 0); |
| CheckVariable(MobilizeRewriteFilter::kMarginalBlocks, 0); |
| CheckVariable(MobilizeRewriteFilter::kDeletedElements, 0); |
| } |
| |
| TEST_F(MobilizeRewriteFunctionalTest, MultipleBodysWithContent) { |
| TwoBodysTest( |
| "multiple_bodys_with_content", |
| "123<div data-mobile-role='marginal'>567</div>", |
| "<div data-mobile-role='content'>890</div>" |
| "<div data-mobile-role='header'>abc</div>"); |
| CheckVariable(MobilizeRewriteFilter::kKeeperBlocks, 0); |
| CheckVariable(MobilizeRewriteFilter::kHeaderBlocks, 1); |
| CheckVariable(MobilizeRewriteFilter::kNavigationalBlocks, 0); |
| CheckVariable(MobilizeRewriteFilter::kContentBlocks, 1); |
| CheckVariable(MobilizeRewriteFilter::kMarginalBlocks, 1); |
| CheckVariable(MobilizeRewriteFilter::kDeletedElements, 0); |
| } |
| |
| TEST_F(MobilizeRewriteFunctionalTest, HeaderWithinBody) { |
| BodyUnchanged( |
| "header_within_body", |
| "<div data-mobile-role='content'>123<div data-mobile-role='header'>" |
| "456</div>789</div>"); |
| CheckVariable(MobilizeRewriteFilter::kKeeperBlocks, 0); |
| CheckVariable(MobilizeRewriteFilter::kHeaderBlocks, 1); |
| CheckVariable(MobilizeRewriteFilter::kNavigationalBlocks, 0); |
| CheckVariable(MobilizeRewriteFilter::kContentBlocks, 1); |
| CheckVariable(MobilizeRewriteFilter::kMarginalBlocks, 0); |
| CheckVariable(MobilizeRewriteFilter::kDeletedElements, 0); |
| } |
| |
| TEST_F(MobilizeRewriteFunctionalTest, HeaderWithinHeader) { |
| // Note: this should occur primarily as a result of a nested HTML5 tag, as the |
| // labeler should not label children with the parent's label. |
| BodyUnchanged( |
| "header_within_header", |
| "<div data-mobile-role='header'>123<div data-mobile-role='header'>" |
| "456</div>789</div>"); |
| CheckVariable(MobilizeRewriteFilter::kKeeperBlocks, 0); |
| CheckVariable(MobilizeRewriteFilter::kHeaderBlocks, 2); |
| CheckVariable(MobilizeRewriteFilter::kNavigationalBlocks, 0); |
| CheckVariable(MobilizeRewriteFilter::kContentBlocks, 0); |
| CheckVariable(MobilizeRewriteFilter::kMarginalBlocks, 0); |
| CheckVariable(MobilizeRewriteFilter::kDeletedElements, 0); |
| } |
| |
| class MobilizeRewriteThemeTest : public MobilizeRewriteFunctionalTest { |
| protected: |
| virtual bool LayoutMode() const { return false; } |
| }; |
| |
| TEST_F(MobilizeRewriteThemeTest, ConfigureTheme) { |
| options()->ClearSignatureForTesting(); |
| ASSERT_EQ(RewriteOptions::kOptionOk, |
| options()->SetOptionFromName(RewriteOptions::kMobTheme, |
| "#ff0000 #0000ff")); |
| GoogleString original = StrCat("<head></head>", Body()); |
| |
| GoogleString expected = StrCat( |
| "<head>", HeadAndViewport(false /* layout_mode */), Styles(LayoutMode()), |
| "</head>", ExpectedBody("[255,0,0]", "[0,0,255]")); |
| ValidateExpected("ConfigureTheme", original, expected); |
| |
| ASSERT_EQ(RewriteOptions::kOptionOk, |
| options()->SetOptionFromName(RewriteOptions::kMobTheme, |
| "#ff0000 #0000ff http://logo.com")); |
| expected = StrCat("<head>", HeadAndViewport(false /* layout_mode*/), |
| Styles(LayoutMode()), "</head>", |
| ExpectedBody("[255,0,0]", "[0,0,255]")); |
| ValidateExpected("ConfigureTheme2", original, expected); |
| } |
| |
| TEST_F(MobilizeRewriteThemeTest, PreComputeTheme) { |
| options()->ClearSignatureForTesting(); |
| options()->EnableFilter(RewriteOptions::kMobilizePrecompute); |
| GoogleString original = StrCat("<head></head>", Body()); |
| |
| GoogleString expected = |
| StrCat("<head>", HeadAndViewport(false /* layout_mode */), |
| Styles(LayoutMode()), "</head>", ExpectedBody()); |
| ValidateExpected("Precompute", original, expected); |
| } |
| |
| // Check we are called correctly from the driver. |
| class MobilizeRewriteEndToEndTest : public MobilizeRewriteFilterTest { |
| protected: |
| MobilizeRewriteEndToEndTest() {} |
| |
| virtual void SetUp() { |
| RewriteTestBase::SetUp(); |
| SetHtmlMimetype(); // Don't wrap scripts in <![CDATA[ ]]> |
| options()->ClearSignatureForTesting(); |
| options()->set_mob_phone_number(kPhoneNumber); |
| options()->set_mob_conversion_id(kConversionId); |
| options()->set_mob_phone_conversion_label(kPhoneConversionLabel); |
| options()->set_mob_beacon_url(kMobBeaconUrl); |
| options()->set_mob_layout(false); |
| options()->set_mob_nav(true); |
| } |
| |
| virtual bool AddBody() const { return false; } |
| virtual bool AddHtmlTags() const { return false; } |
| virtual bool LayoutMode() const { return options()->mob_layout(); } |
| |
| void Layout(bool layout) { |
| options()->set_mob_layout(layout); |
| AddFilter(RewriteOptions::kMobilize); |
| } |
| |
| void ValidateWithUA(StringPiece test_name, StringPiece user_agent, |
| StringPiece input, StringPiece expected) { |
| SetCurrentUserAgent(user_agent); |
| // We need to add the input to our fetcher so the |
| // menu extractor can see it. |
| GoogleString url = StrCat(kTestDomain, test_name, ".html"); |
| SetResponseWithDefaultHeaders(url, kContentTypeHtml, input, 1000); |
| ValidateExpected(test_name, input, expected); |
| } |
| |
| GoogleString NoScriptRedirect(StringPiece test_name) const { |
| GoogleString url = StrCat(kTestDomain, test_name, |
| ".html?PageSpeed=noscript"); |
| return StringPrintf(kNoScriptRedirectFormatter, url.c_str(), url.c_str()); |
| } |
| |
| StdioFileSystem filesystem_; |
| |
| private: |
| DISALLOW_COPY_AND_ASSIGN(MobilizeRewriteEndToEndTest); |
| }; |
| |
| TEST_F(MobilizeRewriteEndToEndTest, FullPageLayout) { |
| // These tests will break when the CSS is changed. Update the expected output |
| // accordingly. |
| Layout(true); |
| GoogleString original_buffer; |
| GoogleString original_filename = |
| StrCat(GTestSrcDir(), kTestDataDir, kOriginal); |
| ASSERT_TRUE(filesystem_.ReadFile(original_filename.c_str(), &original_buffer, |
| message_handler())); |
| GoogleString rewritten_buffer; |
| GoogleString rewritten_filename = |
| StrCat(GTestSrcDir(), kTestDataDir, kRewritten); |
| ASSERT_TRUE(filesystem_.ReadFile(rewritten_filename.c_str(), |
| &rewritten_buffer, message_handler())); |
| GlobalReplaceSubstring("@@VIEWPORT@@", "", &rewritten_buffer); |
| GlobalReplaceSubstring( |
| "@@SPACER@@", |
| StrCat(NoScriptRedirect("EndToEndMobileLayout"), Spacer(), Scrim()), |
| &rewritten_buffer); |
| GlobalReplaceSubstring("@@HEAD_SCRIPT_LOAD@@", |
| HeadAndViewport(true /* layout_mode */), |
| &rewritten_buffer); |
| GlobalReplaceSubstring("@@HEAD_STYLES@@", Styles(true), &rewritten_buffer); |
| GlobalReplaceSubstring("@@TRAILING_SCRIPT_LOADS@@", ScriptsAtEndOfBody(), |
| &rewritten_buffer); |
| ValidateWithUA("EndToEndMobileLayout", |
| UserAgentMatcherTestBase::kAndroidChrome21UserAgent, |
| original_buffer, rewritten_buffer); |
| } |
| |
| TEST_F(MobilizeRewriteEndToEndTest, NonMobileLayout) { |
| // Don't mobilize on a non-mobile browser. |
| Layout(true); |
| GoogleString original_buffer; |
| GoogleString original_filename = |
| StrCat(GTestSrcDir(), kTestDataDir, kOriginal); |
| ASSERT_TRUE(filesystem_.ReadFile(original_filename.c_str(), &original_buffer, |
| message_handler())); |
| ValidateWithUA("EndToEndNonMobileLayout", |
| UserAgentMatcherTestBase::kChrome37UserAgent, |
| original_buffer, original_buffer); |
| } |
| |
| TEST_F(MobilizeRewriteEndToEndTest, FullPage) { |
| Layout(false); |
| GoogleString original_buffer; |
| GoogleString original_filename = |
| StrCat(GTestSrcDir(), kTestDataDir, kOriginal); |
| ASSERT_TRUE(filesystem_.ReadFile(original_filename.c_str(), &original_buffer, |
| message_handler())); |
| GoogleString rewritten_buffer; |
| GoogleString rewritten_filename = |
| StrCat(GTestSrcDir(), kTestDataDir, kRewritten); |
| ASSERT_TRUE(filesystem_.ReadFile(rewritten_filename.c_str(), |
| &rewritten_buffer, message_handler())); |
| |
| GlobalReplaceSubstring("@@VIEWPORT@@", |
| "<meta name=\"viewport\" content=\"width=100px;\"/>", |
| &rewritten_buffer); |
| GlobalReplaceSubstring("@@SPACER@@", |
| StrCat(NoScriptRedirect("EndToEndMobile"), Spacer()), |
| &rewritten_buffer); |
| GlobalReplaceSubstring("@@HEAD_SCRIPT_LOAD@@", |
| HeadAndViewport(false /* layout_mode */), |
| &rewritten_buffer); |
| GlobalReplaceSubstring("@@HEAD_STYLES@@", Styles(false), &rewritten_buffer); |
| GlobalReplaceSubstring("@@TRAILING_SCRIPT_LOADS@@", ScriptsAtEndOfBody(), |
| &rewritten_buffer); |
| ValidateWithUA("EndToEndMobile", |
| UserAgentMatcherTestBase::kAndroidChrome21UserAgent, |
| original_buffer, rewritten_buffer); |
| ValidateWithUA("EndToEndMobile", |
| UserAgentMatcherTestBase::kGoogleAdsBotMobileUserAgent, |
| original_buffer, rewritten_buffer); |
| } |
| |
| TEST_F(MobilizeRewriteEndToEndTest, NonMobile) { |
| // Don't mobilize on a non-mobile browser. |
| Layout(false); |
| GoogleString original_buffer; |
| GoogleString original_filename = |
| StrCat(GTestSrcDir(), kTestDataDir, kOriginal); |
| ASSERT_TRUE(filesystem_.ReadFile(original_filename.c_str(), &original_buffer, |
| message_handler())); |
| ValidateWithUA("NonMobile", |
| UserAgentMatcherTestBase::kChrome37UserAgent, |
| original_buffer, original_buffer); |
| ValidateWithUA("NonMobile", |
| UserAgentMatcherTestBase::kGoogleAdsBotUserAgent, |
| original_buffer, original_buffer); |
| } |
| |
| class MobilizeRewriteFilterNoLayoutTest : public MobilizeRewriteFunctionalTest { |
| protected: |
| virtual bool LayoutMode() const { return false; } |
| }; |
| |
| TEST_F(MobilizeRewriteFilterNoLayoutTest, AddStyleAndViewport) { |
| HeadTest("add_style_and_viewport", "", "", 0, 0); |
| } |
| |
| TEST_F(MobilizeRewriteFilterNoLayoutTest, BeaconCat) { |
| options()->ClearSignatureForTesting(); |
| options()->set_mob_beacon_category("'experiment2'"); |
| server_context()->ComputeSignature(options()); |
| Parse("beacon_cat", "<head>"); |
| EXPECT_NE(GoogleString::npos, output_buffer_.find( |
| ";window.psMobBeaconCategory=\'\\'experiment2\\'\';")) |
| << output_buffer_; |
| } |
| |
| } // namespace |
| |
| } // namespace net_instaweb |