/*
 * 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_
