Squashed 'third_party/ctemplate/' content from commit 6742f62
Change-Id: I828e4e4c906f13ba19944d78a8a78652b62949af
git-subtree-dir: third_party/ctemplate
git-subtree-split: 6742f6233db12f545e90baa8f34f5c29c4eb396a
diff --git a/src/tests/htmlparser_cpp_test.cc b/src/tests/htmlparser_cpp_test.cc
new file mode 100644
index 0000000..a8bcf79
--- /dev/null
+++ b/src/tests/htmlparser_cpp_test.cc
@@ -0,0 +1,629 @@
+// Copyright (c) 2007, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+// ---
+// Author: falmeida@google.com (Filipe Almeida)
+//
+// Verify at different points during HTML processing that the parser is in the
+// correct state.
+//
+// The annotated file consists of regular html blocks and html processing
+// instructions with a target name of "state" and a list of comma separated key
+// value pairs describing the expected state or invoking a parser method.
+// Example:
+//
+// <html><body><?state state=text, tag=body ?>
+//
+// For a more detailed explanation of the acceptable values please consult
+// htmlparser_cpp.h. Following is a list of the possible keys:
+//
+// state: Current parser state as returned by HtmlParser::state().
+// Possible values: text, tag, attr, value, comment or error.
+// tag: Current tag name as returned by HtmlParser::tag()
+// attr: Current attribute name as returned by HtmlParser::attr()
+// attr_type: Current attribute type as returned by HtmlParser::attr_type()
+// Possible values: none, regular, uri, js or style.
+// attr_quoted: True if the attribute is quoted, false if it's not.
+// in_js: True if currently processing javascript (either an attribute value
+// that expects javascript, a script block or the parser being in
+// MODE_JS)
+// js_quoted: True if inside a javascript string literal.
+// js_state: Current javascript state as returned by
+// HtmlParser::javascript_state().
+// Possible values: text, q, dq, regexp or comment.
+// in_css: True if currently inside a CSS section or attribute.
+// line_number: Integer value containing the current line count.
+// column_number: Integer value containing the current column count.
+// value_index: Integer value containing the current character index in the
+// current value starting from 0.
+// is_url_start: True if if this is the first character of a url attribute.
+// reset: If true, resets the parser state to it's initial values.
+// reset_mode: Similar to reset but receives an argument that changes the
+// parser mode into either mode html or mode js.
+// insert_text: Executes HtmlParser::InsertText() if the argument is true.
+
+#include "config_for_unittests.h"
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <string>
+#include <utility>
+#include <vector>
+#include <map>
+#include "htmlparser/htmlparser_cpp.h"
+#include "ctemplate/template_pathops.h"
+#include "base/util.h"
+
+#define FAIL() EXPECT_TRUE(false)
+TEST_INIT // Among other things, defines RUN_ALL_TESTS
+
+using std::map;
+using std::pair;
+using std::string;
+using std::vector;
+using GOOGLE_NAMESPACE::PathJoin;
+
+namespace ctemplate_htmlparser {
+
+// Maximum file size limit.
+static const int kMaxFileSize = 1000000;
+
+static void ReadToString(const char* filename, string* s) {
+ const int bufsize = 8092;
+ char buffer[bufsize];
+ size_t n;
+ FILE* fp = fopen(filename, "rb");
+ if (!fp) PFATAL(filename);
+ while ((n=fread(buffer, 1, bufsize, fp)) > 0) {
+ if (ferror(fp)) PFATAL(filename);
+ s->append(string(buffer, n));
+ }
+ fclose(fp);
+}
+
+class HtmlparserCppTest : public testing::Test {
+ protected:
+
+ typedef map<string, HtmlParser *> ContextMap;
+
+ // Structure that stores the mapping between an id and a name.
+ struct IdNameMap {
+ int id;
+ const char *name;
+ };
+
+ // Mapping between the enum and the string representation of the state.
+ static const struct IdNameMap kStateMap[];
+
+ // Mapping between the enum and the string representation of the javascript
+ // state.
+ static const struct IdNameMap kJavascriptStateMap[];
+
+ // Mapping between the enum and the string representation of the attribute
+ // type.
+ static const struct IdNameMap kAttributeTypeMap[];
+
+ // Mapping between the enum and the string representation of the reset mode.
+ static const struct IdNameMap kResetModeMap[];
+
+ // String that marks the start of an annotation.
+ static const char kDirectiveBegin[];
+
+ // String that marks the end of an annotation.
+ static const char kDirectiveEnd[];
+
+ // Count the number of lines in a string.
+ static int UpdateLines(const string &str, int line);
+
+ // Count the number of columns in a string.
+ static int UpdateColumns(const string &str, int column);
+
+ // Converts a string to a boolean.
+ static bool StringToBool(const string &value);
+
+ // Returns the name of the corresponding enum_id by consulting an array of
+ // type IdNameMap.
+ const char *IdToName(const struct IdNameMap *list, int enum_id);
+
+ // Returns the enum_id of the correspondent name by consulting an array of
+ // type IdNameMap.
+ int NameToId(const struct IdNameMap *list, const string &name);
+
+ // Reads the filename of an annotated html file and validates the
+ // annotations against the html parser state.
+ void ValidateFile(string filename);
+
+ // Validate an annotation string against the current parser state.
+ void ProcessAnnotation(const string &dir);
+
+ // Validate the parser state against the provided state.
+ void ValidateState(const string &tag);
+
+ // Validate the parser tag name against the provided tag name.
+ void ValidateTag(const string &tag);
+
+ // Validate the parser attribute name against the provided attribute name.
+ void ValidateAttribute(const string &attr);
+
+ // Validate the parser attribute value contents against the provided string.
+ void ValidateValue(const string &contents);
+
+ // Validate the parser attribute type against the provided attribute type.
+ void ValidateAttributeType(const string &attr);
+
+ // Validate the parser attribute quoted state against the provided
+ // boolean.
+ void ValidateAttributeQuoted(const string "ed);
+
+ // Validates the parser in javascript state against the provided boolean.
+ void ValidateInJavascript(const string "ed);
+
+ // Validate the current parser javascript quoted state against the provided
+ // boolean.
+ void ValidateJavascriptQuoted(const string "ed);
+
+ // Validate the javascript parser state against the provided state.
+ void ValidateJavascriptState(const string &expected_state);
+
+ // Validates the parser css state against the provided boolean.
+ void ValidateInCss(const string "ed);
+
+ // Validate the line count against the expected count.
+ void ValidateLine(const string &expected_line);
+
+ // Validate the line count against the expected count.
+ void ValidateColumn(const string &expected_column);
+
+ // Validate the current parser value index against the provided index.
+ void ValidateValueIndex(const string &value_index);
+
+ // Validate the parser is_url_start value against the provided one.
+ void ValidateIsUrlStart(const string &expected_is_url_start);
+
+ void SetUp() {
+ parser_.Reset();
+ }
+
+ void TearDown() {
+ // Delete all parser instances from the context map
+ for (ContextMap::iterator iter = contextMap.begin();
+ iter != contextMap.end(); ++iter) {
+ delete iter->second;
+ }
+ contextMap.clear();
+ }
+
+ // Map containing the registers where the parser context is saved.
+ ContextMap contextMap;
+
+ // Parser instance
+ HtmlParser parser_;
+
+ friend class Test_HtmlparserTest_TestFiles;
+};
+
+const char HtmlparserCppTest::kDirectiveBegin[] = "<?state";
+const char HtmlparserCppTest::kDirectiveEnd[] = "?>";
+
+const struct HtmlparserCppTest::IdNameMap
+ HtmlparserCppTest::kStateMap[] = {
+ { HtmlParser::STATE_TEXT, "text" },
+ { HtmlParser::STATE_TAG, "tag" },
+ { HtmlParser::STATE_ATTR, "attr" },
+ { HtmlParser::STATE_VALUE, "value" },
+ { HtmlParser::STATE_COMMENT, "comment" },
+ { HtmlParser::STATE_JS_FILE, "js_file" },
+ { HtmlParser::STATE_CSS_FILE, "css_file" },
+ { HtmlParser::STATE_ERROR, "error" },
+ { 0, NULL }
+};
+
+const struct HtmlparserCppTest::IdNameMap
+ HtmlparserCppTest::kAttributeTypeMap[] = {
+ { HtmlParser::ATTR_NONE, "none" },
+ { HtmlParser::ATTR_REGULAR, "regular" },
+ { HtmlParser::ATTR_URI, "uri" },
+ { HtmlParser::ATTR_JS, "js" },
+ { HtmlParser::ATTR_STYLE, "style" },
+ { 0, NULL }
+};
+
+const struct HtmlparserCppTest::IdNameMap
+ HtmlparserCppTest::kJavascriptStateMap[] = {
+ { JavascriptParser::STATE_TEXT, "text" },
+ { JavascriptParser::STATE_Q, "q" },
+ { JavascriptParser::STATE_DQ, "dq" },
+ { JavascriptParser::STATE_REGEXP, "regexp" },
+ { JavascriptParser::STATE_COMMENT, "comment" },
+ { 0, NULL }
+};
+
+const struct HtmlparserCppTest::IdNameMap
+ HtmlparserCppTest::kResetModeMap[] = {
+ { HtmlParser::MODE_HTML, "html" },
+ { HtmlParser::MODE_JS, "js" },
+ { HtmlParser::MODE_CSS, "css" },
+ { HtmlParser::MODE_HTML_IN_TAG, "html_in_tag" },
+ { 0, NULL }
+};
+
+
+// Count the number of lines in a string.
+int HtmlparserCppTest::UpdateLines(const string &str, int line) {
+ int linecount = line;
+ for (string::size_type i = 0; i < str.length(); ++i) {
+ if (str[i] == '\n')
+ ++linecount;
+ }
+ return linecount;
+}
+
+// Count the number of columns in a string.
+int HtmlparserCppTest::UpdateColumns(const string &str, int column) {
+ // Number of bytes since the last newline.
+ size_t last_newline = str.rfind('\n');
+
+ // If no newline was found, we just sum up all the characters in the
+ // annotation.
+ if (last_newline == string::npos) {
+ return static_cast<int>(column + str.size() +
+ strlen(kDirectiveBegin) + strlen(kDirectiveEnd));
+ // If a newline was found, the new column count becomes the number of
+ // characters after the last newline.
+ } else {
+ return static_cast<int>(str.size() + strlen(kDirectiveEnd) - last_newline);
+ }
+}
+
+
+// Converts a string to a boolean.
+bool HtmlparserCppTest::StringToBool(const string &value) {
+ if (strcasecmp(value.c_str(), "true") == 0) {
+ return true;
+ } else if (strcasecmp(value.c_str(), "false") == 0) {
+ return false;
+ } else {
+ LOG(FATAL) << "Unknown boolean value";
+ }
+}
+
+// Returns the name of the corresponding enum_id by consulting an array of
+// type IdNameMap.
+const char *HtmlparserCppTest::IdToName(const struct IdNameMap *list,
+ int enum_id) {
+ CHECK(list != NULL);
+ while (list->name) {
+ if (enum_id == list->id) {
+ return list->name;
+ }
+ list++;
+ }
+ LOG(FATAL) << "Unknown id";
+}
+
+// Returns the enum_id of the correspondent name by consulting an array of
+// type IdNameMap.
+int HtmlparserCppTest::NameToId(const struct IdNameMap *list,
+ const string &name) {
+ CHECK(list != NULL);
+ while (list->name) {
+ if (name.compare(list->name) == 0) {
+ return list->id;
+ }
+ list++;
+ }
+ LOG(FATAL) << "Unknown name";
+}
+
+// Validate the parser state against the provided state.
+void HtmlparserCppTest::ValidateState(const string &expected_state) {
+ const char* parsed_state = IdToName(kStateMap, parser_.state());
+ EXPECT_TRUE(parsed_state != NULL);
+ EXPECT_TRUE(!expected_state.empty());
+ EXPECT_EQ(expected_state, string(parsed_state))
+ << "Unexpected state at line " << parser_.line_number();
+}
+
+// Validate the parser tag name against the provided tag name.
+void HtmlparserCppTest::ValidateTag(const string &expected_tag) {
+ EXPECT_TRUE(parser_.tag() != NULL);
+ EXPECT_TRUE(expected_tag == parser_.tag())
+ << "Unexpected attr tag name at line " << parser_.line_number();
+}
+
+// Validate the parser attribute name against the provided attribute name.
+void HtmlparserCppTest::ValidateAttribute(const string &expected_attr) {
+ EXPECT_TRUE(parser_.attribute() != NULL);
+ EXPECT_EQ(expected_attr, parser_.attribute())
+ << "Unexpected attr name value at line " << parser_.line_number();
+}
+
+// Validate the parser attribute value contents against the provided string.
+void HtmlparserCppTest::ValidateValue(const string &expected_value) {
+ EXPECT_TRUE(parser_.value() != NULL);
+ const string parsed_state(parser_.value());
+ EXPECT_EQ(expected_value, parsed_state)
+ << "Unexpected value at line " << parser_.line_number();
+}
+
+// Validate the parser attribute type against the provided attribute type.
+void HtmlparserCppTest::ValidateAttributeType(
+ const string &expected_attr_type) {
+ const char *parsed_attr_type = IdToName(kAttributeTypeMap,
+ parser_.AttributeType());
+ EXPECT_TRUE(parsed_attr_type != NULL);
+ EXPECT_TRUE(!expected_attr_type.empty());
+ EXPECT_EQ(expected_attr_type, string(parsed_attr_type))
+ << "Unexpected attr_type value at line " << parser_.line_number();
+}
+
+// Validate the parser attribute quoted state against the provided
+// boolean.
+void HtmlparserCppTest::ValidateAttributeQuoted(
+ const string &expected_attr_quoted) {
+ bool attr_quoted_bool = StringToBool(expected_attr_quoted);
+ EXPECT_EQ(attr_quoted_bool, parser_.IsAttributeQuoted())
+ << "Unexpected attr_quoted value at line " << parser_.line_number();
+}
+
+// Validates the parser in javascript state against the provided boolean.
+void HtmlparserCppTest::ValidateInJavascript(const string &expected_in_js) {
+ bool in_js_bool = StringToBool(expected_in_js);
+ EXPECT_EQ(in_js_bool, parser_.InJavascript())
+ << "Unexpected in_js value at line " << parser_.line_number();
+}
+
+// Validate the current parser javascript quoted state against the provided
+// boolean.
+void HtmlparserCppTest::ValidateJavascriptQuoted(
+ const string &expected_js_quoted) {
+ bool js_quoted_bool = StringToBool(expected_js_quoted);
+ EXPECT_EQ(js_quoted_bool, parser_.IsJavascriptQuoted())
+ << "Unexpected js_quoted value at line " << parser_.line_number();
+}
+
+// Validate the javascript parser state against the provided state.
+void HtmlparserCppTest::ValidateJavascriptState(const string &expected_state) {
+ const char* parsed_state = IdToName(kJavascriptStateMap,
+ parser_.javascript_state());
+ EXPECT_TRUE(parsed_state != NULL);
+ EXPECT_TRUE(!expected_state.empty());
+ EXPECT_EQ(expected_state, string(parsed_state))
+ << "Unexpected javascript state at line " << parser_.line_number();
+}
+
+// Validates the parser css state against the provided boolean.
+void HtmlparserCppTest::ValidateInCss(const string &expected_in_css) {
+ bool in_css_bool = StringToBool(expected_in_css);
+ EXPECT_EQ(in_css_bool, parser_.InCss())
+ << "Unexpected in_css value at line " << parser_.line_number();
+}
+
+// Validate the line count against the expected count.
+void HtmlparserCppTest::ValidateLine(const string &expected_line) {
+ int line;
+ CHECK(safe_strto32(expected_line, &line));
+ EXPECT_EQ(line, parser_.line_number())
+ << "Unexpected line count at line " << parser_.line_number();
+}
+
+// Validate the line count against the expected count.
+void HtmlparserCppTest::ValidateColumn(const string &expected_column) {
+ int column;
+ CHECK(safe_strto32(expected_column, &column));
+ EXPECT_EQ(column, parser_.column_number())
+ << "Unexpected column count at line " << parser_.line_number();
+}
+
+// Validate the current parser value index against the provided index.
+void HtmlparserCppTest::ValidateValueIndex(const string &expected_value_index) {
+ int index;
+ CHECK(safe_strto32(expected_value_index, &index));
+ EXPECT_EQ(index, parser_.ValueIndex())
+ << "Unexpected value_index value at line " << parser_.line_number();
+}
+
+// Validate the parser is_url_start value against the provided one.
+void HtmlparserCppTest::ValidateIsUrlStart(
+ const string &expected_is_url_start) {
+ bool is_url_start_bool = StringToBool(expected_is_url_start);
+ EXPECT_EQ(is_url_start_bool, parser_.IsUrlStart())
+ << "Unexpected is_url_start value at line " << parser_.line_number();
+}
+
+// Validate an annotation string against the current parser state.
+//
+// Split the annotation into a list of key value pairs and call the appropriate
+// handler for each pair.
+void HtmlparserCppTest::ProcessAnnotation(const string &annotation) {
+ vector< pair< string, string > > pairs;
+ SplitStringIntoKeyValuePairs(annotation, "=", ",", &pairs);
+
+ vector< pair< string, string > >::iterator iter;
+
+ iter = pairs.begin();
+ for (iter = pairs.begin(); iter != pairs.end(); ++iter) {
+ StripWhiteSpace(&iter->first);
+ StripWhiteSpace(&iter->second);
+
+ if (iter->first.compare("state") == 0) {
+ ValidateState(iter->second);
+ } else if (iter->first.compare("tag") == 0) {
+ ValidateTag(iter->second);
+ } else if (iter->first.compare("attr") == 0) {
+ ValidateAttribute(iter->second);
+ } else if (iter->first.compare("value") == 0) {
+ ValidateValue(iter->second);
+ } else if (iter->first.compare("attr_type") == 0) {
+ ValidateAttributeType(iter->second);
+ } else if (iter->first.compare("attr_quoted") == 0) {
+ ValidateAttributeQuoted(iter->second);
+ } else if (iter->first.compare("in_js") == 0) {
+ ValidateInJavascript(iter->second);
+ } else if (iter->first.compare("js_quoted") == 0) {
+ ValidateJavascriptQuoted(iter->second);
+ } else if (iter->first.compare("js_state") == 0) {
+ ValidateJavascriptState(iter->second);
+ } else if (iter->first.compare("in_css") == 0) {
+ ValidateInCss(iter->second);
+ } else if (iter->first.compare("line_number") == 0) {
+ ValidateLine(iter->second);
+ } else if (iter->first.compare("column_number") == 0) {
+ ValidateColumn(iter->second);
+ } else if (iter->first.compare("value_index") == 0) {
+ ValidateValueIndex(iter->second);
+ } else if (iter->first.compare("is_url_start") == 0) {
+ ValidateIsUrlStart(iter->second);
+ } else if (iter->first.compare("save_context") == 0) {
+ if (!contextMap.count(iter->second)) {
+ contextMap[iter->second] = new HtmlParser();
+ }
+ contextMap[iter->second]->CopyFrom(&parser_);
+ } else if (iter->first.compare("load_context") == 0) {
+ CHECK(contextMap.count(iter->second));
+ parser_.CopyFrom(contextMap[iter->second]);
+ } else if (iter->first.compare("reset") == 0) {
+ if (StringToBool(iter->second)) {
+ parser_.Reset();
+ }
+ } else if (iter->first.compare("reset_mode") == 0) {
+ HtmlParser::Mode mode =
+ static_cast<HtmlParser::Mode>(NameToId(kResetModeMap, iter->second));
+ parser_.ResetMode(mode);
+ } else if (iter->first.compare("insert_text") == 0) {
+ if (StringToBool(iter->second)) {
+ parser_.InsertText();
+ }
+ } else {
+ FAIL() << "Unknown test directive: " << iter->first;
+ }
+ }
+}
+
+// Validates an html annotated file against the parser state.
+//
+// It iterates over the html file splitting it into html blocks and annotation
+// blocks. It sends the html block to the parser and uses the annotation block
+// to validate the parser state.
+void HtmlparserCppTest::ValidateFile(string filename) {
+ // If TEMPLATE_ROOTDIR is set in the environment, it overrides the
+ // default of ".". We use an env-var rather than argv because
+ // that's what automake supports most easily.
+ const char* template_rootdir = getenv("TEMPLATE_ROOTDIR");
+ if (template_rootdir == NULL)
+ template_rootdir = DEFAULT_TEMPLATE_ROOTDIR; // probably "."
+ string dir = PathJoin(template_rootdir, "src");
+ dir = PathJoin(dir, "tests");
+ dir = PathJoin(dir, "htmlparser_testdata");
+ const string fullpath = PathJoin(dir, filename);
+ fprintf(stderr, "Validating %s", fullpath.c_str());
+ string buffer;
+ ReadToString(fullpath.c_str(), &buffer);
+
+ // Start of the current html block.
+ size_t start_html = 0;
+
+ // Start of the next annotation.
+ size_t start_annotation = buffer.find(kDirectiveBegin, 0);
+
+ // Ending of the current annotation.
+ size_t end_annotation = buffer.find(kDirectiveEnd, start_annotation);
+
+ while (start_annotation != string::npos) {
+ string html_block(buffer, start_html, start_annotation - start_html);
+ parser_.Parse(html_block);
+
+ start_annotation += strlen(kDirectiveBegin);
+
+ string annotation_block(buffer, start_annotation,
+ end_annotation - start_annotation);
+ ProcessAnnotation(annotation_block);
+
+ // Update line and column count.
+ parser_.set_line_number(UpdateLines(annotation_block,
+ parser_.line_number()));
+ parser_.set_column_number(UpdateColumns(annotation_block,
+ parser_.column_number()));
+
+ start_html = end_annotation + strlen(kDirectiveEnd);
+ start_annotation = buffer.find(kDirectiveBegin, start_html);
+ end_annotation = buffer.find(kDirectiveEnd, start_annotation);
+
+ // Check for unclosed annotation.
+ CHECK(!(start_annotation != string::npos &&
+ end_annotation == string::npos));
+ }
+}
+
+static vector<string> g_filenames;
+#define TEST_FILE(testname, filename) \
+ struct Register_##testname { \
+ Register_##testname() { g_filenames.push_back(filename); } \
+ }; \
+ static Register_##testname g_register_##testname
+
+TEST(HtmlparserTest, TestFiles) {
+ HtmlparserCppTest tester;
+ for (vector<string>::const_iterator it = g_filenames.begin();
+ it != g_filenames.end(); ++it) {
+ tester.SetUp();
+ tester.ValidateFile(*it);
+ tester.TearDown();
+ }
+}
+
+TEST_FILE(SimpleHtml, "simple.html");
+TEST_FILE(Comments, "comments.html");
+TEST_FILE(JavascriptBlock, "javascript_block.html");
+TEST_FILE(JavascriptAttribute, "javascript_attribute.html");
+TEST_FILE(JavascriptRegExp, "javascript_regexp.html");
+TEST_FILE(Tags, "tags.html");
+TEST_FILE(Context, "context.html");
+TEST_FILE(Reset, "reset.html");
+TEST_FILE(CData, "cdata.html");
+TEST_FILE(LineCount, "position.html");
+
+TEST(Htmlparser, Error) {
+ HtmlParser html;
+
+ EXPECT_EQ(html.GetErrorMessage(), (const char *)NULL);
+ EXPECT_EQ(html.Parse("<a href='http://www.google.com' ''>\n"),
+ HtmlParser::STATE_ERROR);
+
+ EXPECT_STREQ(html.GetErrorMessage(),
+ "Unexpected character '\\'' in state 'tag_space'");
+ html.Reset();
+ EXPECT_EQ(html.GetErrorMessage(), (const char *)NULL);
+}
+
+} // namespace security_streamhtmlparser
+
+int main(int argc, char **argv) {
+
+ return RUN_ALL_TESTS();
+}