LCOV - code coverage report
Current view: top level - home/snapwebsites/snapcpp/snapwebsites/snapdatabase/tests - xml.cpp (source / functions) Hit Total Coverage
Test: coverage.info Lines: 172 174 98.9 %
Date: 2019-12-15 17:13:15 Functions: 5 5 100.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : // Copyright (c) 2019  Made to Order Software Corp.  All Rights Reserved
       2             : //
       3             : // https://snapwebsites.org/project/snapdatabase
       4             : // contact@m2osw.com
       5             : //
       6             : // This program is free software; you can redistribute it and/or modify
       7             : // it under the terms of the GNU General Public License as published by
       8             : // the Free Software Foundation; either version 2 of the License, or
       9             : // (at your option) any later version.
      10             : //
      11             : // This program is distributed in the hope that it will be useful,
      12             : // but WITHOUT ANY WARRANTY; without even the implied warranty of
      13             : // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      14             : // GNU General Public License for more details.
      15             : //
      16             : // You should have received a copy of the GNU General Public License along
      17             : // with this program; if not, write to the Free Software Foundation, Inc.,
      18             : // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
      19             : 
      20             : // self
      21             : //
      22             : #include    "main.h"
      23             : 
      24             : 
      25             : // snaplogger lib
      26             : //
      27             : #include    <snapdatabase/exception.h>
      28             : #include    <snapdatabase/data/xml.h>
      29             : 
      30             : 
      31             : // C++ lib
      32             : //
      33             : #include    <fstream>
      34             : 
      35             : 
      36             : // C lib
      37             : //
      38             : #include    <sys/stat.h>
      39             : #include    <sys/types.h>
      40             : 
      41             : 
      42             : 
      43             : namespace
      44             : {
      45             : 
      46             : 
      47           8 : std::string get_folder_name()
      48             : {
      49          16 :     std::string const xml_path(SNAP_CATCH2_NAMESPACE::g_tmp_dir + "/xml");
      50             : 
      51           8 :     if(mkdir(xml_path.c_str(), 0700) != 0)
      52             :     {
      53           7 :         if(errno != EEXIST)
      54             :         {
      55           0 :             perror(("could not create directory \"" + xml_path + "\"").c_str());
      56           0 :             return std::string();
      57             :         }
      58             :     }
      59             : 
      60           8 :     return xml_path;
      61             : }
      62             : 
      63             : 
      64             : }
      65             : 
      66             : 
      67             : 
      68           9 : CATCH_TEST_CASE("XML Basics", "[xml]")
      69             : {
      70          14 :     CATCH_START_SECTION("empty")
      71             :     {
      72           2 :         std::string const xml;
      73             : 
      74           2 :         std::string const xml_path(get_folder_name());
      75           2 :         std::string const filename(xml_path + "/empty.xml");
      76             : 
      77             :         // create empty file
      78             :         {
      79           2 :             std::ofstream f;
      80           1 :             f.open(filename);
      81           1 :             CATCH_REQUIRE(f.is_open());
      82             :         }
      83             : 
      84           1 :         CATCH_REQUIRE_THROWS_MATCHES(
      85             :                   snapdatabase::xml(filename)
      86             :                 , snapdatabase::unexpected_token
      87             :                 , Catch::Matchers::ExceptionMessage(
      88             :                           "snapdatabase_error: File \""
      89             :                         + filename
      90             :                         + "\" cannot be empty or include anything other than a processor tag and comments before the root tag.", true));
      91             :     }
      92             :     CATCH_END_SECTION()
      93             : 
      94          14 :     CATCH_START_SECTION("empty root tag")
      95             :     {
      96           2 :         std::string const xml;
      97             : 
      98           2 :         std::string const xml_path(get_folder_name());
      99           2 :         std::string const filename(xml_path + "/empty-tag.xml");
     100             : 
     101             :         // create file with one empty tag
     102             :         {
     103           2 :             std::ofstream f;
     104           1 :             f.open(filename);
     105           1 :             CATCH_REQUIRE(f.is_open());
     106           1 :             f << "<empty/>";
     107             :         }
     108             : 
     109           1 :         CATCH_REQUIRE_THROWS_MATCHES(
     110             :                   snapdatabase::xml(filename)
     111             :                 , snapdatabase::unexpected_token
     112             :                 , Catch::Matchers::ExceptionMessage(
     113             :                           "snapdatabase_error: File \""
     114             :                         + filename
     115             :                         + "\" root tag cannot be an empty tag.", true));
     116             :     }
     117             :     CATCH_END_SECTION()
     118             : 
     119          14 :     CATCH_START_SECTION("empty root")
     120             :     {
     121           2 :         std::string const xml;
     122             : 
     123           2 :         std::string const xml_path(get_folder_name());
     124           2 :         std::string const filename(xml_path + "/empty-tag.xml");
     125             : 
     126             :         // create file with one empty tag
     127             :         {
     128           2 :             std::ofstream f;
     129           1 :             f.open(filename);
     130           1 :             CATCH_REQUIRE(f.is_open());
     131           1 :             f << "<empty></empty>";
     132             :         }
     133             : 
     134           2 :         snapdatabase::xml x(filename);
     135           2 :         snapdatabase::xml_node::pointer_t root(x.root());
     136           1 :         CATCH_REQUIRE(root != nullptr);
     137           1 :         CATCH_REQUIRE(root->tag_name() == "empty");
     138           1 :         CATCH_REQUIRE(root->text().empty());
     139           1 :         CATCH_REQUIRE(root->all_attributes().empty());
     140           1 :         CATCH_REQUIRE(root->parent() == nullptr);
     141           1 :         CATCH_REQUIRE(root->first_child() == nullptr);
     142           1 :         CATCH_REQUIRE(root->last_child() == nullptr);
     143           1 :         CATCH_REQUIRE(root->next() == nullptr);
     144           1 :         CATCH_REQUIRE(root->previous() == nullptr);
     145             :     }
     146             :     CATCH_END_SECTION()
     147             : 
     148          14 :     CATCH_START_SECTION("empty root with preprocessor")
     149             :     {
     150           2 :         std::string const xml;
     151             : 
     152           2 :         std::string const xml_path(get_folder_name());
     153           2 :         std::string const filename(xml_path + "/empty-tag.xml");
     154             : 
     155             :         // create file with one empty tag
     156             :         {
     157           2 :             std::ofstream f;
     158           1 :             f.open(filename);
     159           1 :             CATCH_REQUIRE(f.is_open());
     160           1 :             f << "<?xml version=\"1.0\"?><still-empty></still-empty>";
     161             :         }
     162             : 
     163           2 :         snapdatabase::xml x(filename);
     164           2 :         snapdatabase::xml_node::pointer_t root(x.root());
     165           1 :         CATCH_REQUIRE(root != nullptr);
     166           1 :         CATCH_REQUIRE(root->tag_name() == "still-empty");
     167           1 :         CATCH_REQUIRE(root->text().empty());
     168           1 :         CATCH_REQUIRE(root->all_attributes().empty());
     169           1 :         CATCH_REQUIRE(root->parent() == nullptr);
     170           1 :         CATCH_REQUIRE(root->first_child() == nullptr);
     171           1 :         CATCH_REQUIRE(root->last_child() == nullptr);
     172           1 :         CATCH_REQUIRE(root->next() == nullptr);
     173           1 :         CATCH_REQUIRE(root->previous() == nullptr);
     174             :     }
     175             :     CATCH_END_SECTION()
     176             : 
     177          14 :     CATCH_START_SECTION("empty root with comment & preprocessor")
     178             :     {
     179           2 :         std::string const xml;
     180             : 
     181           2 :         std::string const xml_path(get_folder_name());
     182           2 :         std::string const filename(xml_path + "/quite-empty.xml");
     183             : 
     184             :         // create file with one empty tag
     185             :         {
     186           2 :             std::ofstream f;
     187           1 :             f.open(filename);
     188           1 :             CATCH_REQUIRE(f.is_open());
     189           1 :             f << "<!-- name='rotor' --><?xml version=\"1.0\"?><quite-empty></quite-empty>";
     190             :         }
     191             : 
     192           2 :         snapdatabase::xml x(filename);
     193           2 :         snapdatabase::xml_node::pointer_t root(x.root());
     194           1 :         CATCH_REQUIRE(root != nullptr);
     195           1 :         CATCH_REQUIRE(root->tag_name() == "quite-empty");
     196           1 :         CATCH_REQUIRE(root->text().empty());
     197           1 :         CATCH_REQUIRE(root->all_attributes().empty());
     198           1 :         CATCH_REQUIRE(root->parent() == nullptr);
     199           1 :         CATCH_REQUIRE(root->first_child() == nullptr);
     200           1 :         CATCH_REQUIRE(root->last_child() == nullptr);
     201           1 :         CATCH_REQUIRE(root->next() == nullptr);
     202           1 :         CATCH_REQUIRE(root->previous() == nullptr);
     203             :     }
     204             :     CATCH_END_SECTION()
     205             : 
     206          14 :     CATCH_START_SECTION("empty root with comment & preprocessor & attributes")
     207             :     {
     208           2 :         std::string const xml;
     209             : 
     210           2 :         std::string const xml_path(get_folder_name());
     211           2 :         std::string const filename(xml_path + "/root-attributes.xml");
     212             : 
     213             :         // create file with one empty tag
     214             :         {
     215           2 :             std::ofstream f;
     216           1 :             f.open(filename);
     217           1 :             CATCH_REQUIRE(f.is_open());
     218           1 :             f << "<!--\n"
     219             :                  "name='next level'\n"
     220             :                  "-->\n"
     221             :                  "\n"
     222             :                  "<?xml version=\"1.0\"?>\n"
     223             :                  "<root-canal quite=\"quite\" size='123' very=\"true\">"
     224             :                  " \t \t \t "
     225             :                  "</root-canal>";
     226             :         }
     227             : 
     228           2 :         snapdatabase::xml x(filename);
     229           2 :         snapdatabase::xml_node::pointer_t root(x.root());
     230           1 :         CATCH_REQUIRE(root != nullptr);
     231           1 :         CATCH_REQUIRE(root->tag_name() == "root-canal");
     232           1 :         CATCH_REQUIRE(root->text() == " \t \t \t ");
     233           1 :         CATCH_REQUIRE(root->all_attributes().size() == 3);
     234           1 :         CATCH_REQUIRE(root->attribute("quite") == "quite");
     235           1 :         CATCH_REQUIRE(root->attribute("size") == "123");
     236           1 :         CATCH_REQUIRE(root->attribute("very") == "true");
     237           1 :         CATCH_REQUIRE(root->parent() == nullptr);
     238           1 :         CATCH_REQUIRE(root->first_child() == nullptr);
     239           1 :         CATCH_REQUIRE(root->last_child() == nullptr);
     240           1 :         CATCH_REQUIRE(root->next() == nullptr);
     241           1 :         CATCH_REQUIRE(root->previous() == nullptr);
     242             :     }
     243             :     CATCH_END_SECTION()
     244             : 
     245          14 :     CATCH_START_SECTION("entities test")
     246             :     {
     247           2 :         std::string const xml;
     248             : 
     249           2 :         std::string const xml_path(get_folder_name());
     250           2 :         std::string const filename(xml_path + "/entities.xml");
     251             : 
     252             :         // create file with one empty tag
     253             :         {
     254           2 :             std::ofstream f;
     255           1 :             f.open(filename);
     256           1 :             CATCH_REQUIRE(f.is_open());
     257           1 :             f << "<!--\n"
     258             :                  "name='entitie&#x73;'\n"
     259             :                  "-->\n"
     260             :                  "\n"
     261             :                  "<?xml version=\"1.0\"?>\n"
     262             :                  "<entity-a-gogo quite=\"&#x71;uit&#101;\" size='1&#x32;3'"
     263             :                         " very=\"&quot;true&quot;\" special-entry=\"&quot;&lt;it&apos;s special &amp; weird&gt;&quot;\">"
     264             :                  "</entity-a-gogo>";
     265             :         }
     266             : 
     267           2 :         snapdatabase::xml x(filename);
     268           2 :         snapdatabase::xml_node::pointer_t root(x.root());
     269           1 :         CATCH_REQUIRE(root != nullptr);
     270           1 :         CATCH_REQUIRE(root->tag_name() == "entity-a-gogo");
     271           1 :         CATCH_REQUIRE(root->all_attributes().size() == 4);
     272           1 :         CATCH_REQUIRE(root->attribute("quite") == "quite");
     273           1 :         CATCH_REQUIRE(root->attribute("size") == "123");
     274           1 :         CATCH_REQUIRE(root->attribute("very") == "\"true\"");
     275           1 :         CATCH_REQUIRE(root->attribute("special-entry") == "\"<it's special & weird>\"");
     276           1 :         CATCH_REQUIRE(root->parent() == nullptr);
     277           1 :         CATCH_REQUIRE(root->first_child() == nullptr);
     278           1 :         CATCH_REQUIRE(root->last_child() == nullptr);
     279           1 :         CATCH_REQUIRE(root->next() == nullptr);
     280           1 :         CATCH_REQUIRE(root->previous() == nullptr);
     281             :     }
     282             :     CATCH_END_SECTION()
     283           7 : }
     284             : 
     285             : 
     286           3 : CATCH_TEST_CASE("XML Tree", "[xml]")
     287             : {
     288           2 :     CATCH_START_SECTION("tree")
     289             :     {
     290           2 :         std::string const xml;
     291             : 
     292           2 :         std::string const xml_path(get_folder_name());
     293           2 :         std::string const filename(xml_path + "/tree.xml");
     294             : 
     295             :         // create empty file
     296             :         {
     297           2 :             std::ofstream f;
     298           1 :             f.open(filename);
     299           1 :             CATCH_REQUIRE(f.is_open());
     300             :             f << "<root>"
     301             :                   << "<parent>"
     302             :                       << "<child>DATA 1</child>"
     303             :                       << "<child>DATA 2</child>"
     304             :                       << "<child>DATA 3</child>"
     305             :                   << "</parent>"
     306           1 :               << "</root>";
     307             :         }
     308             : 
     309           2 :         snapdatabase::xml x(filename);
     310           2 :         snapdatabase::xml_node::pointer_t root(x.root());
     311           1 :         CATCH_REQUIRE(root != nullptr);
     312           1 :         CATCH_REQUIRE(root->parent() == nullptr);
     313           2 :         snapdatabase::xml_node::pointer_t parent_node(root->first_child());
     314           1 :         CATCH_REQUIRE(parent_node != nullptr);
     315           1 :         CATCH_REQUIRE(root->last_child() == parent_node);
     316           1 :         CATCH_REQUIRE(root->next() == nullptr);
     317           1 :         CATCH_REQUIRE(root->previous() == nullptr);
     318             : 
     319           1 :         CATCH_REQUIRE(parent_node->parent() == root);
     320           2 :         snapdatabase::xml_node::pointer_t child1_node(parent_node->first_child());
     321           2 :         snapdatabase::xml_node::pointer_t child2_node(child1_node->next());
     322           2 :         snapdatabase::xml_node::pointer_t child3_node(child2_node->next());
     323           1 :         CATCH_REQUIRE(child1_node != nullptr);
     324           1 :         CATCH_REQUIRE(child2_node != nullptr);
     325           1 :         CATCH_REQUIRE(child3_node != nullptr);
     326           1 :         CATCH_REQUIRE(parent_node->last_child() == child3_node);
     327           1 :         CATCH_REQUIRE(parent_node->next() == nullptr);
     328           1 :         CATCH_REQUIRE(parent_node->previous() == nullptr);
     329             : 
     330           1 :         CATCH_REQUIRE(child1_node->parent() == parent_node);
     331           1 :         CATCH_REQUIRE(child2_node->parent() == parent_node);
     332           1 :         CATCH_REQUIRE(child3_node->parent() == parent_node);
     333             : 
     334           1 :         CATCH_REQUIRE(child1_node->first_child() == nullptr);
     335           1 :         CATCH_REQUIRE(child2_node->first_child() == nullptr);
     336           1 :         CATCH_REQUIRE(child3_node->first_child() == nullptr);
     337             : 
     338           1 :         CATCH_REQUIRE(child1_node->last_child() == nullptr);
     339           1 :         CATCH_REQUIRE(child2_node->last_child() == nullptr);
     340           1 :         CATCH_REQUIRE(child3_node->last_child() == nullptr);
     341             : 
     342           1 :         CATCH_REQUIRE(child1_node->text() == "DATA 1");
     343           1 :         CATCH_REQUIRE(child2_node->text() == "DATA 2");
     344           1 :         CATCH_REQUIRE(child3_node->text() == "DATA 3");
     345             : 
     346           1 :         CATCH_REQUIRE(child1_node->next() == child2_node);
     347           1 :         CATCH_REQUIRE(child2_node->previous() == child1_node);
     348             : 
     349           1 :         CATCH_REQUIRE(child2_node->next() == child3_node);
     350           1 :         CATCH_REQUIRE(child3_node->previous() == child2_node);
     351             : 
     352           1 :         CATCH_REQUIRE(child3_node->next() == nullptr);
     353           1 :         CATCH_REQUIRE(child1_node->previous() == nullptr);
     354             :     }
     355             :     CATCH_END_SECTION()
     356           7 : }
     357             : 
     358             : 
     359             : 
     360             : // vim: ts=4 sw=4 et

Generated by: LCOV version 1.13