LCOV - code coverage report
Current view: top level - tests - tld_test_emails.cpp (source / functions) Hit Total Coverage
Test: coverage.info Lines: 163 279 58.4 %
Date: 2018-01-27 17:19:43 Functions: 6 8 75.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* TLD library -- test the TLD interface for emails
       2             :  * Copyright (C) 2013-2017  Made to Order Software Corp.
       3             :  *
       4             :  * Permission is hereby granted, free of charge, to any person obtaining a
       5             :  * copy of this software and associated documentation files (the
       6             :  * "Software"), to deal in the Software without restriction, including
       7             :  * without limitation the rights to use, copy, modify, merge, publish,
       8             :  * distribute, sublicense, and/or sell copies of the Software, and to
       9             :  * permit persons to whom the Software is furnished to do so, subject to
      10             :  * the following conditions:
      11             :  *
      12             :  * The above copyright notice and this permission notice shall be included
      13             :  * in all copies or substantial portions of the Software.
      14             :  *
      15             :  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
      16             :  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
      17             :  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
      18             :  * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
      19             :  * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
      20             :  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
      21             :  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
      22             :  */
      23             : 
      24             : /** \file
      25             :  * \brief Test the tld_email_list class.
      26             :  *
      27             :  * This file implements various tests to verify that the
      28             :  * tld_email_list functions as expected.
      29             :  */
      30             : 
      31             : #include "libtld/tld.h"
      32             : #include <stdlib.h>
      33             : #include <stdio.h>
      34             : #include <string.h>
      35             : #include <sstream>
      36             : 
      37             : /// The number of errors encountered before exiting.
      38             : int err_count = 0;
      39             : 
      40             : /// Whether to be verbose, turned off by default.
      41             : int verbose = 0;
      42             : 
      43             : 
      44             : /** \brief Print an error.
      45             :  *
      46             :  * This function prints the specified \p msg in stderr and increases
      47             :  * the error counter by one.
      48             :  *
      49             :  * \param[in] msg  The message to be printed.
      50             :  */
      51           0 : void error(const std::string& msg)
      52             : {
      53           0 :     fprintf(stderr, "%s\n", msg.c_str());
      54           0 :     ++err_count;
      55           0 : }
      56             : 
      57             : 
      58             : /// Macro to check that exceptions are raised without having to write the try/catch each time.
      59             : #define EXPECTED_THROW(s, e) \
      60             :     try \
      61             :     { \
      62             :         static_cast<void>(s); \
      63             :         error("error: bad." #s "() of \"\" did not throw an error."); \
      64             :     } \
      65             :     catch(const e&) \
      66             :     { \
      67             :     }
      68             : 
      69             : 
      70             : /** \brief Define a valid email string.
      71             :  *
      72             :  * This structure is used to define a valid email string. The string may
      73             :  * include any number of emails as defined by the \p f_count field. Note
      74             :  * that the count is increased by 1 for each group definition in the list
      75             :  * defined in the \p f_input_email string.
      76             :  *
      77             :  * This structure is used to validate many different types of email
      78             :  * addresses to make sure that our parser works properly.
      79             :  */
      80             : struct valid_email
      81             : {
      82             :     /// The valid emails to be parsed.
      83             :     const char *        f_input_email;
      84             :     /// The number of emails returned on f_input_email was parsed, plus one per group.
      85             :     int                 f_count;
      86             : };
      87             : 
      88             : //const char *        f_group;
      89             : //const char *        f_original_email;
      90             : //const char *        f_fullname;
      91             : //const char *        f_username;
      92             : //const char *        f_domain;
      93             : //const char *        f_email_only;
      94             : //const char *        f_canonicalized_email;
      95             : 
      96             : /// List of results to verify all the fields of the parser output. There is one entry per group and email.
      97             : const tld_email list_of_results[] =
      98             : {
      99             :     { "", "MAILER-DAEMON@mail.exdox.com (Mail Delivery System)",
     100             :       "", "MAILER-DAEMON", "mail.exdox.com", "MAILER-DAEMON@mail.exdox.com", "MAILER-DAEMON@mail.exdox.com" },
     101             : #if 1
     102             :     { "", "alexis@m2osw.com",
     103             :       "", "alexis", "m2osw.com", "alexis@m2osw.com", "alexis@m2osw.com" },
     104             :     { "", "a@m2osw.com",
     105             :       "", "a", "m2osw.com", "a@m2osw.com", "a@m2osw.com" },
     106             :     { "", "b@c.com",
     107             :       "", "b", "c.com", "b@c.com", "b@c.com" },
     108             :     { "", "alexis@m2osw.com",
     109             :       "", "alexis", "m2osw.com", "alexis@m2osw.com", "alexis@m2osw.com" },
     110             :     { "", "\"Wilke, Alexis\" <alexis@m2osw.com>",
     111             :       "Wilke, Alexis", "alexis", "m2osw.com", "alexis@m2osw.com", "\"Wilke, Alexis\" <alexis@m2osw.com>" },
     112             :     { "", "(* Pascal Comments *) \t alexis@m2osw.com\n (Just (kidding) he! he!)",
     113             :       "", "alexis", "m2osw.com", "alexis@m2osw.com", "alexis@m2osw.com" },
     114             :     { "", "(Start-Comment)alexis@ \t [ \t m2osw.com \t ] \n (More (comment) here)",
     115             :       "", "alexis", "m2osw.com", "alexis@m2osw.com", "alexis@m2osw.com" },
     116             :     { "", "(Test with dots in user name) al.ex.is@ \t [ \t m2osw.com \t ] \n (More (comments) there)",
     117             :       "", "al.ex.is", "m2osw.com", "al.ex.is@m2osw.com", "al.ex.is@m2osw.com" },
     118             :     { "", "< (Test with dots in user name) al.ex.is@ \t [ \t m2osw.com \t ] \n (More (comments) there) >",
     119             :       "", "al.ex.is", "m2osw.com", "al.ex.is@m2osw.com", "al.ex.is@m2osw.com" },
     120             :     { "", "(With full name) Alexis Wilke < (Test with dots in user name) al.ex.is@ \t [ \t m2osw.com \t ] \n (More (comments) there) >",
     121             :       "Alexis Wilke", "al.ex.is", "m2osw.com", "al.ex.is@m2osw.com", "Alexis Wilke <al.ex.is@m2osw.com>" },
     122             :     { "This Group", "",
     123             :       "", "", "", "", "" },
     124             :     { "This Group", "(With full name) Alexis Wilke < \n alexis \t @ \t [ \t m2osw.com \t ] \n (Less) >",
     125             :       "Alexis Wilke", "alexis", "m2osw.com", "alexis@m2osw.com", "Alexis Wilke <alexis@m2osw.com>" },
     126             :     { "People", "",
     127             :       "", "", "", "", "" },
     128             :     { "People", "Alexis Wilke <alexis@m2osw.com>",
     129             :       "Alexis Wilke", "alexis", "m2osw.com", "alexis@m2osw.com", "Alexis Wilke <alexis@m2osw.com>" },
     130             :     { "People", "John Smith <john@m2osw.com>",
     131             :       "John Smith", "john", "m2osw.com", "john@m2osw.com", "John Smith <john@m2osw.com>" },
     132             :     { "Lists", "",
     133             :       "", "", "", "", "" },
     134             :     { "Lists", "Contact <contact@m2osw.com>",
     135             :       "Contact", "contact", "m2osw.com", "contact@m2osw.com", "Contact <contact@m2osw.com>" },
     136             :     { "Lists", "Resume <resume@m2osw.com>",
     137             :       "Resume", "resume", "m2osw.com", "resume@m2osw.com", "Resume <resume@m2osw.com>" },
     138             :     { "", "normal@m2osw.com",
     139             :       "", "normal", "m2osw.com", "normal@m2osw.com", "normal@m2osw.com" },
     140             :     { "No-Reply", "",
     141             :       "", "", "", "", "" },
     142             :     { "No-Reply", "no-reply@m2osw.com",
     143             :       "", "no-reply", "m2osw.com", "no-reply@m2osw.com", "no-reply@m2osw.com" },
     144             :     { "", "\"Complex <name> for !a! \\\"USER\\\"\" <user@example.co.uk>",
     145             :       "Complex <name> for !a! \"USER\"", "user", "example.co.uk", "user@example.co.uk", "\"Complex <name> for !a! \\\"USER\\\"\" <user@example.co.uk>" },
     146             :     { "", "(Comment \n New-Line) alexis@m2osw.com",
     147             :       "", "alexis", "m2osw.com", "alexis@m2osw.com", "alexis@m2osw.com" },
     148             :     { "", "(Comment (Sub-Comment (Sub-Sub-Comment (Sub-Sub-Sub-Comment \\) This is still the Sub-Sub-Sub-Comment!!!)))) alexis@m2osw.com",
     149             :       "", "alexis", "m2osw.com", "alexis@m2osw.com", "alexis@m2osw.com" },
     150             :     { "Group with  some sub-comments", "",
     151             :       "", "", "", "", "" },
     152             :     { "Group with  some sub-comments", "alexis@m2osw.com",
     153             :       "", "alexis", "m2osw.com", "alexis@m2osw.com", "alexis@m2osw.com" },
     154             :     // TBD: since the colons get canonicalized to %3A we do not need the '[' and ']' in the canonicalized version
     155             :     { "", "\"Wilke, Alexis\" <\"alexis,wilke\"@[:special:.m2osw.com]>",
     156             :       "Wilke, Alexis", "alexis,wilke", ":special:.m2osw.com", "\"alexis,wilke\"@[:special:.m2osw.com]", "\"Wilke, Alexis\" <\"alexis,wilke\"@%3Aspecial%3A.m2osw.com>" },
     157             :     { "", "alexis@m2osw.com (Simple Comment)",
     158             :       "", "alexis", "m2osw.com", "alexis@m2osw.com", "alexis@m2osw.com" },
     159             : #endif
     160             : 
     161             :     { NULL, NULL, NULL, NULL, NULL, NULL, NULL }
     162             : };
     163             : 
     164             : /// The list of valid emails used to check the parser out.
     165             : const valid_email list_of_valid_emails[] =
     166             : {
     167             :     { "MAILER-DAEMON@mail.exdox.com (Mail Delivery System)", 1},
     168             : #if 1
     169             :     { "alexis@m2osw.com", 1 },
     170             :     { "a@m2osw.com", 1 },
     171             :     { "b@c.com", 1 },
     172             :     { " \t alexis@m2osw.com\n \t", 1 },
     173             :     { "\"Wilke, Alexis\" <alexis@m2osw.com>", 1 },
     174             :     { " (* Pascal Comments *) \t alexis@m2osw.com\n (Just (kidding) he! he!) \t", 1 },
     175             :     { "(Start-Comment)alexis@ \t [ \t m2osw.com \t ] \n (More (comment) here) \r\n\t", 1 },
     176             :     { "(Test with dots in user name) al.ex.is@ \t [ \t m2osw.com \t ] \n (More (comments) there) \r\n\t", 1 },
     177             :     { "< (Test with dots in user name) al.ex.is@ \t [ \t m2osw.com \t ] \n (More (comments) there) > \r\n\t", 1 },
     178             :     { "(With full name) Alexis Wilke < (Test with dots in user name) al.ex.is@ \t [ \t m2osw.com \t ] \n (More (comments) there) > \r\n\t", 1 },
     179             :     { "  (Now a group:) This Group: (With full name) Alexis Wilke < \n alexis \t @ \t [ \t m2osw.com \t ] \n (Less) >; \r\n\t", 2 },
     180             :     { "People: Alexis Wilke <alexis@m2osw.com>, John Smith <john@m2osw.com>; Lists: Contact <contact@m2osw.com>, Resume <resume@m2osw.com>; normal@m2osw.com, No-Reply: no-reply@m2osw.com;", 9 },
     181             :     { "\"Complex <name> for !a! \\\"USER\\\"\" <user@example.co.uk>", 1 },
     182             :     { "(Comment \n New-Line) alexis@m2osw.com", 1 },
     183             :     { "(Comment (Sub-Comment (Sub-Sub-Comment (Sub-Sub-Sub-Comment \\) This is still the Sub-Sub-Sub-Comment!!!)))) alexis@m2osw.com", 1 },
     184             :     { "Group with (Comment (Sub-Comment (Sub-Sub-Comment (Sub-Sub-Sub-Comment \\) This is still the Sub-Sub-Sub-Comment!!!)))) some sub-comments \t : alexis@m2osw.com;", 2 },
     185             :     { "\"Wilke, Alexis\" <\"alexis,wilke\"@[:special:.m2osw.com]>", 1 },
     186             :     { "alexis@m2osw.com (Simple Comment)", 1 },
     187             : #endif
     188             : 
     189             :     // end of list
     190             :     { NULL, 0 }
     191             : };
     192             : 
     193             : 
     194             : /** \brief Transform an email string in a C-like string.
     195             :  *
     196             :  * This function transforms the characters in \p e into a set of C-like
     197             :  * escape characters so it can safely be printed in the console.
     198             :  *
     199             :  * For example, the character 0x09 is transformed to the character \\t.
     200             :  *
     201             :  * \param[in] e  The email to be transformed.
     202             :  *
     203             :  * \return The transformed email.
     204             :  */
     205           0 : std::string email_to_vstring(const std::string& e)
     206             : {
     207           0 :     std::string result;
     208             :     char buf[3];
     209             : 
     210           0 :     for(const char *s(e.c_str()); *s != '\0'; ++s)
     211             :     {
     212           0 :         if(static_cast<unsigned char>(*s) < ' ')
     213             :         {
     214           0 :             switch(*s)
     215             :             {
     216           0 :             case '\a': result += "\\a"; break;
     217           0 :             case '\b': result += "\\b"; break;
     218           0 :             case '\f': result += "\\f"; break;
     219           0 :             case '\n': result += "\\n"; break;
     220           0 :             case '\r': result += "\\r"; break;
     221           0 :             case '\t': result += "\\t"; break;
     222           0 :             case '\v': result += "\\v"; break;
     223             :             default:
     224           0 :                 buf[0] = '^';
     225           0 :                 buf[1] = *s + '@';
     226           0 :                 buf[2] = '\0';
     227           0 :                 result += buf;
     228           0 :                 break;
     229             : 
     230             :            }
     231             :         }
     232           0 :         else if(*s == 0x7F)
     233             :         {
     234           0 :             result += "<DEL>";
     235             :         }
     236           0 :         else if(static_cast<unsigned char>(*s) > 0x80)
     237             :         {
     238             :             static const char *hc = "0123456789ABCDEF";
     239           0 :             result += "\\x";
     240           0 :             buf[0] = hc[*s >> 4];
     241           0 :             buf[1] = hc[*s & 15];
     242           0 :             buf[2] = '\0';
     243           0 :             result += buf;
     244             :         }
     245             :         else
     246             :         {
     247           0 :             result += *s;
     248             :         }
     249             :     }
     250             : 
     251           0 :     return result;
     252             : }
     253             : 
     254             : 
     255           1 : void test_valid_emails()
     256             : {
     257           1 :     const tld_email *results(list_of_results);
     258          20 :     for(const valid_email *v(list_of_valid_emails); v->f_input_email != NULL; ++v)
     259             :     {
     260          19 :         if(verbose)
     261             :         {
     262           0 :             printf("*** testing email \"%s\", start with C++ test\n", email_to_vstring(v->f_input_email).c_str());
     263           0 :             fflush(stdout);
     264             :         }
     265             : 
     266          19 :         const tld_email * const cresults(results);
     267             : 
     268             :         // C++ test
     269             :         {
     270          38 :             tld_email_list list;
     271          19 :             tld_result r(list.parse(v->f_input_email, 0));
     272          19 :             int max(v->f_count);
     273          19 :             if(r != TLD_RESULT_SUCCESS)
     274             :             {
     275           0 :                 fprintf(stderr, "return value is %d instead of %d with [%s]\n", r, TLD_RESULT_SUCCESS, v->f_input_email);
     276           0 :                 error("error: unexpected return value.");
     277           0 :                 results += max;
     278             :             }
     279          19 :             else if(list.count() != max)
     280             :             {
     281           0 :                 fprintf(stderr, "parse() returned %d as count, expected %d\n", list.count(), max);
     282           0 :                 error("error: unexpected count");
     283           0 :                 results += max;
     284             :             }
     285             :             else
     286             :             {
     287             :                 // test the C++ function first
     288             :                 {
     289          38 :                     tld_email_list::tld_email_t e;
     290          48 :                     for(int i(0); i < max; ++i, ++results)
     291             :                     {
     292          29 :                         if(results->f_group == NULL)
     293             :                         {
     294           0 :                             error("error: end of results array reached before completion of the test.\n");
     295           0 :                             return;
     296             :                         }
     297             : 
     298          29 :                         if(!list.next(e))
     299             :                         {
     300           0 :                             error("error: next() returned false too soon.");
     301             :                         }
     302          29 :                         if(e.f_group != results->f_group)
     303             :                         {
     304           0 :                             error("error: next() returned the wrong group. Got \"" + e.f_group + "\" instead of \"" + results->f_group + "\".");
     305             :                         }
     306          29 :                         if(e.f_original_email != results->f_original_email)
     307             :                         {
     308           0 :                             error("error: next() returned the wrong original email. Got \"" + e.f_original_email + "\" instead of \"" + results->f_original_email + "\".");
     309             :                         }
     310          29 :                         if(e.f_fullname != results->f_fullname)
     311             :                         {
     312           0 :                             error("error: next() returned the wrong fullname. Got \"" + e.f_fullname + "\" instead of \"" + results->f_fullname + "\".");
     313             :                         }
     314          29 :                         if(e.f_username != results->f_username)
     315             :                         {
     316           0 :                             error("error: next() returned the wrong username. Got \"" + e.f_username + "\" instead of \"" + results->f_username + "\".");
     317             :                         }
     318          29 :                         if(e.f_domain != results->f_domain)
     319             :                         {
     320           0 :                             error("error: next() returned the wrong username. Got \"" + e.f_domain + "\" instead of \"" + results->f_domain + "\".");
     321             :                         }
     322          29 :                         if(e.f_email_only != results->f_email_only)
     323             :                         {
     324           0 :                             error("error: next() returned the wrong email only. Got \"" + e.f_email_only + "\" instead of \"" + results->f_email_only + "\".");
     325             :                         }
     326          29 :                         if(e.f_canonicalized_email != results->f_canonicalized_email)
     327             :                         {
     328           0 :                             error("error: next() returned the wrong canonicalized email. Got \"" + e.f_canonicalized_email + "\" instead of \"" + results->f_canonicalized_email + "\".");
     329             :                         }
     330             :                     }
     331          19 :                     if(list.next(e))
     332             :                     {
     333           0 :                         error("error: next(e) returned the wrong result, it should be false after the whole set of emails were read.");
     334             :                     }
     335             :                 }
     336             :                 // try the C function which also allows us to test the rewind()
     337          19 :                 list.rewind();
     338             :                 {
     339          19 :                     results = cresults;
     340             :                     tld_email e;
     341          48 :                     for(int i(0); i < max; ++i, ++results)
     342             :                     {
     343          29 :                         if(!list.next(&e))
     344             :                         {
     345           0 :                             error("error: next() returned false too soon.");
     346             :                         }
     347          29 :                         if(strcmp(e.f_group, results->f_group) != 0)
     348             :                         {
     349           0 :                             error("error: next() returned the wrong group. Got \"" + std::string(e.f_group) + "\" from \"" + results->f_group + "\".");
     350             :                         }
     351          29 :                         if(strcmp(e.f_original_email, results->f_original_email) != 0)
     352             :                         {
     353           0 :                             error("error: next() returned the wrong original email. Got \"" + std::string(e.f_original_email) + "\" instead of \"" + results->f_original_email + "\".");
     354             :                         }
     355          29 :                         if(strcmp(e.f_fullname, results->f_fullname) != 0)
     356             :                         {
     357           0 :                             error("error: next() returned the wrong fullname.");
     358             :                         }
     359          29 :                         if(strcmp(e.f_username, results->f_username) != 0)
     360             :                         {
     361           0 :                             error("error: next() returned the wrong username.");
     362             :                         }
     363          29 :                         if(strcmp(e.f_domain, results->f_domain) != 0)
     364             :                         {
     365           0 :                             error("error: next() returned the wrong username.");
     366             :                         }
     367          29 :                         if(strcmp(e.f_email_only, results->f_email_only) != 0)
     368             :                         {
     369           0 :                             error("error: next() returned the wrong email only.");
     370             :                         }
     371          29 :                         if(strcmp(e.f_canonicalized_email, results->f_canonicalized_email) != 0)
     372             :                         {
     373           0 :                             error("error: next() returned the wrong canonicalized email.");
     374             :                         }
     375             :                     }
     376          19 :                     if(list.next(&e))
     377             :                     {
     378           0 :                         error("error: next(&e) returned the wrong result, it should be false after the whole set of emails were read.");
     379             :                     }
     380             :                 }
     381             :             }
     382             :         }
     383             : 
     384          19 :         if(verbose)
     385             :         {
     386           0 :             printf("*** C test now\n");
     387           0 :             fflush(stdout);
     388             :         }
     389             :         // C test
     390             :         {
     391             :             tld_email_list *list;
     392          19 :             list = tld_email_alloc();
     393          19 :             tld_result r = tld_email_parse(list, v->f_input_email, 0);
     394          19 :             const int max(v->f_count);
     395          19 :             if(r != TLD_RESULT_SUCCESS)
     396             :             {
     397           0 :                 fprintf(stderr, "return value is %d instead of %d for \"%s\"\n", r, TLD_RESULT_SUCCESS, v->f_input_email);
     398           0 :                 error("error: unexpected return value.");
     399             :             }
     400          19 :             else if(tld_email_count(list) != max)
     401             :             {
     402           0 :                 fprintf(stderr, "parse() returned %d as count, expected %d\n", tld_email_count(list), max);
     403           0 :                 error("error: unexpected count");
     404             :             }
     405             :             else
     406             :             {
     407             :                 // test the C++ function first
     408          57 :                 for(int repeat(0); repeat < 2; ++repeat)
     409             :                 {
     410          38 :                     results = cresults;
     411             :                     struct tld_email e;
     412          96 :                     for(int i(0); i < max; ++i, ++results)
     413             :                     {
     414          58 :                         if(results->f_group == NULL)
     415             :                         {
     416           0 :                             error("error: end of results array reached before completion of the test.\n");
     417           0 :                             return;
     418             :                         }
     419             : 
     420          58 :                         if(tld_email_next(list, &e) != 1)
     421             :                         {
     422           0 :                             error("error: next() returned false too soon.");
     423             :                         }
     424          58 :                         if(strcmp(e.f_group, results->f_group) != 0)
     425             :                         {
     426           0 :                             error("error: next() returned the wrong group. Got \"" + std::string(e.f_group) + "\" from \"" + results->f_group + "\".");
     427             :                         }
     428          58 :                         if(strcmp(e.f_original_email, results->f_original_email) != 0)
     429             :                         {
     430           0 :                             error("error: next() returned the wrong original email. Got \"" + std::string(e.f_original_email) + "\" instead of \"" + results->f_original_email + "\".");
     431             :                         }
     432          58 :                         if(strcmp(e.f_fullname, results->f_fullname) != 0)
     433             :                         {
     434           0 :                             error("error: next() returned the wrong fullname.");
     435             :                         }
     436          58 :                         if(strcmp(e.f_username, results->f_username) != 0)
     437             :                         {
     438           0 :                             error("error: next() returned the wrong username.");
     439             :                         }
     440          58 :                         if(strcmp(e.f_domain, results->f_domain) != 0)
     441             :                         {
     442           0 :                             error("error: next() returned the wrong username.");
     443             :                         }
     444          58 :                         if(strcmp(e.f_email_only, results->f_email_only) != 0)
     445             :                         {
     446           0 :                             error("error: next() returned the wrong email only.");
     447             :                         }
     448          58 :                         if(strcmp(e.f_canonicalized_email, results->f_canonicalized_email) != 0)
     449             :                         {
     450           0 :                             error("error: next() returned the wrong canonicalized email.");
     451             :                         }
     452             :                     }
     453          38 :                     if(tld_email_next(list, &e) != 0)
     454             :                     {
     455           0 :                         error("error: next(&e) returned the wrong result, it should be false after the whole set of emails were read.");
     456             :                     }
     457             :                     // try again
     458          38 :                     tld_email_rewind(list);
     459             :                 }
     460             :             }
     461          19 :             tld_email_free(list);
     462             :         }
     463             :     }
     464             : 
     465             :     {
     466             :         // all valid atom characters
     467             :         const char valid_chars[] =
     468             :             "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
     469             :             "abcdefghijklmnopqrstuvwxyz"
     470             :             "0123456789"
     471           1 :             "!#$%&'*+-/=?^_`{|}~" // here there is a NUL
     472             :         ;
     473          82 :         for(size_t i(0); i < sizeof(valid_chars) / sizeof(valid_chars[0]) - 1; ++i)
     474             :         {
     475         162 :             tld_email_list list;
     476         162 :             std::string e("abc");
     477          81 :             e += valid_chars[i];
     478          81 :             e += "def@m2osw.com";
     479          81 :             if(verbose)
     480             :             {
     481           0 :                 printf("*** testing all atom characters with email \"%s\"\n", email_to_vstring(e).c_str());
     482           0 :                 fflush(stdout);
     483             :             }
     484          81 :             tld_result r(list.parse(e, 0));
     485          81 :             if(r != TLD_RESULT_SUCCESS)
     486             :             {
     487           0 :                 fprintf(stderr, "call to list.parse() failed with %d expected %d for email \"%s\" (all valid atom characters)\n", r, TLD_RESULT_SUCCESS, e.c_str());
     488           0 :                 error("error: unexpected return value.");
     489             :             }
     490             :         }
     491             :     }
     492             : 
     493             :     {
     494             :         // all valid quoted characters: " " to "\x7E" except the " and \ characters
     495             :         if(sizeof(int) < 4)
     496             :         {
     497             :             error("error: the ctrl variable needs to be at least 32 bits");
     498             :             return;
     499             :         }
     500           1 :         const int ctrl(1 << '\t');
     501         127 :         for(size_t i(1); i <= 126; ++i)
     502             :         {
     503         126 :             switch(i)
     504             :             {
     505             :             case ' ':   // at this point we disallow the space which causes problems with Snap!
     506             :             case '\t':  // at this point we disallow the tab which causes problems with Snap!
     507             :             case '"':
     508             :             case '\\':
     509             :             case 0x7F:  // not included in the loop anyway
     510           4 :                 break;
     511             : 
     512             :             default:
     513         122 :                 if(i >= ' ' || (ctrl & (1 << i)) != 0)
     514             :                 {
     515         184 :                     tld_email_list list;
     516         184 :                     std::string e("\"abc");
     517          92 :                     e += static_cast<char>(i);
     518          92 :                     e += "def\"@m2osw.com";
     519          92 :                     if(verbose)
     520             :                     {
     521           0 :                         printf("*** testing all atom characters with email \"%s\"\n", email_to_vstring(e).c_str());
     522           0 :                         fflush(stdout);
     523             :                     }
     524          92 :                     tld_result r(list.parse(e, 0));
     525          92 :                     if(r != TLD_RESULT_SUCCESS)
     526             :                     {
     527           0 :                         fprintf(stderr, "call to list.parse() failed with %d expected %d for email \"%s\" (all valid characters)\n", r, TLD_RESULT_SUCCESS, email_to_vstring(e).c_str());
     528           0 :                         error("error: unexpected return value.");
     529             :                     }
     530             :                 }
     531         122 :                 break;
     532             : 
     533             :             }
     534             :         }
     535             :     }
     536             : 
     537             :     {
     538             :         // all valid quoted pair: '\t' and " " to "\x7E"
     539             :         // -- at this time the \t and " " do not work here
     540          95 :         for(size_t i(33); i <= 126; ++i)
     541             :         {
     542         188 :             tld_email_list list;
     543         188 :             std::string e("\"abc\\");
     544          94 :             if(i == 31)
     545             :             {
     546           0 :                 e += static_cast<char>('\t');
     547             :             }
     548             :             else
     549             :             {
     550          94 :                 e += static_cast<char>(i);
     551             :             }
     552          94 :             e += "def\"@m2osw.com";
     553          94 :             if(verbose)
     554             :             {
     555           0 :                 printf("*** testing all atom characters with email \"%s\"\n", email_to_vstring(e).c_str());
     556           0 :                 fflush(stdout);
     557             :             }
     558          94 :             tld_result r(list.parse(e, 0));
     559          94 :             if(r != TLD_RESULT_SUCCESS)
     560             :             {
     561           0 :                 fprintf(stderr, "call to list.parse() failed with %d expected %d for email \"%s\" (all valid quoted pairs)\n", r, TLD_RESULT_SUCCESS, email_to_vstring(e).c_str());
     562           0 :                 error("error: unexpected return value.");
     563             :             }
     564             :         }
     565             :     }
     566             : 
     567             :     {
     568             :         // all valid comment characters: " " to "\x7E" except the " and \ characters
     569             :         if(sizeof(int) < 4)
     570             :         {
     571             :             error("error: the ctrl variable needs to be at least 32 bits");
     572             :             return;
     573             :         }
     574           1 :         const int ctrl((1 << '\t') | (1 << '\r') | (1 << '\n'));
     575         127 :         for(size_t i(1); i <= 126; ++i)
     576             :         {
     577             :             // we skip all the special characters in a comment since
     578             :             // those are already tested somewhere else
     579         126 :             switch(i)
     580             :             {
     581             :             case '(': // avoid a sub-comment
     582             :             case ')': // avoid closing the comment mid-way
     583             :             case '\\':  // tested somewhere else
     584             :             case 0x7F:  // not included in the loop anyway
     585           3 :                 break;
     586             : 
     587             :             default:
     588         123 :                 if(i >= ' ' || (ctrl & (1 << i)) != 0)
     589             :                 {
     590         190 :                     tld_email_list list;
     591         190 :                     std::string e("(Comment \"");
     592          95 :                     e += static_cast<char>(i);
     593          95 :                     e += "\" char.) alexis@m2osw.com";
     594          95 :                     if(verbose)
     595             :                     {
     596           0 :                         printf("*** testing all atom characters with email \"%s\"\n", email_to_vstring(e).c_str());
     597           0 :                         fflush(stdout);
     598             :                     }
     599          95 :                     tld_result r(list.parse(e, 0));
     600          95 :                     if(r != TLD_RESULT_SUCCESS)
     601             :                     {
     602           0 :                         error("error: unexpected return value.");
     603             :                     }
     604             :                 }
     605         123 :                 break;
     606             : 
     607             :             }
     608             :         }
     609             :     }
     610             : 
     611             :     {
     612             :         // all valid domain characters: "!" to "\x7E" except the [, ], and \ characters
     613          95 :         for(size_t i('!'); i <= 126; ++i)
     614             :         {
     615             :             // a dot is valid but we cannot test it between two other dots
     616          94 :             if(i == '[' || i == ']' || i == '\\' || i == '.')
     617             :             {
     618           4 :                 continue;
     619             :             }
     620         180 :             tld_email_list list;
     621         180 :             std::string e("alexis@[ m2osw.");
     622          90 :             e += static_cast<char>(i);
     623          90 :             if(i == '%')
     624             :             {
     625           1 :                 e += "25";
     626             :             }
     627          90 :             e += ".com\t]";
     628          90 :             if(verbose)
     629             :             {
     630           0 :                 printf("*** testing all atom characters with email \"%s\"\n", email_to_vstring(e).c_str());
     631           0 :                 fflush(stdout);
     632             :             }
     633          90 :             tld_result r(list.parse(e, 0));
     634          90 :             if(r != TLD_RESULT_SUCCESS)
     635             :             {
     636           0 :                 error("error: unexpected return value while testing a domain with special character \"" + e + "\"");
     637             :             }
     638             :         }
     639             :     }
     640             : 
     641             :     {
     642           1 :         if(tld_email_list::quote_string("Test quoting a simple comment", '(') != "(Test quoting a simple comment)")
     643             :         {
     644           0 :             error("error: unexpected return value when testing a simple comment quotation");
     645             :         }
     646           1 :         if(tld_email_list::quote_string("Test (quoting) a complex )comment(", '(') != "(Test \\(quoting\\) a complex \\)comment\\()")
     647             :         {
     648           0 :             error("error: unexpected return value when testing a complex comment quotation");
     649             :         }
     650             :     }
     651             : }
     652             : 
     653             : 
     654             : 
     655             : 
     656             : /** \brief Define an invalid email.
     657             :  *
     658             :  * This structure is used to list invalid emails in order to test that such
     659             :  * emails are not accepted by the parser. The structure includes the expected
     660             :  * result as well as a string pointer to the invalid email.
     661             :  */
     662             : struct invalid_email
     663             : {
     664             :     /// The expected reslut, if the call does not return this exact value the test fails
     665             :     tld_result          f_result;
     666             :     /// The pointer to the invalid email to be tested
     667             :     const char *        f_input_email;
     668             : };
     669             : 
     670             : const invalid_email list_of_invalid_emails[] =
     671             : {
     672             :     { TLD_RESULT_NULL, "alexism2osw.com (missing @)" },
     673             :     { TLD_RESULT_INVALID, "doug barbieri@m2osw.com\n \t (space in email address)" },
     674             :     { TLD_RESULT_NO_TLD, "doug_barbieri@m2osw com\n \t (space in email domain)" },
     675             :     { TLD_RESULT_NOT_FOUND, "doug_barbieri@m2osw.com  org    (space in email domain after dot)" },
     676             :     { TLD_RESULT_NOT_FOUND, "<doug_barbieri@m2osw.com  org>  (space in email domain after dot)" },
     677             :     { TLD_RESULT_INVALID, "<doug_barbieri@this sub domain.m2osw.com>  (space in email domain after dot)" },
     678             :     { TLD_RESULT_INVALID, " \v alexis@m2osw.com\n \t (bad control)" },
     679             :     { TLD_RESULT_INVALID, " (* Pascal Comments *) \t alexis@m2osw.com\n (missing closing parenthesis\\)" },
     680             :     { TLD_RESULT_INVALID, "(Start-Comment)alexis@ \t [ \t m2osw.com \t ] \n (extra after domain done) \"more\tdata\" \r\n\t" },
     681             :     { TLD_RESULT_INVALID, "(Test with dots in user name) al.ex.is@ \t(missing closing bracket ]) [ \t m2osw.com \t " },
     682             :     { TLD_RESULT_NULL, "< (Test with dots in user name) al.ex.is@ \t [ \t m2osw.com \t ] \n (Missing >) \r\n\t" },
     683             :     { TLD_RESULT_INVALID, "(Full name with period) Alexis.Wilke < (Test with dots in user name) al.ex.is@ \t [ \t m2osw.com \t ] \n (More (comments) there) > \r\n\t" },
     684             :     { TLD_RESULT_INVALID, "  (Now a group:) This Group: (With full name) Alexis Wilke < \n alexis \t @ \t [ \t m2osw.com \t ] \n (missing ;) > \r\n\t" },
     685             :     { TLD_RESULT_INVALID, "Good Group: alexis@m2osw.com, bad-group: test@example.com;" },
     686             :     { TLD_RESULT_INVALID, "(No Group Name): alexis@m2osw.com;" },
     687             :     { TLD_RESULT_INVALID, " (No Group Name) : alexis@m2osw.com;" },
     688             :     { TLD_RESULT_INVALID, ": alexis@m2osw.com;" },
     689             :     { TLD_RESULT_INVALID, "(Group with CTRL) Group \v Unexpected: alexis@m2osw.com;" },
     690             :     { TLD_RESULT_INVALID, "\"alexis@m2osw.com;" },
     691             :     { TLD_RESULT_INVALID, "\"alexis@m2osw.com;\v\"" },
     692             :     { TLD_RESULT_NO_TLD, "alexis@m2osw.com, valid@group.com; alexis@m2osw.com, invalid@group" },
     693             :     { TLD_RESULT_NO_TLD, "alexis@m2osw.com, valid@group.com; alexis@m2osw.com, invalid@group;" },
     694             :     { TLD_RESULT_NOT_FOUND, "alexis@m2osw.com, valid@group.com; alexis@m2osw.com, invalid@unknown.tld" },
     695             :     { TLD_RESULT_NOT_FOUND, "alexis@m2osw.com, valid@group.com; alexis@m2osw.com, invalid@unknown.tld;" },
     696             :     { TLD_RESULT_INVALID, "\"Alexis Wilke\\" },  // \ followed by NUL
     697             :     { TLD_RESULT_INVALID, "(Comment with \\\\ followed by NUL: \\" },
     698             :     { TLD_RESULT_INVALID, "(Test Errors Once Done) \"Wilke, Alexis\" <alexis@m2osw.com> \"Bad\"" },
     699             :     { TLD_RESULT_INVALID, "(Comment with CTRL \b) \"Wilke, Alexis\" <alexis@m2osw.com>" },
     700             :     { TLD_RESULT_INVALID, "[m2osw.com]" }, // missing user name
     701             :     { TLD_RESULT_INVALID, "good@[bad-slash\\.com]" },
     702             :     { TLD_RESULT_INVALID, "good@[bad[reopen.com]" },
     703             :     { TLD_RESULT_INVALID, "good@[bad-duplicate.com] more.net" }, // two domains
     704             :     { TLD_RESULT_INVALID, "(Test Errors Once Done) \"Wilke, Alexis\" <alexis@m2osw.com> [Bad]" },
     705             :     { TLD_RESULT_INVALID, "(Test Errors Once Done) alexis@start[Bad]" },
     706             :     { TLD_RESULT_INVALID, "(Test Errors Once Done) alexis@[first][Bad]" },
     707             :     { TLD_RESULT_INVALID, "(Test Errors Once Done) alexis@[control:\v]" },
     708             :     { TLD_RESULT_NULL, "(Test Errors Once Done) alexis@[ spaces BAD]" },
     709             :     { TLD_RESULT_NULL, "(Wind Domain...) alexis@[    ]" },
     710             :     { TLD_RESULT_NULL, "(More Spaces Test) alexis@[no-left-trim no-right-trim]" },
     711             :     { TLD_RESULT_NULL, "(Dot Dot Dot Domain) alexis@[ . . . ]" },
     712             :     { TLD_RESULT_INVALID, "(Dot Only Domain) alexis@[ . ]" },
     713             :     { TLD_RESULT_INVALID, "(Spurious Angle) alexis>@m2osw.com" },
     714             :     { TLD_RESULT_INVALID, "(Spurious Angle) alexis@m2osw.com>" },
     715             :     { TLD_RESULT_INVALID, "(Double Angle) <alexis@m2osw.com>>" },
     716             :     { TLD_RESULT_NULL, "(Missing domain) <alexis@>" },
     717             :     { TLD_RESULT_NULL, "(Missing domain) alexis@" },
     718             :     { TLD_RESULT_INVALID, "(2 domains) <alexis@[m2osw.com]bad>" },
     719             :     { TLD_RESULT_INVALID, "(Double @) <alexis@m2osw.com> @" },
     720             :     { TLD_RESULT_INVALID, "(Double @) alexis@m2osw.com@" },
     721             :     { TLD_RESULT_INVALID, "(Extra Chars) <alexis@m2osw.com> bad" },
     722             :     { TLD_RESULT_NULL, "(Empty username within brackets) <@m2osw.com>" },
     723             :     { TLD_RESULT_NULL, "(Empty User Name) @m2osw.com" },
     724             :     { TLD_RESULT_INVALID, "(Cannot start with a dot) .alexis@m2osw.com" },
     725             :     { TLD_RESULT_INVALID, "(Cannot start with a dot) <.alexis@m2osw.com>" },
     726             :     { TLD_RESULT_INVALID, "(Cannot end with a dot) alexis.@m2osw.com" },
     727             :     { TLD_RESULT_INVALID, "(Cannot end with a dot) <alexis.@m2osw.com>" },
     728             :     { TLD_RESULT_INVALID, "(Cannot include double dots) ale..xis@m2osw.com" },
     729             :     { TLD_RESULT_NOT_FOUND, "(End domain with dot not considered valid!) alexis@m2osw.com." },
     730             :     { TLD_RESULT_INVALID, "(End domain with dot not considered valid!) <alexis@m2osw.com.>" },
     731             :     { TLD_RESULT_NULL, "(Bad Emails) alexis,m2osw.com" },
     732             :     { TLD_RESULT_INVALID, "(Bad Char) alexis@m2osw\001com" },
     733             :     { TLD_RESULT_NOT_FOUND, "(Bad Extension) alexis@m2osw.comm" },
     734             :     { TLD_RESULT_INVALID, "(Bad Extension) alexis@m2osw.ar" },
     735             :     { TLD_RESULT_INVALID, "(Bad Extension) alexis@m2osw.nom.ar" },
     736             :     { TLD_RESULT_NO_TLD, "(Bad Extension) alexis@m2osw" },
     737             :     { TLD_RESULT_INVALID, "(Bad Extension) alexis@[m2osw..com]" },
     738             : 
     739             :     // end of list
     740             :     { TLD_RESULT_SUCCESS, NULL }
     741             : };
     742             : 
     743           1 : void test_invalid_emails()
     744             : {
     745          67 :     for(const invalid_email *v(list_of_invalid_emails); v->f_input_email != NULL; ++v)
     746             :     {
     747          66 :         if(verbose)
     748             :         {
     749           0 :             printf("+++ testing email \"%s\"\n", email_to_vstring(v->f_input_email).c_str());
     750             :         }
     751             : 
     752             :         // C++ test
     753             :         {
     754         132 :             tld_email_list list;
     755          66 :             tld_result r(list.parse(v->f_input_email, 0));
     756          66 :             if(r != v->f_result)
     757             :             {
     758           0 :                 std::stringstream ss;
     759           0 :                 ss << "error: unexpected return value. Got " << static_cast<int>(r) << ", expected " << static_cast<int>(v->f_result) << " for \"" << v->f_input_email << "\" (C++)";
     760           0 :                 error(ss.str());
     761             :             }
     762             :         }
     763             : 
     764             :         // C test
     765             :         {
     766             :             tld_email_list *list;
     767          66 :             list = tld_email_alloc();
     768          66 :             tld_result r = tld_email_parse(list, v->f_input_email, 0);
     769          66 :             if(r != v->f_result)
     770             :             {
     771           0 :                 std::stringstream ss;
     772           0 :                 ss << "error: unexpected return value. Got " << static_cast<int>(r) << ", expected " << static_cast<int>(v->f_result) << " for \"" << v->f_input_email << "\" (C)";
     773           0 :                 error(ss.str());
     774             :             }
     775          66 :             tld_email_free(list);
     776          66 :             list = NULL;
     777             :         }
     778             :     }
     779           1 : }
     780             : 
     781             : 
     782           6 : void contract_furfilled(tld_email_list::tld_email_t & e)
     783             : {
     784          12 :     if(!e.f_group.empty()
     785           6 :     || !e.f_original_email.empty()
     786           6 :     || !e.f_fullname.empty()
     787           6 :     || !e.f_username.empty()
     788           6 :     || !e.f_domain.empty()
     789           6 :     || !e.f_email_only.empty()
     790          12 :     || !e.f_canonicalized_email.empty())
     791             :     {
     792           0 :         error("error: one of the structure parameters was modified on error!");
     793             :     }
     794           6 : }
     795             : 
     796             : 
     797           1 : void test_direct_email()
     798             : {
     799           2 :     tld_email_list::tld_email_t email;
     800             : 
     801             :     ////////////// EMAILS
     802             :     // missing closing \"
     803           2 :     EXPECTED_THROW(email.parse("\"blah alexis@m2osw.com"), std::logic_error);
     804           1 :     contract_furfilled(email);
     805             : 
     806             :     // missing closing )
     807           2 :     EXPECTED_THROW(email.parse("(comment alexis@m2osw.com"), std::logic_error);
     808           1 :     contract_furfilled(email);
     809             : 
     810             :     // use of \ at the end of the comment
     811           2 :     EXPECTED_THROW(email.parse("(comment\\"), std::logic_error);
     812           1 :     contract_furfilled(email);
     813             : 
     814             :     // missing closing ]
     815           2 :     EXPECTED_THROW(email.parse("alexis@[m2osw.com"), std::logic_error);
     816           1 :     contract_furfilled(email);
     817             : 
     818             :     ////////////// GROUP
     819             :     // missing closing )
     820           2 :     EXPECTED_THROW(email.parse_group("Group (comment"), std::logic_error);
     821           1 :     contract_furfilled(email);
     822             : 
     823             :     // use of \ at the end of the comment
     824           2 :     EXPECTED_THROW(email.parse_group("Group (comment \\"), std::logic_error);
     825           1 :     contract_furfilled(email);
     826           1 : }
     827             : 
     828             : 
     829             : 
     830             : /** \brief Structure used to define a set of fields to test.
     831             :  *
     832             :  * This structure is used in this test to define a list of fields
     833             :  * to test against the library.
     834             :  */
     835             : struct email_field_types
     836             : {
     837             :     const char *            f_field;
     838             :     tld_email_field_type    f_type;
     839             : };
     840             : 
     841             : /** \var email_field_types::f_field
     842             :  * \brief The name of the field to be tested.
     843             :  */
     844             : /** \var email_field_types::f_type
     845             :  * \brief The type we expect the library to return for that field.
     846             :  */
     847             : 
     848             : const email_field_types list_of_email_field_types[] =
     849             : {
     850             :     // make sure case does not have side effects
     851             :     { "to", TLD_EMAIL_FIELD_TYPE_ADDRESS_LIST },
     852             :     { "To", TLD_EMAIL_FIELD_TYPE_ADDRESS_LIST },
     853             :     { "tO", TLD_EMAIL_FIELD_TYPE_ADDRESS_LIST },
     854             :     { "TO", TLD_EMAIL_FIELD_TYPE_ADDRESS_LIST },
     855             : 
     856             :     // check all fields that are expected to include emails
     857             :     { "from", TLD_EMAIL_FIELD_TYPE_MAILBOX_LIST },
     858             :     { "resent-from", TLD_EMAIL_FIELD_TYPE_MAILBOX_LIST },
     859             :     { "sender", TLD_EMAIL_FIELD_TYPE_MAILBOX },
     860             :     { "resent-sender", TLD_EMAIL_FIELD_TYPE_MAILBOX },
     861             :     { "to", TLD_EMAIL_FIELD_TYPE_ADDRESS_LIST },
     862             :     { "cc", TLD_EMAIL_FIELD_TYPE_ADDRESS_LIST },
     863             :     { "reply-to", TLD_EMAIL_FIELD_TYPE_ADDRESS_LIST },
     864             :     { "resent-to", TLD_EMAIL_FIELD_TYPE_ADDRESS_LIST },
     865             :     { "resent-cc", TLD_EMAIL_FIELD_TYPE_ADDRESS_LIST },
     866             :     { "bcc", TLD_EMAIL_FIELD_TYPE_ADDRESS_LIST_OPT },
     867             :     { "resent-bcc", TLD_EMAIL_FIELD_TYPE_ADDRESS_LIST_OPT },
     868             : 
     869             :     // check all fields with a colon
     870             :     { "from: someone", TLD_EMAIL_FIELD_TYPE_MAILBOX_LIST },
     871             :     { "resent-from: someone", TLD_EMAIL_FIELD_TYPE_MAILBOX_LIST },
     872             :     { "sender: someone", TLD_EMAIL_FIELD_TYPE_MAILBOX },
     873             :     { "resent-sender: someone", TLD_EMAIL_FIELD_TYPE_MAILBOX },
     874             :     { "to: someone", TLD_EMAIL_FIELD_TYPE_ADDRESS_LIST },
     875             :     { "cc: someone", TLD_EMAIL_FIELD_TYPE_ADDRESS_LIST },
     876             :     { "reply-to: someone", TLD_EMAIL_FIELD_TYPE_ADDRESS_LIST },
     877             :     { "resent-to: someone", TLD_EMAIL_FIELD_TYPE_ADDRESS_LIST },
     878             :     { "resent-cc: someone", TLD_EMAIL_FIELD_TYPE_ADDRESS_LIST },
     879             :     { "bcc: someone", TLD_EMAIL_FIELD_TYPE_ADDRESS_LIST_OPT },
     880             :     { "resent-bcc: someone", TLD_EMAIL_FIELD_TYPE_ADDRESS_LIST_OPT },
     881             : 
     882             :     // check other fields
     883             :     { "message-id", TLD_EMAIL_FIELD_TYPE_UNKNOWN },
     884             :     { "date", TLD_EMAIL_FIELD_TYPE_UNKNOWN },
     885             :     { "subject", TLD_EMAIL_FIELD_TYPE_UNKNOWN },
     886             :     { "x-extension", TLD_EMAIL_FIELD_TYPE_UNKNOWN },
     887             : 
     888             :     // check other fields with a colon
     889             :     { "message-id: something", TLD_EMAIL_FIELD_TYPE_UNKNOWN },
     890             :     { "date: something", TLD_EMAIL_FIELD_TYPE_UNKNOWN },
     891             :     { "subject: something", TLD_EMAIL_FIELD_TYPE_UNKNOWN },
     892             :     { "x-extension: something", TLD_EMAIL_FIELD_TYPE_UNKNOWN },
     893             : 
     894             :     // check for invalid field names
     895             :     { "s\xfc\x62ject", TLD_EMAIL_FIELD_TYPE_INVALID },
     896             :     { "subj\xe9\x63t", TLD_EMAIL_FIELD_TYPE_INVALID },
     897             :     { "-bad-dash", TLD_EMAIL_FIELD_TYPE_INVALID },
     898             :     { "0bad-digit", TLD_EMAIL_FIELD_TYPE_INVALID },
     899             :     { "1bad-digit", TLD_EMAIL_FIELD_TYPE_INVALID },
     900             :     { "2bad-digit", TLD_EMAIL_FIELD_TYPE_INVALID },
     901             :     { "3bad-digit", TLD_EMAIL_FIELD_TYPE_INVALID },
     902             :     { "4bad-digit", TLD_EMAIL_FIELD_TYPE_INVALID },
     903             :     { "5bad-digit", TLD_EMAIL_FIELD_TYPE_INVALID },
     904             :     { "6bad-digit", TLD_EMAIL_FIELD_TYPE_INVALID },
     905             :     { "7bad-digit", TLD_EMAIL_FIELD_TYPE_INVALID },
     906             :     { "8bad-digit", TLD_EMAIL_FIELD_TYPE_INVALID },
     907             :     { "9bad-digit", TLD_EMAIL_FIELD_TYPE_INVALID },
     908             :     { "" /*empty*/, TLD_EMAIL_FIELD_TYPE_INVALID },
     909             : };
     910             : 
     911           1 : void test_email_field_types()
     912             : {
     913          49 :     for(size_t i(0); i < sizeof(list_of_email_field_types) / sizeof(list_of_email_field_types[0]); ++i)
     914             :     {
     915          48 :         tld_email_field_type type(tld_email_list::email_field_type(list_of_email_field_types[i].f_field));
     916          48 :         if(type != list_of_email_field_types[i].f_type)
     917             :         {
     918           0 :             std::stringstream ss;
     919           0 :             ss << "error: email type mismatch for \"" << list_of_email_field_types[i].f_field
     920           0 :                 << "\", expected " << static_cast<int>(list_of_email_field_types[i].f_type)
     921           0 :                 << ", got " << static_cast<int>(type) << " instead.";
     922           0 :             error(ss.str());
     923             :         }
     924             :     }
     925           1 : }
     926             : 
     927             : 
     928             : 
     929           1 : int main(int argc, char *argv[])
     930             : {
     931           1 :     printf("testing tld emails version %s\n", tld_version());
     932             : 
     933           1 :     if(argc > 1)
     934             :     {
     935           0 :         if(strcmp(argv[1], "-v") == 0)
     936             :         {
     937           0 :             verbose = 1;
     938             :         }
     939             :     }
     940             : 
     941             :     /* Call all the tests, one by one.
     942             :      *
     943             :      * Failures are "recorded" in the err_count global variable
     944             :      * and the process stops with an error message and exit(1)
     945             :      * if err_count is not zero.
     946             :      *
     947             :      * Exceptions that should not occur are expected to also
     948             :      * be caught and reported as errors.
     949             :      */
     950             :     try
     951             :     {
     952           1 :         test_valid_emails();
     953           1 :         test_invalid_emails();
     954           1 :         test_direct_email();
     955           1 :         test_email_field_types();
     956             :     }
     957           0 :     catch(const invalid_domain&)
     958             :     {
     959           0 :         error("error: caught an exception when all emails are expected to be valid.");
     960             :     }
     961             : 
     962           1 :     if(err_count)
     963             :     {
     964           0 :         fprintf(stderr, "%d error%s occured.\n",
     965           0 :                     err_count, err_count != 1 ? "s" : "");
     966             :     }
     967           1 :     exit(err_count ? 1 : 0);
     968             : }
     969             : 
     970             : /* vim: ts=4 sw=4 et
     971             :  */

Generated by: LCOV version 1.12