1 #include <boost/test/auto_unit_test.hpp>
2 #include "zypp/CpeId.h"
7 using zypp::SetCompare;
8 using zypp::SetRelation;
10 typedef CpeId::Value Value;
12 ///////////////////////////////////////////////////////////////////
13 /// Symmetric attribute compare if wildcards are involved!
14 /// The specs define any comarison with a wildcarded attribute as
15 /// target to return \c uncomparable:
17 /// wildcardfree <=> wildcarded ==> uncomparable,
18 /// wildcarded <=> wildcardfree ==> superset or disjoint
20 /// But a symmetric result is much more intuitive:
22 /// wildcardfree <=> wildcarded ==> subset or disjoint
23 /// wildcarded <=> wildcardfree ==> superset or disjoint
25 ///////////////////////////////////////////////////////////////////
26 #define WFN_STRICT_SPEC 0
28 #define defVALUE(N,S) \
29 const std::string N##Str( S ); \
32 defVALUE( wildcardfree, "STrv\\*al\\?" ); // '\?' quoted?
33 const std::string wildcardfreeUri( "STrv%2aal%3f" );
34 const std::string wildcardfreeFs( "STrv\\*al\\?" );
36 defVALUE( wildcardfree2, "stRV\\*al\\\\\\?" ); // '\\\?' backslash, quoted?
38 defVALUE( wildcarded, "strv\\*AL?" ); // '?' ?
39 const std::string wildcardedUri( "strv%2aAL%01" );
40 const std::string wildcardedFs( "strv\\*AL?" );
42 defVALUE( wildcarded2, "strv\\*AL\\\\?" ); // '\\?' backslash, ?
46 BOOST_AUTO_TEST_CASE(cpeid_value_ANY)
48 for ( const auto & c : { Value(), Value(nullptr), Value("*"), Value::ANY } )
50 BOOST_CHECK( c.isANY() );
51 BOOST_CHECK( ! c.isNA() );
52 BOOST_CHECK( c.isLogical() );
53 BOOST_CHECK( ! c.isString() );
54 BOOST_CHECK( c == Value::ANY );
55 BOOST_CHECK( c == nullptr ); // ANY
56 BOOST_CHECK( c != Value::NA );
57 BOOST_CHECK( c != wildcardfree );
58 BOOST_CHECK( c != wildcarded );
59 BOOST_CHECK( ! c.isWildcardfree() );
60 BOOST_CHECK( ! c.isWildcarded() );
61 BOOST_CHECK_EQUAL( c.asFs(), "*" );
62 BOOST_CHECK_EQUAL( c.asUri(), "" );
63 BOOST_CHECK_EQUAL( c.asWfn(), "*" );
64 BOOST_CHECK_EQUAL( c.asString(), c.asWfn() );
68 BOOST_AUTO_TEST_CASE(cpeid_value_NA)
70 for ( const auto & c : { Value(""), Value::NA } )
72 BOOST_CHECK( ! c.isANY() );
73 BOOST_CHECK( c.isNA() );
74 BOOST_CHECK( c.isLogical() );
75 BOOST_CHECK( ! c.isString() );
76 BOOST_CHECK( c != Value::ANY );
77 BOOST_CHECK( c == Value::NA );
78 BOOST_CHECK( c == std::string() ); // NA
79 BOOST_CHECK( c == "" ); // NA
80 BOOST_CHECK( c != wildcardfree );
81 BOOST_CHECK( c != wildcarded );
82 BOOST_CHECK( ! c.isWildcardfree() );
83 BOOST_CHECK( ! c.isWildcarded() );
84 BOOST_CHECK_EQUAL( c.asFs(), "-" );
85 BOOST_CHECK_EQUAL( c.asUri(), "-" );
86 BOOST_CHECK_EQUAL( c.asWfn(), "" );
87 BOOST_CHECK_EQUAL( c.asString(), c.asWfn() );
91 BOOST_AUTO_TEST_CASE(cpeid_value_string_wildcardfree)
93 for ( const auto & c : { wildcardfree } )
95 BOOST_CHECK( ! c.isANY() );
96 BOOST_CHECK( ! c.isNA() );
97 BOOST_CHECK( ! c.isLogical() );
98 BOOST_CHECK( c.isString() );
99 BOOST_CHECK( c != Value::ANY );
100 BOOST_CHECK( c != Value::NA );
101 BOOST_CHECK( c == wildcardfree );
102 BOOST_CHECK( c == wildcardfreeStr );
103 BOOST_CHECK( c == wildcardfreeStr.c_str() );
104 BOOST_CHECK( c != wildcarded );
105 BOOST_CHECK( c.isWildcardfree() );
106 BOOST_CHECK( ! c.isWildcarded() );
107 BOOST_CHECK_EQUAL( c.asFs(), wildcardfreeFs );
108 BOOST_CHECK_EQUAL( c.asUri(), wildcardfreeUri );
109 BOOST_CHECK_EQUAL( c.asWfn(), wildcardfreeStr );
110 BOOST_CHECK_EQUAL( c.asString(), c.asWfn() );
113 BOOST_CHECK( wildcardfree2 == wildcardfree2 );
114 BOOST_CHECK( wildcardfree2 != wildcardfree );
115 BOOST_CHECK( wildcardfree2 != wildcarded );
116 BOOST_CHECK( wildcardfree2.isWildcardfree() );
117 BOOST_CHECK( ! wildcardfree2.isWildcarded() );
120 BOOST_AUTO_TEST_CASE(cpeid_value_string_wildcarded)
122 for ( const auto & c : { wildcarded } )
124 BOOST_CHECK( ! c.isANY() );
125 BOOST_CHECK( ! c.isNA() );
126 BOOST_CHECK( ! c.isLogical() );
127 BOOST_CHECK( c.isString() );
128 BOOST_CHECK( c != Value::ANY );
129 BOOST_CHECK( c != Value::NA );
130 BOOST_CHECK( c != wildcardfree );
132 BOOST_CHECK( c != wildcarded ); // !!! According to the CPE Name Matching Specification Version 2.3
133 // unquoted wildcard characters yield an undefined result (not ==).
135 BOOST_CHECK( c == wildcarded );
137 BOOST_CHECK( ! c.isWildcardfree() );
138 BOOST_CHECK( c.isWildcarded() );
139 BOOST_CHECK_EQUAL( c.asFs(), wildcardedFs );
140 BOOST_CHECK_EQUAL( c.asUri(), wildcardedUri );
141 BOOST_CHECK_EQUAL( c.asWfn(), wildcardedStr );
142 BOOST_CHECK_EQUAL( c.asString(), c.asWfn() );
146 BOOST_CHECK( wildcarded2 != wildcarded2 ); // unquoted wildcard characters yield an undefined result (not ==).
148 BOOST_CHECK( wildcarded2 == wildcarded2 );
150 BOOST_CHECK( wildcarded2 != wildcardfree );
151 BOOST_CHECK( wildcarded2 != wildcarded );
152 BOOST_CHECK( ! wildcarded2.isWildcardfree() );
153 BOOST_CHECK( wildcarded2.isWildcarded() );
158 BOOST_AUTO_TEST_CASE(cpeid_value_valid)
160 static const char *const hdig = "0123456789abcdef";
162 for ( char ch = 0x00; ch >= 0; ++ch )
164 // cout << "==== " << unsigned(ch) << endl;
165 char qchstr[] = { '\\', ch, '\0' };
166 std::string chstr( qchstr+1 );
167 char pchstr[] = { '%', hdig[(unsigned char)(ch)/16], hdig[(unsigned char)(ch)%16], '\0' };
171 BOOST_CHECK( Value( chstr ).isNA() );
172 BOOST_CHECK_THROW( (Value( chstr, Value::fsFormat )), std::invalid_argument );
173 BOOST_CHECK( Value( chstr, Value::uriFormat ).isANY() );
175 else if ( ch <= ' ' || '~' < ch )
177 BOOST_CHECK_THROW( (Value( chstr )), std::invalid_argument );
178 BOOST_CHECK_THROW( (Value( chstr, Value::fsFormat )), std::invalid_argument );
179 BOOST_CHECK_THROW( (Value( chstr, Value::uriFormat )), std::invalid_argument );
181 else if ( ( '0' <= ch && ch <= '9' )
182 || ( 'A' <= ch && ch <= 'Z' )
183 || ( 'a' <= ch && ch <= 'z' )
186 BOOST_CHECK( Value( chstr ).isString() );
187 BOOST_CHECK( Value( chstr, Value::fsFormat ).isString() );
188 BOOST_CHECK( Value( chstr, Value::uriFormat ).isString() );
190 BOOST_CHECK_THROW( (Value( qchstr )), std::invalid_argument );
191 BOOST_CHECK( Value( qchstr, Value::fsFormat ).isString() );
192 BOOST_CHECK( Value( qchstr, Value::uriFormat ).isString() );
194 BOOST_CHECK( Value( pchstr, Value::uriFormat ).isString() );
196 else if ( ch == '*' )
198 BOOST_CHECK( Value( chstr ).isANY() );
199 BOOST_CHECK( Value( chstr, Value::fsFormat ).isANY() );
200 BOOST_CHECK( Value( chstr, Value::uriFormat ).isString() );
202 BOOST_CHECK( Value( qchstr ).isString() );
203 BOOST_CHECK( Value( qchstr, Value::fsFormat ).isString() );
204 BOOST_CHECK( Value( qchstr, Value::uriFormat ).isString() );
206 BOOST_CHECK( Value( pchstr, Value::uriFormat ).isString() );
208 else if ( ch == '?' )
210 BOOST_CHECK( Value( chstr ).isString() );
211 BOOST_CHECK( Value( chstr, Value::fsFormat ).isString() );
212 BOOST_CHECK( Value( chstr, Value::uriFormat ).isString() );
214 BOOST_CHECK( Value( qchstr ).isString() );
215 BOOST_CHECK( Value( qchstr, Value::fsFormat ).isString() );
216 BOOST_CHECK( Value( qchstr, Value::uriFormat ).isString() );
218 BOOST_CHECK( Value( pchstr, Value::uriFormat ).isString() );
220 else if ( ch == '-' )
222 BOOST_CHECK_THROW( (Value( chstr )), std::invalid_argument );
223 BOOST_CHECK( Value( chstr, Value::fsFormat ).isNA() );
224 BOOST_CHECK( Value( chstr, Value::uriFormat ).isNA() );
226 BOOST_CHECK_THROW( (Value( qchstr )), std::invalid_argument );
227 BOOST_CHECK( Value( qchstr, Value::fsFormat ).isString() );
228 BOOST_CHECK( Value( qchstr, Value::uriFormat ).isString() );
230 BOOST_CHECK( Value( pchstr, Value::uriFormat ).isString() );
232 else if ( ch == '\\' )
234 BOOST_CHECK_THROW( (Value( chstr )), std::invalid_argument );
235 BOOST_CHECK_THROW( (Value( chstr, Value::fsFormat )), std::invalid_argument );
236 BOOST_CHECK( (Value( chstr, Value::uriFormat )).isString() );
238 BOOST_CHECK( Value( qchstr ).isString() );
239 BOOST_CHECK( Value( qchstr, Value::fsFormat ).isString() );
240 BOOST_CHECK( Value( qchstr, Value::uriFormat ).isString() );
242 BOOST_CHECK( Value( pchstr, Value::uriFormat ).isString() );
246 BOOST_CHECK_THROW( (Value( chstr )), std::invalid_argument );
247 Value f( chstr, Value::fsFormat );
248 BOOST_CHECK( f.isString() );
249 Value u( chstr, Value::uriFormat );
250 BOOST_CHECK( u.isString() );
252 BOOST_CHECK_EQUAL( f.asString(), u.asString() );
255 BOOST_CHECK_EQUAL( f.asFs(), chstr );
256 BOOST_CHECK_EQUAL( f.asUri(), chstr );
260 BOOST_CHECK_EQUAL( f.asFs(), qchstr );
261 BOOST_CHECK_EQUAL( f.asUri(), pchstr );
264 BOOST_CHECK( Value( qchstr ).isString() );
265 BOOST_CHECK( Value( qchstr, Value::fsFormat ).isString() );
266 BOOST_CHECK( Value( qchstr, Value::uriFormat ).isString() );
268 BOOST_CHECK( Value( pchstr, Value::uriFormat ).isString() );
272 BOOST_CHECK_THROW( Value( "\\!\\a\\-\\_\\.\\!" ), std::invalid_argument );
273 BOOST_CHECK_EQUAL( Value( "\\!\\a\\-\\_\\.\\!", Value::fsFormat ).asFs(), "\\!a-_.\\!" );
276 BOOST_AUTO_TEST_CASE(cpeid_type_checks)
278 for ( const auto & c : { Value::ANY, Value::NA, wildcardfree, wildcarded } )
280 BOOST_CHECK_EQUAL( c.isANY(), c.type() == Value::Type::ANY );
281 BOOST_CHECK_EQUAL( c.isNA(), c.type() == Value::Type::NA );
282 BOOST_CHECK_EQUAL( c.isWildcardfree(), c.type() == Value::Type::wildcardfree );
283 BOOST_CHECK_EQUAL( c.isWildcarded(), c.type() == Value::Type::wildcarded );
284 BOOST_CHECK_EQUAL( c.isLogical(), c.isLogical( c.type() ) );
285 BOOST_CHECK_EQUAL( c.isString(), c.isString( c.type() ) );
286 BOOST_CHECK_EQUAL( c.isLogical(), ! c.isString() );
290 BOOST_AUTO_TEST_CASE(cpeid_compare)
292 BOOST_CHECK( compare( Value::ANY, Value::ANY, SetCompare::equal ) );
293 BOOST_CHECK( compare( Value::ANY, Value::NA, SetCompare::properSuperset ) );
294 BOOST_CHECK( compare( Value::ANY, wildcardfree, SetCompare::properSuperset ) );
296 BOOST_CHECK( compare( Value::ANY, wildcarded, SetCompare::uncomparable ) );
298 BOOST_CHECK( compare( Value::ANY, wildcarded, SetCompare::properSuperset ) );
301 BOOST_CHECK( compare( Value::NA, Value::ANY, SetCompare::properSubset ) );
302 BOOST_CHECK( compare( Value::NA, Value::NA, SetCompare::equal ) );
303 BOOST_CHECK( compare( Value::NA, wildcardfree, SetCompare::disjoint ) );
305 BOOST_CHECK( compare( Value::NA, wildcarded, SetCompare::uncomparable ) );
307 BOOST_CHECK( compare( Value::NA, wildcarded, SetCompare::disjoint ) );
310 BOOST_CHECK( compare( wildcardfree, Value::ANY, SetCompare::properSubset ) );
311 BOOST_CHECK( compare( wildcardfree, Value::NA, SetCompare::disjoint ) );
312 //BOOST_CHECK( compare( wildcardfree, wildcardfree, _NeedsCloserLook, // equal or disjoint
313 BOOST_CHECK( compare( wildcardfree, wildcardfree, SetCompare::equal ) );
314 BOOST_CHECK( compare( wildcardfree, wildcardfree2, SetCompare::disjoint ) );
316 BOOST_CHECK( compare( wildcardfree, wildcarded, SetCompare::uncomparable ) );
318 //BOOST_CHECK( compare( wildcardfree, wildcarded, _NeedsCloserLook, // subset or disjoint
319 BOOST_CHECK( compare( wildcardfree, wildcarded, SetCompare::properSubset ) );
320 BOOST_CHECK( compare( wildcardfree, wildcarded2, SetCompare::disjoint ) );
323 BOOST_CHECK( compare( wildcarded, Value::ANY, SetCompare::properSubset ) );
324 BOOST_CHECK( compare( wildcarded, Value::NA, SetCompare::disjoint ) );
325 //BOOST_CHECK( compare( wildcarded, wildcardfree, _NeedsCloserLook, // superset or disjoint
326 BOOST_CHECK( compare( wildcarded, wildcardfree, SetCompare::properSuperset ) );
327 BOOST_CHECK( compare( wildcarded, wildcardfree2, SetCompare::disjoint ) );
329 BOOST_CHECK( compare( wildcarded, wildcarded, SetCompare::uncomparable ) );
331 //BOOST_CHECK( compare( wildcarded, wildcarded, _NeedsCloserLook, // equal or uncomparable
332 BOOST_CHECK( compare( wildcarded, wildcarded, SetCompare::equal ) );
333 BOOST_CHECK( compare( wildcarded, wildcarded2, SetCompare::uncomparable ) );
338 BOOST_AUTO_TEST_CASE(cpeid_value_string_wildcard)
340 for ( const auto & c : { Value( "a" ), Value( "\\*" ), Value( "\\?" ) } )
342 BOOST_CHECK( c.isWildcardfree() );
343 BOOST_CHECK( !c.isWildcarded() );
346 for ( const auto & c : { Value( "*\\*" ), Value( "\\**" ), Value( "?" ), Value( "??\\?" ), Value( "\\???" ) } )
348 BOOST_CHECK( !c.isWildcardfree() );
349 BOOST_CHECK( c.isWildcarded() );
353 ///////////////////////////////////////////////////////////////////
354 ///////////////////////////////////////////////////////////////////
356 BOOST_AUTO_TEST_CASE(cpeid_basics)
358 BOOST_CHECK_THROW( CpeId( "malformed" ), std::invalid_argument );
359 CpeId none( "malformed", CpeId::noThrow );
360 BOOST_CHECK_EQUAL( CpeId::NoThrowType::lastMalformed, "malformed" );
361 CpeId( "", CpeId::noThrow );
362 BOOST_CHECK_EQUAL( CpeId::NoThrowType::lastMalformed, "" );
364 for ( const auto & c : { CpeId(), CpeId( nullptr ), CpeId( "" ), CpeId( std::string() ) } )
366 BOOST_CHECK( ! c ); // evaluate false in boolean context
367 BOOST_CHECK_EQUAL( c.asString(), c.asFs() );
368 BOOST_CHECK_EQUAL( c.asFs(), "cpe:2.3:*:*:*:*:*:*:*:*:*:*:*" );
369 BOOST_CHECK_EQUAL( c.asUri(), "cpe:/" );
370 BOOST_CHECK_EQUAL( c.asWfn(), "wfn:[]" );
371 BOOST_CHECK_EQUAL( c, none ); // matching!!
374 for ( const auto & c : { CpeId( "cpe:/o:sle" ), CpeId( "cpe:/o:*" ) } )
376 BOOST_CHECK( c ); // evaluate true in boolean context
377 BOOST_CHECK( ! c.asString().empty() );// empty string rep
378 BOOST_CHECK_EQUAL( c, c ); // matching!!
382 void testStrconv( const std::string & fs, const std::string & uri, const std::string & wfn )
385 CpeId fromURI( uri );
387 BOOST_CHECK_EQUAL( fromFS, fromURI );
389 for ( const auto & c : { fromFS, fromURI } )
391 BOOST_CHECK_EQUAL( c.asFs(), fs );
392 BOOST_CHECK_EQUAL( c.asUri(), uri );
393 BOOST_CHECK_EQUAL( c.asWfn(), wfn );
397 BOOST_AUTO_TEST_CASE(cpeid_strconv)
399 // colon embedded in product value
400 testStrconv ( "cpe:2.3:a:opensuse:lib\\:zypp:14.16.0:beta:*:*:*:*:*:-",
401 "cpe:/a:opensuse:lib%3azypp:14.16.0:beta:~~~~~-",
402 "wfn:[part=\"a\",vendor=\"opensuse\",product=\"lib\\:zypp\",version=\"14\\.16\\.0\",update=\"beta\",other=NA]" );
404 testStrconv ( "cpe:2.3:a:hp:insight_diagnostics:7.4.0.1570:-:*:*:online:win2003:x64:*",
405 "cpe:/a:hp:insight_diagnostics:7.4.0.1570:-:~~online~win2003~x64~",
406 "wfn:[part=\"a\",vendor=\"hp\",product=\"insight_diagnostics\",version=\"7\\.4\\.0\\.1570\",update=NA,sw_edition=\"online\",target_sw=\"win2003\",target_hw=\"x64\"]" );
408 testStrconv ( "cpe:2.3:a:hp:openview_network_manager:7.51:*:*:*:*:linux:*:*",
409 "cpe:/a:hp:openview_network_manager:7.51::~~~linux~~",
410 "wfn:[part=\"a\",vendor=\"hp\",product=\"openview_network_manager\",version=\"7\\.51\",target_sw=\"linux\"]" );
412 testStrconv ( "cpe:2.3:a:foo\\\\bar:big\\$money_manager_2010:*:*:*:*:special:ipod_touch:80gb:*",
413 "cpe:/a:foo%5cbar:big%24money_manager_2010:::~~special~ipod_touch~80gb~",
414 "wfn:[part=\"a\",vendor=\"foo\\\\bar\",product=\"big\\$money_manager_2010\",sw_edition=\"special\",target_sw=\"ipod_touch\",target_hw=\"80gb\"]" );
416 BOOST_CHECK_THROW( (CpeId( "cpe:/x:" )), std::invalid_argument ); // illegal part 'x'
417 BOOST_CHECK_THROW( CpeId( "cpe:/a:foo%5cbar:big%24money_2010%07:::~~special~ipod_touch~80gb~" ), std::invalid_argument ); // illegal %07
418 BOOST_CHECK_EQUAL( CpeId( "cpe:/a:foo~bar:big%7emoney_2010" ).asUri(), "cpe:/a:foo%7ebar:big%7emoney_2010" ); // unescaped ~ is ok but not preferred
421 BOOST_AUTO_TEST_CASE(cpeid_matches)
423 CpeId sle( "cpe:/o:sles" );
424 CpeId win( "cpe:/o:windows" );
426 CpeId ons( "cpe:2.3:o:??????s" );
427 CpeId oops( "cpe:2.3:o:?????s" );
429 BOOST_CHECK_EQUAL( compare( sle, win ), SetRelation::disjoint );
431 BOOST_CHECK_EQUAL( compare( sle, any ), SetRelation::subset );
432 BOOST_CHECK_EQUAL( compare( win, any ), SetRelation::subset );
434 BOOST_CHECK_EQUAL( compare( any, sle ), SetRelation::superset );
435 BOOST_CHECK_EQUAL( compare( any, win ), SetRelation::superset );
438 BOOST_CHECK_EQUAL( compare( sle, ons ), SetRelation::uncomparable );
439 BOOST_CHECK_EQUAL( compare( win, ons ), SetRelation::uncomparable );
441 BOOST_CHECK_EQUAL( compare( sle, ons ), SetRelation::subset );
442 BOOST_CHECK_EQUAL( compare( win, ons ), SetRelation::subset );
445 BOOST_CHECK_EQUAL( compare( ons, sle ), SetRelation::superset );
446 BOOST_CHECK_EQUAL( compare( ons, win ), SetRelation::superset );
448 BOOST_CHECK_EQUAL( compare( oops, sle ), SetRelation::superset );
449 BOOST_CHECK_EQUAL( compare( oops, win ), SetRelation::disjoint );