blob: cadfdc257e21829a98ce1d97b0072e1ce62441cc [file] [log] [blame]
/*
* Copyright 2011 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: sligocki@google.com (Shawn Ligocki)
// Base class for tests which do rewrites within CSS.
#ifndef NET_INSTAWEB_REWRITER_PUBLIC_CSS_REWRITE_TEST_BASE_H_
#define NET_INSTAWEB_REWRITER_PUBLIC_CSS_REWRITE_TEST_BASE_H_
#include "base/logging.h"
#include "net/instaweb/rewriter/public/css_filter.h"
#include "net/instaweb/rewriter/public/rewrite_options.h"
#include "net/instaweb/rewriter/public/rewrite_test_base.h"
#include "pagespeed/kernel/base/statistics.h"
#include "pagespeed/kernel/base/string.h"
#include "pagespeed/kernel/base/string_util.h"
#include "pagespeed/kernel/html/html_parse_test_base.h"
namespace net_instaweb {
class ResourceNamer;
class CssRewriteTestBase : public RewriteTestBase {
protected:
CssRewriteTestBase() {
num_blocks_rewritten_ =
statistics()->GetVariable(CssFilter::kBlocksRewritten);
num_fallback_rewrites_ =
statistics()->GetVariable(CssFilter::kFallbackRewrites);
num_parse_failures_ = statistics()->GetVariable(CssFilter::kParseFailures);
num_rewrites_dropped_ =
statistics()->GetVariable(CssFilter::kRewritesDropped);
total_bytes_saved_ = statistics()->GetUpDownCounter(
CssFilter::kTotalBytesSaved);
total_original_bytes_ =
statistics()->GetVariable(CssFilter::kTotalOriginalBytes);
num_uses_ = statistics()->GetVariable(CssFilter::kUses);
num_flatten_imports_charset_mismatch_ =
statistics()->GetVariable(CssFilter::kCharsetMismatch);
num_flatten_imports_invalid_url_ =
statistics()->GetVariable(CssFilter::kInvalidUrl);
num_flatten_imports_limit_exceeded_ =
statistics()->GetVariable(CssFilter::kLimitExceeded);
num_flatten_imports_minify_failed_ =
statistics()->GetVariable(CssFilter::kMinifyFailed);
num_flatten_imports_recursion_ =
statistics()->GetVariable(CssFilter::kRecursion);
num_flatten_imports_complex_queries_ =
statistics()->GetVariable(CssFilter::kComplexQueries);
}
~CssRewriteTestBase();
virtual void SetUp() {
RewriteTestBase::SetUp();
options()->set_always_rewrite_css(true);
AddFilter(RewriteOptions::kRewriteCss);
}
enum ValidationFlags {
kNoFlags = 0,
kExpectSuccess = 1<<0, // CSS parser succeeds and URL should be rewritten.
kExpectCached = 1<<1, // CSS parser succeeds and URL should be rewritten,
// but everything is from the cache so zero stats.
kExpectNoChange = 1<<2, // CSS parser succeeds but the URL is not rewritten
// because we increased the size of contents.
kExpectFallback = 1<<3, // CSS parser fails, fallback succeeds.
kExpectFailure = 1<<4, // CSS parser fails, fallback failed or disabled.
// TODO(sligocki): Explain why we turn off stats check at each use-site.
kNoStatCheck = 1<<5,
// TODO(sligocki): Why would we ever want to clear fetcher?
kNoClearFetcher = 1<<6,
// TODO(sligocki): Explain why we turn off other contexts.
kNoOtherContexts = 1<<7,
kLinkCharsetIsUTF8 = 1<<8,
kLinkScreenMedia = 1<<9,
kLinkPrintMedia = 1<<10,
kMetaCharsetUTF8 = 1<<11,
kMetaCharsetISO88591 = 1<<12,
kMetaHttpEquiv = 1<<13,
kMetaHttpEquivUnquoted = 1<<14,
// Flags to the check various import flattening failure statistics.
kFlattenImportsCharsetMismatch = 1<<15,
kFlattenImportsInvalidUrl = 1<<16,
kFlattenImportsLimitExceeded = 1<<17,
kFlattenImportsMinifyFailed = 1<<18,
kFlattenImportsRecursion = 1<<19,
kFlattenImportsComplexQueries = 1<<20,
// Flags to allow methods to know if the HTML is the test input or output.
kInputHtml = 1<<21,
kOutputHtml = 1<<22,
};
static bool ExactlyOneTrue(bool a, bool b) {
return a ^ b;
}
static bool ExactlyOneTrue(bool a, bool b, bool c) {
return ExactlyOneTrue(a, ExactlyOneTrue(b, c));
}
static bool ExactlyOneTrue(bool a, bool b, bool c, bool d) {
return ExactlyOneTrue(a, ExactlyOneTrue(b, c, d));
}
static bool ExactlyOneTrue(bool a, bool b, bool c, bool d, bool e) {
return ExactlyOneTrue(a, ExactlyOneTrue(b, c, d, e));
}
bool FlagSet(int flags, ValidationFlags f) const {
return (flags & f) != 0;
}
// Sanity check on flags passed in.
void CheckFlags(int flags) {
CHECK(ExactlyOneTrue(FlagSet(flags, kExpectSuccess),
FlagSet(flags, kExpectCached),
FlagSet(flags, kExpectNoChange),
FlagSet(flags, kExpectFallback),
FlagSet(flags, kExpectFailure)));
}
// Check that inline CSS gets rewritten correctly.
bool ValidateRewriteInlineCss(StringPiece id,
StringPiece css_input,
StringPiece expected_css_output,
int flags);
void GetNamerForCss(StringPiece id,
StringPiece expected_css_output,
ResourceNamer* namer);
GoogleString ExpectedUrlForNamer(const ResourceNamer& namer);
GoogleString ExpectedUrlForCss(StringPiece id,
StringPiece expected_css_output);
// Check that external CSS gets rewritten correctly.
void ValidateRewriteExternalCss(StringPiece id,
StringPiece css_input,
StringPiece expected_css_output,
int flags) {
ValidateRewriteExternalCssUrl(id, StrCat(kTestDomain, id, ".css"),
css_input, expected_css_output, flags);
}
void ValidateRewriteExternalCssUrl(StringPiece id,
StringPiece css_url,
StringPiece css_input,
StringPiece expected_css_output,
int flags);
// Makes an HTML document with an external CSS link.
GoogleString MakeHtmlWithExternalCssLink(StringPiece css_url, int flags,
bool insert_debug_message);
// Makes a CSS body with an external image link, with nice indentation.
GoogleString MakeIndentedCssWithImage(StringPiece image_url);
// Makes a minified CSS body with an external image link.
GoogleString MakeMinifiedCssWithImage(StringPiece image_url);
// Extract the background image from the css text
GoogleString ExtractCssBackgroundImage(StringPiece in_css);
void ValidateRewrite(StringPiece id,
StringPiece css_input,
StringPiece gold_output,
int flags) {
if (ValidateRewriteInlineCss(StrCat(id, "-inline"),
css_input, gold_output, flags)) {
// Don't run for external CSS unless inline succeeds.
ValidateRewriteExternalCss(StrCat(id, "-external"),
css_input, gold_output, flags);
}
}
void ValidateFailParse(StringPiece id, StringPiece css_input) {
ValidateRewrite(id, css_input, css_input, kExpectFailure);
}
// Reset all Variables.
void ResetStats();
// Validate HTML rewrite as well as checking statistics.
bool ValidateWithStats(
StringPiece id,
StringPiece html_input, StringPiece expected_html_output,
StringPiece css_input, StringPiece expected_css_output,
int flags);
// Helper to test for how we handle trailing junk
void TestCorruptUrl(const char* junk);
Variable* num_blocks_rewritten_;
Variable* num_fallback_rewrites_;
Variable* num_parse_failures_;
Variable* num_rewrites_dropped_;
UpDownCounter* total_bytes_saved_;
Variable* total_original_bytes_;
Variable* num_uses_;
Variable* num_flatten_imports_charset_mismatch_;
Variable* num_flatten_imports_invalid_url_;
Variable* num_flatten_imports_limit_exceeded_;
Variable* num_flatten_imports_minify_failed_;
Variable* num_flatten_imports_recursion_;
Variable* num_flatten_imports_complex_queries_;
};
} // namespace net_instaweb
#endif // NET_INSTAWEB_REWRITER_PUBLIC_CSS_REWRITE_TEST_BASE_H_