1 ////////////////////////////////////////////////////////////////////////////////
2 //
3 // Copyright 2006 - 2021, Paul Beckingham, Federico Hernandez.
4 //
5 // Permission is hereby granted, free of charge, to any person obtaining a copy
6 // of this software and associated documentation files (the "Software"), to deal
7 // in the Software without restriction, including without limitation the rights
8 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 // copies of the Software, and to permit persons to whom the Software is
10 // furnished to do so, subject to 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 MERCHANTABILITY,
17 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18 // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 // SOFTWARE.
22 //
23 // http://www.opensource.org/licenses/mit-license.php
24 //
25 ////////////////////////////////////////////////////////////////////////////////
26 
27 #include <cmake.h>
28 #include <shared.h>
29 #include <test.h>
30 
31 ////////////////////////////////////////////////////////////////////////////////
main(int,char **)32 int main (int, char**)
33 {
34   UnitTest t (204);
35 
36   // void wrapText (std::vector <std::string>& lines, const std::string& text, const int width, bool hyphenate)
37   std::string text = "This is a test of the line wrapping code.";
38   std::vector <std::string> lines;
39   wrapText (lines, text, 10, true);
40   t.is (lines.size (), (size_t) 5, "wrapText 'This is a test of the line wrapping code.' -> total 5 lines");
41   t.is (lines[0], "This is a",     "wrapText line 0 -> 'This is a'");
42   t.is (lines[1], "test of",       "wrapText line 1 -> 'test of'");
43   t.is (lines[2], "the line",      "wrapText line 2 -> 'the line'");
44   t.is (lines[3], "wrapping",      "wrapText line 3 -> 'wrapping'");
45   t.is (lines[4], "code.",         "wrapText line 4 -> 'code.'");
46 
47   text = "This ☺ is a test of utf8 line extraction.";
48   lines.clear ();
49   wrapText (lines, text, 7, true);
50   t.is (lines.size (), (size_t) 7, "wrapText 'This ☺ is a test of utf8 line extraction.' -> total 7 lines");
51   t.is (lines[0], "This ☺",        "wrapText line 0 -> 'This ☺'");
52   t.is (lines[1], "is a",          "wrapText line 1 -> 'is a'");
53   t.is (lines[2], "test of",       "wrapText line 2 -> 'test of'");
54   t.is (lines[3], "utf8",          "wrapText line 3 -> 'utf8'");
55   t.is (lines[4], "line",          "wrapText line 4 -> 'line'");
56   t.is (lines[5], "extrac-",       "wrapText line 5 -> 'extrac-'");
57   t.is (lines[6], "tion.",         "wrapText line 6 -> 'tion.'");
58 
59   text = "one two three\n  four";
60   lines.clear ();
61   wrapText (lines, text, 13, true);
62   t.is (lines.size (), (size_t) 2, "wrapText 'one two three\\n  four' -> 2 lines");
63   t.is (lines[0], "one two three", "wrapText line 0 -> 'one two three'");
64   t.is (lines[1], "  four",        "wrapText line 1 -> '  four'");
65 
66   // void extractLine (std::string& text, std::string& line, int length, bool hyphenate, unsigned int& offset)
67   text = "This ☺ is a test of utf8 line extraction.";
68   unsigned int offset = 0;
69   std::string line;
70   extractLine (line, text, 7, true, offset);
71   t.is (line, "This ☺", "extractLine 7 'This ☺ is a test of utf8 line extraction.' -> 'This ☺'");
72 
73   // void extractLine (std::string& text, std::string& line, int length, bool hyphenate, unsigned int& offset)
74   text = "line 1\nlengthy second line that exceeds width";
75   offset = 0;
76   extractLine (line, text, 10, true, offset);
77   t.is (line, "line 1", "extractLine 10 'line 1\\nlengthy second line that exceeds width' -> 'line 1'");
78 
79   extractLine (line, text, 10, true, offset);
80   t.is (line, "lengthy", "extractLine 10 'lengthy second line that exceeds width' -> 'lengthy'");
81 
82   extractLine (line, text, 10, true, offset);
83   t.is (line, "second", "extractLine 10 'second line that exceeds width' -> 'second'");
84 
85   extractLine (line, text, 10, true, offset);
86   t.is (line, "line that", "extractLine 10 'line that exceeds width' -> 'line that'");
87 
88   extractLine (line, text, 10, true, offset);
89   t.is (line, "exceeds", "extractLine 10 'exceeds width' -> 'exceeds'");
90 
91   extractLine (line, text, 10, true, offset);
92   t.is (line, "width", "extractLine 10 'width' -> 'width'");
93 
94   t.notok (extractLine (line, text, 10, true, offset), "extractLine 10 '' -> ''");
95 
96   text = "AAAAAAAAAABBBBBBBBBB";
97   offset = 0;
98   extractLine (line, text, 10, true, offset);
99   t.is (line, "AAAAAAAAA-", "extractLine hyphenated unbreakable line");
100   t.diag (line);
101 
102 /*
103   TODO Resolve above against below, from Taskwarrior 2.6.0
104 
105   // void extractLine (std::string& text, std::string& line, int length, bool hyphenate, unsigned int& offset)
106   std::string text = "This ☺ is a test of utf8 line extraction.";
107   unsigned int offset = 0;
108   std::string line;
109   extractLine (line, text, 7, true, offset);
110   t.is (line, "This ☺", "extractLine 7 'This ☺ is a test of utf8 line extraction.' -> 'This ☺'");
111 
112   // void extractLine (std::string& text, std::string& line, int length, bool hyphenate, unsigned int& offset)
113   text = "line 1\nlengthy second line that exceeds width";
114   offset = 0;
115   extractLine (line, text, 10, true, offset);
116   t.is (line, "line 1", "extractLine 10 'line 1\\nlengthy second line that exceeds width' -> 'line 1'");
117 
118   extractLine (line, text, 10, true, offset);
119   t.is (line, "lengthy", "extractLine 10 'lengthy second line that exceeds width' -> 'lengthy'");
120 
121   extractLine (line, text, 10, true, offset);
122   t.is (line, "second", "extractLine 10 'second line that exceeds width' -> 'second'");
123 
124   extractLine (line, text, 10, true, offset);
125   t.is (line, "line that", "extractLine 10 'line that exceeds width' -> 'line that'");
126 
127   extractLine (line, text, 10, true, offset);
128   t.is (line, "exceeds", "extractLine 10 'exceeds width' -> 'exceeds'");
129 
130   extractLine (line, text, 10, true, offset);
131   t.is (line, "width", "extractLine 10 'width' -> 'width'");
132 
133   t.notok (extractLine (line, text, 10, true, offset), "extractLine 10 '' -> ''");
134 
135   text = "AAAAAAAAAABBBBBBBBBB";
136   offset = 0;
137   extractLine (line, text, 10, true, offset);
138   t.is (line, "AAAAAAAAA-", "extractLine hyphenated unbreakable line 'AAAAAAAAAABBBBBBBBBB'/10 -> 'AAAAAAAAA-'");
139 
140   extractLine (line, text, 10, true, offset);
141   t.is (line, "ABBBBBBBB-", "extractLine hyphenated unbreakable line 'AAAAAAAAAABBBBBBBBBB'/10 -> 'ABBBBBBBB-'");
142 
143   extractLine (line, text, 10, true, offset);
144   t.is (line, "BB", "extractLine hyphenated unbreakable line 'AAAAAAAAAABBBBBBBBBB'/10 -> 'BB'");
145 
146   text = "4444 333  ";
147   offset = 0;
148   while (extractLine (line, text, 9, true, offset))
149     std::cout << "# line '" << line << "' offset " << offset << "\n";
150 */
151 
152   // std::vector <std::string> split (const std::string& input, const char delimiter)
153   std::string unsplit;
154   std::vector <std::string> items = split (unsplit, '-');
155   t.is (items.size (), (size_t) 0, "split '' '-' -> 0 items");
156 
157   unsplit = "a";
158   items = split (unsplit, '-');
159   t.is (items.size (), (size_t) 1, "split 'a' '-' -> 1 item");
160   t.is (items[0], "a",             "split 'a' '-' -> 'a'");
161 
162   items = split (unsplit, '-');
163   t.is (items.size (), (size_t) 1, "split 'a' '-' -> 1 item");
164   t.is (items[0], "a",             "split 'a' '-' -> 'a'");
165 
166   unsplit = "-";
167   items = split (unsplit, '-');
168   t.is (items.size (), (size_t) 2, "split '-' '-' -> '' ''");
169   t.is (items[0], "",              "split '-' '-' -> [0] ''");
170   t.is (items[1], "",              "split '-' '-' -> [1] ''");
171 
172   unsplit = "-a-bc--def";
173   items = split (unsplit, '-');
174   t.is (items.size (), (size_t) 5, "split '-a-bc--def' '-' -> '' 'a' 'bc' '' 'def'");
175   t.is (items[0], "",              "split '-a-bc--def' '-' -> [0] ''");
176   t.is (items[1], "a",             "split '-a-bc--def' '-' -> [1] 'a'");
177   t.is (items[2], "bc",            "split '-a-bc--def' '-' -> [2] 'bc'");
178   t.is (items[3], "",              "split '-a-bc--def' '-' -> [3] ''");
179   t.is (items[4], "def",           "split '-a-bc--def' '-' -> [4] 'def'");
180 
181   // std::vector <std::string> split (const std::string& input);
182   unsplit = "";
183   items = split (unsplit);
184   t.is (items.size (), (size_t) 0, "split '' -> 0 items");
185 
186   unsplit = "abc";
187   items = split (unsplit);
188   t.is (items.size (), (size_t) 1, "split 'abc' -> 1 item");
189   t.is (items[0], "abc",           "split 'abc' -> [0] 'abc'");
190 
191   unsplit = "a b c";
192   items = split (unsplit);
193   t.is (items.size (), (size_t) 3, "split 'a b c' -> 3 items");
194   t.is (items[0], "a",             "split 'a b c' -> [0] 'a'");
195   t.is (items[1], "b",             "split 'a b c' -> [1] 'b'");
196   t.is (items[2], "c",             "split 'a b c' -> [2] 'c'");
197 
198   unsplit = "  a   b   c  ";
199   items = split (unsplit);
200   t.is (items.size (), (size_t) 3, "split '  a  b  c  ' -> 3 items");
201   t.is (items[0], "a",             "split '  a  b  c  ' -> [0] 'a'");
202   t.is (items[1], "b",             "split '  a  b  c  ' -> [1] 'b'");
203   t.is (items[2], "c",             "split '  a  b  c  ' -> [2] 'c'");
204 
205   // std::string join (const std::string&r, const std::vector<int>&)
206   // std::string join (const std::string&r, const std::vector<std::string>&)
207   std::vector <std::string> unjoined;
208   std::string joined;
209 
210   joined = join ("", unjoined);
211   t.is (joined.length (), (size_t) 0,  "join -> length 0");
212   t.is (joined,           "",          "join -> ''");
213 
214   unjoined = {"", "a", "bc", "def"};
215   joined = join ("", unjoined);
216   t.is (joined.length (), (size_t) 6, "join '' 'a' 'bc' 'def' -> length 6");
217   t.is (joined,           "abcdef",   "join '' 'a' 'bc' 'def' -> 'abcdef'");
218 
219   joined = join ("-", unjoined);
220   t.is (joined.length (), (size_t) 9,  "join '' - 'a' - 'bc' - 'def' -> length 9");
221   t.is (joined,           "-a-bc-def", "join '' - 'a' - 'bc' - 'def' -> '-a-bc-def'");
222 
223   std::vector <int> unjoined_ints {1, 2, 3, 4};
224   t.is (join ("-", unjoined_ints), "1-2-3-4", "join 1 - 2 - 3 - 4 -> '1-2-3-4'");
225 
226   // std::string trim (const std::string&);
227   t.is (trim ("one"),     "one",   "trim 'one' --> 'one'");
228   t.is (trim ("  one"),   "one",   "trim '  one' --> 'one'");
229   t.is (trim ("one  "),   "one",   "trim 'one  ' --> 'one'");
230   t.is (trim ("  one  "), "one",   "trim '  one  ' --> 'one'");
231   t.is (trim (""),        "",      "trim '' --> ''");
232   t.is (trim (" \t\r\f\nfoo\n\f\r\t "), "foo",
233                                    "trim ' \t\r\f\nfoo\n\f\r\t ' --> 'foo'");
234 
235   t.is (trim ("abcdedcba", "abc"), "ded", "trim 'abcdedcba', 'abc' --> 'ded'");
236 
237   // std::string ltrim (const std::string&);
238   t.is (ltrim ("one"),     "one",   "ltrim 'one' --> 'one'");
239   t.is (ltrim ("  one"),   "one",   "ltrim '  one' --> 'one'");
240   t.is (ltrim ("one  "),   "one  ", "ltrim 'one  ' --> 'one  '");
241   t.is (ltrim ("  one  "), "one  ", "ltrim '  one  ' --> 'one  '");
242   t.is (ltrim (""),        "",      "ltrim '' --> ''");
243   t.is (ltrim ("  "),      "",      "ltrim '  ' --> ''");
244   t.is (ltrim (" \t\r\f\nfoo\n\f\r\t "), "foo\n\f\r\t ",
245                                     "ltrim ' \t\r\f\nfoo\n\f\r\t ' --> 'foo\\n\\f\\r\\t '");
246 
247   // std::string rtrim (const std::string&);
248   t.is (rtrim ("one"),     "one",   "rtrim 'one' --> 'one'");
249   t.is (rtrim ("  one"),   "  one", "rtrim '  one' --> '  one'");
250   t.is (rtrim ("one  "),   "one",   "rtrim 'one  ' --> 'one'");
251   t.is (rtrim ("  one  "), "  one", "rtrim '  one' --> '  one'");
252   t.is (rtrim (""),        "",      "rtrim '' --> ''");
253   t.is (rtrim ("  "),      "",      "rtrim '  ' --> ''");
254   t.is (rtrim (" \t\r\f\nfoo\n\f\r\t "), " \t\r\f\nfoo",
255                                     "rtrim ' \t\r\f\nfoo\n\f\r\t ' --> ' \\t\\r\\f\\nfoo'");
256 
257   // int longestWord (const std::string&)
258   t.is (longestWord ("    "),                   0, "longestWord (    ) --> 0");
259   t.is (longestWord ("this is a test"),         4, "longestWord (this is a test) --> 4");
260   t.is (longestWord ("this is a better test"),  6, "longestWord (this is a better test) --> 6");
261   t.is (longestWord ("house Çirçös clown"),     6, "longestWord (Çirçös) --> 6");
262 
263   // int longestLine (const std::string&)
264   t.is (longestLine ("one two three four"),    18, "longestLine (one two three four) --> 18");
265   t.is (longestLine ("one\ntwo three four"),   14, "longestLine (one\\ntwo three four) --> 14");
266   t.is (longestLine ("one\ntwo\nthree\nfour"),  5, "longestLine (one\\ntwo\\nthree\\nfour) --> 5");
267 
268   // bool compare (const std::string&, const std::string&, bool sensitive = true);
269   t.notok (compare ("a", "b"), "compare 'a' : 'b' --> false");
270   t.notok (compare ("a", ""),  "compare 'a' : ''  --> false");
271   t.notok (compare ("", "b"),  "compare ''  : 'b' --> false");
272   t.ok    (compare ("", ""),   "compare ''  : ''  --> true");
273   t.notok (compare ("A", "a"),        "compare            'A' : 'a' --> false");
274   t.notok (compare ("A", "a", true),  "compare sensitive  'A' : 'a' --> false");
275   t.ok    (compare ("A", "a", false), "compare !sensitive 'A' : 'a' --> true");
276 
277   // bool closeEnough (const std::string&, const std::string&, unsigned int minLength = 0);
278   t.ok (closeEnough ("foobar", "foobar"),      "closeEnough foobar == foobar");
279   t.ok (closeEnough ("foobar", "foobar", 0),   "closeEnough foobar == foobar,0");
280   t.ok (closeEnough ("foobar", "foobar", 1),   "closeEnough foobar == foobar,1");
281   t.ok (closeEnough ("foobar", "foobar", 2),   "closeEnough foobar == foobar,2");
282   t.ok (closeEnough ("foobar", "foobar", 3),   "closeEnough foobar == foobar,3");
283   t.ok (closeEnough ("foobar", "foobar", 4),   "closeEnough foobar == foobar,4");
284   t.ok (closeEnough ("foobar", "foobar", 5),   "closeEnough foobar == foobar,5");
285   t.ok (closeEnough ("foobar", "foobar", 6),   "closeEnough foobar == foobar,6");
286   t.ok (closeEnough ("foobar", "foo",    3),   "closeEnough foobar == foo,3");
287 
288   // int matchLength (const std::string&, const std::string&, unsigned int minLength = 0);
289   t.is (matchLength ("",       "foobar"), 0, "matchLength '' == foobar --> 0");
290   t.is (matchLength ("f",      "foobar"), 1, "matchLength f == foobar --> 1");
291   t.is (matchLength ("fo",     "foobar"), 2, "matchLength fo == foobar --> 2");
292   t.is (matchLength ("foo",    "foobar"), 3, "matchLength foo == foobar --> 3");
293   t.is (matchLength ("foob",   "foobar"), 4, "matchLength foob == foobar --> 4");
294   t.is (matchLength ("fooba",  "foobar"), 5, "matchLength fooba == foobar --> 5");
295   t.is (matchLength ("foobar", "foobar"), 6, "matchLength foobar == foobar --> 6");
296   t.is (matchLength ("foobar", "fooba"),  5, "matchLength foobar == fooba --> 5");
297   t.is (matchLength ("foobar", "foob"),   4, "matchLength foobar == foob --> 4");
298   t.is (matchLength ("foobar", "foo"),    3, "matchLength foobar == foo --> 3");
299   t.is (matchLength ("foobar", "fo"),     2, "matchLength foobar == fo --> 2");
300   t.is (matchLength ("foobar", "f"),      1, "matchLength foobar == f --> 1");
301   t.is (matchLength ("foobar", ""),       0, "matchLength foobar == '' --> 0");
302 
303   t.is (matchLength ("foobar", "foodmixer"), 3, "matchLength foobar == foodmixer --> 3");
304   t.is (matchLength ("foodmixer", "foobar"), 3, "matchLength foodmixer == foobar --> 3");
305 
306   // std::string lowerCase (const std::string&);
307   t.is (lowerCase (""),   "",   "lowerCase '' --> ''");
308   t.is (lowerCase ("a"),  "a",  "lowerCase 'a' --> 'a'");
309   t.is (lowerCase ("aA"), "aa", "lowerCase 'aA' --> 'aa'");
310   t.is (lowerCase ("A"),  "a",  "lowerCase 'A' --> 'a'");
311   t.is (lowerCase ("$"),  "$",  "lowerCase '$' --> '$'");
312 
313   // std::string upperCase (const std::string&);
314   t.is (upperCase (""),   "",   "upperCase '' --> ''");
315   t.is (upperCase ("a"),  "A",  "upperCase 'a' --> 'A'");
316   t.is (upperCase ("aA"), "AA", "upperCase 'aA' --> 'AA'");
317   t.is (upperCase ("A"),  "A",  "upperCase 'A' --> 'A'");
318   t.is (upperCase ("$"),  "$",  "upperCase '$' --> '$'");
319 
320   // std::string upperCaseFirst (const std::string&);
321   t.is (upperCaseFirst (""),   "",   "upperCaseFirst '' --> ''");
322   t.is (upperCaseFirst ("a"),  "A",  "upperCaseFirst 'a' --> 'A'");
323   t.is (upperCaseFirst ("A"),  "A",  "upperCaseFirst 'A' --> 'A'");
324   t.is (upperCaseFirst ("aa"), "Aa", "upperCaseFirst 'aa' --> 'Aa'");
325   t.is (upperCaseFirst ("$"),  "$",  "upperCaseFirst '$' --> '$'");
326 
327   // std::string str_replace (const std::string&, const std::string&, const std::string&);
328   std::string input = "Lorem ipsum dolor sit amet, est aliquip scaevola dignissim in, vim nominavi electram te.";
329   t.is (str_replace (input, "x", "X"),
330         "Lorem ipsum dolor sit amet, est aliquip scaevola dignissim in, vim nominavi electram te.",
331         "str_replace 'x' -- 'X' (NOP)");
332 
333   t.is (str_replace (input, "e", "E"),
334         "LorEm ipsum dolor sit amEt, Est aliquip scaEvola dignissim in, vim nominavi ElEctram tE.",
335         "str_replace 'e' -- 'E'");
336 
337   // std::string::size_type find (const std::string&, const std::string&, bool sensitive = true);
338   // std::string::size_type find (const std::string&, const std::string&, std::string::size_type, bool sensitive = true);
339   // Make sure degenerate cases are handled.
340   t.is ((int) find ("foo", ""), (int) 0,                           "find foo !contains ''");
341   t.is ((int) find ("", "foo"), (int) std::string::npos,           "find '' !contains foo");
342 
343   // Make sure the default is case-sensitive.
344   t.is ((int) find ("foo", "fo"), 0,                               "find foo contains fo");
345   t.is ((int) find ("foo", "FO"), (int) std::string::npos,         "find foo !contains fo");
346 
347   // Test case-sensitive.
348   t.is ((int) find ("foo", "xx", true), (int) std::string::npos,   "find foo !contains xx");
349   t.is ((int) find ("foo", "oo", true), 1,                         "find foo contains oo");
350 
351   t.is ((int) find ("foo", "fo", true), 0,                         "find foo contains fo");
352   t.is ((int) find ("foo", "FO", true), (int) std::string::npos,   "find foo !contains fo");
353   t.is ((int) find ("FOO", "fo", true), (int) std::string::npos,   "find foo !contains fo");
354   t.is ((int) find ("FOO", "FO", true), 0,                         "find foo contains fo");
355 
356   // Test case-insensitive.
357   t.is ((int) find ("foo", "xx", false),  (int) std::string::npos, "find foo !contains xx (caseless)");
358   t.is ((int) find ("foo", "oo", false),  1,                       "find foo contains oo (caseless)");
359 
360   t.is ((int) find ("foo", "fo", false),  0,                       "find foo contains fo (caseless)");
361   t.is ((int) find ("foo", "FO", false),  0,                       "find foo contains FO (caseless)");
362   t.is ((int) find ("FOO", "fo", false),  0,                       "find FOO contains fo (caseless)");
363   t.is ((int) find ("FOO", "FO", false),  0,                       "find FOO contains FO (caseless)");
364 
365   // Test start offset.
366   t.is ((int) find ("one two three", "e",  3, true), (int) 11,     "find offset obeyed");
367   t.is ((int) find ("one two three", "e", 11, true), (int) 11,     "find offset obeyed");
368 
369   t.is ((int) find ("one two three", "e",  3, false), (int) 11,    "find offset obeyed");
370   t.is ((int) find ("one two three", "e", 11, false), (int) 11,    "find offset obeyed");
371 
372   // Test osName actually recognizes OS.
373   t.ok (osName () != "<unknown>",                                  "osName: Recognizes OS as: " + osName ());
374 
375   // Test cppCompliance actually recognizes compliance level.
376   t.ok (cppCompliance () != "non-compliant",                       "cppCompliance: Recognizes compiler compliance level as: " + cppCompliance ());
377 
378   // Test IPv4/IPv6 address parsing.
379   std::string address;
380   int port;
381   input = "127.0.0.1";
382   t.ok    (isIPv4Address (input, address, port),           "isIPv4Address " + input + " --> yes");
383   t.is    (address, "127.0.0.1",                           "isIPv4Address " + input + " --> address correct");
384   t.is    (port, 0,                                        "isIPv4Address " + input + " --> port correct");
385   t.notok (isIPv6Address (input, address, port),           "isIPv6Address " + input + " --> no");
386 
387   input = "127.0.0.1:80";
388   t.ok    (isIPv4Address (input, address, port),           "isIPv4Address " + input + " --> yes");
389   t.is    (address, "127.0.0.1",                           "isIPv4Address " + input + " --> address correct");
390   t.is    (port, 80,                                       "isIPv4Address " + input + " --> port correct");
391   t.notok (isIPv6Address (input, address, port),           "isIPv6Address " + input + " --> no");
392 
393   input = "::1";
394   t.notok (isIPv4Address (input, address, port),           "isIPv4Address " + input + " --> no");
395   t.ok    (isIPv6Address (input, address, port),           "isIPv6Address " + input + " --> yes");
396   t.is    (address, "::1",                                 "isIPv6Address " + input + " --> address correct");
397   t.is    (port, 0,                                        "isIPv6Address " + input + " --> port correct");
398 
399   input = "[::1]:80";
400   t.notok (isIPv4Address (input, address, port),           "isIPv4Address " + input + " --> no");
401   t.ok    (isIPv6Address (input, address, port),           "isIPv6Address " + input + " --> yes");
402   t.is    (address, "::1",                                 "isIPv6Address " + input + " --> address correct");
403   t.is    (port, 80,                                       "isIPv6Address " + input + " --> port correct");
404 
405   input = "2605:2700:0:3::4713:93e3";
406   t.notok (isIPv4Address (input, address, port),           "isIPv4Address " + input + " --> no");
407   t.ok    (isIPv6Address (input, address, port),           "isIPv6Address " + input + " --> yes");
408   t.is    (address, "2605:2700:0:3::4713:93e3",            "isIPv6Address " + input + " --> address correct");
409   t.is    (port, 0,                                        "isIPv6Address " + input + " --> port correct");
410 
411   input = "[2605:2700:0:3::4713:93e3]:80";
412   t.notok (isIPv4Address (input, address, port),           "isIPv4Address " + input + " --> no");
413   t.ok    (isIPv6Address (input, address, port),           "isIPv6Address " + input + " --> yes");
414   t.is    (address, "2605:2700:0:3::4713:93e3",            "isIPv6Address " + input + " --> address correct");
415   t.is    (port, 80,                                       "isIPv6Address " + input + " --> port correct");
416 
417   input = "2001:db8:85a3:0:0:8a2e:370:7334";
418   t.notok (isIPv4Address (input, address, port),            "isIPv4Address " + input + " --> no");
419   t.ok    (isIPv6Address (input, address, port),            "isIPv6Address " + input + " --> yes");
420   t.is    (address, "2001:db8:85a3:0:0:8a2e:370:7334",      "isIPv6Address " + input + " --> address correct");
421   t.is    (port, 0,                                         "isIPv6Address " + input + " --> port correct");
422 
423   input = "2001:db8:85a3::8a2e:370:7334";
424   t.notok (isIPv4Address (input, address, port),            "isIPv4Address " + input + " --> no");
425   t.ok    (isIPv6Address (input, address, port),            "isIPv6Address " + input + " --> yes");
426   t.is    (address, "2001:db8:85a3::8a2e:370:7334",         "isIPv6Address " + input + " --> address correct");
427   t.is    (port, 0,                                         "isIPv6Address " + input + " --> port correct");
428 
429   input = "[2001:db8:85a3:8d3:1319:8a2e:370:7348]:443";
430   t.notok (isIPv4Address (input, address, port),            "isIPv4Address " + input + " --> no");
431   t.ok    (isIPv6Address (input, address, port),            "isIPv6Address " + input + " --> yes");
432   t.is    (address, "2001:db8:85a3:8d3:1319:8a2e:370:7348", "isIPv6Address " + input + " --> address correct");
433   t.is    (port, 443,                                       "isIPv6Address " + input + " --> port correct");
434 
435   input = "::ffff:192.168.0.1";
436   t.notok (isIPv4Address (input, address, port),            "isIPv4Address " + input + " --> no");
437   t.ok    (isIPv6Address (input, address, port),            "isIPv6Address " + input + " --> yes");
438   t.is    (address, "::ffff:192.168.0.1",                   "isIPv6Address " + input + " --> address correct");
439   t.is    (port, 0,                                         "isIPv6Address " + input + " --> port correct");
440 
441   input = "[::ffff:71.19.147.227]:80";
442   t.notok (isIPv4Address (input, address, port),            "isIPv4Address " + input + " --> no");
443   t.ok    (isIPv6Address (input, address, port),            "isIPv6Address " + input + " --> yes");
444   t.is    (address, "::ffff:71.19.147.227",                 "isIPv6Address " + input + " --> address correct");
445   t.is    (port, 80,                                        "isIPv6Address " + input + " --> port correct");
446 
447   input = "::";
448   t.notok (isIPv4Address (input, address, port),            "isIPv4Address " + input + " --> no");
449   t.ok    (isIPv6Address (input, address, port),            "isIPv6Address " + input + " --> yes");
450   t.is    (address, "::",                                   "isIPv6Address " + input + " --> address correct");
451   t.is    (port, 00,                                        "isIPv6Address " + input + " --> port correct");
452 
453   return 0;
454 }
455 
456 ////////////////////////////////////////////////////////////////////////////////
457