diff --git a/examples/biteme.lol.cpp b/examples/biteme.lol.cpp index 029f567..dc3b051 100644 --- a/examples/biteme.lol.cpp +++ b/examples/biteme.lol.cpp @@ -11,7 +11,7 @@ #include int main() { - docpp::HTML::Section html(docpp::HTML::ELEMENT_HTML, {}); + docpp::HTML::Section html(docpp::HTML::Tag::Html, {}); html.push_back({"title", {}, "Google"}); @@ -30,9 +30,9 @@ int main() { }}, }}; - html.push_back({"style", {}, sheet.get(docpp::CSS::FORMATTING_PRETTY)}); + html.push_back({"style", {}, sheet.get(docpp::CSS::Formatting::Pretty)}); - docpp::HTML::Section div{docpp::HTML::ELEMENT_DIV, {docpp::HTML::Property("class", "center")}}; + docpp::HTML::Section div{docpp::HTML::Tag::Div, {docpp::HTML::Property("class", "center")}}; div.push_back({"font", {docpp::HTML::Property("color", "blue")}, "G"}); div.push_back({"font", {docpp::HTML::Property("color", "red")}, "o"}); @@ -43,11 +43,11 @@ int main() { html.push_back(div); - docpp::HTML::Section div2{docpp::HTML::ELEMENT_DIV, {docpp::HTML::Property("align", "center")}}; + docpp::HTML::Section div2{docpp::HTML::Tag::Div, {docpp::HTML::Property("align", "center")}}; docpp::HTML::Section form{"form", {{docpp::HTML::Property("action", "https://google.com/search"), docpp::HTML::Property("method", "get")}}}; - form.push_back({"input", docpp::HTML::Properties({docpp::HTML::Property("type", "text"), docpp::HTML::Property("name", "q")}), "", docpp::HTML::TYPE_SELF_CLOSING}); - form.push_back({"input", docpp::HTML::Properties({docpp::HTML::Property("type", "submit"), docpp::HTML::Property("value", "Search!")}), "", docpp::HTML::TYPE_SELF_CLOSING}); + form.push_back({"input", docpp::HTML::Properties({docpp::HTML::Property("type", "text"), docpp::HTML::Property("name", "q")}), "", docpp::HTML::Type::Self_Closing}); + form.push_back({"input", docpp::HTML::Properties({docpp::HTML::Property("type", "submit"), docpp::HTML::Property("value", "Search!")}), "", docpp::HTML::Type::Self_Closing}); div2.push_back(form); html.push_back(div2); @@ -56,7 +56,7 @@ int main() { std::ofstream file("biteme.lol.html"); - file << doc.get(docpp::HTML::FORMATTING_PRETTY); + file << doc.get(docpp::HTML::Formatting::Pretty); file.close(); diff --git a/examples/hello-world.cpp b/examples/hello-world.cpp index a4312ee..b95ac4b 100644 --- a/examples/hello-world.cpp +++ b/examples/hello-world.cpp @@ -19,7 +19,7 @@ int main() { docpp::HTML::Document doc{}; /* This is an HTML section. It can hold any number of elements and/or sections. - * The first argument is the type of section, and this can either be a predefined value (e.g., docpp::HTML::ELEMENT_HTML) or a + * The first argument is the type of section, and this can either be a predefined value (e.g., docpp::HTML::Tag::Html) or a * custom value in the form of an std::string object. * * The second argument is an HTMLProperties object, which is a collection of Property objects. Each property is a std::pair of an @@ -32,10 +32,10 @@ int main() { * * To get the section as an std::string object, call section.get(). */ - docpp::HTML::Section htmlSection(docpp::HTML::ELEMENT_HTML, {}); // - docpp::HTML::Section headSection(docpp::HTML::ELEMENT_HEAD, {}); // - docpp::HTML::Section bodySection(docpp::HTML::ELEMENT_BODY, {}); // - docpp::HTML::Section footerSection(docpp::HTML::ELEMENT_FOOTER, {}); // + docpp::HTML::Section htmlSection(docpp::HTML::Tag::Html, {}); // + docpp::HTML::Section headSection(docpp::HTML::Tag::Head, {}); // + docpp::HTML::Section bodySection(docpp::HTML::Tag::Body, {}); // + docpp::HTML::Section footerSection(docpp::HTML::Tag::Footer, {}); // /* This is an HTML element. Unlike a section, an element cannot hold any other elements or sections, rather it holds text and/or attributes. * The first argument is the type of element, and this should simply be the tag name (e.g., "p", "h1", "a", etc.). @@ -48,7 +48,7 @@ int main() { * * The fourth argument is an integer representing the closing tag type. This can be one of the following: * - * - docpp::HTML::TYPE_NON_CLOSED: No closing tag will be appended. + * - docpp::HTML::Type::Non_Closed: No closing tag will be appended. * Example: * - docpp::HTML::TYPE_NON_SELF_CLOSING: A closing tag will be appended. * Example:

Hello world

