blob: f1e0e61999af605b4189c3adaf82e87a59b9be30 [file] [log] [blame]
/*
* Copyright 2010 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: jmarantz@google.com (Joshua Marantz)
// Infrastructure for testing html parsing and rewriting.
#ifndef PAGESPEED_KERNEL_HTML_HTML_PARSE_TEST_BASE_H_
#define PAGESPEED_KERNEL_HTML_HTML_PARSE_TEST_BASE_H_
#include "pagespeed/kernel/base/basictypes.h"
#include "pagespeed/kernel/base/gtest.h"
#include "pagespeed/kernel/base/mock_message_handler.h"
#include "pagespeed/kernel/base/null_mutex.h"
#include "pagespeed/kernel/base/scoped_ptr.h"
#include "pagespeed/kernel/base/string.h"
#include "pagespeed/kernel/base/string_util.h"
#include "pagespeed/kernel/base/string_writer.h"
#include "pagespeed/kernel/html/html_parse.h"
#include "pagespeed/kernel/html/html_writer_filter.h"
#include "pagespeed/kernel/http/google_url.h"
namespace net_instaweb {
// Shared infrastructure for unit-testing the HTML parser.
class HtmlParseTestBaseNoAlloc : public testing::Test {
protected:
static const char kTestDomain[];
static const char kXhtmlDtd[]; // DOCTYPE string for claiming XHTML
HtmlParseTestBaseNoAlloc()
: message_handler_(new NullMutex),
write_to_string_(&output_buffer_),
added_filter_(false) {
}
virtual ~HtmlParseTestBaseNoAlloc();
// To make the tests more concise, we generally omit the <html>...</html>
// tags bracketing the input. The libxml parser will add those in
// if we don't have them. To avoid having that make the test data more
// verbose, we automatically add them in the test infrastructure, both
// for stimulus and expected response.
//
// This flag controls whether we also add <body>...</body> tags. In
// the case html_parse_test, we go ahead and add them in. In the
// case of the rewriter tests, we want to explicitly control/observe
// the head and the body so we don't add the body tags in
// automatically. So classes that derive from HtmlParseTestBase must
// override this variable to indicate which they prefer.
virtual bool AddBody() const = 0;
// If true, prepends "<html>\n" and appends "</html>" to input text
// prior to parsing it. This was originally done for consistency with
// libxml2 but that's long since been made irrelevant and we should probably
// just stop doing it. Adding the virtual function here should help us
// incrementally update tests & their gold results.
virtual bool AddHtmlTags() const { return true; }
// Set a doctype string (e.g. "<!doctype html>") to be inserted before the
// rest of the document (for the current test only). If none is set, it
// defaults to the empty string.
void SetDoctype(StringPiece directive) {
directive.CopyToString(&doctype_string_);
}
virtual GoogleString AddHtmlBody(StringPiece html) {
GoogleString ret;
if (AddHtmlTags()) {
ret = AddBody() ? "<html><body>\n" : "<html>\n";
StrAppend(&ret, html, (AddBody() ? "</body></html>\n" : "</html>"));
} else {
html.CopyToString(&ret);
}
return ret;
}
// Check that the output HTML is serialized to string-compare
// precisely with the input.
void ValidateNoChanges(StringPiece case_id, StringPiece html_input) {
ValidateExpected(case_id, html_input, html_input);
}
// Fail to ValidateNoChanges.
void ValidateNoChangesFail(StringPiece case_id, StringPiece html_input) {
ValidateExpectedFail(case_id, html_input, html_input);
}
void SetupWriter() {
SetupWriter(&html_writer_filter_);
}
void SetupWriter(scoped_ptr<HtmlWriterFilter>* html_writer_filter) {
output_buffer_.clear();
if (html_writer_filter->get() == NULL) {
html_writer_filter->reset(new HtmlWriterFilter(html_parse()));
(*html_writer_filter)->set_writer(&write_to_string_);
html_parse()->AddFilter(html_writer_filter->get());
}
}
// Parse html_input, the result is stored in output_buffer_.
void Parse(StringPiece case_id, StringPiece html_input) {
// HtmlParser needs a valid HTTP URL to evaluate relative paths,
// so we create a dummy URL.
GoogleString dummy_url = StrCat(kTestDomain, case_id, ".html");
ParseUrl(dummy_url, html_input);
}
// Parse given an explicit URL rather than an id to build URL around.
virtual void ParseUrl(StringPiece url, StringPiece html_input);
// Validate that the output HTML serializes as specified in
// 'expected', which might not be identical to the input.
// Also, returns true if result came out as expected.
bool ValidateExpected(StringPiece case_id,
StringPiece html_input,
StringPiece expected);
// Same as ValidateExpected, but with an explicit URL rather than an id.
bool ValidateExpectedUrl(StringPiece url,
StringPiece html_input,
StringPiece expected);
// Fail to ValidateExpected.
void ValidateExpectedFail(StringPiece case_id,
StringPiece html_input,
StringPiece expected);
virtual HtmlParse* html_parse() = 0;
const GoogleUrl& html_gurl() { return html_parse()->google_url(); }
MockMessageHandler message_handler_;
StringWriter write_to_string_;
GoogleString output_buffer_;
bool added_filter_;
scoped_ptr<HtmlWriterFilter> html_writer_filter_;
GoogleString doctype_string_;
private:
DISALLOW_COPY_AND_ASSIGN(HtmlParseTestBaseNoAlloc);
};
class HtmlParseTestBase : public HtmlParseTestBaseNoAlloc {
public:
HtmlParseTestBase() : html_parse_(&message_handler_) { }
protected:
virtual HtmlParse* html_parse() { return &html_parse_; }
HtmlParse html_parse_;
private:
DISALLOW_COPY_AND_ASSIGN(HtmlParseTestBase);
};
} // namespace net_instaweb
#endif // PAGESPEED_KERNEL_HTML_HTML_PARSE_TEST_BASE_H_