f779eaccba87d3f480017fe7907fffee925f60ec
[platform/upstream/libzypp.git] / tests / zypp / base / String_test.cc
1 #include <boost/test/unit_test.hpp>
2
3 #include "zypp/base/LogTools.h"
4 #include "zypp/base/String.h"
5
6 using boost::unit_test::test_suite;
7 using boost::unit_test::test_case;
8 using namespace boost::unit_test;
9
10 using namespace std;
11 using namespace zypp;
12 using namespace zypp::str;
13
14 #define RXspecial "\\^.[$()|*+?{"
15
16 BOOST_AUTO_TEST_CASE(str2rx)
17 {
18   char s[] = "c";
19   char x[] = "\\c";
20   for ( const char * ch = RXspecial; *ch; ++ch )
21   {
22     s[0] = x[1] = *ch;
23     BOOST_CHECK_EQUAL( str::rxEscapeStr( s ), x );
24   }
25 }
26
27 BOOST_AUTO_TEST_CASE(glob2rx)
28 {
29   {
30     char s[] = "c";
31     char x[] = "\\c";
32     for ( const char * ch = RXspecial; *ch; ++ch )
33     {
34       s[0] = x[1] = *ch;
35       if ( *ch == '?' )
36         BOOST_CHECK_EQUAL( str::rxEscapeGlob( s ), "." );
37       else if ( *ch == '*' )
38         BOOST_CHECK_EQUAL( str::rxEscapeGlob( s ), ".*" );
39       else if ( *ch == '[' )
40         BOOST_CHECK_EQUAL( str::rxEscapeGlob( s ), "\\[" );     // no closing ] so it is literal
41         else if ( *ch == '\\' )
42           BOOST_CHECK_EQUAL( str::rxEscapeGlob( s ), "\\" );    // actually an input error as "\" is not a valid GLOB
43           else
44           {
45             s[0] = x[1] = *ch;
46             BOOST_CHECK_EQUAL( str::rxEscapeGlob( s ), x );
47           }
48     }
49     std::string a( str::rxEscapeStr( RXspecial ) );     // all rx/glob special chars are literally (\-escaped)
50     BOOST_CHECK_EQUAL( str::rxEscapeGlob( a ), a );     // nothing more to escape.
51
52     // character class: contains "]["
53     BOOST_CHECK_EQUAL( str::rxEscapeGlob( "[][]" ),     "[][]" );
54     BOOST_CHECK_EQUAL( str::rxEscapeGlob( "[^][]" ),    "[^][]" );
55     BOOST_CHECK_EQUAL( str::rxEscapeGlob( "[!][]" ),    "[^][]" );      // glob allows ! and ^ to negate a cclass
56
57     // no character class: no closing ']' so take it literally (the ] would be member of the cclass, not the closing ])
58     BOOST_CHECK_EQUAL( str::rxEscapeGlob( "[]" ),       "\\[]" );
59     BOOST_CHECK_EQUAL( str::rxEscapeGlob( "[!]" ),      "\\[!]" );
60     BOOST_CHECK_EQUAL( str::rxEscapeGlob( "[^]" ),      "\\[\\^]" );
61   }
62 }
63
64 BOOST_AUTO_TEST_CASE(gsubTest)
65 {
66   string olds = "olds";
67   string news = "new string";
68
69   BOOST_CHECK_EQUAL(gsub("test olds string",olds,news), "test new string string");
70   BOOST_CHECK_EQUAL(gsub("no string",olds,news),"no string");
71   BOOST_CHECK_EQUAL(gsub("oldsolds",olds,news),"new stringnew string");
72 }
73
74 BOOST_AUTO_TEST_CASE(replaceAllTest)
75 {
76   string olds = "olds";
77   string news = "new string";
78   string tests;
79
80   tests = "test olds string";
81   replaceAll(tests,olds,news);
82   BOOST_CHECK_EQUAL(tests, "test new string string");
83
84   tests = "no string";
85   replaceAll(tests,olds,news);
86   BOOST_CHECK_EQUAL(tests, "no string");
87
88   tests = "oldsolds";
89   replaceAll(tests,olds,news);
90   BOOST_CHECK_EQUAL(tests, "new stringnew string");
91 }
92
93 BOOST_AUTO_TEST_CASE(testsplitEscaped)
94 {
95   string s( "simple non-escaped string" );
96   vector<string> v;
97
98   splitEscaped( s, std::back_inserter(v) );
99   BOOST_CHECK_EQUAL( v.size(), 3 );
100   BOOST_CHECK_EQUAL( v[0], "simple" );
101   BOOST_CHECK_EQUAL( v[1], "non-escaped" );
102   BOOST_CHECK_EQUAL( v[2], "string" );
103
104   v.clear();
105   s = string( "\"escaped sentence \"" );
106   splitEscaped( s, std::back_inserter(v) );
107   BOOST_CHECK_EQUAL( v.size(), 1 );
108   BOOST_CHECK_EQUAL( v[0], "escaped sentence " );
109
110   v.clear();
111   s = string( "\"escaped \\\\sent\\\"ence \\\\\"" );
112   splitEscaped( s, std::back_inserter(v) );
113   BOOST_CHECK_EQUAL( v.size(), 1 );
114   BOOST_CHECK_EQUAL( v[0], "escaped \\sent\"ence \\" );
115
116   v.clear();
117   s = string( "escaped sentence\\ with\\ space" );
118   splitEscaped( s, std::back_inserter(v) );
119   BOOST_CHECK_EQUAL( v.size(), 2 );
120   BOOST_CHECK_EQUAL( v[0], "escaped" );
121   BOOST_CHECK_EQUAL( v[1], "sentence with space" );
122
123   // split - join
124   v.clear();
125   s = "some line \"\" foo\\ a foo\\\\ b";
126   str::splitEscaped( s, std::back_inserter(v) );
127   BOOST_CHECK_EQUAL( v.size(), 6 );
128   BOOST_CHECK_EQUAL( v[0], "some" );
129   BOOST_CHECK_EQUAL( v[1], "line" );
130   BOOST_CHECK_EQUAL( v[2], "" );
131   BOOST_CHECK_EQUAL( v[3], "foo a" );
132   BOOST_CHECK_EQUAL( v[4], "foo\\" );
133   BOOST_CHECK_EQUAL( v[5], "b" );
134   BOOST_CHECK_EQUAL( s, str::joinEscaped( v.begin(), v.end() ) );
135
136   // split - join using alternate sepchar
137   s = str::joinEscaped( v.begin(), v.end(), 'o' );
138   v.clear();
139   str::splitEscaped( s, std::back_inserter(v), "o" );
140   BOOST_CHECK_EQUAL( v.size(), 6 );
141   BOOST_CHECK_EQUAL( v[0], "some" );
142   BOOST_CHECK_EQUAL( v[1], "line" );
143   BOOST_CHECK_EQUAL( v[2], "" );
144   BOOST_CHECK_EQUAL( v[3], "foo a" );
145   BOOST_CHECK_EQUAL( v[4], "foo\\" );
146   BOOST_CHECK_EQUAL( v[5], "b" );
147   BOOST_CHECK_EQUAL( s, str::joinEscaped( v.begin(), v.end(), 'o' ) );
148 }
149
150 BOOST_AUTO_TEST_CASE(bnc_909772)
151 {
152   // While \-escaping processes single-quote, double-quote, backslash and sepchar[ ]
153   // deescaping failed to process the quotes correctly.
154   std::string s;
155   std::vector<std::string> v;
156
157   v.clear();
158   v.push_back("");
159   v.push_back("'\" \\");
160   v.push_back("\\'\\\"\\ \\\\");
161   s = str::joinEscaped( v.begin(), v.end() );
162   BOOST_CHECK_EQUAL( s, "\"\""  " "  "\\'\\\"\\ \\\\"  " "  "\\\\\\'\\\\\\\"\\\\\\ \\\\\\\\" );
163
164   s += " ";
165   s += "'"   "\\\\\" \\ \\\\"   "'\\ single";   // single quote: all literal, no ' inside
166
167   s += " ";
168   s += "\""   "\\'\\\" \\ \\\\"   "\"\\ double";// double quote: all literal except \\ \"
169
170   v.clear();
171   splitEscaped( s, std::back_inserter(v) );
172   BOOST_CHECK_EQUAL( v.size(), 5 );
173   BOOST_CHECK_EQUAL( v[0], "" );
174   BOOST_CHECK_EQUAL( v[1], "'\" \\" );
175   BOOST_CHECK_EQUAL( v[2], "\\'\\\"\\ \\\\" );
176   BOOST_CHECK_EQUAL( v[3], "\\\\\" \\ \\\\ single" );
177   BOOST_CHECK_EQUAL( v[4], "\\'\" \\ \\ double" );
178 }
179
180 BOOST_AUTO_TEST_CASE(testsplitEscapedWithEmpty)
181 {
182   string s( "simple:non-escaped:string" );
183   vector<string> v;
184
185   BOOST_CHECK_EQUAL(splitFieldsEscaped(s, std::back_inserter(v)), 3);
186   BOOST_CHECK_EQUAL(v.size(), 3);
187
188   v.clear();
189   s = "non-escaped:with::spaces:";
190   BOOST_CHECK_EQUAL(splitFieldsEscaped(s, std::back_inserter(v)), 5);
191   BOOST_CHECK_EQUAL(v.size(), 5);
192
193   v.clear();
194   s = "::";
195   BOOST_CHECK_EQUAL(splitFieldsEscaped(s, std::back_inserter(v)), 3);
196   BOOST_CHECK_EQUAL(v.size(), 3);
197
198   v.clear();
199   s = ":escaped::with\\:spaces";
200   BOOST_CHECK_EQUAL(splitFieldsEscaped(s, std::back_inserter(v)), 4);
201   BOOST_CHECK_EQUAL(v.size(), 4);
202 }
203
204 BOOST_AUTO_TEST_CASE(test_escape)
205 {
206   string badass = "bad|ass\\|worse";
207   string escaped = str::escape(badass, '|');
208
209   BOOST_CHECK_EQUAL( escaped, "bad\\|ass\\\\\\|worse" );
210 }
211
212 BOOST_AUTO_TEST_CASE(conversions)
213 {
214     BOOST_CHECK_EQUAL(str::numstring(42),     "42");
215     BOOST_CHECK_EQUAL(str::numstring(42, 6),  "    42");
216     BOOST_CHECK_EQUAL(str::numstring(42, -6), "42    ");
217
218     BOOST_CHECK_EQUAL(str::hexstring(42),     "0x0000002a");
219     BOOST_CHECK_EQUAL(str::hexstring(42, 6),  "0x002a");
220     BOOST_CHECK_EQUAL(str::hexstring(42, -6), "0x2a  ");
221
222     BOOST_CHECK_EQUAL(str::octstring(42),     "00052");
223     BOOST_CHECK_EQUAL(str::octstring(42, 6),  "000052");
224     BOOST_CHECK_EQUAL(str::octstring(42, -6), "052   ");
225
226     BOOST_CHECK_EQUAL(str::strtonum<int>("42"), 42);
227
228     BOOST_CHECK_EQUAL(str::toLower("This IS A TeST"), "this is a test");
229     BOOST_CHECK_EQUAL(str::toUpper("This IS A TeST"), "THIS IS A TEST");
230     BOOST_CHECK_EQUAL(str::compareCI("TeST", "test"), 0);
231
232     BOOST_CHECK_EQUAL(str::compareCI("TeST", "test"), 0);
233     BOOST_CHECK_EQUAL(str::compareCI("TeST", "test"), 0);
234 }
235
236 BOOST_AUTO_TEST_CASE(conversions_to_bool)
237 {
238   // true iff true-string {1,on,yes,true}
239   BOOST_CHECK_EQUAL( str::strToTrue("1"),     true );
240   BOOST_CHECK_EQUAL( str::strToTrue("42"),    true );
241   BOOST_CHECK_EQUAL( str::strToTrue("ON"),    true );
242   BOOST_CHECK_EQUAL( str::strToTrue("YES"),   true );
243   BOOST_CHECK_EQUAL( str::strToTrue("TRUE"),  true );
244   BOOST_CHECK_EQUAL( str::strToTrue("0"),     false );
245   BOOST_CHECK_EQUAL( str::strToTrue("OFF"),   false );
246   BOOST_CHECK_EQUAL( str::strToTrue("NO"),    false );
247   BOOST_CHECK_EQUAL( str::strToTrue("FALSE"), false );
248   BOOST_CHECK_EQUAL( str::strToTrue(""),      false );
249   BOOST_CHECK_EQUAL( str::strToTrue("foo"),   false );
250
251   // false iff false-string {0,off,no,false}
252   BOOST_CHECK_EQUAL( str::strToFalse("1"),     true );
253   BOOST_CHECK_EQUAL( str::strToFalse("42"),    true );
254   BOOST_CHECK_EQUAL( str::strToFalse("ON"),    true );
255   BOOST_CHECK_EQUAL( str::strToFalse("YES"),   true );
256   BOOST_CHECK_EQUAL( str::strToFalse("TRUE"),  true );
257   BOOST_CHECK_EQUAL( str::strToFalse("0"),     false );
258   BOOST_CHECK_EQUAL( str::strToFalse("OFF"),   false );
259   BOOST_CHECK_EQUAL( str::strToFalse("NO"),    false );
260   BOOST_CHECK_EQUAL( str::strToFalse("FALSE"), false );
261   BOOST_CHECK_EQUAL( str::strToFalse(""),      true );
262   BOOST_CHECK_EQUAL( str::strToFalse("foo"),   true );
263
264   // true iff true-string
265   BOOST_CHECK_EQUAL( str::strToBool("TRUE",  false), true );
266   BOOST_CHECK_EQUAL( str::strToBool("FALSE", false), false );
267   BOOST_CHECK_EQUAL( str::strToBool("",      false), false );
268   BOOST_CHECK_EQUAL( str::strToBool("foo",   false), false );
269
270   // false iff false-string
271   BOOST_CHECK_EQUAL( str::strToBool("TRUE",  true),  true );
272   BOOST_CHECK_EQUAL( str::strToBool("FALSE", true),  false );
273   BOOST_CHECK_EQUAL( str::strToBool("",      true),  true );
274   BOOST_CHECK_EQUAL( str::strToBool("foo",   true),  true );
275
276   // true/false iff true/false-string, else unchanged
277   bool ret;
278   ret = true; BOOST_CHECK_EQUAL( str::strToBoolNodefault("TRUE",  ret),  true );
279   ret = true; BOOST_CHECK_EQUAL( str::strToBoolNodefault("FALSE", ret),  false );
280   ret = true; BOOST_CHECK_EQUAL( str::strToBoolNodefault("",      ret),  true );
281   ret = true; BOOST_CHECK_EQUAL( str::strToBoolNodefault("foo",   ret),  true );
282
283   ret = false; BOOST_CHECK_EQUAL( str::strToBoolNodefault("TRUE",  ret),  true );
284   ret = false; BOOST_CHECK_EQUAL( str::strToBoolNodefault("FALSE", ret),  false );
285   ret = false; BOOST_CHECK_EQUAL( str::strToBoolNodefault("",      ret),  false );
286   ret = false; BOOST_CHECK_EQUAL( str::strToBoolNodefault("foo",   ret),  false );
287 }
288
289 BOOST_AUTO_TEST_CASE(operations)
290 {
291     BOOST_CHECK_EQUAL(str::ltrim(" \t f \t ffo \t "), "f \t ffo \t ");
292     BOOST_CHECK_EQUAL(str::rtrim(" \t f \t ffo \t "), " \t f \t ffo");
293     BOOST_CHECK_EQUAL(str::trim(" \t f \t ffo \t "),  "f \t ffo");
294
295     // strip first
296     {
297         string tostrip(" Oh! la la ");
298         string word( str::stripFirstWord(tostrip, true) ); // ltrim first
299         BOOST_CHECK_EQUAL(word, "Oh!");
300         BOOST_CHECK_EQUAL(tostrip, "la la ");
301     }
302     {
303         string tostrip(" Oh! la la ");
304         string word( str::stripFirstWord(tostrip, false) ); // no ltrim first
305         BOOST_CHECK_EQUAL(word, "");
306         BOOST_CHECK_EQUAL(tostrip, "Oh! la la ");
307     }
308
309     // strip last
310     {
311         string tostrip(" Oh! la la ");
312         string word( str::stripLastWord(tostrip, true) ); // rtrim first
313         BOOST_CHECK_EQUAL(word, "la");
314         BOOST_CHECK_EQUAL(tostrip, " Oh! la");
315     }
316     {
317         string tostrip(" Oh! la la ");
318         string word( str::stripLastWord(tostrip, false) ); // no rtrim first
319         BOOST_CHECK_EQUAL(word, "");
320         BOOST_CHECK_EQUAL(tostrip, " Oh! la la");
321     }
322 }
323
324 BOOST_AUTO_TEST_CASE(prefix_suffix)
325 {
326   BOOST_CHECK( str::hasPrefix("abcXabcYabc", "abcX") );
327   BOOST_CHECK( str::hasSuffix("abcXabcYabc", "Yabc") );
328
329   BOOST_CHECK_EQUAL( str::stripPrefix("abcXabcYabc", "abcX"),  "abcYabc" );
330   BOOST_CHECK_EQUAL( str::stripSuffix("abcXabcYabc", "Yabc"),  "abcXabc" );
331
332   BOOST_CHECK( ! str::hasPrefix("abcXabcYabc", "ac") );
333   BOOST_CHECK( ! str::hasSuffix("abcXabcYabc", "ac") );
334
335   BOOST_CHECK_EQUAL( str::stripPrefix("abcXabcYabc", "ac"),  "abcXabcYabc" );
336   BOOST_CHECK_EQUAL( str::stripSuffix("abcXabcYabc", "ac"),  "abcXabcYabc" );
337
338   BOOST_CHECK( str::startsWith("abcXabcYabc", "abc") );
339   BOOST_CHECK( str::endsWith("abcXabcYabc", "abc") );
340
341   BOOST_CHECK( str::contains("abcXabcYabc", "XabcY") );
342   BOOST_CHECK( ! str::contains("abcXabcYabc", "xabcy") );
343   BOOST_CHECK( str::containsCI("abcXabcYabc", "xabcy") );
344
345   BOOST_CHECK_EQUAL( str::commonPrefix("", ""),         0 );
346   BOOST_CHECK_EQUAL( str::commonPrefix("a", ""),        0 );
347   BOOST_CHECK_EQUAL( str::commonPrefix("", "b"),        0 );
348   BOOST_CHECK_EQUAL( str::commonPrefix("a", "b"),       0 );
349   BOOST_CHECK_EQUAL( str::commonPrefix("c", "c"),       1 );
350   BOOST_CHECK_EQUAL( str::commonPrefix("ca", "cb"),     1 );
351 }
352
353 BOOST_AUTO_TEST_CASE(hexencode_hexdecode)
354 {
355   std::string o;
356   o.reserve( 256 );
357   for ( unsigned i = 1; i < 256; ++i )
358     o += i;
359
360   std::string e( str::hexencode( o ) );
361   // encoded contains nothing but [%a-zA-Z0-9]
362   for ( unsigned i = 0; i < 255; ++i )
363   {
364     char ch = e[i];
365     BOOST_CHECK( ch == '%'
366                  || ( 'a' <= ch && ch <= 'z' )
367                  || ( 'A' <= ch && ch <= 'Z' )
368                  || ( '0' <= ch && ch <= '9' ) );
369   }
370
371   std::string d( str::hexdecode( e ) );
372   // decoded equals original
373   BOOST_CHECK( o == d );
374
375   // Test %XX is decoded for hexdigits only
376   const char *const dig = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
377   for ( const char * d1 = dig; *d1; ++d1 )
378     for ( const char * d2 = dig; *d2; ++d2 )
379     {
380       std::string eu( "%" );
381       eu += *d1; eu += *d2;
382       std::string el( str::toLower(eu) );
383
384       std::string u( str::hexdecode( eu ) );
385       std::string l( str::hexdecode( el ) );
386
387       if ( *d1 <= 'F' &&  *d2 <= 'F' )
388       {
389         BOOST_CHECK_EQUAL( u, l );              // no matter if upper or lower case hexdigit
390         BOOST_CHECK_EQUAL( u.size(), 1 );       // size 1 == decoded
391       }
392       else
393       {
394         BOOST_CHECK_EQUAL( u, eu );             // no hexdigits remain unchanged
395         BOOST_CHECK_EQUAL( l, el );
396      }
397     }
398 }