@@ -61,7 +61,7 @@ int main() { /* Add the title and meta elements to the head section. */ headSection.push_back(titleElement); - headSection.push_back(docpp::HTML::Element("meta", {{docpp::HTML::Property("name", "description"), docpp::HTML::Property("content", "Hello world document description!")}}, "", docpp::HTML::TYPE_NON_CLOSED)); + headSection.push_back(docpp::HTML::Element("meta", {{docpp::HTML::Property("name", "description"), docpp::HTML::Property("content", "Hello world document description!")}}, "", docpp::HTML::Type::Non_Closed)); /* This is a CSS document. It is essentially the CSS equivalent of an HTML section. * It is essentially a collection of Element objects, which is a collection of Property objects. @@ -84,14 +84,14 @@ int main() { stylesheet.push_back(bodyStyling); /* To get the stylesheet as an std::string object, call stylesheet.get(). It can then be used in an Element object. */ - const std::string& css = stylesheet.get(docpp::CSS::FORMATTING_PRETTY); // body { background-color: black; color: white; } + const std::string& css = stylesheet.get(docpp::CSS::Formatting::Pretty); // body { background-color: black; color: white; } headSection.push_back(docpp::HTML::Element("style", {}, css)); // /* Add a paragraph element to the footer section. */ footerSection.push_back(docpp::HTML::Element("p", {}, "This is the footer.")); //

This is the footer.

- docpp::HTML::Section divSection(docpp::HTML::ELEMENT_DIV, {{docpp::HTML::Property("id", "main")}}); //
+ docpp::HTML::Section divSection(docpp::HTML::Tag::Div, {{docpp::HTML::Property("id", "main")}}); //
/* Add a header element and a paragraph element to the div section. */ divSection.push_back(docpp::HTML::Element("h1", {}, "Hello world!")); //

Hello world!

@@ -113,10 +113,10 @@ int main() { /* Finally, let's output the document to a file and print it to standard output. */ std::ofstream file("hello-world.html"); - /* Optionally, you can use the get() method with the docpp::HTML::FORMATTING_PRETTY argument to get a *slightly* more readable document. + /* Optionally, you can use the get() method with the docpp::HTML::Formatting::Pretty argument to get a *slightly* more readable document. * The same goes for the CSS document. Or, you can use docpp::HTML::FORMATTING_NEWLINE to get a document with elements separated by newlines. */ - file << doc.get(docpp::HTML::FORMATTING_PRETTY); + file << doc.get(docpp::HTML::Formatting::Pretty); file.close(); diff --git a/examples/speedie-page.cpp b/examples/speedie-page.cpp index b28b495..f1841a1 100644 --- a/examples/speedie-page.cpp +++ b/examples/speedie-page.cpp @@ -3,7 +3,7 @@ #include docpp::HTML::Section getCSS() { - docpp::HTML::Section css{docpp::HTML::ELEMENT_STYLE}; + docpp::HTML::Section css{docpp::HTML::Tag::Style}; docpp::CSS::Stylesheet stylesheet{}; @@ -180,20 +180,20 @@ docpp::HTML::Section getCSS() { } }); - css.push_back({docpp::HTML::ELEMENT_EMPTY_NO_FORMAT, {}, stylesheet.get(docpp::CSS::FORMATTING_PRETTY, 4)}); + css.push_back({docpp::HTML::Tag::Empty_No_Formatting, {}, stylesheet.get(docpp::CSS::Formatting::Pretty, 4)}); return css; } docpp::HTML::Section getNavbar(docpp::HTML::Section& e) { - docpp::HTML::Section navbar(docpp::HTML::ELEMENT_DIV, {{docpp::HTML::Property{{"class", "navbar"}}}}); - docpp::HTML::Section span(docpp::HTML::ELEMENT_SPAN, {}); + docpp::HTML::Section navbar(docpp::HTML::Tag::Div, {{docpp::HTML::Property{{"class", "navbar"}}}}); + docpp::HTML::Section span(docpp::HTML::Tag::Span, {}); - span.push_back({docpp::HTML::ELEMENT_EMPTY, {}, "speedie.site\n"}); + span.push_back({docpp::HTML::Tag::Empty, {}, "speedie.site\n"}); const auto append_to_span = [&](const std::string& img, const std::string& url, const std::string& text) { - span.push_back({docpp::HTML::ELEMENT_IMG, {{docpp::HTML::Property{{"src", img}}, docpp::HTML::Property{{"width", "16"}}, docpp::HTML::Property{{"height", "16"}}}}, ""}); - span.push_back({docpp::HTML::ELEMENT_A, {{docpp::HTML::Property{{"href", url}}}}, text}); + span.push_back({docpp::HTML::Tag::Img, {{docpp::HTML::Property{{"src", img}}, docpp::HTML::Property{{"width", "16"}}, docpp::HTML::Property{{"height", "16"}}}}, ""}); + span.push_back({docpp::HTML::Tag::A, {{docpp::HTML::Property{{"href", url}}}}, text}); }; append_to_span("img/home.png", "/", "Home"); @@ -208,15 +208,15 @@ docpp::HTML::Section getNavbar(docpp::HTML::Section& e) { } docpp::HTML::Section getHead() { - docpp::HTML::Section e{docpp::HTML::ELEMENT_HEAD}; + docpp::HTML::Section e{docpp::HTML::Tag::Head}; - docpp::HTML::Element content_type{docpp::HTML::ELEMENT_META, {{docpp::HTML::Property{{"http-equiv", "content-type"}}, docpp::HTML::Property{{"content", "text/html; charset=utf-8"}}}}}; - docpp::HTML::Element charset{docpp::HTML::ELEMENT_META, {{docpp::HTML::Property{{"charset", "UTF-8"}}}}}; - docpp::HTML::Element favicon(docpp::HTML::ELEMENT_LINK, {{docpp::HTML::Property{{"rel", "icon"}}, docpp::HTML::Property{{"type", "image/x-icon"}}, docpp::HTML::Property{{"href", "/img/favicon.svg"}}}}); - docpp::HTML::Element description(docpp::HTML::ELEMENT_META, {{docpp::HTML::Property{{"name", "description"}}, docpp::HTML::Property{{"content", "Welcome to my personal website."}}}}); - docpp::HTML::Element author(docpp::HTML::ELEMENT_META, {{docpp::HTML::Property{{"name", "author"}}, docpp::HTML::Property{{"content", "speedie"}}}}); - docpp::HTML::Element title(docpp::HTML::ELEMENT_TITLE, {}, "speedie's site"); - docpp::HTML::Section css{docpp::HTML::ELEMENT_STYLE}; + docpp::HTML::Element content_type{docpp::HTML::Tag::Meta, {{docpp::HTML::Property{{"http-equiv", "content-type"}}, docpp::HTML::Property{{"content", "text/html; charset=utf-8"}}}}}; + docpp::HTML::Element charset{docpp::HTML::Tag::Meta, {{docpp::HTML::Property{{"charset", "UTF-8"}}}}}; + docpp::HTML::Element favicon(docpp::HTML::Tag::Link, {{docpp::HTML::Property{{"rel", "icon"}}, docpp::HTML::Property{{"type", "image/x-icon"}}, docpp::HTML::Property{{"href", "/img/favicon.svg"}}}}); + docpp::HTML::Element description(docpp::HTML::Tag::Meta, {{docpp::HTML::Property{{"name", "description"}}, docpp::HTML::Property{{"content", "Welcome to my personal website."}}}}); + docpp::HTML::Element author(docpp::HTML::Tag::Meta, {{docpp::HTML::Property{{"name", "author"}}, docpp::HTML::Property{{"content", "speedie"}}}}); + docpp::HTML::Element title(docpp::HTML::Tag::Title, {}, "speedie's site"); + docpp::HTML::Section css{docpp::HTML::Tag::Style}; e.push_back(content_type); e.push_back(favicon); @@ -229,23 +229,23 @@ docpp::HTML::Section getHead() { } docpp::HTML::Section getMain() { - docpp::HTML::Section content(docpp::HTML::ELEMENT_DIV, {{docpp::HTML::Property{{"class", "content"}}}}); + docpp::HTML::Section content(docpp::HTML::Tag::Div, {{docpp::HTML::Property{{"class", "content"}}}}); - content.push_back({docpp::HTML::ELEMENT_H2, {}, "Hello world!"}); - content.push_back({docpp::HTML::ELEMENT_P, {}, "Hello there! This is a replica of my old website, using docpp to generate the HTML. With that said. This only provides the index page, so many links are not functional. This is more to show off that docpp can be used to generate a proper website."}); - content.push_back({docpp::HTML::ELEMENT_H3, {}, "Links"}); + content.push_back({docpp::HTML::Tag::H2, {}, "Hello world!"}); + content.push_back({docpp::HTML::Tag::P, {}, "Hello there! This is a replica of my old website, using docpp to generate the HTML. With that said. This only provides the index page, so many links are not functional. This is more to show off that docpp can be used to generate a proper website."}); + content.push_back({docpp::HTML::Tag::H3, {}, "Links"}); - docpp::HTML::Section links(docpp::HTML::ELEMENT_DIV, {{docpp::HTML::Property{{"class", "links"}}}}); - docpp::HTML::Section table(docpp::HTML::ELEMENT_TABLE); + docpp::HTML::Section links(docpp::HTML::Tag::Div, {{docpp::HTML::Property{{"class", "links"}}}}); + docpp::HTML::Section table(docpp::HTML::Tag::Table); static const auto append_to_table = [&](const std::string& img, const std::string& url, const std::string& short_text, const std::string& long_text) { - docpp::HTML::Section tr{docpp::HTML::ELEMENT_TR}; - docpp::HTML::Section td{docpp::HTML::ELEMENT_TD}; - docpp::HTML::Section td2{docpp::HTML::ELEMENT_TD}; + docpp::HTML::Section tr{docpp::HTML::Tag::Tr}; + docpp::HTML::Section td{docpp::HTML::Tag::Td}; + docpp::HTML::Section td2{docpp::HTML::Tag::Td}; - td.push_back({docpp::HTML::ELEMENT_IMG, {{docpp::HTML::Property{{"src", img}}, docpp::HTML::Property{{"width", "16"}}, docpp::HTML::Property{{"height", "16"}}}}, ""}); - td.push_back({docpp::HTML::ELEMENT_A, {{docpp::HTML::Property{{"href", url}}}}, short_text}); - td2.push_back({docpp::HTML::ELEMENT_EMPTY, {}, long_text + "\n"}); + td.push_back({docpp::HTML::Tag::Img, {{docpp::HTML::Property{{"src", img}}, docpp::HTML::Property{{"width", "16"}}, docpp::HTML::Property{{"height", "16"}}}}, ""}); + td.push_back({docpp::HTML::Tag::A, {{docpp::HTML::Property{{"href", url}}}}, short_text}); + td2.push_back({docpp::HTML::Tag::Empty, {}, long_text + "\n"}); tr.push_back(td); tr.push_back(td2); @@ -265,25 +265,25 @@ docpp::HTML::Section getMain() { } docpp::HTML::Section getFooter() { - docpp::HTML::Section footer(docpp::HTML::ELEMENT_FOOTER); - docpp::HTML::Section div(docpp::HTML::ELEMENT_DIV, {{docpp::HTML::Property("class", "column")}}); - docpp::HTML::Section span(docpp::HTML::ELEMENT_SPAN, {{docpp::HTML::Property("class", "links")}}); + docpp::HTML::Section footer(docpp::HTML::Tag::Footer); + docpp::HTML::Section div(docpp::HTML::Tag::Div, {{docpp::HTML::Property("class", "column")}}); + docpp::HTML::Section span(docpp::HTML::Tag::Span, {{docpp::HTML::Property("class", "links")}}); - span.push_back({docpp::HTML::ELEMENT_A, {{docpp::HTML::Property("class", "links"), docpp::HTML::Property("href", "https://git.speedie.site")}}, "Git"}); - span.push_back({docpp::HTML::ELEMENT_A, {{docpp::HTML::Property("class", "links"), docpp::HTML::Property("href", "https://ls.speedie.site")}}, "Downloads"}); - span.push_back({docpp::HTML::ELEMENT_A, {{docpp::HTML::Property("class", "links"), docpp::HTML::Property("href", "privacy.html")}}, "Licensing"}); + span.push_back({docpp::HTML::Tag::A, {{docpp::HTML::Property("class", "links"), docpp::HTML::Property("href", "https://git.speedie.site")}}, "Git"}); + span.push_back({docpp::HTML::Tag::A, {{docpp::HTML::Property("class", "links"), docpp::HTML::Property("href", "https://ls.speedie.site")}}, "Downloads"}); + span.push_back({docpp::HTML::Tag::A, {{docpp::HTML::Property("class", "links"), docpp::HTML::Property("href", "privacy.html")}}, "Licensing"}); div.push_back(span); - div.push_back({docpp::HTML::ELEMENT_P, {{docpp::HTML::Property("style", "padding-top: 0px;")}}, "Made in Sweden"}); + div.push_back({docpp::HTML::Tag::P, {{docpp::HTML::Property("style", "padding-top: 0px;")}}, "Made in Sweden"}); footer.push_back(div); return footer; } int main() { - docpp::HTML::Section html_section = docpp::HTML::Section(docpp::HTML::ELEMENT_HTML); + docpp::HTML::Section html_section = docpp::HTML::Section(docpp::HTML::Tag::Html); docpp::HTML::Section head{getHead()}; - docpp::HTML::Section body(docpp::HTML::ELEMENT_BODY); + docpp::HTML::Section body(docpp::HTML::Tag::Body); body.push_back(getMain()); @@ -295,8 +295,8 @@ int main() { docpp::HTML::Document html_doc(html_section); - std::cout << html_doc.get(docpp::HTML::FORMATTING_PRETTY) << "\n"; + std::cout << html_doc.get(docpp::HTML::Formatting::Pretty) << "\n"; std::ofstream fs{"speedie-page.html"}; - fs << html_doc.get(docpp::HTML::FORMATTING_PRETTY); + fs << html_doc.get(docpp::HTML::Formatting::Pretty); fs.close(); } diff --git a/include/docpp.hpp b/include/docpp.hpp index 21149ea..96401f1 100644 --- a/include/docpp.hpp +++ b/include/docpp.hpp @@ -15,9 +15,9 @@ #include /** - * @brief A namespace to represent HTML elements and documents + * @brief A inline namespace to represent HTML elements and documents */ -namespace docpp { +inline namespace docpp { /** * @brief A class to represent an exception when an index is out of range */ @@ -47,178 +47,178 @@ namespace docpp { }; /** - * @brief A namespace to represent HTML elements and documents + * @brief A inline namespace to represent HTML elements and documents */ - namespace HTML { + inline namespace HTML { /** * @brief Enum for element tags. */ - enum Tag { - ELEMENT_EMPTY, /* Empty element */ - ELEMENT_EMPTY_NO_FORMAT, /* Empty element, that ignores any formatting by get() calls. */ - ELEMENT_ABBREVIATION, /* */ - ELEMENT_ABBR, /* */ - ELEMENT_ACRONYM, /* */ - ELEMENT_ADDRESS, /*
*/ - ELEMENT_ANCHOR, /* */ - ELEMENT_A, /* */ - ELEMENT_APPLET, /* */ - ELEMENT_ARTICLE, /*
*/ - ELEMENT_AREA, /* */ - ELEMENT_ASIDE, /* */ - ELEMENT_AUDIO, /* */ - ELEMENT_BASE, /* */ - ELEMENT_BASEFONT, /* */ - ELEMENT_BDI, /* */ - ELEMENT_BDO, /* */ - ELEMENT_BGSOUND, /* */ - ELEMENT_BIG, /* */ - ELEMENT_BLOCKQUOTE, /*
*/ - ELEMENT_BODY, /* */ - ELEMENT_BOLD, /* */ - ELEMENT_B, /* */ - ELEMENT_BR, /*
*/ - ELEMENT_BREAK, /*
*/ - ELEMENT_BUTTON, /* */ - ELEMENT_CAPTION, /* */ - ELEMENT_CANVAS, /* */ - ELEMENT_CENTER, /*
*/ - ELEMENT_CITE, /* */ - ELEMENT_CODE, /* */ - ELEMENT_COLGROUP, /* */ - ELEMENT_COL, /* */ - ELEMENT_COLUMN, /* */ - ELEMENT_DATA, /* */ - ELEMENT_DATALIST, /* */ - ELEMENT_DD, /*
*/ - ELEMENT_DFN, /* */ - ELEMENT_DEFINE, /* */ - ELEMENT_DELETE, /* */ - ELEMENT_DEL, /* */ - ELEMENT_DETAILS, /*
*/ - ELEMENT_DIALOG, /* */ - ELEMENT_DIR, /* */ - ELEMENT_DIV, /*
*/ - ELEMENT_DL, /*
*/ - ELEMENT_DT, /*
*/ - ELEMENT_EMBED, /* */ - ELEMENT_FIELDSET, /*
*/ - ELEMENT_FIGCAPTION, /*
*/ - ELEMENT_FIGURE, /*
*/ - ELEMENT_FONT, /* */ - ELEMENT_FOOTER, /*
*/ - ELEMENT_FORM, /*
*/ - ELEMENT_FRAME, /* */ - ELEMENT_FRAMESET, /* */ - ELEMENT_HEAD, /* */ - ELEMENT_HEADER, /*
*/ - ELEMENT_H1, /*

*/ - ELEMENT_H2, /*

*/ - ELEMENT_H3, /*

*/ - ELEMENT_H4, /*

*/ - ELEMENT_H5, /*
*/ - ELEMENT_H6, /*
*/ - ELEMENT_HGROUP, /*
*/ - ELEMENT_HR, /*
*/ - ELEMENT_HTML, /* */ - ELEMENT_IFRAME, /* */ - ELEMENT_IMAGE, /* */ - ELEMENT_IMG, /* */ - ELEMENT_INPUT, /* */ - ELEMENT_INS, /* */ - ELEMENT_ISINDEX, /* */ - ELEMENT_ITALIC, /* */ - ELEMENT_I, /* */ - ELEMENT_KBD, /* */ - ELEMENT_KEYGEN, /* */ - ELEMENT_LABEL, /* */ - ELEMENT_LEGEND, /* */ - ELEMENT_LIST, /*
  • */ - ELEMENT_LI, /*
  • */ - ELEMENT_LINK, /* */ - ELEMENT_MAIN, /*
    */ - ELEMENT_MARK, /* */ - ELEMENT_MARQUEE, /* */ - ELEMENT_MENUITEM, /* */ - ELEMENT_META, /* */ - ELEMENT_METER, /* */ - ELEMENT_NAV, /* */ - ELEMENT_NOBREAK, /* */ - ELEMENT_NOBR, /* */ - ELEMENT_NOEMBED, /* */ - ELEMENT_NOSCRIPT, /* */ - ELEMENT_OBJECT, /* */ - ELEMENT_OPTGROUP, /* */ - ELEMENT_OPTION, /* */ - ELEMENT_OUTPUT, /* */ - ELEMENT_PARAGRAPH, /*

    */ - ELEMENT_P, /*

    */ - ELEMENT_PARAM, /* */ - ELEMENT_PHRASE, /* */ - ELEMENT_PRE, /*
     */
    -            ELEMENT_PROGRESS, /*  */
    -            ELEMENT_QUOTE, /*  */
    -            ELEMENT_Q, /*  */
    -            ELEMENT_RP, /*  */
    -            ELEMENT_RT, /*  */
    -            ELEMENT_RUBY, /*  */
    -            ELEMENT_OUTDATED, /*  */
    -            ELEMENT_S, /*  */
    -            ELEMENT_SAMPLE, /*  */
    -            ELEMENT_SAMP, /*  */
    -            ELEMENT_SCRIPT, /*  */
    -            ELEMENT_SECTION, /* 
    */ - ELEMENT_SMALL, /* */ - ELEMENT_SOURCE, /* */ - ELEMENT_SPACER, /* */ - ELEMENT_SPAN, /* */ - ELEMENT_STRIKE, /* */ - ELEMENT_STRONG, /* */ - ELEMENT_STYLE, /* */ - ELEMENT_SUB, /* */ - ELEMENT_SUBSCRIPT, /* */ - ELEMENT_SUP, /* */ - ELEMENT_SUPERSCRIPT, /* */ - ELEMENT_SUMMARY, /* */ - ELEMENT_SVG, /* */ - ELEMENT_TABLE, /*
    */ - ELEMENT_TBODY, /* */ - ELEMENT_TD, /* */ - ELEMENT_TEMPLATE, /* */ - ELEMENT_TFOOT, /* */ - ELEMENT_TH, /* */ - ELEMENT_THEAD, /* */ - ELEMENT_TIME, /* */ - ELEMENT_TITLE, /* */ - ELEMENT_TR, /* */ - ELEMENT_TRACK, /* */ - ELEMENT_TT, /* */ - ELEMENT_UNDERLINE, /* */ - ELEMENT_U, /* */ - ELEMENT_VAR, /* */ - ELEMENT_VIDEO, /* */ - ELEMENT_WBR, /* */ - ELEMENT_XMP, /* */ + enum class Tag { + Empty, /* Empty element */ + Empty_No_Formatting, /* Empty element, that ignores any formatting by get() calls. */ + Abbreviation, /* */ + Abbr, /* */ + Acronym, /* */ + Address, /*
    */ + Anchor, /* */ + A, /* */ + Applet, /* */ + Article, /*
    */ + Area, /* */ + Aside, /* */ + Audio, /* */ + Base, /* */ + Basefont, /* */ + Bdi, /* */ + Bdo, /* */ + Bgsound, /* */ + Big, /* */ + Blockquote, /*
    */ + Body, /* */ + Bold, /* */ + B, /* */ + Br, /*
    */ + Break, /*
    */ + Button, /* */ + Caption, /* */ + Canvas, /* */ + Center, /*
    */ + Cite, /* */ + Code, /* */ + Colgroup, /* */ + Col, /* */ + Column, /* */ + Data, /* */ + Datalist, /* */ + Dd, /*
    */ + Dfn, /* */ + Define, /* */ + Delete, /* */ + Del, /* */ + Details, /*
    */ + Dialog, /* */ + Dir, /* */ + Div, /*
    */ + Dl, /*
    */ + Dt, /*
    */ + Embed, /* */ + Fieldset, /*
    */ + Figcaption, /*
    */ + Figure, /*
    */ + Font, /* */ + Footer, /*
    */ + Form, /*
    */ + Frame, /* */ + Frameset, /* */ + Head, /* */ + Header, /*
    */ + H1, /*

    */ + H2, /*

    */ + H3, /*

    */ + H4, /*

    */ + H5, /*
    */ + H6, /*
    */ + Hgroup, /*
    */ + Hr, /*
    */ + Html, /* */ + Iframe, /* */ + Image, /* */ + Img, /* */ + Input, /* */ + Ins, /* */ + Isindex, /* */ + Italic, /* */ + I, /* */ + Kbd, /* */ + Keygen, /* */ + Label, /* */ + Legend, /* */ + List, /*
  • */ + Li, /*
  • */ + Link, /* */ + Main, /*
    */ + Mark, /* */ + Marquee, /* */ + Menuitem, /* */ + Meta, /* */ + Meter, /* */ + Nav, /* */ + Nobreak, /* */ + Nobr, /* */ + Noembed, /* */ + Noscript, /* */ + Object, /* */ + Optgroup, /* */ + Option, /* */ + Output, /* */ + Paragraph, /*

    */ + P, /*

    */ + Param, /* */ + Phrase, /* */ + Pre, /*
     */
    +            Progress, /*  */
    +            Quote, /*  */
    +            Q, /*  */
    +            Rp, /*  */
    +            Rt, /*  */
    +            Ruby, /*  */
    +            Outdated, /*  */
    +            S, /*  */
    +            Sample, /*  */
    +            Samp, /*  */
    +            Script, /*  */
    +            Section, /* 
    */ + Small, /* */ + Source, /* */ + Spacer, /* */ + Span, /* */ + Strike, /* */ + Strong, /* */ + Style, /* */ + Sub, /* */ + Subscript, /* */ + Sup, /* */ + Superscript, /* */ + Summary, /* */ + Svg, /* */ + Table, /*
    */ + Tbody, /* */ + Td, /* */ + Template, /* */ + Tfoot, /* */ + Th, /* */ + Thead, /* */ + Time, /* */ + Title, /* */ + Tr, /* */ + Track, /* */ + Tt, /* */ + Underline, /* */ + U, /* */ + Var, /* */ + Video, /* */ + Wbr, /* */ + Xmp, /* */ }; /** * @brief Enum for element types. */ - enum Type { - TYPE_SELF_CLOSING, /* Self-closing element ()*/ - TYPE_NON_SELF_CLOSING, /* Non-self-closing element () */ - TYPE_NON_CLOSED, /* Non-closed element () */ - TYPE_TEXT, /* Text element (my text here). Note that this does *not* append a newline character. */ - TYPE_TEXT_TAB, /* Text element with tab characters appropriately prepended (my text here). Note that this does *not* append a newline character. */ + enum class Type { + Self_Closing, /* Self-closing element ()*/ + Non_Self_Closing, /* Non-self-closing element () */ + Non_Closed, /* Non-closed element () */ + Text_No_Formatting, /* Text element with no formatting (my text here). */ + Text, /* Text element with tab characters appropriately prepended (my text here). Note that this does *not* append a newline character. */ }; /** * @brief Enum for formatting options. */ - enum Formatting { - FORMATTING_NONE, /* No formatting. Output is in the form of one long string of text, and a single newline character. */ - FORMATTING_PRETTY, /* Pretty formatting. Output is formatted with newlines and tabs as deemed appropriate. */ - FORMATTING_NEWLINE, /* Newline formatting. Each element has a newline appended. */ + enum class Formatting { + None, /* No formatting. Output is in the form of one long string of text, and a single newline character. */ + Pretty, /* Pretty formatting. Output is formatted with newlines and tabs as deemed appropriate. */ + Newline, /* Newline formatting. Each element has a newline appended. */ }; /** @@ -318,6 +318,21 @@ namespace docpp { * @param property The property. */ void set(const std::pair& property); + /** + * @brief Clear the property + */ + void clear(); + /** + * @brief Check if the property is empty + * @return bool True if the property is empty, false otherwise + */ + bool empty() const; + + Property& operator=(const Property& property); + Property& operator=(const std::pair& property); + bool operator==(const Property& property) const; + bool operator!=(const Property& property) const; + }; /** @@ -446,6 +461,15 @@ namespace docpp { * @return size_type The size of the element */ size_type size() const; + /** + * @brief Clear the properties + */ + void clear(); + /** + * @brief Check if the properties are empty + * @return bool True if the properties are empty, false otherwise + */ + bool empty() const; /** * @brief Prepend a property to the element * @param property The property to add @@ -470,10 +494,16 @@ namespace docpp { * @brief Construct a new Properties object */ Properties() = default; - Properties operator=(const Properties& properties); - Properties operator=(const std::vector& properties); - Properties operator=(const Property& property); - void operator+=(const Property& property); + Properties& operator=(const Properties& properties); + Properties& operator=(const std::vector& properties); + Properties& operator=(const Property& property); + bool operator==(const Properties& properties) const; + bool operator==(const Property& property) const; + bool operator!=(const Properties& properties) const; + bool operator!=(const Property& property) const; + Property operator[](const size_type& index) const; + Properties& operator+=(const Property& property); + Properties& operator+=(const Properties& properties); }; /** @@ -483,7 +513,7 @@ namespace docpp { private: std::string tag{}; std::string data{}; - Type type{TYPE_NON_SELF_CLOSING}; + Type type{Type::Non_Self_Closing}; Properties properties{}; protected: public: @@ -500,7 +530,7 @@ namespace docpp { * @param data The data of the element * @param type The close tag type. */ - Element(const std::string& tag, const Properties& properties = {}, const std::string& data = {}, const Type type = TYPE_NON_SELF_CLOSING) : tag(tag), properties(properties), data(data), type(type) {}; + Element(const std::string& tag, const Properties& properties = {}, const std::string& data = {}, const Type type = Type::Non_Self_Closing) : tag(tag), properties(properties), data(data), type(type) {}; /** * @brief Construct a new Element object * @param tag The tag of the element @@ -519,18 +549,50 @@ namespace docpp { * @param data The data of the element * @param type The close tag type. */ - void set(const std::string& tag, const Properties& properties = {}, const std::string& data = {}, const Type type = TYPE_NON_SELF_CLOSING); + void set(const std::string& tag, const Properties& properties = {}, const std::string& data = {}, const Type type = Type::Non_Self_Closing); + /** + * @brief Set the tag, properties, and data of the element + * @param tag The tag of the element + * @param properties The properties of the element + * @param data The data of the element + */ + void set(const Tag tag, const Properties& properties = {}, const std::string& data = {}); + /** + * @brief Set the tag of the element + * @param tag The tag of the element + */ + void set_tag(const std::string& tag); + /** + * @brief Set the tag of the element + * @param tag The tag of the element + */ + void set_tag(const Tag tag); + /** + * @brief Set the data of the element + * @param data The data of the element + */ + void set_data(const std::string& data); + /** + * @brief Set the properties of the element + * @param properties The properties of the element + */ + void set_properties(const Properties& properties); + /** + * @brief Set the type of the element + * @param type The type of the element + */ + void set_type(const Type type); /** * @brief Get the element in the form of an HTML tag. * @return std::string The tag of the element */ - std::string get(const Formatting formatting = FORMATTING_NONE, const int tabc = 0) const; + std::string get(const Formatting formatting = Formatting::None, const int tabc = 0) const; /** * @brief Get the element in the form of a specific type. * @return T The element in the form of a specific type */ - template T get(const Formatting formatting = FORMATTING_NONE, const int tabc = 0) const { + template T get(const Formatting formatting = Formatting::None, const int tabc = 0) const { if (std::is_same::value) { return this->get(formatting, tabc); } @@ -568,9 +630,30 @@ namespace docpp { } return T(this->data); } + /** + * @brief Get the properties of the element + * @return Properties The properties of the element + */ + Properties get_properties() const; + /** + * @brief Get the type of the element + * @return Type The type of the element + */ + Type get_type() const; + /** + * @brief Clear the element + */ + void clear(); + /** + * @brief Check if the element is empty. + * @return bool True if the element is empty, false otherwise. + */ + bool empty() const; - Element operator=(const Element& element); - void operator+=(const std::string& data); + Element& operator=(const Element& element); + Element& operator+=(const std::string& data); + bool operator==(const Element& element) const; + bool operator!=(const Element& element) const; }; /** @@ -717,19 +800,52 @@ namespace docpp { * @return size_type The size of the section */ size_type size() const; + /** + * @brief Clear the section + */ + void clear(); + /** + * @brief Check if the section is empty + * @return bool True if the section is empty, false otherwise + */ + bool empty() const; /** * @brief Construct a new Section object * @param tag The tag of the section * @param properties The properties of the section + * @param elements The elements of the section */ - Section(const std::string& tag, const Properties& properties = {}) : tag(tag), properties(properties) {}; + Section(const std::string& tag, const Properties& properties = {}, const std::vector& elements = {}) : tag(tag), properties(properties) { + for (const auto& element : elements) this->push_back(element); + }; /** * @brief Construct a new Section object * @param tag The tag of the section * @param properties The properties of the section + * @param elements The elements of the section */ - Section(const Tag tag, const Properties& properties = {}) : tag(resolve_tag(tag).first), properties(properties) {}; + Section(const Tag tag, const Properties& properties = {}, const std::vector& elements = {}) : tag(resolve_tag(tag).first), properties(properties) { + for (const auto& element : elements) this->push_back(element); + }; + /** + * @brief Construct a new Section object + * @param tag The tag of the section + * @param properties The properties of the section + * @param sections The sections of the section + */ + Section(const std::string& tag, const Properties& properties, const std::vector
    & sections) : tag(tag), properties(properties) { + for (const auto& section : sections) this->push_back(section); + }; + /** + * @brief Construct a new Section object + * @param tag The tag of the section + * @param properties The properties of the section + * @param sections The sections of the section + */ + Section(const Tag tag, const Properties& properties, const std::vector
    & sections) : tag(resolve_tag(tag).first), properties(properties) { + for (const auto& section : sections) this->push_back(section); + }; /** * @brief Construct a new Section object */ @@ -748,6 +864,21 @@ namespace docpp { * @param classes The classes of the section */ void set(const Tag tag, const Properties& properties = {}); + /** + * @brief Set the tag of the section + * @param tag The tag of the section + */ + void set_tag(const std::string& tag); + /** + * @brief Set the tag of the section + * @param tag The tag of the section + */ + void set_tag(const Tag tag); + /** + * @brief Set the properties of the section + * @param properties The properties of the section + */ + void set_properties(const Properties& properties); /** * @brief Swap two elements in the section * @param index1 The index of the first element @@ -781,21 +912,46 @@ namespace docpp { * @brief Dump the entire section. * @return std::string The section */ - std::string get(const Formatting formatting = FORMATTING_NONE, const int tabc = 0) const; + std::string get(const Formatting formatting = Formatting::None, const int tabc = 0) const; /** * @brief Get the element in the form of a specific type. * @return T The element in the form of a specific type */ - template T get(const Formatting formatting = FORMATTING_NONE, const int tabc = 0) const { + template T get(const Formatting formatting = Formatting::None, const int tabc = 0) const { if (std::is_same::value) { return this->get(formatting, tabc); } return T(this->get(formatting, tabc)); } - Section operator=(const Section& section); - void operator+=(const Element& element); - void operator+=(const Section& section); + /** + * @brief Get the tag of the section + * @return std::string The tag of the section + */ + std::string get_tag() const; + /** + * @brief Get the tag of the section in a specific type + * @return T The tag of the section + */ + template T get_tag() const { + if (std::is_same::value) { + return this->tag; + } + return T(this->tag); + } + /** + * @brief Get the properties of the section + * @return Properties The properties of the section + */ + Properties get_properties() const; + + Section& operator=(const Section& section); + Section& operator+=(const Element& element); + Section& operator+=(const Section& section); + bool operator==(const Element& element) const; + bool operator==(const Section& section) const; + bool operator!=(const Element& element) const; + bool operator!=(const Section& section) const; Element operator[](const int& index) const; private: size_type index{}; @@ -827,12 +983,12 @@ namespace docpp { * @param std::string The type to return * @return std::string The document */ - std::string get(const Formatting formatting = FORMATTING_NONE, const int tabc = 0) const; + std::string get(const Formatting formatting = Formatting::None, const int tabc = 0) const; /** * @brief Get the document in the form of a specific type. * @return T The document in the form of a specific type */ - template T get(const Formatting formatting = FORMATTING_NONE, const int tabc = 0) const { + template T get(const Formatting formatting = Formatting::None, const int tabc = 0) const { if (std::is_same::value) { return this->get(formatting, tabc); } @@ -871,6 +1027,14 @@ namespace docpp { * @param doctype The doctype to set */ void set_doctype(const std::string& doctype); + /** + * @brief Check if the document is empty + */ + bool empty() const; + /** + * @brief Clear the document + */ + void clear(); /** * @brief Construct a new Document object */ @@ -881,22 +1045,26 @@ namespace docpp { */ Document(const Section& document, const std::string& doctype = "") : document(document), doctype(doctype) {}; - Document operator=(const Document& document); - Document operator=(const Section& section); + Document& operator=(const Document& document); + Document& operator=(const Section& section); + bool operator==(const Document& document) const; + bool operator==(const Section& section) const; + bool operator!=(const Document& document) const; + bool operator!=(const Section& section) const; }; - } // namespace HTML + } // inline namespace HTML /** - * @brief A namespace to represent CSS elements and documents + * @brief A inline namespace to represent CSS elements and documents */ - namespace CSS { + inline namespace CSS { /** * @brief Enum for formatting options. */ - enum Formatting { - FORMATTING_NONE, - FORMATTING_PRETTY, - FORMATTING_NEWLINE, + enum class Formatting { + None, + Pretty, + Newline, }; /** @@ -993,8 +1161,8 @@ namespace docpp { */ void set(const std::string& key, const std::string& value); - Property operator=(const Property& property); - Property operator=(const std::pair& property); + Property& operator=(const Property& property); + Property& operator=(const std::pair& property); }; /** @@ -1150,12 +1318,12 @@ namespace docpp { * @brief Get the element * @return std::pair> The element */ - std::string get(const Formatting formatting = FORMATTING_NONE, const int tabc = 0) const; + std::string get(const Formatting formatting = Formatting::None, const int tabc = 0) const; /** * @brief Get the element in the form of a specific type. * @return T The element in the form of a specific type */ - template T get(const Formatting formatting = FORMATTING_NONE, const int tabc = 0) const { + template T get(const Formatting formatting = Formatting::None, const int tabc = 0) const { if (std::is_same::value) { return this->get(formatting, tabc); } @@ -1182,10 +1350,10 @@ namespace docpp { */ std::vector get_properties() const; - Element operator=(const Element& element); - Element operator=(const std::pair>& element); - void operator+=(const Property& property); - Property operator[](const int& index) const; + Element& operator=(const Element& element); + Element& operator=(const std::pair>& element); + Element& operator+=(const Property& property); + Property operator[](const size_type& index) const; }; /** @@ -1335,21 +1503,21 @@ namespace docpp { * @brief Get the stylesheet * @return std::string The stylesheet */ - std::string get(const Formatting formatting = FORMATTING_NONE, const int tabc = 0) const; + std::string get(const Formatting formatting = Formatting::None, const int tabc = 0) const; /** * @brief Get the stylesheet in the form of a specific type. * @return T The stylesheet in the form of a specific type */ - template T get(const Formatting formatting = FORMATTING_NONE, const int tabc = 0) const { + template T get(const Formatting formatting = Formatting::None, const int tabc = 0) const { if (std::is_same::value) { return this->get(formatting, tabc); } return T(this->get(formatting, tabc)); } - Stylesheet operator=(const Stylesheet& stylesheet); - void operator+=(const Element& element); + Stylesheet& operator=(const Stylesheet& stylesheet); + Stylesheet& operator+=(const Element& element); Element operator[](const int& index) const; }; - } // namespace CSS -} // namespace docpp + } // inline namespace CSS +} // inline namespace docpp diff --git a/src/docpp.cpp b/src/docpp.cpp index 1e1ef54..6809771 100644 --- a/src/docpp.cpp +++ b/src/docpp.cpp @@ -34,23 +34,90 @@ void docpp::HTML::Property::set(const std::pair& prope this->property = property; } -docpp::HTML::Properties docpp::HTML::Properties::operator=(const docpp::HTML::Property& property) { +docpp::HTML::Property& docpp::HTML::Property::operator=(const docpp::HTML::Property& property) { + this->set(property.get()); + return *this; +} + +docpp::HTML::Property& docpp::HTML::Property::operator=(const std::pair& property) { + this->set(property); + return *this; +} + +bool docpp::HTML::Property::operator==(const docpp::HTML::Property& property) const { + return this->property == property.get(); +} + +bool docpp::HTML::Property::operator!=(const docpp::HTML::Property& property) const { + return this->property != property.get(); +} + +void docpp::HTML::Property::clear() { + this->property = {}; +} + +bool docpp::HTML::Property::empty() const { + return this->property.first.empty() && this->property.second.empty(); +} + +docpp::HTML::Properties& docpp::HTML::Properties::operator=(const docpp::HTML::Property& property) { this->properties = {property}; return *this; } -docpp::HTML::Properties docpp::HTML::Properties::operator=(const docpp::HTML::Properties& properties) { +docpp::HTML::Properties& docpp::HTML::Properties::operator=(const docpp::HTML::Properties& properties) { this->set(properties.get_properties()); return *this; } -docpp::HTML::Properties docpp::HTML::Properties::operator=(const std::vector& properties) { +docpp::HTML::Properties& docpp::HTML::Properties::operator=(const std::vector& properties) { this->set(properties); return *this; } -void docpp::HTML::Properties::operator+=(const docpp::HTML::Property& property) { +docpp::HTML::Property docpp::HTML::Properties::operator[](const size_type& index) const { + return this->at(index); +} + +bool docpp::HTML::Properties::operator==(const docpp::HTML::Properties& properties) const { + return this->properties == properties.get_properties(); +} + +bool docpp::HTML::Properties::operator==(const docpp::HTML::Property& property) const { + for (const docpp::HTML::Property& it : this->properties) { + if (it.get() == property.get()) { + return true; + } + } + + return false; +} + +bool docpp::HTML::Properties::operator!=(const docpp::HTML::Properties& properties) const { + return this->properties != properties.get_properties(); +} + +bool docpp::HTML::Properties::operator!=(const docpp::HTML::Property& property) const { + for (const docpp::HTML::Property& it : this->properties) { + if (it.get() == property.get()) { + return false; + } + } + + return true; +} + +docpp::HTML::Properties& docpp::HTML::Properties::operator+=(const docpp::HTML::Property& property) { this->push_back(property); + return *this; +} + +docpp::HTML::Properties& docpp::HTML::Properties::operator+=(const docpp::HTML::Properties& properties) { + for (docpp::HTML::Properties::const_iterator it{properties.cbegin()}; it != properties.cend(); it++) { + this->push_back(*it); + } + + return *this; } std::vector docpp::HTML::Properties::get_properties() const { @@ -135,6 +202,14 @@ docpp::HTML::Properties::size_type docpp::HTML::Properties::size() const { return this->properties.size(); } +void docpp::HTML::Properties::clear() { + this->properties.clear(); +} + +bool docpp::HTML::Properties::empty() const { + return this->properties.empty(); +} + void docpp::HTML::Properties::swap(const size_type index1, const size_type index2) { if (index1 < 0 || index1 >= this->properties.size() || index2 < 0 || index2 >= this->properties.size()) { throw docpp::out_of_range("Index out of range"); @@ -148,28 +223,65 @@ void docpp::HTML::Properties::swap(const docpp::HTML::Property& property1, const } -docpp::HTML::Element docpp::HTML::Element::operator=(const docpp::HTML::Element& element) { +docpp::HTML::Element& docpp::HTML::Element::operator=(const docpp::HTML::Element& element) { this->set(element.get_tag(), element.properties, element.get_data(), element.type); return *this; } -void docpp::HTML::Element::operator+=(const std::string& data) { +docpp::HTML::Element& docpp::HTML::Element::operator+=(const std::string& data) { this->data += data; + return *this; +} + +bool docpp::HTML::Element::operator==(const docpp::HTML::Element& element) const { + return this->tag == element.get_tag() && this->properties == element.properties && this->data == element.get_data() && this->type == element.type; +} + +bool docpp::HTML::Element::operator!=(const docpp::HTML::Element& element) const { + return this->tag != element.get_tag() || this->properties != element.properties || this->data != element.get_data() || this->type != element.type; } void docpp::HTML::Element::set(const std::string& tag, const Properties& properties, const std::string& data, const Type type) { + this->set_tag(tag); + this->set_properties(properties); + this->set_data(data); + this->set_type(type); +} + +void docpp::HTML::Element::set(const Tag tag, const Properties& properties, const std::string& data) { + this->set_tag(tag); + this->set_properties(properties); + this->set_data(data); +} + +void docpp::HTML::Element::set_tag(const std::string& tag) { this->tag = tag; +} + +void docpp::HTML::Element::set_tag(const Tag tag) { + std::pair resolved{resolve_tag(tag)}; + this->tag = resolved.first; + this->type = resolved.second; +} + +void docpp::HTML::Element::set_data(const std::string& data) { this->data = data; - this->properties = properties; +} + +void docpp::HTML::Element::set_type(const Type type) { this->type = type; } +void docpp::HTML::Element::set_properties(const Properties& properties) { + this->properties = properties; +} + std::string docpp::HTML::Element::get(const Formatting formatting, const int tabc) const { std::string ret{}; - if (this->type == docpp::HTML::TYPE_TEXT) { + if (this->type == docpp::HTML::Type::Text_No_Formatting) { return this->data; - } else if (this->type == docpp::HTML::TYPE_TEXT_TAB) { + } else if (this->type == docpp::HTML::Type::Text) { for (size_type i{0}; i < tabc; i++) { ret += "\t"; } @@ -177,7 +289,7 @@ std::string docpp::HTML::Element::get(const Formatting formatting, const int tab return ret + this->data; } - if (formatting == docpp::HTML::FORMATTING_PRETTY) { + if (formatting == docpp::HTML::Formatting::Pretty) { for (size_type i{0}; i < tabc; i++) { ret += "\t"; } @@ -192,17 +304,17 @@ std::string docpp::HTML::Element::get(const Formatting formatting, const int tab ret += " " + it.get_key() + "=\"" + it.get_value() + "\""; } - if (this->type != docpp::HTML::TYPE_SELF_CLOSING) { + if (this->type != docpp::HTML::Type::Self_Closing) { ret += ">"; } - if (this->type == docpp::HTML::TYPE_NON_SELF_CLOSING) { + if (this->type == docpp::HTML::Type::Non_Self_Closing) { ret += this->data + "tag + ">"; - } else if (this->type == docpp::HTML::TYPE_SELF_CLOSING) { + } else if (this->type == docpp::HTML::Type::Self_Closing) { ret += this->data + "/>"; } - if (formatting == docpp::HTML::FORMATTING_PRETTY || formatting == docpp::HTML::FORMATTING_NEWLINE) { + if (formatting == docpp::HTML::Formatting::Pretty || formatting == docpp::HTML::Formatting::Newline) { ret += "\n"; } @@ -217,7 +329,25 @@ std::string docpp::HTML::Element::get_data() const { return this->data; } -docpp::HTML::Section docpp::HTML::Section::operator=(const docpp::HTML::Section& section) { +docpp::HTML::Type docpp::HTML::Element::get_type() const { + return this->type; +} + +docpp::HTML::Properties docpp::HTML::Element::get_properties() const { + return this->properties; +} + +bool docpp::HTML::Element::empty() const { + return this->tag.empty() && this->data.empty() && this->properties.empty(); +} + +void docpp::HTML::Element::clear() { + this->tag.clear(); + this->data.clear(); + this->properties.clear(); +} + +docpp::HTML::Section& docpp::HTML::Section::operator=(const docpp::HTML::Section& section) { this->tag = section.tag; this->properties = section.properties; this->elements = section.elements; @@ -227,170 +357,213 @@ docpp::HTML::Section docpp::HTML::Section::operator=(const docpp::HTML::Section& return *this; } -void docpp::HTML::Section::operator+=(const docpp::HTML::Element& element) { +docpp::HTML::Section& docpp::HTML::Section::operator+=(const docpp::HTML::Element& element) { this->push_back(element); + return *this; } -void docpp::HTML::Section::operator+=(const docpp::HTML::Section& section) { +docpp::HTML::Section& docpp::HTML::Section::operator+=(const docpp::HTML::Section& section) { this->push_back(section); + return *this; } docpp::HTML::Element docpp::HTML::Section::operator[](const int& index) const { return this->at(index); } +bool docpp::HTML::Section::operator==(const docpp::HTML::Section& section) const { + return this->tag == section.tag && this->properties == section.properties && this->elements == section.elements && this->sections == section.sections && this->index == section.index; +} + +bool docpp::HTML::Section::operator==(const docpp::HTML::Element& element) const { + for (const Element& it : this->get_elements()) { + if (it.get() == element.get()) { + return true; + } + } + + return false; +} + +bool docpp::HTML::Section::operator!=(const docpp::HTML::Section& section) const { + return this->tag != section.tag || this->properties != section.properties || this->elements != section.elements || this->sections != section.sections || this->index != section.index; +} + +bool docpp::HTML::Section::operator!=(const docpp::HTML::Element& element) const { + for (const Element& it : this->get_elements()) { + if (it.get() == element.get()) { + return false; + } + } + + return true; +} + void docpp::HTML::Section::set(const std::string& tag, const Properties& properties) { this->tag = tag; this->properties = properties; } +void docpp::HTML::Section::set_tag(const std::string& tag) { + this->tag = tag; +} + +void docpp::HTML::Section::set_tag(const Tag tag) { + std::pair resolved{resolve_tag(tag)}; + this->tag = resolved.first; +} + +void docpp::HTML::Section::set_properties(const Properties& properties) { + this->properties = properties; +} + std::pair docpp::HTML::resolve_tag(const Tag tag) { - const std::unordered_map> tag_map{ - {ELEMENT_EMPTY, {"", docpp::HTML::TYPE_TEXT_TAB}}, - {ELEMENT_EMPTY_NO_FORMAT, {"", docpp::HTML::TYPE_TEXT}}, - {ELEMENT_ABBREVIATION, {"abbr", docpp::HTML::TYPE_NON_SELF_CLOSING}}, - {ELEMENT_ABBR, {"abbr", docpp::HTML::TYPE_NON_SELF_CLOSING}}, - {ELEMENT_ACRONYM, {"acronym", docpp::HTML::TYPE_NON_SELF_CLOSING}}, - {ELEMENT_ADDRESS, {"address", docpp::HTML::TYPE_NON_SELF_CLOSING}}, - {ELEMENT_APPLET, {"applet", docpp::HTML::TYPE_NON_SELF_CLOSING}}, - {ELEMENT_ANCHOR, {"a", docpp::HTML::TYPE_NON_SELF_CLOSING}}, - {ELEMENT_A, {"a", docpp::HTML::TYPE_NON_SELF_CLOSING}}, - {ELEMENT_ARTICLE, {"article", docpp::HTML::TYPE_NON_SELF_CLOSING}}, - {ELEMENT_AREA, {"area", docpp::HTML::TYPE_NON_CLOSED}}, - {ELEMENT_ASIDE, {"aside", docpp::HTML::TYPE_NON_SELF_CLOSING}}, - {ELEMENT_AUDIO, {"audio", docpp::HTML::TYPE_NON_SELF_CLOSING}}, - {ELEMENT_BASE, {"base", docpp::HTML::TYPE_NON_CLOSED}}, - {ELEMENT_BASEFONT, {"basefont", docpp::HTML::TYPE_NON_CLOSED}}, - {ELEMENT_BDI, {"bdi", docpp::HTML::TYPE_NON_SELF_CLOSING}}, - {ELEMENT_BDO, {"bdo", docpp::HTML::TYPE_NON_SELF_CLOSING}}, - {ELEMENT_BGSOUND, {"bgsound", docpp::HTML::TYPE_NON_SELF_CLOSING}}, - {ELEMENT_BIG, {"big", docpp::HTML::TYPE_NON_SELF_CLOSING}}, - {ELEMENT_BLOCKQUOTE, {"blockquote", docpp::HTML::TYPE_NON_SELF_CLOSING}}, - {ELEMENT_BODY, {"body", docpp::HTML::TYPE_NON_SELF_CLOSING}}, - {ELEMENT_B, {"b", docpp::HTML::TYPE_NON_SELF_CLOSING}}, - {ELEMENT_BOLD, {"b", docpp::HTML::TYPE_NON_SELF_CLOSING}}, - {ELEMENT_BR, {"br", docpp::HTML::TYPE_NON_CLOSED}}, - {ELEMENT_BREAK, {"br", docpp::HTML::TYPE_NON_CLOSED}}, - {ELEMENT_BUTTON, {"button", docpp::HTML::TYPE_NON_CLOSED}}, - {ELEMENT_CAPTION, {"caption", docpp::HTML::TYPE_NON_SELF_CLOSING}}, - {ELEMENT_CANVAS, {"canvas", docpp::HTML::TYPE_NON_SELF_CLOSING}}, - {ELEMENT_CENTER, {"center", docpp::HTML::TYPE_NON_SELF_CLOSING}}, - {ELEMENT_CITE, {"cite", docpp::HTML::TYPE_NON_SELF_CLOSING}}, - {ELEMENT_CODE, {"code", docpp::HTML::TYPE_NON_SELF_CLOSING}}, - {ELEMENT_COLGROUP, {"colgroup", docpp::HTML::TYPE_NON_SELF_CLOSING}}, - {ELEMENT_COLUMN, {"col", docpp::HTML::TYPE_NON_CLOSED}}, - {ELEMENT_COL, {"col", docpp::HTML::TYPE_NON_CLOSED}}, - {ELEMENT_DATA, {"data", docpp::HTML::TYPE_NON_SELF_CLOSING}}, - {ELEMENT_DATALIST, {"datalist", docpp::HTML::TYPE_NON_SELF_CLOSING}}, - {ELEMENT_DD, {"dd", docpp::HTML::TYPE_NON_SELF_CLOSING}}, - {ELEMENT_DFN, {"dfn", docpp::HTML::TYPE_NON_SELF_CLOSING}}, - {ELEMENT_DEFINE, {"dfn", docpp::HTML::TYPE_NON_SELF_CLOSING}}, - {ELEMENT_DELETE, {"del", docpp::HTML::TYPE_NON_SELF_CLOSING}}, - {ELEMENT_DEL, {"del", docpp::HTML::TYPE_NON_SELF_CLOSING}}, - {ELEMENT_DETAILS, {"details", docpp::HTML::TYPE_NON_SELF_CLOSING}}, - {ELEMENT_DIALOG, {"dialog", docpp::HTML::TYPE_NON_SELF_CLOSING}}, - {ELEMENT_DIR, {"dir", docpp::HTML::TYPE_NON_SELF_CLOSING}}, - {ELEMENT_DIV, {"div", docpp::HTML::TYPE_NON_SELF_CLOSING}}, - {ELEMENT_DL, {"dl", docpp::HTML::TYPE_NON_SELF_CLOSING}}, - {ELEMENT_DT, {"dt", docpp::HTML::TYPE_NON_SELF_CLOSING}}, - {ELEMENT_EMBED, {"embed", docpp::HTML::TYPE_NON_CLOSED}}, - {ELEMENT_FIELDSET, {"fieldset", docpp::HTML::TYPE_NON_SELF_CLOSING}}, - {ELEMENT_FIGCAPTION, {"figcaption", docpp::HTML::TYPE_NON_SELF_CLOSING}}, - {ELEMENT_FIGURE, {"figure", docpp::HTML::TYPE_NON_SELF_CLOSING}}, - {ELEMENT_FONT, {"font", docpp::HTML::TYPE_NON_SELF_CLOSING}}, - {ELEMENT_FOOTER, {"footer", docpp::HTML::TYPE_NON_SELF_CLOSING}}, - {ELEMENT_FORM, {"form", docpp::HTML::TYPE_NON_SELF_CLOSING}}, - {ELEMENT_FRAME, {"frame", docpp::HTML::TYPE_SELF_CLOSING}}, - {ELEMENT_FRAMESET, {"frameset", docpp::HTML::TYPE_NON_SELF_CLOSING}}, - {ELEMENT_HEAD, {"head", docpp::HTML::TYPE_NON_SELF_CLOSING}}, - {ELEMENT_HEADER, {"header", docpp::HTML::TYPE_NON_SELF_CLOSING}}, - {ELEMENT_H1, {"h1", docpp::HTML::TYPE_NON_SELF_CLOSING}}, - {ELEMENT_H2, {"h2", docpp::HTML::TYPE_NON_SELF_CLOSING}}, - {ELEMENT_H3, {"h3", docpp::HTML::TYPE_NON_SELF_CLOSING}}, - {ELEMENT_H4, {"h4", docpp::HTML::TYPE_NON_SELF_CLOSING}}, - {ELEMENT_H5, {"h5", docpp::HTML::TYPE_NON_SELF_CLOSING}}, - {ELEMENT_H6, {"h6", docpp::HTML::TYPE_NON_SELF_CLOSING}}, - {ELEMENT_HR, {"hr", docpp::HTML::TYPE_NON_CLOSED}}, - {ELEMENT_HGROUP, {"hgroup", docpp::HTML::TYPE_NON_SELF_CLOSING}}, - {ELEMENT_HTML, {"html", docpp::HTML::TYPE_NON_SELF_CLOSING}}, - {ELEMENT_IFRAME, {"iframe", docpp::HTML::TYPE_NON_SELF_CLOSING}}, - {ELEMENT_IMAGE, {"img", docpp::HTML::TYPE_NON_SELF_CLOSING}}, - {ELEMENT_IMG, {"img", docpp::HTML::TYPE_NON_CLOSED}}, - {ELEMENT_INPUT, {"input", docpp::HTML::TYPE_SELF_CLOSING}}, - {ELEMENT_INS, {"ins", docpp::HTML::TYPE_NON_SELF_CLOSING}}, - {ELEMENT_ISINDEX, {"isindex", docpp::HTML::TYPE_NON_CLOSED}}, - {ELEMENT_ITALIC, {"i", docpp::HTML::TYPE_NON_SELF_CLOSING}}, - {ELEMENT_I, {"i", docpp::HTML::TYPE_NON_SELF_CLOSING}}, - {ELEMENT_KBD, {"kbd", docpp::HTML::TYPE_NON_SELF_CLOSING}}, - {ELEMENT_KEYGEN, {"keygen", docpp::HTML::TYPE_NON_CLOSED}}, - {ELEMENT_LABEL, {"label", docpp::HTML::TYPE_NON_SELF_CLOSING}}, - {ELEMENT_LEGEND, {"legend", docpp::HTML::TYPE_NON_SELF_CLOSING}}, - {ELEMENT_LIST, {"li", docpp::HTML::TYPE_NON_SELF_CLOSING}}, - {ELEMENT_LI, {"li", docpp::HTML::TYPE_NON_SELF_CLOSING}}, - {ELEMENT_LINK, {"link", docpp::HTML::TYPE_NON_CLOSED}}, - {ELEMENT_MAIN, {"main", docpp::HTML::TYPE_NON_SELF_CLOSING}}, - {ELEMENT_MARK, {"mark", docpp::HTML::TYPE_NON_SELF_CLOSING}}, - {ELEMENT_MARQUEE, {"marquee", docpp::HTML::TYPE_NON_SELF_CLOSING}}, - {ELEMENT_MENUITEM, {"menuitem", docpp::HTML::TYPE_NON_SELF_CLOSING}}, - {ELEMENT_META, {"meta", docpp::HTML::TYPE_NON_CLOSED}}, - {ELEMENT_METER, {"meter", docpp::HTML::TYPE_NON_SELF_CLOSING}}, - {ELEMENT_NAV, {"nav", docpp::HTML::TYPE_NON_SELF_CLOSING}}, - {ELEMENT_NOBREAK, {"nobr", docpp::HTML::TYPE_NON_SELF_CLOSING}}, - {ELEMENT_NOBR, {"nobr", docpp::HTML::TYPE_NON_SELF_CLOSING}}, - {ELEMENT_NOEMBED, {"noembed", docpp::HTML::TYPE_NON_SELF_CLOSING}}, - {ELEMENT_NOSCRIPT, {"noscript", docpp::HTML::TYPE_NON_SELF_CLOSING}}, - {ELEMENT_OBJECT, {"object", docpp::HTML::TYPE_NON_SELF_CLOSING}}, - {ELEMENT_OPTGROUP, {"optgroup", docpp::HTML::TYPE_NON_SELF_CLOSING}}, - {ELEMENT_OPTION, {"option", docpp::HTML::TYPE_NON_SELF_CLOSING}}, - {ELEMENT_OUTPUT, {"output", docpp::HTML::TYPE_NON_SELF_CLOSING}}, - {ELEMENT_PARAGRAPH, {"p", docpp::HTML::TYPE_NON_SELF_CLOSING}}, - {ELEMENT_P, {"p", docpp::HTML::TYPE_NON_SELF_CLOSING}}, - {ELEMENT_PARAM, {"param", docpp::HTML::TYPE_NON_CLOSED}}, - {ELEMENT_PHRASE, {"phrase", docpp::HTML::TYPE_NON_SELF_CLOSING}}, - {ELEMENT_PRE, {"pre", docpp::HTML::TYPE_NON_SELF_CLOSING}}, - {ELEMENT_PROGRESS, {"progress", docpp::HTML::TYPE_NON_SELF_CLOSING}}, - {ELEMENT_QUOTE, {"q", docpp::HTML::TYPE_NON_SELF_CLOSING}}, - {ELEMENT_Q, {"q", docpp::HTML::TYPE_NON_SELF_CLOSING}}, - {ELEMENT_RP, {"rp", docpp::HTML::TYPE_NON_SELF_CLOSING}}, - {ELEMENT_RT, {"rt", docpp::HTML::TYPE_NON_SELF_CLOSING}}, - {ELEMENT_RUBY, {"ruby", docpp::HTML::TYPE_NON_SELF_CLOSING}}, - {ELEMENT_OUTDATED, {"s", docpp::HTML::TYPE_NON_SELF_CLOSING}}, - {ELEMENT_S, {"s", docpp::HTML::TYPE_NON_SELF_CLOSING}}, - {ELEMENT_SAMPLE, {"samp", docpp::HTML::TYPE_NON_SELF_CLOSING}}, - {ELEMENT_SAMP, {"samp", docpp::HTML::TYPE_NON_SELF_CLOSING}}, - {ELEMENT_SCRIPT, {"script", docpp::HTML::TYPE_NON_SELF_CLOSING}}, - {ELEMENT_SECTION, {"section", docpp::HTML::TYPE_NON_SELF_CLOSING}}, - {ELEMENT_SMALL, {"small", docpp::HTML::TYPE_NON_SELF_CLOSING}}, - {ELEMENT_SOURCE, {"source", docpp::HTML::TYPE_NON_SELF_CLOSING}}, - {ELEMENT_SPACER, {"spacer", docpp::HTML::TYPE_NON_SELF_CLOSING}}, - {ELEMENT_SPAN, {"span", docpp::HTML::TYPE_NON_SELF_CLOSING}}, - {ELEMENT_STRIKE, {"strike", docpp::HTML::TYPE_NON_SELF_CLOSING}}, - {ELEMENT_STRONG, {"strong", docpp::HTML::TYPE_NON_SELF_CLOSING}}, - {ELEMENT_STYLE, {"style", docpp::HTML::TYPE_NON_CLOSED}}, - {ELEMENT_SUB, {"sub", docpp::HTML::TYPE_NON_SELF_CLOSING}}, - {ELEMENT_SUBSCRIPT, {"sub", docpp::HTML::TYPE_NON_SELF_CLOSING}}, - {ELEMENT_SUP, {"sup", docpp::HTML::TYPE_NON_SELF_CLOSING}}, - {ELEMENT_SUPERSCRIPT, {"sup", docpp::HTML::TYPE_NON_SELF_CLOSING}}, - {ELEMENT_SUMMARY, {"summary", docpp::HTML::TYPE_NON_SELF_CLOSING}}, - {ELEMENT_SVG, {"svg", docpp::HTML::TYPE_NON_CLOSED}}, - {ELEMENT_TABLE, {"table", docpp::HTML::TYPE_NON_SELF_CLOSING}}, - {ELEMENT_TBODY, {"tbody", docpp::HTML::TYPE_NON_SELF_CLOSING}}, - {ELEMENT_TD, {"td", docpp::HTML::TYPE_NON_SELF_CLOSING}}, - {ELEMENT_TEMPLATE, {"template", docpp::HTML::TYPE_NON_SELF_CLOSING}}, - {ELEMENT_TFOOT, {"tfoot", docpp::HTML::TYPE_NON_SELF_CLOSING}}, - {ELEMENT_TH, {"th", docpp::HTML::TYPE_NON_SELF_CLOSING}}, - {ELEMENT_TR, {"tr", docpp::HTML::TYPE_NON_SELF_CLOSING}}, - {ELEMENT_THEAD, {"thead", docpp::HTML::TYPE_NON_SELF_CLOSING}}, - {ELEMENT_TIME, {"time", docpp::HTML::TYPE_NON_SELF_CLOSING}}, - {ELEMENT_TITLE, {"title", docpp::HTML::TYPE_NON_SELF_CLOSING}}, - {ELEMENT_TRACK, {"track", docpp::HTML::TYPE_NON_CLOSED}}, - {ELEMENT_TT, {"tt", docpp::HTML::TYPE_NON_SELF_CLOSING}}, - {ELEMENT_UNDERLINE, {"u", docpp::HTML::TYPE_NON_SELF_CLOSING}}, - {ELEMENT_U, {"u", docpp::HTML::TYPE_NON_SELF_CLOSING}}, - {ELEMENT_VAR, {"var", docpp::HTML::TYPE_NON_SELF_CLOSING}}, - {ELEMENT_VIDEO, {"video", docpp::HTML::TYPE_NON_SELF_CLOSING}}, - {ELEMENT_WBR, {"wbr", docpp::HTML::TYPE_NON_CLOSED}}, - {ELEMENT_XMP, {"xmp", docpp::HTML::TYPE_NON_SELF_CLOSING}}, + static const std::unordered_map> tag_map{ + {Tag::Empty, {"", docpp::HTML::Type::Text}}, + {Tag::Empty_No_Formatting, {"", docpp::HTML::Type::Text_No_Formatting}}, + {Tag::Abbreviation, {"abbr", docpp::HTML::Type::Non_Self_Closing}}, + {Tag::Abbr, {"abbr", docpp::HTML::Type::Non_Self_Closing}}, + {Tag::Acronym, {"acronym", docpp::HTML::Type::Non_Self_Closing}}, + {Tag::Address, {"address", docpp::HTML::Type::Non_Self_Closing}}, + {Tag::Applet, {"applet", docpp::HTML::Type::Non_Self_Closing}}, + {Tag::Anchor, {"a", docpp::HTML::Type::Non_Self_Closing}}, + {Tag::A, {"a", docpp::HTML::Type::Non_Self_Closing}}, + {Tag::Article, {"article", docpp::HTML::Type::Non_Self_Closing}}, + {Tag::Area, {"area", docpp::HTML::Type::Non_Closed}}, + {Tag::Aside, {"aside", docpp::HTML::Type::Non_Self_Closing}}, + {Tag::Audio, {"audio", docpp::HTML::Type::Non_Self_Closing}}, + {Tag::Base, {"base", docpp::HTML::Type::Non_Closed}}, + {Tag::Basefont, {"basefont", docpp::HTML::Type::Non_Closed}}, + {Tag::Bdi, {"bdi", docpp::HTML::Type::Non_Self_Closing}}, + {Tag::Bdo, {"bdo", docpp::HTML::Type::Non_Self_Closing}}, + {Tag::Bgsound, {"bgsound", docpp::HTML::Type::Non_Self_Closing}}, + {Tag::Big, {"big", docpp::HTML::Type::Non_Self_Closing}}, + {Tag::Blockquote, {"blockquote", docpp::HTML::Type::Non_Self_Closing}}, + {Tag::Body, {"body", docpp::HTML::Type::Non_Self_Closing}}, + {Tag::B, {"b", docpp::HTML::Type::Non_Self_Closing}}, + {Tag::Bold, {"b", docpp::HTML::Type::Non_Self_Closing}}, + {Tag::Br, {"br", docpp::HTML::Type::Non_Closed}}, + {Tag::Break, {"br", docpp::HTML::Type::Non_Closed}}, + {Tag::Button, {"button", docpp::HTML::Type::Non_Closed}}, + {Tag::Caption, {"caption", docpp::HTML::Type::Non_Self_Closing}}, + {Tag::Canvas, {"canvas", docpp::HTML::Type::Non_Self_Closing}}, + {Tag::Center, {"center", docpp::HTML::Type::Non_Self_Closing}}, + {Tag::Cite, {"cite", docpp::HTML::Type::Non_Self_Closing}}, + {Tag::Code, {"code", docpp::HTML::Type::Non_Self_Closing}}, + {Tag::Colgroup, {"colgroup", docpp::HTML::Type::Non_Self_Closing}}, + {Tag::Column, {"col", docpp::HTML::Type::Non_Closed}}, + {Tag::Col, {"col", docpp::HTML::Type::Non_Closed}}, + {Tag::Data, {"data", docpp::HTML::Type::Non_Self_Closing}}, + {Tag::Datalist, {"datalist", docpp::HTML::Type::Non_Self_Closing}}, + {Tag::Dd, {"dd", docpp::HTML::Type::Non_Self_Closing}}, + {Tag::Dfn, {"dfn", docpp::HTML::Type::Non_Self_Closing}}, + {Tag::Define, {"dfn", docpp::HTML::Type::Non_Self_Closing}}, + {Tag::Delete, {"del", docpp::HTML::Type::Non_Self_Closing}}, + {Tag::Del, {"del", docpp::HTML::Type::Non_Self_Closing}}, + {Tag::Details, {"details", docpp::HTML::Type::Non_Self_Closing}}, + {Tag::Dialog, {"dialog", docpp::HTML::Type::Non_Self_Closing}}, + {Tag::Dir, {"dir", docpp::HTML::Type::Non_Self_Closing}}, + {Tag::Div, {"div", docpp::HTML::Type::Non_Self_Closing}}, + {Tag::Dl, {"dl", docpp::HTML::Type::Non_Self_Closing}}, + {Tag::Dt, {"dt", docpp::HTML::Type::Non_Self_Closing}}, + {Tag::Embed, {"embed", docpp::HTML::Type::Non_Closed}}, + {Tag::Fieldset, {"fieldset", docpp::HTML::Type::Non_Self_Closing}}, + {Tag::Figcaption, {"figcaption", docpp::HTML::Type::Non_Self_Closing}}, + {Tag::Figure, {"figure", docpp::HTML::Type::Non_Self_Closing}}, + {Tag::Font, {"font", docpp::HTML::Type::Non_Self_Closing}}, + {Tag::Footer, {"footer", docpp::HTML::Type::Non_Self_Closing}}, + {Tag::Form, {"form", docpp::HTML::Type::Non_Self_Closing}}, + {Tag::Frame, {"frame", docpp::HTML::Type::Self_Closing}}, + {Tag::Frameset, {"frameset", docpp::HTML::Type::Non_Self_Closing}}, + {Tag::Head, {"head", docpp::HTML::Type::Non_Self_Closing}}, + {Tag::Header, {"header", docpp::HTML::Type::Non_Self_Closing}}, + {Tag::H1, {"h1", docpp::HTML::Type::Non_Self_Closing}}, + {Tag::H2, {"h2", docpp::HTML::Type::Non_Self_Closing}}, + {Tag::H3, {"h3", docpp::HTML::Type::Non_Self_Closing}}, + {Tag::H4, {"h4", docpp::HTML::Type::Non_Self_Closing}}, + {Tag::H5, {"h5", docpp::HTML::Type::Non_Self_Closing}}, + {Tag::H6, {"h6", docpp::HTML::Type::Non_Self_Closing}}, + {Tag::Hr, {"hr", docpp::HTML::Type::Non_Closed}}, + {Tag::Hgroup, {"hgroup", docpp::HTML::Type::Non_Self_Closing}}, + {Tag::Html, {"html", docpp::HTML::Type::Non_Self_Closing}}, + {Tag::Iframe, {"iframe", docpp::HTML::Type::Non_Self_Closing}}, + {Tag::Image, {"img", docpp::HTML::Type::Non_Closed}}, + {Tag::Img, {"img", docpp::HTML::Type::Non_Closed}}, + {Tag::Input, {"input", docpp::HTML::Type::Self_Closing}}, + {Tag::Ins, {"ins", docpp::HTML::Type::Non_Self_Closing}}, + {Tag::Isindex, {"isindex", docpp::HTML::Type::Non_Closed}}, + {Tag::Italic, {"i", docpp::HTML::Type::Non_Self_Closing}}, + {Tag::I, {"i", docpp::HTML::Type::Non_Self_Closing}}, + {Tag::Kbd, {"kbd", docpp::HTML::Type::Non_Self_Closing}}, + {Tag::Keygen, {"keygen", docpp::HTML::Type::Non_Closed}}, + {Tag::Label, {"label", docpp::HTML::Type::Non_Self_Closing}}, + {Tag::Legend, {"legend", docpp::HTML::Type::Non_Self_Closing}}, + {Tag::List, {"li", docpp::HTML::Type::Non_Self_Closing}}, + {Tag::Li, {"li", docpp::HTML::Type::Non_Self_Closing}}, + {Tag::Link, {"link", docpp::HTML::Type::Non_Closed}}, + {Tag::Main, {"main", docpp::HTML::Type::Non_Self_Closing}}, + {Tag::Mark, {"mark", docpp::HTML::Type::Non_Self_Closing}}, + {Tag::Marquee, {"marquee", docpp::HTML::Type::Non_Self_Closing}}, + {Tag::Menuitem, {"menuitem", docpp::HTML::Type::Non_Self_Closing}}, + {Tag::Meta, {"meta", docpp::HTML::Type::Non_Closed}}, + {Tag::Meter, {"meter", docpp::HTML::Type::Non_Self_Closing}}, + {Tag::Nav, {"nav", docpp::HTML::Type::Non_Self_Closing}}, + {Tag::Nobreak, {"nobr", docpp::HTML::Type::Non_Self_Closing}}, + {Tag::Nobr, {"nobr", docpp::HTML::Type::Non_Self_Closing}}, + {Tag::Noembed, {"noembed", docpp::HTML::Type::Non_Self_Closing}}, + {Tag::Noscript, {"noscript", docpp::HTML::Type::Non_Self_Closing}}, + {Tag::Object, {"object", docpp::HTML::Type::Non_Self_Closing}}, + {Tag::Optgroup, {"optgroup", docpp::HTML::Type::Non_Self_Closing}}, + {Tag::Option, {"option", docpp::HTML::Type::Non_Self_Closing}}, + {Tag::Output, {"output", docpp::HTML::Type::Non_Self_Closing}}, + {Tag::Paragraph, {"p", docpp::HTML::Type::Non_Self_Closing}}, + {Tag::P, {"p", docpp::HTML::Type::Non_Self_Closing}}, + {Tag::Param, {"param", docpp::HTML::Type::Non_Closed}}, + {Tag::Phrase, {"phrase", docpp::HTML::Type::Non_Self_Closing}}, + {Tag::Pre, {"pre", docpp::HTML::Type::Non_Self_Closing}}, + {Tag::Progress, {"progress", docpp::HTML::Type::Non_Self_Closing}}, + {Tag::Quote, {"q", docpp::HTML::Type::Non_Self_Closing}}, + {Tag::Q, {"q", docpp::HTML::Type::Non_Self_Closing}}, + {Tag::Rp, {"rp", docpp::HTML::Type::Non_Self_Closing}}, + {Tag::Rt, {"rt", docpp::HTML::Type::Non_Self_Closing}}, + {Tag::Ruby, {"ruby", docpp::HTML::Type::Non_Self_Closing}}, + {Tag::Outdated, {"s", docpp::HTML::Type::Non_Self_Closing}}, + {Tag::S, {"s", docpp::HTML::Type::Non_Self_Closing}}, + {Tag::Sample, {"samp", docpp::HTML::Type::Non_Self_Closing}}, + {Tag::Samp, {"samp", docpp::HTML::Type::Non_Self_Closing}}, + {Tag::Script, {"script", docpp::HTML::Type::Non_Self_Closing}}, + {Tag::Section, {"section", docpp::HTML::Type::Non_Self_Closing}}, + {Tag::Small, {"small", docpp::HTML::Type::Non_Self_Closing}}, + {Tag::Source, {"source", docpp::HTML::Type::Non_Self_Closing}}, + {Tag::Spacer, {"spacer", docpp::HTML::Type::Non_Self_Closing}}, + {Tag::Span, {"span", docpp::HTML::Type::Non_Self_Closing}}, + {Tag::Strike, {"strike", docpp::HTML::Type::Non_Self_Closing}}, + {Tag::Strong, {"strong", docpp::HTML::Type::Non_Self_Closing}}, + {Tag::Style, {"style", docpp::HTML::Type::Non_Closed}}, + {Tag::Sub, {"sub", docpp::HTML::Type::Non_Self_Closing}}, + {Tag::Subscript, {"sub", docpp::HTML::Type::Non_Self_Closing}}, + {Tag::Sup, {"sup", docpp::HTML::Type::Non_Self_Closing}}, + {Tag::Superscript, {"sup", docpp::HTML::Type::Non_Self_Closing}}, + {Tag::Summary, {"summary", docpp::HTML::Type::Non_Self_Closing}}, + {Tag::Svg, {"svg", docpp::HTML::Type::Non_Closed}}, + {Tag::Table, {"table", docpp::HTML::Type::Non_Self_Closing}}, + {Tag::Tbody, {"tbody", docpp::HTML::Type::Non_Self_Closing}}, + {Tag::Td, {"td", docpp::HTML::Type::Non_Self_Closing}}, + {Tag::Template, {"template", docpp::HTML::Type::Non_Self_Closing}}, + {Tag::Tfoot, {"tfoot", docpp::HTML::Type::Non_Self_Closing}}, + {Tag::Th, {"th", docpp::HTML::Type::Non_Self_Closing}}, + {Tag::Tr, {"tr", docpp::HTML::Type::Non_Self_Closing}}, + {Tag::Thead, {"thead", docpp::HTML::Type::Non_Self_Closing}}, + {Tag::Time, {"time", docpp::HTML::Type::Non_Self_Closing}}, + {Tag::Title, {"title", docpp::HTML::Type::Non_Self_Closing}}, + {Tag::Track, {"track", docpp::HTML::Type::Non_Closed}}, + {Tag::Tt, {"tt", docpp::HTML::Type::Non_Self_Closing}}, + {Tag::Underline, {"u", docpp::HTML::Type::Non_Self_Closing}}, + {Tag::U, {"u", docpp::HTML::Type::Non_Self_Closing}}, + {Tag::Var, {"var", docpp::HTML::Type::Non_Self_Closing}}, + {Tag::Video, {"video", docpp::HTML::Type::Non_Self_Closing}}, + {Tag::Wbr, {"wbr", docpp::HTML::Type::Non_Closed}}, + {Tag::Xmp, {"xmp", docpp::HTML::Type::Non_Self_Closing}}, }; if (tag_map.find(tag) != tag_map.end()) { @@ -530,18 +703,26 @@ docpp::HTML::Section::size_type docpp::HTML::Section::find(const Section& sectio } docpp::HTML::Section::size_type docpp::HTML::Section::find(const std::string& str) { - const std::vector elements = this->get_elements(); + const std::vector elements{this->get_elements()}; - for (size_type i{0}; i < elements.size(); i++) { - if (!elements.at(i).get().compare(str)) { + for (size_type i{0}; i < this->size(); i++) { + if (elements.size() <= i) { + break; + } + + if (elements.at(i).get().find(str) != docpp::HTML::Section::npos) { return i; } } - const std::vector
    sections = this->get_sections(); + const std::vector sections{this->get_sections()}; - for (size_type i{0}; i < sections.size(); i++) { - if (!sections.at(i).get().compare(str)) { + for (size_type i{0}; i < this->size(); i++) { + if (elements.size() <= i) { + break; + } + + if (elements.at(i).get().find(str) != docpp::HTML::Section::npos) { return i; } } @@ -585,6 +766,18 @@ docpp::HTML::Section::size_type docpp::HTML::Section::size() const { return this->index; } +void docpp::HTML::Section::clear() { + this->tag.clear(); + this->properties.clear(); + this->elements.clear(); + this->sections.clear(); + this->index = 0; +} + +bool docpp::HTML::Section::empty() const { + return this->index == 0; +} + std::vector docpp::HTML::Section::get_elements() const { std::vector ret{}; ret.reserve(this->index); @@ -621,7 +814,7 @@ std::string docpp::HTML::Section::get(const Formatting formatting, const int tab } } - if (formatting == docpp::HTML::FORMATTING_PRETTY) { + if (formatting == docpp::HTML::Formatting::Pretty) { for (size_type i{0}; i < tabcount; i++) { ret += "\t"; } @@ -639,7 +832,7 @@ std::string docpp::HTML::Section::get(const Formatting formatting, const int tab ret += ">"; - if (formatting == docpp::HTML::FORMATTING_PRETTY || formatting == docpp::HTML::FORMATTING_NEWLINE) { + if (formatting == docpp::HTML::Formatting::Pretty || formatting == docpp::HTML::Formatting::Newline) { ret += "\n"; } } @@ -650,13 +843,13 @@ std::string docpp::HTML::Section::get(const Formatting formatting, const int tab } else if (this->sections.find(i) != this->sections.end()) { ret += this->sections.at(i).get(formatting, tabcount + 1); - if (formatting == docpp::HTML::FORMATTING_PRETTY || formatting == docpp::HTML::FORMATTING_NEWLINE) { + if (formatting == docpp::HTML::Formatting::Pretty || formatting == docpp::HTML::Formatting::Newline) { ret += "\n"; } } } - if (formatting == docpp::HTML::FORMATTING_PRETTY) { + if (formatting == docpp::HTML::Formatting::Pretty) { for (size_type i{0}; i < tabcount; i++) { ret += "\t"; } @@ -667,6 +860,14 @@ std::string docpp::HTML::Section::get(const Formatting formatting, const int tab return std::move(ret); } +std::string docpp::HTML::Section::get_tag() const { + return this->tag; +} + +docpp::HTML::Properties docpp::HTML::Section::get_properties() const { + return this->properties; +} + void docpp::HTML::Section::swap(const size_type index1, const size_type index2) { if (this->elements.find(index1) != this->elements.end() && this->elements.find(index2) != this->elements.end()) { std::swap(this->elements[index1], this->elements[index2]); @@ -686,7 +887,7 @@ void docpp::HTML::Section::swap(const Section& section1, const Section& section2 } std::string docpp::HTML::Document::get(const Formatting formatting, const int tabc) const { - return this->doctype + (formatting == FORMATTING_PRETTY ? "\n" : formatting == FORMATTING_NEWLINE ? "\n" : "") + this->document.get(formatting, tabc); + return this->doctype + (formatting == Formatting::Pretty ? "\n" : formatting == Formatting::Newline ? "\n" : "") + this->document.get(formatting, tabc); } docpp::HTML::Section& docpp::HTML::Document::get_section() { @@ -701,17 +902,42 @@ void docpp::HTML::Document::set_doctype(const std::string& doctype) { this->doctype = doctype; } -docpp::HTML::Document docpp::HTML::Document::operator=(const docpp::HTML::Document& document) { +void docpp::HTML::Document::clear() { + this->doctype.clear(); + this->document.clear(); +} + +bool docpp::HTML::Document::empty() const { + return this->doctype.empty() && this->document.empty(); +} + +docpp::HTML::Document& docpp::HTML::Document::operator=(const docpp::HTML::Document& document) { this->set(document.get()); this->set_doctype(document.get_doctype()); return *this; } -docpp::HTML::Document docpp::HTML::Document::operator=(const docpp::HTML::Section& section) { +docpp::HTML::Document& docpp::HTML::Document::operator=(const docpp::HTML::Section& section) { this->set(section); return *this; } +bool docpp::HTML::Document::operator==(const docpp::HTML::Document& document) const { + return this->get() == document.get(); +} + +bool docpp::HTML::Document::operator==(const docpp::HTML::Section& section) const { + return this->document == section; +} + +bool docpp::HTML::Document::operator!=(const docpp::HTML::Document& document) const { + return this->doctype != document.get_doctype() || this->document != document.document; +} + +bool docpp::HTML::Document::operator!=(const docpp::HTML::Section& section) const { + return this->document != section; +} + std::string docpp::HTML::Document::get_doctype() const { return this->doctype; } @@ -744,26 +970,27 @@ void docpp::CSS::Property::set(const std::string& key, const std::string& value) this->property = std::make_pair(key, value); } -docpp::CSS::Property docpp::CSS::Property::operator=(const docpp::CSS::Property& property) { +docpp::CSS::Property& docpp::CSS::Property::operator=(const docpp::CSS::Property& property) { this->set(property.get()); return *this; } -docpp::CSS::Property docpp::CSS::Property::operator=(const std::pair& property) { +docpp::CSS::Property& docpp::CSS::Property::operator=(const std::pair& property) { this->set(property); return *this; } -docpp::CSS::Element docpp::CSS::Element::operator=(const docpp::CSS::Element& element) { +docpp::CSS::Element& docpp::CSS::Element::operator=(const docpp::CSS::Element& element) { this->set({element.get_tag(), element.get_properties()}); return *this; } -void docpp::CSS::Element::operator+=(const Property& property) { +docpp::CSS::Element& docpp::CSS::Element::operator+=(const Property& property) { this->push_back(property); + return *this; } -docpp::CSS::Property docpp::CSS::Element::operator[](const int& index) const { +docpp::CSS::Property docpp::CSS::Element::operator[](const size_type& index) const { return this->at(index); } @@ -856,7 +1083,7 @@ std::string docpp::CSS::Element::get(const Formatting formatting, const int tabc std::string ret{}; if (this->element.first.compare("")) { - if (formatting == docpp::CSS::FORMATTING_PRETTY) { + if (formatting == docpp::CSS::Formatting::Pretty) { for (size_type i{0}; i < tabc; i++) { ret += "\t"; } @@ -864,7 +1091,7 @@ std::string docpp::CSS::Element::get(const Formatting formatting, const int tabc ret += this->element.first + " {"; - if (formatting == docpp::CSS::FORMATTING_PRETTY || formatting == docpp::CSS::FORMATTING_NEWLINE) { + if (formatting == docpp::CSS::Formatting::Pretty || formatting == docpp::CSS::Formatting::Newline) { ret += "\n"; } @@ -872,7 +1099,7 @@ std::string docpp::CSS::Element::get(const Formatting formatting, const int tabc if (!it.get_key().compare("")) continue; if (!it.get_value().compare("")) continue; - if (formatting == docpp::CSS::FORMATTING_PRETTY) { + if (formatting == docpp::CSS::Formatting::Pretty) { for (size_type i{0}; i < tabc + 1; i++) { ret += "\t"; } @@ -880,12 +1107,12 @@ std::string docpp::CSS::Element::get(const Formatting formatting, const int tabc ret += it.get_key() + ": " + it.get_value() + ";"; - if (formatting == docpp::CSS::FORMATTING_PRETTY || formatting == docpp::CSS::FORMATTING_NEWLINE) { + if (formatting == docpp::CSS::Formatting::Pretty || formatting == docpp::CSS::Formatting::Newline) { ret += "\n"; } } - if (formatting == docpp::CSS::FORMATTING_PRETTY) { + if (formatting == docpp::CSS::Formatting::Pretty) { for (size_type i{0}; i < tabc; i++) { ret += "\t"; } @@ -893,7 +1120,7 @@ std::string docpp::CSS::Element::get(const Formatting formatting, const int tabc ret += "}"; - if (formatting == docpp::CSS::FORMATTING_PRETTY || formatting == docpp::CSS::FORMATTING_NEWLINE) { + if (formatting == docpp::CSS::Formatting::Pretty || formatting == docpp::CSS::Formatting::Newline) { ret += "\n"; } } @@ -937,13 +1164,14 @@ void docpp::CSS::Stylesheet::erase(const size_type index) { this->elements.erase(this->elements.begin() + index); } -docpp::CSS::Stylesheet docpp::CSS::Stylesheet::operator=(const docpp::CSS::Stylesheet& stylesheet) { +docpp::CSS::Stylesheet& docpp::CSS::Stylesheet::operator=(const docpp::CSS::Stylesheet& stylesheet) { this->set(stylesheet.get_elements()); return *this; } -void docpp::CSS::Stylesheet::operator+=(const Element& element) { +docpp::CSS::Stylesheet& docpp::CSS::Stylesheet::operator+=(const Element& element) { this->push_back(element); + return *this; } docpp::CSS::Element docpp::CSS::Stylesheet::operator[](const int& index) const { diff --git a/tests/test.cpp b/tests/test.cpp index 0bd6d43..a36c8b2 100644 --- a/tests/test.cpp +++ b/tests/test.cpp @@ -1,459 +1,1392 @@ #include +#include #include #include +inline namespace HTML { + void test_tag() { + static const std::unordered_map> expected_values{ + {docpp::HTML::Tag::Empty, {"", docpp::HTML::Type::Text}}, + {docpp::HTML::Tag::Empty_No_Formatting, {"", docpp::HTML::Type::Text_No_Formatting}}, + {docpp::HTML::Tag::Abbreviation, {"abbr", docpp::HTML::Type::Non_Self_Closing}}, + {docpp::HTML::Tag::Abbr, {"abbr", docpp::HTML::Type::Non_Self_Closing}}, + {docpp::HTML::Tag::Acronym, {"acronym", docpp::HTML::Type::Non_Self_Closing}}, + {docpp::HTML::Tag::Address, {"address", docpp::HTML::Type::Non_Self_Closing}}, + {docpp::HTML::Tag::Applet, {"applet", docpp::HTML::Type::Non_Self_Closing}}, + {docpp::HTML::Tag::Anchor, {"a", docpp::HTML::Type::Non_Self_Closing}}, + {docpp::HTML::Tag::A, {"a", docpp::HTML::Type::Non_Self_Closing}}, + {docpp::HTML::Tag::Article, {"article", docpp::HTML::Type::Non_Self_Closing}}, + {docpp::HTML::Tag::Area, {"area", docpp::HTML::Type::Non_Closed}}, + {docpp::HTML::Tag::Aside, {"aside", docpp::HTML::Type::Non_Self_Closing}}, + {docpp::HTML::Tag::Audio, {"audio", docpp::HTML::Type::Non_Self_Closing}}, + {docpp::HTML::Tag::Base, {"base", docpp::HTML::Type::Non_Closed}}, + {docpp::HTML::Tag::Basefont, {"basefont", docpp::HTML::Type::Non_Closed}}, + {docpp::HTML::Tag::Bdi, {"bdi", docpp::HTML::Type::Non_Self_Closing}}, + {docpp::HTML::Tag::Bdo, {"bdo", docpp::HTML::Type::Non_Self_Closing}}, + {docpp::HTML::Tag::Bgsound, {"bgsound", docpp::HTML::Type::Non_Self_Closing}}, + {docpp::HTML::Tag::Big, {"big", docpp::HTML::Type::Non_Self_Closing}}, + {docpp::HTML::Tag::Blockquote, {"blockquote", docpp::HTML::Type::Non_Self_Closing}}, + {docpp::HTML::Tag::Body, {"body", docpp::HTML::Type::Non_Self_Closing}}, + {docpp::HTML::Tag::B, {"b", docpp::HTML::Type::Non_Self_Closing}}, + {docpp::HTML::Tag::Bold, {"b", docpp::HTML::Type::Non_Self_Closing}}, + {docpp::HTML::Tag::Br, {"br", docpp::HTML::Type::Non_Closed}}, + {docpp::HTML::Tag::Break, {"br", docpp::HTML::Type::Non_Closed}}, + {docpp::HTML::Tag::Button, {"button", docpp::HTML::Type::Non_Closed}}, + {docpp::HTML::Tag::Caption, {"caption", docpp::HTML::Type::Non_Self_Closing}}, + {docpp::HTML::Tag::Canvas, {"canvas", docpp::HTML::Type::Non_Self_Closing}}, + {docpp::HTML::Tag::Center, {"center", docpp::HTML::Type::Non_Self_Closing}}, + {docpp::HTML::Tag::Cite, {"cite", docpp::HTML::Type::Non_Self_Closing}}, + {docpp::HTML::Tag::Code, {"code", docpp::HTML::Type::Non_Self_Closing}}, + {docpp::HTML::Tag::Colgroup, {"colgroup", docpp::HTML::Type::Non_Self_Closing}}, + {docpp::HTML::Tag::Column, {"col", docpp::HTML::Type::Non_Closed}}, + {docpp::HTML::Tag::Col, {"col", docpp::HTML::Type::Non_Closed}}, + {docpp::HTML::Tag::Data, {"data", docpp::HTML::Type::Non_Self_Closing}}, + {docpp::HTML::Tag::Datalist, {"datalist", docpp::HTML::Type::Non_Self_Closing}}, + {docpp::HTML::Tag::Dd, {"dd", docpp::HTML::Type::Non_Self_Closing}}, + {docpp::HTML::Tag::Dfn, {"dfn", docpp::HTML::Type::Non_Self_Closing}}, + {docpp::HTML::Tag::Define, {"dfn", docpp::HTML::Type::Non_Self_Closing}}, + {docpp::HTML::Tag::Delete, {"del", docpp::HTML::Type::Non_Self_Closing}}, + {docpp::HTML::Tag::Del, {"del", docpp::HTML::Type::Non_Self_Closing}}, + {docpp::HTML::Tag::Details, {"details", docpp::HTML::Type::Non_Self_Closing}}, + {docpp::HTML::Tag::Dialog, {"dialog", docpp::HTML::Type::Non_Self_Closing}}, + {docpp::HTML::Tag::Dir, {"dir", docpp::HTML::Type::Non_Self_Closing}}, + {docpp::HTML::Tag::Div, {"div", docpp::HTML::Type::Non_Self_Closing}}, + {docpp::HTML::Tag::Dl, {"dl", docpp::HTML::Type::Non_Self_Closing}}, + {docpp::HTML::Tag::Dt, {"dt", docpp::HTML::Type::Non_Self_Closing}}, + {docpp::HTML::Tag::Embed, {"embed", docpp::HTML::Type::Non_Closed}}, + {docpp::HTML::Tag::Fieldset, {"fieldset", docpp::HTML::Type::Non_Self_Closing}}, + {docpp::HTML::Tag::Figcaption, {"figcaption", docpp::HTML::Type::Non_Self_Closing}}, + {docpp::HTML::Tag::Figure, {"figure", docpp::HTML::Type::Non_Self_Closing}}, + {docpp::HTML::Tag::Font, {"font", docpp::HTML::Type::Non_Self_Closing}}, + {docpp::HTML::Tag::Footer, {"footer", docpp::HTML::Type::Non_Self_Closing}}, + {docpp::HTML::Tag::Form, {"form", docpp::HTML::Type::Non_Self_Closing}}, + {docpp::HTML::Tag::Frame, {"frame", docpp::HTML::Type::Self_Closing}}, + {docpp::HTML::Tag::Frameset, {"frameset", docpp::HTML::Type::Non_Self_Closing}}, + {docpp::HTML::Tag::Head, {"head", docpp::HTML::Type::Non_Self_Closing}}, + {docpp::HTML::Tag::Header, {"header", docpp::HTML::Type::Non_Self_Closing}}, + {docpp::HTML::Tag::H1, {"h1", docpp::HTML::Type::Non_Self_Closing}}, + {docpp::HTML::Tag::H2, {"h2", docpp::HTML::Type::Non_Self_Closing}}, + {docpp::HTML::Tag::H3, {"h3", docpp::HTML::Type::Non_Self_Closing}}, + {docpp::HTML::Tag::H4, {"h4", docpp::HTML::Type::Non_Self_Closing}}, + {docpp::HTML::Tag::H5, {"h5", docpp::HTML::Type::Non_Self_Closing}}, + {docpp::HTML::Tag::H6, {"h6", docpp::HTML::Type::Non_Self_Closing}}, + {docpp::HTML::Tag::Hr, {"hr", docpp::HTML::Type::Non_Closed}}, + {docpp::HTML::Tag::Hgroup, {"hgroup", docpp::HTML::Type::Non_Self_Closing}}, + {docpp::HTML::Tag::Html, {"html", docpp::HTML::Type::Non_Self_Closing}}, + {docpp::HTML::Tag::Iframe, {"iframe", docpp::HTML::Type::Non_Self_Closing}}, + {docpp::HTML::Tag::Image, {"img", docpp::HTML::Type::Non_Closed}}, + {docpp::HTML::Tag::Img, {"img", docpp::HTML::Type::Non_Closed}}, + {docpp::HTML::Tag::Input, {"input", docpp::HTML::Type::Self_Closing}}, + {docpp::HTML::Tag::Ins, {"ins", docpp::HTML::Type::Non_Self_Closing}}, + {docpp::HTML::Tag::Isindex, {"isindex", docpp::HTML::Type::Non_Closed}}, + {docpp::HTML::Tag::Italic, {"i", docpp::HTML::Type::Non_Self_Closing}}, + {docpp::HTML::Tag::I, {"i", docpp::HTML::Type::Non_Self_Closing}}, + {docpp::HTML::Tag::Kbd, {"kbd", docpp::HTML::Type::Non_Self_Closing}}, + {docpp::HTML::Tag::Keygen, {"keygen", docpp::HTML::Type::Non_Closed}}, + {docpp::HTML::Tag::Label, {"label", docpp::HTML::Type::Non_Self_Closing}}, + {docpp::HTML::Tag::Legend, {"legend", docpp::HTML::Type::Non_Self_Closing}}, + {docpp::HTML::Tag::List, {"li", docpp::HTML::Type::Non_Self_Closing}}, + {docpp::HTML::Tag::Li, {"li", docpp::HTML::Type::Non_Self_Closing}}, + {docpp::HTML::Tag::Link, {"link", docpp::HTML::Type::Non_Closed}}, + {docpp::HTML::Tag::Main, {"main", docpp::HTML::Type::Non_Self_Closing}}, + {docpp::HTML::Tag::Mark, {"mark", docpp::HTML::Type::Non_Self_Closing}}, + {docpp::HTML::Tag::Marquee, {"marquee", docpp::HTML::Type::Non_Self_Closing}}, + {docpp::HTML::Tag::Menuitem, {"menuitem", docpp::HTML::Type::Non_Self_Closing}}, + {docpp::HTML::Tag::Meta, {"meta", docpp::HTML::Type::Non_Closed}}, + {docpp::HTML::Tag::Meter, {"meter", docpp::HTML::Type::Non_Self_Closing}}, + {docpp::HTML::Tag::Nav, {"nav", docpp::HTML::Type::Non_Self_Closing}}, + {docpp::HTML::Tag::Nobreak, {"nobr", docpp::HTML::Type::Non_Self_Closing}}, + {docpp::HTML::Tag::Nobr, {"nobr", docpp::HTML::Type::Non_Self_Closing}}, + {docpp::HTML::Tag::Noembed, {"noembed", docpp::HTML::Type::Non_Self_Closing}}, + {docpp::HTML::Tag::Noscript, {"noscript", docpp::HTML::Type::Non_Self_Closing}}, + {docpp::HTML::Tag::Object, {"object", docpp::HTML::Type::Non_Self_Closing}}, + {docpp::HTML::Tag::Optgroup, {"optgroup", docpp::HTML::Type::Non_Self_Closing}}, + {docpp::HTML::Tag::Option, {"option", docpp::HTML::Type::Non_Self_Closing}}, + {docpp::HTML::Tag::Output, {"output", docpp::HTML::Type::Non_Self_Closing}}, + {docpp::HTML::Tag::Paragraph, {"p", docpp::HTML::Type::Non_Self_Closing}}, + {docpp::HTML::Tag::P, {"p", docpp::HTML::Type::Non_Self_Closing}}, + {docpp::HTML::Tag::Param, {"param", docpp::HTML::Type::Non_Closed}}, + {docpp::HTML::Tag::Phrase, {"phrase", docpp::HTML::Type::Non_Self_Closing}}, + {docpp::HTML::Tag::Pre, {"pre", docpp::HTML::Type::Non_Self_Closing}}, + {docpp::HTML::Tag::Progress, {"progress", docpp::HTML::Type::Non_Self_Closing}}, + {docpp::HTML::Tag::Quote, {"q", docpp::HTML::Type::Non_Self_Closing}}, + {docpp::HTML::Tag::Q, {"q", docpp::HTML::Type::Non_Self_Closing}}, + {docpp::HTML::Tag::Rp, {"rp", docpp::HTML::Type::Non_Self_Closing}}, + {docpp::HTML::Tag::Rt, {"rt", docpp::HTML::Type::Non_Self_Closing}}, + {docpp::HTML::Tag::Ruby, {"ruby", docpp::HTML::Type::Non_Self_Closing}}, + {docpp::HTML::Tag::Outdated, {"s", docpp::HTML::Type::Non_Self_Closing}}, + {docpp::HTML::Tag::S, {"s", docpp::HTML::Type::Non_Self_Closing}}, + {docpp::HTML::Tag::Sample, {"samp", docpp::HTML::Type::Non_Self_Closing}}, + {docpp::HTML::Tag::Samp, {"samp", docpp::HTML::Type::Non_Self_Closing}}, + {docpp::HTML::Tag::Script, {"script", docpp::HTML::Type::Non_Self_Closing}}, + {docpp::HTML::Tag::Section, {"section", docpp::HTML::Type::Non_Self_Closing}}, + {docpp::HTML::Tag::Small, {"small", docpp::HTML::Type::Non_Self_Closing}}, + {docpp::HTML::Tag::Source, {"source", docpp::HTML::Type::Non_Self_Closing}}, + {docpp::HTML::Tag::Spacer, {"spacer", docpp::HTML::Type::Non_Self_Closing}}, + {docpp::HTML::Tag::Span, {"span", docpp::HTML::Type::Non_Self_Closing}}, + {docpp::HTML::Tag::Strike, {"strike", docpp::HTML::Type::Non_Self_Closing}}, + {docpp::HTML::Tag::Strong, {"strong", docpp::HTML::Type::Non_Self_Closing}}, + {docpp::HTML::Tag::Style, {"style", docpp::HTML::Type::Non_Closed}}, + {docpp::HTML::Tag::Sub, {"sub", docpp::HTML::Type::Non_Self_Closing}}, + {docpp::HTML::Tag::Subscript, {"sub", docpp::HTML::Type::Non_Self_Closing}}, + {docpp::HTML::Tag::Sup, {"sup", docpp::HTML::Type::Non_Self_Closing}}, + {docpp::HTML::Tag::Superscript, {"sup", docpp::HTML::Type::Non_Self_Closing}}, + {docpp::HTML::Tag::Summary, {"summary", docpp::HTML::Type::Non_Self_Closing}}, + {docpp::HTML::Tag::Svg, {"svg", docpp::HTML::Type::Non_Closed}}, + {docpp::HTML::Tag::Table, {"table", docpp::HTML::Type::Non_Self_Closing}}, + {docpp::HTML::Tag::Tbody, {"tbody", docpp::HTML::Type::Non_Self_Closing}}, + {docpp::HTML::Tag::Td, {"td", docpp::HTML::Type::Non_Self_Closing}}, + {docpp::HTML::Tag::Template, {"template", docpp::HTML::Type::Non_Self_Closing}}, + {docpp::HTML::Tag::Tfoot, {"tfoot", docpp::HTML::Type::Non_Self_Closing}}, + {docpp::HTML::Tag::Th, {"th", docpp::HTML::Type::Non_Self_Closing}}, + {docpp::HTML::Tag::Tr, {"tr", docpp::HTML::Type::Non_Self_Closing}}, + {docpp::HTML::Tag::Thead, {"thead", docpp::HTML::Type::Non_Self_Closing}}, + {docpp::HTML::Tag::Time, {"time", docpp::HTML::Type::Non_Self_Closing}}, + {docpp::HTML::Tag::Title, {"title", docpp::HTML::Type::Non_Self_Closing}}, + {docpp::HTML::Tag::Track, {"track", docpp::HTML::Type::Non_Closed}}, + {docpp::HTML::Tag::Tt, {"tt", docpp::HTML::Type::Non_Self_Closing}}, + {docpp::HTML::Tag::Underline, {"u", docpp::HTML::Type::Non_Self_Closing}}, + {docpp::HTML::Tag::U, {"u", docpp::HTML::Type::Non_Self_Closing}}, + {docpp::HTML::Tag::Var, {"var", docpp::HTML::Type::Non_Self_Closing}}, + {docpp::HTML::Tag::Video, {"video", docpp::HTML::Type::Non_Self_Closing}}, + {docpp::HTML::Tag::Wbr, {"wbr", docpp::HTML::Type::Non_Closed}}, + {docpp::HTML::Tag::Xmp, {"xmp", docpp::HTML::Type::Non_Self_Closing}}, + }; + + for (const auto& it : expected_values) { + REQUIRE((docpp::HTML::resolve_tag(it.first).first == it.second.first && docpp::HTML::resolve_tag(it.first).second == it.second.second)); + } + } + + void test_exceptions() { + try { + throw docpp::out_of_range{}; + } catch (const docpp::out_of_range& e) { + REQUIRE(std::string(e.what()) == "Out of range"); + } + + try { + throw docpp::out_of_range{"Out of range, very very out of range"}; + } catch (const docpp::out_of_range& e) { + REQUIRE(std::string(e.what()) == "Out of range, very very out of range"); + } + + try { + throw docpp::invalid_argument{}; + } catch (const docpp::invalid_argument& e) { + REQUIRE(std::string(e.what()) == "Invalid argument"); + } + + try { + throw docpp::invalid_argument{"Invalid, very very invalid argument"}; + } catch (const docpp::invalid_argument& e) { + REQUIRE(std::string(e.what()) == "Invalid, very very invalid argument"); + } + } + + void test_npos_values() { + REQUIRE(docpp::HTML::Property::npos == -1); + REQUIRE(docpp::HTML::Properties::npos == -1); + REQUIRE(docpp::HTML::Element::npos == -1); + REQUIRE(docpp::HTML::Section::npos == -1); + REQUIRE(docpp::HTML::Document::npos == -1); + } + + void test_property() { + const auto test_get_and_set = []() { + using namespace docpp::HTML; + + Property property; + + REQUIRE(property.get().first == ""); + REQUIRE(property.get().second == ""); + REQUIRE(property.get_key() == ""); + REQUIRE(property.get_value() == ""); + + property.set({"key", "value"}); + + REQUIRE(property.get().first == "key"); + REQUIRE(property.get().second == "value"); + REQUIRE(property.get_key() == "key"); + REQUIRE(property.get_value() == "value"); + + property.set_key("new_key"); + property.set_value("new_value"); + + REQUIRE(property.get().first == "new_key"); + REQUIRE(property.get().second == "new_value"); + REQUIRE(property.get_key() == "new_key"); + REQUIRE(property.get_value() == "new_value"); + + property.set_key("newer_key"); + + REQUIRE(property.get().first == "newer_key"); + REQUIRE(property.get().second == "new_value"); + REQUIRE(property.get_key() == "newer_key"); + REQUIRE(property.get_value() == "new_value"); + + property.set_value("newer_value"); + + REQUIRE(property.get().first == "newer_key"); + REQUIRE(property.get().second == "newer_value"); + REQUIRE(property.get_key() == "newer_key"); + REQUIRE(property.get_value() == "newer_value"); + + REQUIRE(property.empty() == false); + + property.clear(); + + REQUIRE(property.empty() == true); + }; + + const auto test_copy_property = []() { + using namespace docpp::HTML; + + docpp::HTML::Property property; + + property.set({"key", "value"}); + }; + + test_get_and_set(); + test_copy_property(); + } + + void test_properties() { + const auto test_get_and_set = []() { + using namespace docpp::HTML; + + Properties properties; + + REQUIRE(properties.size() == 0); + + properties.push_back({"key1", "value1"}); + properties.push_back({"key2", "value2"}); + properties.push_back({"key3", "value3"}); + + REQUIRE(properties.size() == 3); + + std::size_t index = 0; + for (const auto& it : properties) { + if (index == 0) { + REQUIRE(it.get().first == "key1"); + REQUIRE(it.get().second == "value1"); + } else if (index == 1) { + REQUIRE(it.get().first == "key2"); + REQUIRE(it.get().second == "value2"); + } else if (index == 2) { + REQUIRE(it.get().first == "key3"); + REQUIRE(it.get().second == "value3"); + } + + ++index; + } + + REQUIRE(properties.at(0).get().first == "key1"); + REQUIRE(properties.at(0).get().second == "value1"); + REQUIRE(properties.at(1).get().first == "key2"); + REQUIRE(properties.at(1).get().second == "value2"); + REQUIRE(properties.at(2).get().first == "key3"); + REQUIRE(properties.at(2).get().second == "value3"); + + // should fail, out of range + try { + properties.at(3); + } catch (const out_of_range& e) { + REQUIRE(std::string(e.what()) == "Index out of range"); + } + + REQUIRE(properties[0] == properties.at(0)); + REQUIRE(properties[1] == properties.at(1)); + REQUIRE(properties[2] == properties.at(2)); + }; + + const auto test_copy_properties = []() { + using namespace docpp::HTML; + + Properties properties; + + properties += {"key1", "value1"}; + properties += {"key2", "value2"}; + properties += {"key3", "value3"}; + + Properties new_properties = properties; + + REQUIRE(properties == new_properties); + + properties.clear(); + }; + + const auto test_iterators = []() { + using namespace docpp::HTML; + + Properties properties = {{{"key1", "value1"}, {"key2", "value2"}, {"key3", "value3"}}}; + + std::size_t index{0}; + for (Properties::iterator it = properties.begin(); it != properties.end(); ++it) { + if (index == 0) { + REQUIRE(it->get().first == "key1"); + REQUIRE(it->get().second == "value1"); + } else if (index == 1) { + REQUIRE(it->get().first == "key2"); + REQUIRE(it->get().second == "value2"); + } else if (index == 2) { + REQUIRE(it->get().first == "key3"); + REQUIRE(it->get().second == "value3"); + } + + ++index; + } + + index = 0; + for (Properties::const_iterator it = properties.cbegin(); it != properties.cend(); ++it) { + if (index == 0) { + REQUIRE(it->get().first == "key1"); + REQUIRE(it->get().second == "value1"); + } else if (index == 1) { + REQUIRE(it->get().first == "key2"); + REQUIRE(it->get().second == "value2"); + } else if (index == 2) { + REQUIRE(it->get().first == "key3"); + REQUIRE(it->get().second == "value3"); + } + + ++index; + } + + index = 0; + for (Properties::reverse_iterator it = properties.rbegin(); it != properties.rend(); ++it) { + if (index == 0) { + REQUIRE(it->get().first == "key3"); + REQUIRE(it->get().second == "value3"); + } else if (index == 1) { + REQUIRE(it->get().first == "key2"); + REQUIRE(it->get().second == "value2"); + } else if (index == 2) { + REQUIRE(it->get().first == "key1"); + REQUIRE(it->get().second == "value1"); + } + + ++index; + } + + index = 0; + for (Properties::const_reverse_iterator it = properties.crbegin(); it != properties.crend(); ++it) { + if (index == 0) { + REQUIRE(it->get().first == "key3"); + REQUIRE(it->get().second == "value3"); + } else if (index == 1) { + REQUIRE(it->get().first == "key2"); + REQUIRE(it->get().second == "value2"); + } else if (index == 2) { + REQUIRE(it->get().first == "key1"); + REQUIRE(it->get().second == "value1"); + } + + ++index; + } + + index = 0; + for (const auto& it : properties) { + if (index == 0) { + REQUIRE(it.get().first == "key1"); + REQUIRE(it.get().second == "value1"); + } else if (index == 1) { + REQUIRE(it.get().first == "key2"); + REQUIRE(it.get().second == "value2"); + } else if (index == 2) { + REQUIRE(it.get().first == "key3"); + REQUIRE(it.get().second == "value3"); + } + + ++index; + } + }; + + const auto test_find = []() { + using namespace docpp::HTML; + + Properties properties = {{{"key1", "value1"}, {"key2", "value2"}, {"key3", "value3"}}}; + + REQUIRE(properties.find(Property("key1", "value1")) == 0); + REQUIRE(properties.find(Property("key2", "value2")) == 1); + REQUIRE(properties.find(Property("key3", "value3")) == 2); + REQUIRE(properties.find(Property("key4", "value4")) == Properties::npos); + + REQUIRE(properties.find("key1") == 0); + REQUIRE(properties.find("key2") == 1); + REQUIRE(properties.find("key3") == 2); + REQUIRE(properties.find("key4") == Properties::npos); + + REQUIRE(properties.find("value1") == 0); + REQUIRE(properties.find("value2") == 1); + REQUIRE(properties.find("value3") == 2); + REQUIRE(properties.find("value4") == Properties::npos); + + std::size_t pos = properties.find("key1"); + + REQUIRE(properties[pos].get().first == "key1"); + REQUIRE(properties.at(pos).get().first == "key1"); + REQUIRE(properties[pos].get().second == "value1"); + REQUIRE(properties.at(pos).get().second == "value1"); + + pos = properties.find("key2"); + + REQUIRE(properties[pos].get().first == "key2"); + REQUIRE(properties.at(pos).get().first == "key2"); + REQUIRE(properties[pos].get().second == "value2"); + REQUIRE(properties.at(pos).get().second == "value2"); + + pos = properties.find("key3"); + + REQUIRE(properties[pos].get().first == "key3"); + REQUIRE(properties.at(pos).get().first == "key3"); + REQUIRE(properties[pos].get().second == "value3"); + REQUIRE(properties.at(pos).get().second == "value3"); + + pos = properties.find("key4"); + + REQUIRE(pos == Properties::npos); + + try { + properties.at(pos); + } catch (const out_of_range& e) { + REQUIRE(std::string(e.what()) == "Index out of range"); + } + }; + + const auto test_insert = []() { + using namespace docpp::HTML; + + Properties properties = {{{"key1", "value1"}, {"key2", "value2"}, {"key3", "value3"}}}; + + std::size_t pos = properties.find("key1"); + Property found_property = properties[pos]; + + std::size_t pos2 = properties.find("value2"); + properties.insert(pos2, found_property); + + REQUIRE(properties.at(pos2) == found_property); + REQUIRE(properties.get_properties().at(pos2) == found_property); + REQUIRE(properties.get_properties().at(pos2).get().first == "key1"); + }; + + const auto test_swap = []() { + using namespace docpp::HTML; + + Properties properties = {{{"key1", "value1"}, {"key2", "value2"}, {"key3", "value3"}}}; + + std::size_t pos1 = properties.find("key1"); + Property property1 = properties[pos1]; + + std::size_t pos2 = properties.find("key2"); + Property property2 = properties[pos2]; + + properties.swap(pos1, pos2); + + REQUIRE(properties[pos1] == property2); + REQUIRE(properties[pos2] == property1); + + properties.swap(property1, property2); + + REQUIRE(properties[pos1] == property1); + REQUIRE(properties[pos2] == property2); + }; + + const auto test_front_and_back = []() { + using namespace docpp::HTML; + + Properties properties = {{{"key1", "value1"}, {"key2", "value2"}, {"key3", "value3"}}}; + + REQUIRE(properties.front().get().first == "key1"); + REQUIRE(properties.front().get().second == "value1"); + + REQUIRE(properties.back().get().first == "key3"); + REQUIRE(properties.back().get().second == "value3"); + }; + + const auto test_size_empty_and_clear = []() { + using namespace docpp::HTML; + + Properties properties = {{{"key1", "value1"}, {"key2", "value2"}, {"key3", "value3"}}}; + + REQUIRE(properties.size() == 3); + REQUIRE(properties.empty() == false); + + properties.clear(); + + REQUIRE(properties.size() == 0); + REQUIRE(properties.empty() == true); + }; + + const auto test_push_front_and_back = []() { + using namespace docpp::HTML; + + Properties properties; + + properties.push_front({"key1", "value1"}); + properties.push_back({"key2", "value2"}); + + REQUIRE(properties.front().get().first == "key1"); + REQUIRE(properties.front().get().second == "value1"); + + REQUIRE(properties.back().get().first == "key2"); + REQUIRE(properties.back().get().second == "value2"); + }; + + const auto test_constructors = []() { + using namespace docpp::HTML; + + Properties properties = {{{"key1", "value1"}, {"key2", "value2"}, {"key3", "value3"}}}; + + Properties new_properties = properties; + + REQUIRE(properties == new_properties); + + Properties new_properties2 = properties.get_properties(); + + REQUIRE(properties == new_properties2); + + Property property1{"key1", "value1"}; + + Properties new_properties3 = {property1}; + + REQUIRE(new_properties3.size() == 1); + }; + + test_get_and_set(); + test_copy_properties(); + test_iterators(); + test_find(); + test_insert(); + test_swap(); + test_front_and_back(); + test_size_empty_and_clear(); + test_push_front_and_back(); + test_constructors(); + } + + void test_element() { + const auto test_get_and_set = []() { + using namespace docpp::HTML; + + Element element; + + element.set("my_element", {}, {}, docpp::HTML::Type::Non_Self_Closing); + + REQUIRE(element.get_tag() == "my_element"); + REQUIRE(element.get_data() == ""); + REQUIRE(element.get_properties() == Properties{}); + REQUIRE(element.get_type() == docpp::HTML::Type::Non_Self_Closing); + + element.set_tag("new_element"); + element.set_data("new_data"); + element.set_properties(Properties(std::vector{{"key", "value"}, {"key2", "value2"}})); + element.set_type(docpp::HTML::Type::Non_Closed); + + REQUIRE(element.get_tag() == "new_element"); + REQUIRE(element.get_data() == "new_data"); + REQUIRE(element.get_properties().at(0).get().first == "key"); + REQUIRE(element.get_properties().at(0).get().second == "value"); + REQUIRE(element.get_properties().at(1).get().first == "key2"); + REQUIRE(element.get_properties().at(1).get().second == "value2"); + REQUIRE(element.get_type() == docpp::HTML::Type::Non_Closed); + }; + + const auto test_copy_element = []() { + using namespace docpp::HTML; + + Element element; + + element.set("my_element", {}, {}, docpp::HTML::Type::Non_Self_Closing); + + Element new_element = element; + + REQUIRE(element == new_element); + REQUIRE(element.empty() == false); + + element.clear(); + + REQUIRE(element.empty() == true); + + element = std::move(new_element); + + REQUIRE(element.empty() == false); + }; + + const auto test_operators = []() { + using namespace docpp::HTML; + + Element element1; + Element element2; + + element1.set("my_element", {}, {}, docpp::HTML::Type::Non_Self_Closing); + element2.set("my_element", {}, {}, docpp::HTML::Type::Non_Self_Closing); + + REQUIRE(element1 == element2); + + element2.set("new_element", {}, {}, docpp::HTML::Type::Non_Self_Closing); + + REQUIRE(element1 != element2); + + element2 = element1; + + REQUIRE(element1 == element2); + }; + + const auto test_constructors = []() { + using namespace docpp::HTML; + + Element elem{}; + + REQUIRE(elem.get_tag() == ""); + REQUIRE(elem.get_data() == ""); + REQUIRE(elem.get_properties() == Properties{}); + REQUIRE(elem.get_type() == docpp::HTML::Type::Non_Self_Closing); + + Element elem2("my_element", {}, "data", docpp::HTML::Type::Non_Closed); + + REQUIRE(elem2.get_tag() == "my_element"); + REQUIRE(elem2.get_data() == "data"); + REQUIRE(elem2.get_properties() == Properties{}); + REQUIRE(elem2.get_type() == docpp::HTML::Type::Non_Closed); + + Element elem3(docpp::HTML::Tag::H1, {}, "data"); + + REQUIRE(elem3.get_tag() == "h1"); + REQUIRE(elem3.get_data() == "data"); + REQUIRE(elem3.get_properties() == Properties{}); + REQUIRE(elem3.get_type() == docpp::HTML::Type::Non_Self_Closing); + }; + + const auto test_string_get = []() { + using namespace docpp::HTML; + + Element element(docpp::HTML::Tag::H1, {}, "data"); + + REQUIRE(element.get() == "

    data

    "); + REQUIRE(element.get() == "

    data

    "); + REQUIRE(element.get(docpp::HTML::Formatting::None) == "

    data

    "); + REQUIRE(element.get(docpp::HTML::Formatting::Pretty) == "

    data

    \n"); + REQUIRE(element.get(docpp::HTML::Formatting::Newline) == "

    data

    \n"); + }; + + test_get_and_set(); + test_copy_element(); + test_operators(); + test_constructors(); + test_string_get(); + } + + void test_section() { + const auto test_get_and_set = []() { + using namespace docpp::HTML; + + Section section; + + section.set_tag("my_section"); + + REQUIRE(section.get_tag() == "my_section"); + REQUIRE(section.get_sections().empty()); + REQUIRE(section.get_elements().empty()); + REQUIRE(section.get_properties().empty()); + + section.set_tag("new_section"); + section.set_properties({{Property{"key", "value"}, Property{"key2", "value2"}}}); + + REQUIRE(section.get_tag() == "new_section"); + REQUIRE(section.get_properties().at(0).get().first == "key"); + REQUIRE(section.get_properties().at(0).get().second == "value"); + REQUIRE(section.get_properties().at(1).get().first == "key2"); + REQUIRE(section.get_properties().at(1).get().second == "value2"); + + section.set("new_section", {{Property{"key", "value"}, Property{"key2", "value2"}}}); + + REQUIRE(section.get_tag() == "new_section"); + REQUIRE(section.get_properties().at(0).get().first == "key"); + REQUIRE(section.get_properties().at(0).get().second == "value"); + REQUIRE(section.get_properties().at(1).get().first == "key2"); + REQUIRE(section.get_properties().at(1).get().second == "value2"); + + section.set_properties({{Property{"key3", "value3"}, Property{"key4", "value4"}}}); + + REQUIRE(section.get_properties().at(0).get().first == "key3"); + REQUIRE(section.get_properties().at(0).get().second == "value3"); + REQUIRE(section.get_properties().at(1).get().first == "key4"); + REQUIRE(section.get_properties().at(1).get().second == "value4"); + }; + + const auto test_copy_section = []() { + using namespace docpp::HTML; + + Section section; + + section.set("my_section", {{Property{"key", "value"}, Property{"key2", "value2"}}}); + + Section new_section = section; + + REQUIRE(section == new_section); + REQUIRE(section.empty() == true); // should still be empty, because the + // section itself is not an element, it's more of a container element + // in the same vein as a
    element + + section.push_back(Element{}); + + REQUIRE(section.empty() == false); + REQUIRE(section != new_section); + + section.clear(); + + REQUIRE(section.empty() == true); + + section = std::move(new_section); + + REQUIRE(section.empty() == true); + }; + + const auto test_operators = []() { + using namespace docpp::HTML; + + Section section1; + Section section2; + + section1.set("my_section", {{Property{"key", "value"}, Property{"key2", "value2"}}}); + section2.set("my_section", {{Property{"key", "value"}, Property{"key2", "value2"}}}); + + REQUIRE(section1 == section2); + + section2.set("new_section", {{Property{"key", "value"}, Property{"key2", "value2"}}}); + + REQUIRE(section1 != section2); + + section2 = section1; + + REQUIRE(section1 == section2); + }; + + const auto test_constructors = []() { + using namespace docpp::HTML; + + Section section{}; + + REQUIRE(section.get_tag() == ""); + REQUIRE(section.get_sections().empty()); + REQUIRE(section.get_elements().empty()); + REQUIRE(section.get_properties().empty()); + + Section section2("my_section", {{Property{"key", "value"}, Property{"key2", "value2"}}}); + + REQUIRE(section2.get_tag() == "my_section"); + REQUIRE(section2.get_properties().at(0).get().first == "key"); + REQUIRE(section2.get_properties().at(0).get().second == "value"); + REQUIRE(section2.get_properties().at(1).get().first == "key2"); + REQUIRE(section2.get_properties().at(1).get().second == "value2"); + + Section section3(docpp::HTML::Tag::H1, {{Property{"key", "value"}, Property{"key2", "value2"}}}); + + REQUIRE(section3.get_tag() == "h1"); + REQUIRE(section3.get_properties().at(0).get().first == "key"); + REQUIRE(section3.get_properties().at(0).get().second == "value"); + REQUIRE(section3.get_properties().at(1).get().first == "key2"); + REQUIRE(section3.get_properties().at(1).get().second == "value2"); + }; + + const auto test_iterators = []() { + using namespace docpp::HTML; + + Section section{docpp::HTML::Tag::Html, {}}; + + section.push_back(Element{docpp::HTML::Tag::H2, {}}); + section.push_back(Element{docpp::HTML::Tag::H3, {}}); + section.push_back(Element{docpp::HTML::Tag::H4, {}}); + section.push_back(Element{docpp::HTML::Tag::H5, {}}); + section.push_back(Element{docpp::HTML::Tag::H6, {}}); + + Element element; + + std::size_t index{0}; + for (Section::iterator it = section.begin(); it != section.end(); ++it) { + Element element = *it; + + if (index == 0) { + REQUIRE(element.get_tag() == "h2"); + REQUIRE(element.get_type() == docpp::HTML::Type::Non_Self_Closing); + REQUIRE(element.get() == "

    "); + } else if (index == 1) { + REQUIRE(element.get_tag() == "h3"); + REQUIRE(element.get_type() == docpp::HTML::Type::Non_Self_Closing); + REQUIRE(element.get() == "

    "); + } else if (index == 2) { + REQUIRE(element.get_tag() == "h4"); + REQUIRE(element.get_type() == docpp::HTML::Type::Non_Self_Closing); + REQUIRE(element.get() == "

    "); + } else if (index == 3) { + REQUIRE(element.get_tag() == "h5"); + REQUIRE(element.get_type() == docpp::HTML::Type::Non_Self_Closing); + REQUIRE(element.get() == "
    "); + } else if (index == 4) { + REQUIRE(element.get_tag() == "h6"); + REQUIRE(element.get_type() == docpp::HTML::Type::Non_Self_Closing); + REQUIRE(element.get() == "
    "); + } + + ++index; + } + + index = 0; + for (Section::const_iterator it = section.cbegin(); it != section.cend(); ++it) { + Element element = *it; + + if (index == 0) { + REQUIRE(element.get_tag() == "h2"); + REQUIRE(element.get_type() == docpp::HTML::Type::Non_Self_Closing); + REQUIRE(element.get() == "

    "); + } else if (index == 1) { + REQUIRE(element.get_tag() == "h3"); + REQUIRE(element.get_type() == docpp::HTML::Type::Non_Self_Closing); + REQUIRE(element.get() == "

    "); + } else if (index == 2) { + REQUIRE(element.get_tag() == "h4"); + REQUIRE(element.get_type() == docpp::HTML::Type::Non_Self_Closing); + REQUIRE(element.get() == "

    "); + } else if (index == 3) { + REQUIRE(element.get_tag() == "h5"); + REQUIRE(element.get_type() == docpp::HTML::Type::Non_Self_Closing); + REQUIRE(element.get() == "
    "); + } else if (index == 4) { + REQUIRE(element.get_tag() == "h6"); + REQUIRE(element.get_type() == docpp::HTML::Type::Non_Self_Closing); + REQUIRE(element.get() == "
    "); + } + + ++index; + } + + index = 0; + for (Section::reverse_iterator it = section.rbegin(); it != section.rend(); ++it) { + Element element = *it; + + if (index == 0) { + REQUIRE(element.get_tag() == "h6"); + REQUIRE(element.get_type() == docpp::HTML::Type::Non_Self_Closing); + REQUIRE(element.get() == "
    "); + } else if (index == 1) { + REQUIRE(element.get_tag() == "h5"); + REQUIRE(element.get_type() == docpp::HTML::Type::Non_Self_Closing); + REQUIRE(element.get() == "
    "); + } else if (index == 2) { + REQUIRE(element.get_tag() == "h4"); + REQUIRE(element.get_type() == docpp::HTML::Type::Non_Self_Closing); + REQUIRE(element.get() == "

    "); + } else if (index == 3) { + REQUIRE(element.get_tag() == "h3"); + REQUIRE(element.get_type() == docpp::HTML::Type::Non_Self_Closing); + REQUIRE(element.get() == "

    "); + } else if (index == 4) { + REQUIRE(element.get_tag() == "h2"); + REQUIRE(element.get_type() == docpp::HTML::Type::Non_Self_Closing); + REQUIRE(element.get() == "

    "); + } + + ++index; + } + + index = 0; + for (Section::const_reverse_iterator it = section.crbegin(); it != section.crend(); ++it) { + Element element = *it; + + if (index == 0) { + REQUIRE(element.get_tag() == "h6"); + REQUIRE(element.get_type() == docpp::HTML::Type::Non_Self_Closing); + REQUIRE(element.get() == "
    "); + } else if (index == 1) { + REQUIRE(element.get_tag() == "h5"); + REQUIRE(element.get_type() == docpp::HTML::Type::Non_Self_Closing); + REQUIRE(element.get() == "
    "); + } else if (index == 2) { + REQUIRE(element.get_tag() == "h4"); + REQUIRE(element.get_type() == docpp::HTML::Type::Non_Self_Closing); + REQUIRE(element.get() == "

    "); + } else if (index == 3) { + REQUIRE(element.get_tag() == "h3"); + REQUIRE(element.get_type() == docpp::HTML::Type::Non_Self_Closing); + REQUIRE(element.get() == "

    "); + } else if (index == 4) { + REQUIRE(element.get_tag() == "h2"); + REQUIRE(element.get_type() == docpp::HTML::Type::Non_Self_Closing); + REQUIRE(element.get() == "

    "); + } + + ++index; + } + }; + + const auto test_find = []() { + using namespace docpp::HTML; + + Section section{docpp::HTML::Tag::Html, {}}; + + section.push_back(Element{docpp::HTML::Tag::H2, {}, "data"}); + section.push_back(Element{docpp::HTML::Tag::H3, {}, "data"}); + section.push_back(Element{docpp::HTML::Tag::H4, {}, "data"}); + section.push_back(Element{docpp::HTML::Tag::H5, {}, "data"}); + section.push_back(Element{docpp::HTML::Tag::H6, {}, "data"}); + + REQUIRE(section.find(Element{docpp::HTML::Tag::H2, {}, "data"}) == 0); + REQUIRE(section.find(Element{docpp::HTML::Tag::H3, {}, "data"}) == 1); + REQUIRE(section.find(Element{docpp::HTML::Tag::H4, {}, "data"}) == 2); + REQUIRE(section.find(Element{docpp::HTML::Tag::H5, {}, "data"}) == 3); + REQUIRE(section.find(Element{docpp::HTML::Tag::H6, {}, "data"}) == 4); + REQUIRE(section.find(Element{docpp::HTML::Tag::H1, {}, "data"}) == Section::npos); + + REQUIRE(section.find("h2") == 0); + REQUIRE(section.find("h3") == 1); + REQUIRE(section.find("h4") == 2); + REQUIRE(section.find("h5") == 3); + REQUIRE(section.find("h6") == 4); + + REQUIRE(section.find("

    data

    ") == 0); + REQUIRE(section.find("

    data

    ") == 1); + REQUIRE(section.find("

    data

    ") == 2); + REQUIRE(section.find("
    data
    ") == 3); + REQUIRE(section.find("
    data
    ") == 4); + REQUIRE(section.find("data") == 0); + REQUIRE(section.find("h1") == Section::npos); + REQUIRE(section.find("docpp sucks") == Section::npos); + }; + + const auto test_insert = []() { + using namespace docpp::HTML; + + Section section{docpp::HTML::Tag::Html, {}}; + + section.push_back(Element{docpp::HTML::Tag::H2, {}, "data"}); + section.push_back(Element{docpp::HTML::Tag::H3, {}, "data"}); + section.push_back(Element{docpp::HTML::Tag::H4, {}, "data"}); + section.push_back(Element{docpp::HTML::Tag::H5, {}, "data"}); + section.push_back(Element{docpp::HTML::Tag::H6, {}, "data"}); + + std::size_t pos = section.find("h2"); + + Element element = section[pos]; + + std::size_t pos2 = section.find("h4"); + + section.insert(pos2, element); + + REQUIRE(section.at(pos2) == element); + REQUIRE(section.get_elements().at(pos2) == element); + REQUIRE(section.get_elements().at(pos2).get_tag() == "h2"); + }; + + const auto test_swap = []() { + using namespace docpp::HTML; + + Section section{docpp::HTML::Tag::Html, {}}; + + section.push_back(Element{docpp::HTML::Tag::H2, {}, "data"}); + section.push_back(Element{docpp::HTML::Tag::H3, {}, "data"}); + section.push_back(Element{docpp::HTML::Tag::H4, {}, "data"}); + section.push_back(Element{docpp::HTML::Tag::H5, {}, "data"}); + section.push_back(Element{docpp::HTML::Tag::H6, {}, "data"}); + + std::size_t pos1 = section.find("h2"); + Element element1 = section[pos1]; + + std::size_t pos2 = section.find("h4"); + Element element2 = section[pos2]; + + section.swap(pos1, pos2); + + REQUIRE(section[pos1] == element2); + REQUIRE(section[pos2] == element1); + + section.swap(element1, element2); + + REQUIRE(section[pos1] == element1); + REQUIRE(section[pos2] == element2); + }; + + const auto test_front_and_back = []() { + using namespace docpp::HTML; + + Section section{docpp::HTML::Tag::Html, {}}; + + section.push_back(Element{docpp::HTML::Tag::H2, {}, "data"}); + section.push_back(Element{docpp::HTML::Tag::H3, {}, "data"}); + section.push_back(Element{docpp::HTML::Tag::H4, {}, "data"}); + section.push_back(Element{docpp::HTML::Tag::H5, {}, "data"}); + section.push_back(Element{docpp::HTML::Tag::H6, {}, "data"}); + + REQUIRE(section.front().get_tag() == "h2"); + REQUIRE(section.front().get_data() == "data"); + + REQUIRE(section.back().get_tag() == "h6"); + REQUIRE(section.back().get_data() == "data"); + }; + + const auto test_size_empty_and_clear = []() { + using namespace docpp::HTML; + + Section section{docpp::HTML::Tag::Html, {}}; + + section.push_back(Element{docpp::HTML::Tag::H2, {}, "data"}); + section.push_back(Element{docpp::HTML::Tag::H3, {}, "data"}); + section.push_back(Element{docpp::HTML::Tag::H4, {}, "data"}); + section.push_back(Element{docpp::HTML::Tag::H5, {}, "data"}); + section.push_back(Element{docpp::HTML::Tag::H6, {}, "data"}); + + REQUIRE(section.size() == 5); + REQUIRE(section.empty() == false); + + section.clear(); + + REQUIRE(section.size() == 0); + REQUIRE(section.empty() == true); + }; + + const auto test_push_front_and_back = []() { + using namespace docpp::HTML; + + Section section{docpp::HTML::Tag::Html, {}}; + + section.push_front(Element{docpp::HTML::Tag::H2, {}, "data"}); + section.push_back(Element{docpp::HTML::Tag::H3, {}, "data"}); + + REQUIRE(section.front().get_tag() == "h2"); + REQUIRE(section.front().get_data() == "data"); + + REQUIRE(section.back().get_tag() == "h3"); + REQUIRE(section.back().get_data() == "data"); + }; + + const auto test_string_get = []() { + using namespace docpp::HTML; + + Section section{docpp::HTML::Tag::Html, {}}; + + section.push_back(Element{docpp::HTML::Tag::H2, {}, "data"}); + section.push_back(Element{docpp::HTML::Tag::H3, {}, "data"}); + section.push_back(Element{docpp::HTML::Tag::H4, {}, "data"}); + section.push_back(Element{docpp::HTML::Tag::H5, {}, "data"}); + + const std::string expected_1 = "

    data

    data

    data

    data
    "; + const std::string expected_2 = "\n

    data

    \n

    data

    \n

    data

    \n
    data
    \n"; + const std::string expected_3 = "\n\t

    data

    \n\t

    data

    \n\t

    data

    \n\t
    data
    \n"; + + REQUIRE(section.get() == expected_1); + REQUIRE(section.get() == expected_1); + REQUIRE(section.get(docpp::HTML::Formatting::None) == expected_1); + REQUIRE(section.get(docpp::HTML::Formatting::Newline) == expected_2); + REQUIRE(section.get(docpp::HTML::Formatting::Pretty) == expected_3); + }; + + const auto test_handle_elements = []() { + using namespace docpp::HTML; + + Section section{docpp::HTML::Tag::Html, {}}; + + section.push_back(Element{docpp::HTML::Tag::H2, {}, "data"}); + section.push_back(Element{docpp::HTML::Tag::H3, {}, "data"}); + section.push_back(Element{docpp::HTML::Tag::H4, {}, "data"}); + section.push_back(Element{docpp::HTML::Tag::H5, {}, "data"}); + + Element retrieved_elem1 = section.get_elements().at(0); + Element retrieved_elem2 = section.get_elements().at(1); + Element retrieved_elem3 = section.get_elements().at(2); + Element retrieved_elem4 = section.get_elements().at(3); + + REQUIRE(retrieved_elem1.get_tag() == "h2"); + REQUIRE(retrieved_elem1.get_data() == "data"); + REQUIRE(retrieved_elem2.get_tag() == "h3"); + REQUIRE(retrieved_elem2.get_data() == "data"); + REQUIRE(retrieved_elem3.get_tag() == "h4"); + REQUIRE(retrieved_elem3.get_data() == "data"); + REQUIRE(retrieved_elem4.get_tag() == "h5"); + REQUIRE(retrieved_elem4.get_data() == "data"); + }; + + const auto test_handle_sections = []() { + using namespace docpp::HTML; + + Section section{docpp::HTML::Tag::Html, {}}; + + section.push_back(Element{docpp::HTML::Tag::H2, {}, "data"}); + section.push_back(Element{docpp::HTML::Tag::H3, {}, "data"}); + section.push_back(Element{docpp::HTML::Tag::H4, {}, "data"}); + + Section new_section = section; + + new_section.set_tag(docpp::HTML::Tag::Div); + section.push_back(new_section); + + REQUIRE(section.get() == "

    data

    data

    data

    data

    data

    data

    "); + + Section retrieved_section = section.get_sections().at(0); + + REQUIRE(retrieved_section.get_tag() == "div"); + + Element retrieved_elem1 = retrieved_section.get_elements().at(0); + Element retrieved_elem2 = retrieved_section.get_elements().at(1); + Element retrieved_elem3 = retrieved_section.get_elements().at(2); + + REQUIRE(retrieved_elem1.get_tag() == "h2"); + REQUIRE(retrieved_elem1.get_data() == "data"); + REQUIRE(retrieved_elem2.get_tag() == "h3"); + REQUIRE(retrieved_elem2.get_data() == "data"); + REQUIRE(retrieved_elem3.get_tag() == "h4"); + REQUIRE(retrieved_elem3.get_data() == "data"); + }; + + const auto the_test_to_end_all_tests = []() { + using namespace docpp::HTML; + + Section base_section{docpp::HTML::Tag::Html, {}}; + + base_section.push_back(Element{docpp::HTML::Tag::H2, {}, "data"}); + base_section.push_back(Element{docpp::HTML::Tag::H3, {}, "data"}); + base_section.push_back(Element{docpp::HTML::Tag::H4, {}, "data"}); + base_section.push_back(Element{docpp::HTML::Tag::H5, {}, "data"}); + + REQUIRE(base_section.get() == "

    data

    data

    data

    data
    "); + + Section section{docpp::HTML::Tag::Html, {}}; + Section section_plus_plus{docpp::HTML::Tag::Html, {}}; + + // just... why? because i can, that's why + for (std::size_t i = 0; i < 10; ++i) { + Section _section{docpp::HTML::Tag::Div, {}}; + + _section.push_back(Element{docpp::HTML::Tag::P, {}, "Data " + std::to_string(i)}); + + section_plus_plus += _section; + section_plus_plus += section_plus_plus; + + REQUIRE(section_plus_plus.size() == (i + 1) * 2); + } + }; + + test_get_and_set(); + test_copy_section(); + test_operators(); + test_constructors(); + test_iterators(); + test_find(); + test_insert(); + test_swap(); + test_front_and_back(); + test_size_empty_and_clear(); + test_push_front_and_back(); + test_string_get(); + test_constructors(); + test_handle_elements(); + test_handle_sections(); + the_test_to_end_all_tests(); + } + + void test_document() { + const auto test_get_and_set = []() { + using namespace docpp::HTML; + + Document document; + + document.set(Section { + docpp::HTML::Tag::Html, {}, + { + Element{docpp::HTML::Tag::H1, {}, "data1"}, + Element{docpp::HTML::Tag::H2, {}, "data2"}, + Element{docpp::HTML::Tag::H3, {}, "data3"}, + Element{docpp::HTML::Tag::H4, {}, "data4"}, + Element{docpp::HTML::Tag::H5, {}, "data5"}, + Element{docpp::HTML::Tag::H6, {}, "data6"} + } + }); + + REQUIRE(document.get() == "

    data1

    data2

    data3

    data4

    data5
    data6
    "); + REQUIRE(document.get() == "

    data1

    data2

    data3

    data4

    data5
    data6
    "); + REQUIRE(document.get(docpp::HTML::Formatting::None) == "

    data1

    data2

    data3

    data4

    data5
    data6
    "); + REQUIRE(document.get(docpp::HTML::Formatting::Pretty) == "\n\n\t

    data1

    \n\t

    data2

    \n\t

    data3

    \n\t

    data4

    \n\t
    data5
    \n\t
    data6
    \n"); + REQUIRE(document.get(docpp::HTML::Formatting::Newline) == "\n\n

    data1

    \n

    data2

    \n

    data3

    \n

    data4

    \n
    data5
    \n
    data6
    \n"); + + REQUIRE(document.get_doctype() == ""); + REQUIRE(document.get_section() == Section { + docpp::HTML::Tag::Html, {}, + { + Element{docpp::HTML::Tag::H1, {}, "data1"}, + Element{docpp::HTML::Tag::H2, {}, "data2"}, + Element{docpp::HTML::Tag::H3, {}, "data3"}, + Element{docpp::HTML::Tag::H4, {}, "data4"}, + Element{docpp::HTML::Tag::H5, {}, "data5"}, + Element{docpp::HTML::Tag::H6, {}, "data6"} + } + }); + + REQUIRE(document.get_section().get() == "

    data1

    data2

    data3

    data4

    data5
    data6
    "); + + document.set_doctype(""); + + REQUIRE(document.get_doctype() == ""); + REQUIRE(document.get() == "

    data1

    data2

    data3

    data4

    data5
    data6
    "); + }; + + const auto test_copy_document = []() { + using namespace docpp::HTML; + + Document document; + + document.set(Section { + docpp::HTML::Tag::Html, {}, + { + Element{docpp::HTML::Tag::H1, {}, "data1"}, + Element{docpp::HTML::Tag::H2, {}, "data2"}, + Element{docpp::HTML::Tag::H3, {}, "data3"}, + Element{docpp::HTML::Tag::H4, {}, "data4"}, + Element{docpp::HTML::Tag::H5, {}, "data5"}, + Element{docpp::HTML::Tag::H6, {}, "data6"} + } + }); + + Document new_document = document; + + REQUIRE(document == new_document); + REQUIRE(document.empty() == false); + + document.clear(); + + REQUIRE(document.empty() == true); + + document = std::move(new_document); + + REQUIRE(document.empty() == false); + }; + + const auto test_operators = []() { + using namespace docpp::HTML; + + Document document1; + Document document2; + + document1.set(Section { + docpp::HTML::Tag::Html, {}, + { + Element{docpp::HTML::Tag::H1, {}, "data1"}, + Element{docpp::HTML::Tag::H2, {}, "data2"}, + Element{docpp::HTML::Tag::H3, {}, "data3"}, + Element{docpp::HTML::Tag::H4, {}, "data4"}, + Element{docpp::HTML::Tag::H5, {}, "data5"}, + Element{docpp::HTML::Tag::H6, {}, "data6"} + } + }); + + document2.set(Section { + docpp::HTML::Tag::Html, {}, + { + Element{docpp::HTML::Tag::H1, {}, "data1"}, + Element{docpp::HTML::Tag::H2, {}, "data2"}, + Element{docpp::HTML::Tag::H3, {}, "data3"}, + Element{docpp::HTML::Tag::H4, {}, "data4"}, + Element{docpp::HTML::Tag::H5, {}, "data5"}, + Element{docpp::HTML::Tag::H6, {}, "data6"} + } + }); + + REQUIRE(document1 == document2); + + document2.set(Section { + docpp::HTML::Tag::Html, {}, + { + Element{docpp::HTML::Tag::H6, {}, "data1"}, + Element{docpp::HTML::Tag::H5, {}, "data2"}, + Element{docpp::HTML::Tag::H4, {}, "data3"}, + Element{docpp::HTML::Tag::H3, {}, "data4"}, + Element{docpp::HTML::Tag::H2, {}, "data5"}, + Element{docpp::HTML::Tag::H1, {}, "data6"} + } + }); + + REQUIRE(document1 != document2); + }; + + const auto test_constructors = []() { + using namespace docpp::HTML; + + Document document{}; + + REQUIRE(document.get_doctype() == ""); + REQUIRE(document.get_section().get_tag() == ""); + REQUIRE(document.get_section().get_sections().empty()); + REQUIRE(document.get_section().get_elements().empty()); + REQUIRE(document.get_section().get_properties().empty()); + + Document document2(Section { + docpp::HTML::Tag::Html, {}, + { + Element{docpp::HTML::Tag::H1, {}, "data1"}, + Element{docpp::HTML::Tag::H2, {}, "data2"}, + Element{docpp::HTML::Tag::H3, {}, "data3"}, + Element{docpp::HTML::Tag::H4, {}, "data4"}, + Element{docpp::HTML::Tag::H5, {}, "data5"}, + Element{docpp::HTML::Tag::H6, {}, "data6"} + } + }); + + REQUIRE(document2.get_doctype() == ""); + REQUIRE(document2.get_section().get_tag() == "html"); + REQUIRE(document2.get_section().get_sections().empty()); + REQUIRE(document2.get_section().get_elements().size() == 6); + REQUIRE(document2.get_section().get_properties().empty()); + + Document document3(Section(docpp::HTML::Tag::Html, {}, { + Section(docpp::HTML::Tag::Head, {}, { + Element(docpp::HTML::Tag::Title, {}, "Title") + }), + Section(docpp::HTML::Tag::Body, {}, { + Element(docpp::HTML::Tag::H1, {}, "Hello, World!") + }), + }), ""); + + REQUIRE(document3.get_doctype() == ""); + REQUIRE(document3.get_section().get_tag() == "html"); + REQUIRE(document3.get_section().get_sections().size() == 2); + REQUIRE(document3.get_section().get_elements().empty()); + REQUIRE(document3.get_section().get_properties().empty()); + }; + + test_get_and_set(); + test_copy_document(); + test_operators(); + test_constructors(); + } + + void test_html() { + test_tag(); + test_exceptions(); + test_npos_values(); + test_property(); + test_properties(); + test_element(); + test_section(); + test_document(); + } +} // namespace HTML + +inline namespace CSS { + void test_css() { + // TODO: Implement tests for CSS + // Previous tests were ran after the implementation of the CSS namespace, so CSS tests are not necessary at the moment and will be implemented soon + } + +} // namespace CSS + /** * @brief Test cases for the docpp namespace. */ SCENARIO("Test HTML", "[HTML]") { - const auto test1 = []() { - docpp::HTML::Document doc{}; - docpp::HTML::Section html(docpp::HTML::ELEMENT_HTML, {}); - - docpp::HTML::Section head(docpp::HTML::ELEMENT_HEAD, {}); - docpp::HTML::Section body(docpp::HTML::ELEMENT_BODY, {}); - docpp::HTML::Section div(docpp::HTML::ELEMENT_DIV, {}); - docpp::HTML::Section footer(docpp::HTML::ELEMENT_FOOTER, {}); - - head.push_back(docpp::HTML::Element("title", {}, "Test Title")); - body.push_back(docpp::HTML::Element("h1", {}, "Test Header")); - body.push_back(docpp::HTML::Element("p", {}, "Test Paragraph")); - - docpp::HTML::Properties prop{}; - prop.push_back(docpp::HTML::Property(std::pair("id", "test_id"))); - - body.push_back(docpp::HTML::Element("p", prop, "Test Paragraph With ID")); - - div.push_back(docpp::HTML::Element("p", {}, "Test Paragraph In Div")); - body.push_back(div); - - prop.push_back(docpp::HTML::Property(std::pair("class", "class1 class2 class3"))); - - body.push_back(docpp::HTML::Element("p", prop, "Test Paragraph With ID And Class")); - - html.push_back(head); - html.push_back(body); - html.push_back(footer); - - doc.set(html); - - const std::string expected_html{"Test Title

    Test Header

    Test Paragraph

    Test Paragraph With ID

    Test Paragraph In Div

    Test Paragraph With ID And Class

    "}; - - REQUIRE(doc.get() == expected_html); - REQUIRE(doc.get(docpp::HTML::FORMATTING_NEWLINE) == "\n\n\nTest Title\n\n\n

    Test Header

    \n

    Test Paragraph

    \n

    Test Paragraph With ID

    \n
    \n

    Test Paragraph In Div

    \n
    \n

    Test Paragraph With ID And Class

    \n\n
    \n
    \n"); - }; - - const auto test2 = []() { - docpp::HTML::Section section(docpp::HTML::ELEMENT_HTML, {}); - - section.push_back(docpp::HTML::Element("p", {}, "Test 1")); - section.push_back(docpp::HTML::Element("p", {}, "Test 2")); - section.push_back(docpp::HTML::Element("p", {}, "Test 3")); - - section.erase(docpp::HTML::Element("p", {}, "Test 2")); - - REQUIRE(section.get() == "

    Test 1

    Test 3

    "); - REQUIRE(section.get(docpp::HTML::FORMATTING_NEWLINE) == "\n

    Test 1

    \n

    Test 3

    \n"); - }; - - const auto test3 = []() { - docpp::HTML::Section section = docpp::HTML::Section(docpp::HTML::ELEMENT_HTML, {}); - - section.push_back(docpp::HTML::Element("p", {}, "Test 1")); - section.push_back(docpp::HTML::Element("p", {}, "Test 2")); - section.push_back(docpp::HTML::Element("p", {}, "Test 3")); - - std::size_t pos = section.find(docpp::HTML::Element("p", {}, "Test 2")); - section.insert(pos, docpp::HTML::Element("p", {}, "Test 2.5")); - - REQUIRE(section.get() == "

    Test 1

    Test 2.5

    Test 3

    "); - REQUIRE(section.get(docpp::HTML::FORMATTING_NEWLINE) == "\n

    Test 1

    \n

    Test 2.5

    \n

    Test 3

    \n"); - }; - - const auto test4 = []() { - docpp::HTML::Section section = docpp::HTML::Section(docpp::HTML::ELEMENT_HTML, {}); - - section.push_back(docpp::HTML::Element("p", {}, "Test 1")); - section.push_back(docpp::HTML::Element("p", {}, "Test 2")); - section.push_back(docpp::HTML::Element("p", {}, "Test 3")); - - std::size_t pos = section.find(docpp::HTML::Element("p", {}, "Test 2")); - - section.erase(pos); - - REQUIRE(section.get() == "

    Test 1

    Test 3

    "); - REQUIRE(section.get(docpp::HTML::FORMATTING_NEWLINE) == "\n

    Test 1

    \n

    Test 3

    \n"); - }; - - const auto test5 = []() { - docpp::HTML::Section section = docpp::HTML::Section(docpp::HTML::ELEMENT_HTML, {}); - docpp::HTML::Section subsection(docpp::HTML::ELEMENT_DIV, {}); - - subsection.push_back(docpp::HTML::Element("p", {}, "Test 1")); - - docpp::HTML::Section subsection2(docpp::HTML::ELEMENT_DIV, {}); - subsection2.push_back(docpp::HTML::Element("p", {}, "Test 2")); - - subsection.push_back(subsection2); - - section.push_back(subsection); - - docpp::HTML::Document doc{}; - doc.set(section); - - REQUIRE(doc.get() == "

    Test 1

    Test 2

    "); - REQUIRE(doc.get(docpp::HTML::FORMATTING_NEWLINE) == "\n\n
    \n

    Test 1

    \n
    \n

    Test 2

    \n
    \n
    \n"); - }; - - const auto test6 = []() { - docpp::CSS::Stylesheet css{}; - docpp::CSS::Element element{"p", {{"color", "red"}, {"font-size", "16px"}, {"font-family", "Arial"}}}; - - css.push_back(element); - - REQUIRE(css.get() == "p {color: red;font-size: 16px;font-family: Arial;}"); - REQUIRE(css.get(docpp::CSS::FORMATTING_NEWLINE) == "p {\ncolor: red;\nfont-size: 16px;\nfont-family: Arial;\n}\n"); - }; - - const auto test7 = []() { - docpp::CSS::Stylesheet css = docpp::CSS::Stylesheet{}; - docpp::CSS::Element element = docpp::CSS::Element{"p", {{"color", "red"}, {"font-size", "16px"}, {"font-family", "Arial"}}}; - docpp::CSS::Element element2{"div", {{"color", "blue"}, {"font-size", "12px"}, {"font-family", "Arial"}}}; - - css.push_back(element); - css.push_front(element2); - - REQUIRE(css.get() == "div {color: blue;font-size: 12px;font-family: Arial;}p {color: red;font-size: 16px;font-family: Arial;}"); - }; - - const auto test8 = []() { - docpp::CSS::Stylesheet css = docpp::CSS::Stylesheet{}; - docpp::CSS::Element element = docpp::CSS::Element{"p", {{"color", "red"}, {"font-size", "16px"}, {"font-family", "Arial"}}}; - docpp::CSS::Element element2{"div", {{"color", "blue"}, {"font-size", "12px"}, {"font-family", "Arial"}}}; - - css.push_back(element); - css.push_front(element2); - - css.erase(css.find(element2)); - - REQUIRE(css.get() == "p {color: red;font-size: 16px;font-family: Arial;}"); - }; - - const auto test9 = []() { - docpp::CSS::Stylesheet css = docpp::CSS::Stylesheet{}; - docpp::CSS::Element element = docpp::CSS::Element{"p", {{"color", "red"}, {"font-size", "16px"}, {"font-family", "Arial"}}}; - docpp::CSS::Element element2{"div", {{"color", "blue"}, {"font-size", "12px"}, {"font-family", "Arial"}}}; - - css.push_back(element); - css.push_front(element2); - - css.erase(css.find(element2)); - css.push_front(element2); - - css.swap(css.find(element), css.find(element2)); - - REQUIRE(css.get() == "p {color: red;font-size: 16px;font-family: Arial;}div {color: blue;font-size: 12px;font-family: Arial;}"); - - element.push_front(docpp::CSS::Property("font-weight", "bold")); - - REQUIRE(element.get() == "p {font-weight: bold;color: red;font-size: 16px;font-family: Arial;}"); - }; - - const auto test10 = []() { - docpp::HTML::Section section = docpp::HTML::Section(docpp::HTML::ELEMENT_HTML, {}); - - section.push_back(docpp::HTML::Element("p", {}, "Test 1")); - section.push_back(docpp::HTML::Element("p", {}, "Test 2")); - section.push_back(docpp::HTML::Element("p", {}, "Test 3")); - - section.swap(section.find(docpp::HTML::Element("p", {}, "Test 2")), section.find(docpp::HTML::Element("p", {}, "Test 3"))); - - REQUIRE(section.get() == "

    Test 1

    Test 3

    Test 2

    "); - }; - - const auto test11 = []() { - docpp::HTML::Section section = docpp::HTML::Section(docpp::HTML::ELEMENT_HTML, {}); - - section.push_back(docpp::HTML::Element("p", {}, "Test 1")); - section.push_back(docpp::HTML::Element("p", {}, "Test 2")); - section.push_back(docpp::HTML::Element("p", {}, "Test 3")); - - section.swap(docpp::HTML::Element("p", {}, "Test 2"), docpp::HTML::Element("p", {}, "Test 3")); - - REQUIRE(section.get() == "

    Test 1

    Test 3

    Test 2

    "); - }; - - const auto test12 = []() { - docpp::HTML::Section section = docpp::HTML::Section(docpp::HTML::ELEMENT_HTML, {}); - - section.push_back(docpp::HTML::Element("p", {}, "Test 1")); - section.push_back(docpp::HTML::Element("p", {}, "Test 2")); - section.push_back(docpp::HTML::Element("p", {}, "Test 3")); - - section.push_front(docpp::HTML::Element("p", {}, "Test 0")); - - REQUIRE(section.get() == "

    Test 0

    Test 1

    Test 2

    Test 3

    "); - }; - - const auto test13 = []() { - docpp::HTML::Section section = docpp::HTML::Section(docpp::HTML::ELEMENT_HTML, {}); - - section.push_back(docpp::HTML::Element("p", {}, "Test 1")); - section.push_back(docpp::HTML::Element("p", {}, "Test 2")); - section.push_back(docpp::HTML::Element("p", {}, "Test 3")); - section.push_back(docpp::HTML::Element("p", {}, "Test 4")); - section.push_back(docpp::HTML::Element("p", {}, "Test 5")); - section.push_back(docpp::HTML::Element("p", {}, "Test 6")); - - const std::size_t pos{section.find("

    Test 2

    ")}; - - REQUIRE(pos != docpp::HTML::Section::npos); - - const std::size_t pos2{section.find("

    Test 6

    ")}; - - section.erase(pos); - section.erase(pos2); - - REQUIRE(section.get() == "

    Test 1

    Test 3

    Test 4

    Test 5

    "); - }; - - const auto test14 = []() { - docpp::CSS::Element element{"p", {{"color", "red"}, {"font-size", "16px"}, {"font-family", "Arial"}}}; - - const int red = element.find("color"); - - REQUIRE(red != docpp::CSS::Element::npos); - - const int blue = element.find("blue"); - - REQUIRE(blue == docpp::CSS::Element::npos); - - element.erase(red); - - REQUIRE(element.get() == "p {font-size: 16px;font-family: Arial;}"); - - element.insert(red, docpp::CSS::Property("color", "red")); - - REQUIRE(element.get() == "p {color: red;font-size: 16px;font-family: Arial;}"); - }; - - const auto test15 = []() { - docpp::HTML::Properties prop{}; - - prop.push_back(docpp::HTML::Property(std::pair("id", "test_id"))); - prop.push_back(docpp::HTML::Property(std::pair("class", "class1 class2 class3"))); - - REQUIRE(docpp::HTML::Element("p", prop, {}).get() == "

    "); - - const int pos = prop.find("class"); - - REQUIRE(pos != docpp::HTML::Properties::npos); - - const int pos2 = prop.find("class2"); - - REQUIRE(prop.at(pos2).get_key() == "class"); - REQUIRE(prop.at(pos2).get_value() == "class1 class2 class3"); - - REQUIRE(pos2 != docpp::HTML::Properties::npos); - - const int pos3 = prop.find("class4"); - - REQUIRE(pos3 == docpp::HTML::Properties::npos); - - prop.erase(pos); - - REQUIRE(docpp::HTML::Element("p", prop, {}).get() == "

    "); - }; - - const auto test16 = []() { - docpp::HTML::Document doc = docpp::HTML::Section({}); - - doc.get_section().push_back(docpp::HTML::Element("p", {}, "Test 1")); - doc.get_section().push_back(docpp::HTML::Element("p", {}, "Test 2")); - doc.get_section().push_back(docpp::HTML::Element("p", {}, "Test 3")); - - doc.get_section() = docpp::HTML::Section(docpp::HTML::ELEMENT_HTML, {}); - - doc.get_section().push_back(docpp::HTML::Element("p", {}, "Test 4")); - doc.get_section().push_back(docpp::HTML::Element("p", {}, "Test 5")); - doc.get_section().push_back(docpp::HTML::Element("p", {}, "Test 6")); - - doc.get_section() += docpp::HTML::Element("p", {}, "Test 7"); - - REQUIRE(doc.get() == "

    Test 4

    Test 5

    Test 6

    Test 7

    "); - }; - - const auto test17 = []() { - docpp::HTML::Section section = docpp::HTML::Section(docpp::HTML::ELEMENT_HTML, {}); - - section.push_back(docpp::HTML::Element("p", {}, "Test 1")); - section.push_back(docpp::HTML::Element("p", {}, "Test 2")); - section.push_back(docpp::HTML::Element("p", {}, "Test 3")); - - docpp::HTML::Document doc{section}; - - REQUIRE(doc.get(docpp::HTML::FORMATTING_PRETTY) == "\n\n\t

    Test 1

    \n\t

    Test 2

    \n\t

    Test 3

    \n"); - }; - - const auto test18 = []() { - docpp::HTML::Section section = docpp::HTML::Section(docpp::HTML::ELEMENT_EMPTY, {}); - - section.push_back(docpp::HTML::Element("p", {}, "Test 1")); - section.push_back(docpp::HTML::Element("p", {}, "Test 2")); - section.push_back(docpp::HTML::Element("p", {}, "Test 3")); - - REQUIRE(section.get() == "

    Test 1

    Test 2

    Test 3

    "); - }; - - const auto test19 = []() { - docpp::HTML::Section section = docpp::HTML::Section(docpp::HTML::ELEMENT_HTML, {}); - - section.push_back(docpp::HTML::Element("p", {}, "Test 1")); - section.push_back(docpp::HTML::Element("p", {}, "Test 2")); - section.push_back(docpp::HTML::Element("p", {}, "Test 3")); - - REQUIRE(section.front().get() == "

    Test 1

    "); - REQUIRE(section.back().get() == "

    Test 3

    "); - }; - - const auto test20 = []() { - docpp::HTML::Properties prop{}; - - prop.push_back(docpp::HTML::Property(std::pair("id", "test_id"))); - prop.push_back(docpp::HTML::Property(std::pair("class", "class1 class2 class3"))); - prop.push_back(docpp::HTML::Property(std::pair("style", "color: red; font-size: 16px; font-family: Arial;"))); - - for (const docpp::HTML::Property& p : prop) { - REQUIRE(p.get_key() == "id"); - REQUIRE(p.get_value() == "test_id"); - break; - } - - for (docpp::HTML::Properties::iterator it = ++prop.begin(); it != prop.end(); ++it) { - REQUIRE(it->get_key() == "class"); - REQUIRE(it->get_value() == "class1 class2 class3"); - break; - } - }; - - const auto test21 = []() { - docpp::HTML::Section sect{}; - - sect.push_back(docpp::HTML::Element("p", {}, "Test 1")); - sect.push_back(docpp::HTML::Element("p", {}, "Test 2")); - sect.push_back(docpp::HTML::Element("p", {}, "Test 3")); - - for (const docpp::HTML::Element& elem : sect) { - REQUIRE(elem.get() == "

    Test 1

    "); - break; - } - - for (docpp::HTML::Section::iterator it = ++sect.begin(); it != sect.end(); ++it) { - docpp::HTML::Element elem = *it; - REQUIRE(elem.get() == "

    Test 2

    "); - break; - } - }; - - const auto test22 = []() { - docpp::HTML::Section sect{}; - - sect.push_back(docpp::HTML::Element("p", {}, "Test 1")); - sect.push_back(docpp::HTML::Element("p", {}, "Test 2")); - sect.push_back(docpp::HTML::Element("p", {}, "Test 3")); - - bool caught{false}; - try { - sect.at(1337); - } catch (const docpp::out_of_range& e) { - caught = true; - } - - REQUIRE(caught); - }; - - const auto test23 = []() { - docpp::HTML::Section sect{}; - - sect.push_back(docpp::HTML::Element("p", {}, "Test 1")); - sect.push_back(docpp::HTML::Element("p", {}, "Test 2")); - sect.push_back(docpp::HTML::Element("p", {}, "Test 3")); - - REQUIRE(sect.get() == "

    Test 1

    Test 2

    Test 3

    "); - }; - - const auto test24 = []() { - const auto test = docpp::HTML::resolve_tag(docpp::HTML::ELEMENT_HTML); - const auto test2 = docpp::HTML::resolve_tag(docpp::HTML::ELEMENT_HEAD); - const auto test3 = docpp::HTML::resolve_tag(docpp::HTML::ELEMENT_BODY); - const auto test4 = docpp::HTML::resolve_tag(docpp::HTML::ELEMENT_DIV); - const auto test5 = docpp::HTML::resolve_tag(docpp::HTML::ELEMENT_NAV); - const auto test6 = docpp::HTML::resolve_tag(docpp::HTML::ELEMENT_FOOTER); - const auto test7 = docpp::HTML::resolve_tag(docpp::HTML::ELEMENT_P); - const auto test8 = docpp::HTML::resolve_tag(docpp::HTML::ELEMENT_H1); - const auto test9 = docpp::HTML::resolve_tag(docpp::HTML::ELEMENT_H2); - const auto test10 = docpp::HTML::resolve_tag(docpp::HTML::ELEMENT_H3); - const auto test11 = docpp::HTML::resolve_tag(docpp::HTML::ELEMENT_H4); - const auto test12 = docpp::HTML::resolve_tag(docpp::HTML::ELEMENT_H5); - const auto test13 = docpp::HTML::resolve_tag(docpp::HTML::ELEMENT_H6); - - docpp::HTML::Section sect = docpp::HTML::Section(docpp::HTML::ELEMENT_HTML); - docpp::HTML::Section sect2 = docpp::HTML::Section(docpp::HTML::ELEMENT_HEAD); - docpp::HTML::Section sect3 = docpp::HTML::Section(docpp::HTML::ELEMENT_BODY); - docpp::HTML::Section sect4 = docpp::HTML::Section(docpp::HTML::ELEMENT_DIV); - docpp::HTML::Section sect5 = docpp::HTML::Section(docpp::HTML::ELEMENT_NAV); - docpp::HTML::Section sect6 = docpp::HTML::Section(docpp::HTML::ELEMENT_FOOTER); - docpp::HTML::Section sect7 = docpp::HTML::Section(docpp::HTML::ELEMENT_P); - docpp::HTML::Section sect8 = docpp::HTML::Section(docpp::HTML::ELEMENT_H1); - docpp::HTML::Section sect9 = docpp::HTML::Section(docpp::HTML::ELEMENT_H2); - docpp::HTML::Section sect10 = docpp::HTML::Section(docpp::HTML::ELEMENT_H3); - docpp::HTML::Section sect11 = docpp::HTML::Section(docpp::HTML::ELEMENT_H4); - docpp::HTML::Section sect12 = docpp::HTML::Section(docpp::HTML::ELEMENT_H5); - docpp::HTML::Section sect13 = docpp::HTML::Section(docpp::HTML::ELEMENT_H6); - - docpp::HTML::Element elem = docpp::HTML::Element(docpp::HTML::ELEMENT_HTML);; - docpp::HTML::Element elem2 = docpp::HTML::Element(docpp::HTML::ELEMENT_HEAD); - docpp::HTML::Element elem3 = docpp::HTML::Element(docpp::HTML::ELEMENT_BODY); - docpp::HTML::Element elem4 = docpp::HTML::Element(docpp::HTML::ELEMENT_DIV); - docpp::HTML::Element elem5 = docpp::HTML::Element(docpp::HTML::ELEMENT_NAV); - docpp::HTML::Element elem6 = docpp::HTML::Element(docpp::HTML::ELEMENT_FOOTER); - docpp::HTML::Element elem7 = docpp::HTML::Element(docpp::HTML::ELEMENT_P); - docpp::HTML::Element elem8 = docpp::HTML::Element(docpp::HTML::ELEMENT_H1); - docpp::HTML::Element elem9 = docpp::HTML::Element(docpp::HTML::ELEMENT_H2); - docpp::HTML::Element elem10 = docpp::HTML::Element(docpp::HTML::ELEMENT_H3); - docpp::HTML::Element elem11 = docpp::HTML::Element(docpp::HTML::ELEMENT_H4); - docpp::HTML::Element elem12 = docpp::HTML::Element(docpp::HTML::ELEMENT_H5); - docpp::HTML::Element elem13 = docpp::HTML::Element(docpp::HTML::ELEMENT_H6); - }; - - std::vector tests{ - test1, - test2, - test3, - test4, - test5, - test6, - test7, - test8, - test9, - test10, - test11, - test12, - test13, - test14, - test15, - test16, - test17, - test18, - test19, - test20, - test21, - test22, - test23, - test24, - }; - - for (const auto& test : tests) { - test(); - } + HTML::test_html(); +} + +/** + * @brief Test cases for the docpp namespace. + */ +SCENARIO("Test CSS", "[CSS]") { + CSS::test_css(); }