From 3beabd0d425a6266321b3181a85e4e7de1899974 Mon Sep 17 00:00:00 2001 From: Michael Andres Date: Wed, 2 Sep 2009 15:50:13 +0200 Subject: [PATCH] Fix PoolQuery comparison (bnc #528755) --- tests/zypp/PoolQuery_test.cc | 93 ++++++++++++++++++++++------- zypp/PoolQuery.cc | 139 ++++++++++++++++++++++++++++++++----------- zypp/PoolQuery.h | 4 +- 3 files changed, 176 insertions(+), 60 deletions(-) diff --git a/tests/zypp/PoolQuery_test.cc b/tests/zypp/PoolQuery_test.cc index ed92e65..d2a44fe 100644 --- a/tests/zypp/PoolQuery_test.cc +++ b/tests/zypp/PoolQuery_test.cc @@ -20,6 +20,9 @@ BOOST_AUTO_TEST_CASE(pool_query_init) } ///////////////////////////////////////////////////////////////////////////// +static std::ofstream devNull; +#define COUT devNull + struct PrintAndCount { PrintAndCount() : _count(0) {} @@ -27,7 +30,7 @@ struct PrintAndCount bool operator()( const sat::Solvable & solvable ) { zypp::PoolItem pi( zypp::ResPool::instance().find( solvable ) ); - cout << pi.resolvable() << endl; + COUT << pi.resolvable() << endl; ++_count; return true; } @@ -645,27 +648,73 @@ BOOST_AUTO_TEST_CASE(pool_query_serialize) BOOST_AUTO_TEST_CASE(pool_query_equal) { cout << "****equal****" << endl; - PoolQuery q; - q.addString("zypp"); - q.addAttribute(sat::SolvAttr::name); - q.setMatchGlob(); - PoolQuery q2; - q2.addString("zypp"); - q2.addAttribute(sat::SolvAttr::name); - q2.setMatchGlob(); - PoolQuery q3; - q3.addString("zypp"); - q3.addAttribute(sat::SolvAttr::name); - q3.setMatchGlob(); - q3.setRequireAll(true); - PoolQuery q4; - q4.addAttribute(sat::SolvAttr::name,"zypp"); - q4.setMatchGlob(); - - BOOST_CHECK(q==q2); - BOOST_CHECK(q!=q3); - BOOST_CHECK(q==q4); - BOOST_CHECK(q4!=q3); + std::vector v; + { + PoolQuery q; + v.push_back( q ); + } + { + PoolQuery q; + q.addAttribute( sat::SolvAttr::name, "zypper" ); + q.setMatchExact(); + q.setCaseSensitive(true); + v.push_back( q ); + } + { + PoolQuery q; + q.addAttribute( sat::SolvAttr::name, "libzypp" ); // different + q.setMatchExact(); + q.setCaseSensitive(true); + v.push_back( q ); + } + { + PoolQuery q; + q.addAttribute( sat::SolvAttr::vendor, "zypper" ); // different + q.setMatchExact(); + q.setCaseSensitive(true); + v.push_back( q ); + } + { + PoolQuery q; + q.addAttribute( sat::SolvAttr::name, "zypper" ); + q.setMatchExact(); + q.setCaseSensitive(false); // different + v.push_back( q ); + } + { + PoolQuery q; + q.addAttribute( sat::SolvAttr::name, "zypper" ); + q.setMatchSubstring(); // different + q.setCaseSensitive(true); + v.push_back( q ); + } + { + PoolQuery q; + q.addDependency( sat::SolvAttr::provides, "zypper" ); + v.push_back( q ); + } + { + PoolQuery q; + q.addDependency( sat::SolvAttr::provides, "zypper", Rel::GT, Edition("1.0") ); + v.push_back( q ); + } + { + PoolQuery q; + q.addDependency( sat::SolvAttr::provides, "zypper", Rel::GT, Edition("2.0") ); + v.push_back( q ); + } + + for_( li, 0U, v.size() ) + { + for_( ri, 0U, v.size() ) + { + COUT << li << " <> " << ri << endl; + bool equal( v[li] == v[ri] ); + bool nequal( v[li] != v[ri] ); + BOOST_CHECK_EQUAL( equal, li==ri ); + BOOST_CHECK_EQUAL( equal, !nequal ); + } + } } ///////////////////////////////////////////////////////////////////////////// diff --git a/zypp/PoolQuery.cc b/zypp/PoolQuery.cc index 79f5ee6..5f7f51c 100644 --- a/zypp/PoolQuery.cc +++ b/zypp/PoolQuery.cc @@ -54,6 +54,8 @@ namespace zypp * As the \ref predicate takes an iterator pointing to the current * match, it's also suitable for sub-structure (flexarray) inspection * (\see \ref sat::LookupAttr::iterator::solvAttrSubEntry). + * + * \note: \see \ref addPredicate for further constraints. */ struct AttrMatchData { @@ -67,20 +69,63 @@ namespace zypp , attrMatcher( attrMatcher_r ) {} - AttrMatchData( sat::SolvAttr attr_r, const sat::AttrMatcher & attrMatcher_r, const Predicate & predicate_r ) + AttrMatchData( sat::SolvAttr attr_r, const sat::AttrMatcher & attrMatcher_r, + const Predicate & predicate_r, const std::string & predicateStr_r ) : attr( attr_r ) , attrMatcher( attrMatcher_r ) , predicate( predicate_r ) + , predicateStr( predicateStr_r ) {} + /** A usable Predicate must provide a string representation. + * As there is no \c operator== for \ref Predicate, we compare it's + * string representation instead. Actually Predicate deserves to become + * a class which is also serializable, so we can store predicated queries. + */ + template + void addPredicate( const _Predicate & predicate_r ) + { + predicate = predicate_r; + predicateStr = predicate_r.stringRep(); + } + sat::SolvAttr attr; sat::AttrMatcher attrMatcher; Predicate predicate; + std::string predicateStr; }; - std::ostream & operator<<( std::ostream & str, const AttrMatchData & obj ) + /** \relates AttrMatchData */ + inline std::ostream & operator<<( std::ostream & str, const AttrMatchData & obj ) + { + str << obj.attr << ": " << obj.attrMatcher; + if ( obj.predicate ) + str << " +(" << obj.predicateStr << ")"; + return str; + } + + /** \relates AttrMatchData */ + inline bool operator==( const AttrMatchData & lhs, const AttrMatchData & rhs ) + { + return ( lhs.attr == rhs.attr + && lhs.attrMatcher == rhs.attrMatcher + && lhs.predicateStr == rhs.predicateStr ); + } + + /** \relates AttrMatchData */ + inline bool operator!=( const AttrMatchData & lhs, const AttrMatchData & rhs ) + { return !( lhs == rhs ); } + + /** \relates AttrMatchData Arbitrary order for std::container. */ + inline bool operator<( const AttrMatchData & lhs, const AttrMatchData & rhs ) { - return str << obj.attr << ": " << obj.attrMatcher << ( obj.predicate ? " (+predicate)" : "" ); + if ( lhs.attr != rhs.attr ) + return ( lhs.attr < rhs.attr ); + if ( lhs.attrMatcher != rhs.attrMatcher ) + return ( lhs.attrMatcher < rhs.attrMatcher ); + if ( lhs.predicateStr != rhs.predicateStr ) + return ( lhs.predicateStr < rhs.predicateStr ); + return false; } typedef std::list AttrMatchList; @@ -127,6 +172,13 @@ namespace zypp return overlaps( Edition::MatchRange( cap.op(), cap.ed() ), _range ); } + std::string stringRep() const + { + std::ostringstream str; + str << "EditionRange " << _range.op << " " << _range.value; + return str.str(); + } + Edition::MatchRange _range; }; @@ -142,6 +194,13 @@ namespace zypp return overlaps( Edition::MatchRange( Rel::EQ, iter_r.inSolvable().edition() ), _range ); } + std::string stringRep() const + { + std::ostringstream str; + str << "SolvableRange " << _range.op << " " << _range.value; + return str.str(); + } + Edition::MatchRange _range; }; @@ -160,6 +219,13 @@ namespace zypp return _cap.matches( iter_r.asType() ) == CapMatch::yes; } + std::string stringRep() const + { + std::ostringstream str; + str << "CapabilityMatch " << _cap; + return str.str(); + } + Capability _cap; }; @@ -196,7 +262,7 @@ namespace zypp /** Raw attributes */ AttrRawStrMap _attrs; /** Uncompiled attributes with predicate. */ - AttrMatchList _uncompiledPredicated; + std::set _uncompiledPredicated; /** Sat solver search flags */ Match _flags; @@ -219,6 +285,26 @@ namespace zypp //@} public: + + bool operator==( const PoolQuery::Impl & rhs ) const + { + return ( _strings == rhs._strings + && _attrs == rhs._attrs + && _uncompiledPredicated == rhs._uncompiledPredicated + && _flags == rhs._flags + && _match_word == rhs._match_word + && _require_all == rhs._require_all + && _status_flags == rhs._status_flags + && _edition == rhs._edition + && _op == rhs._op + && _repos == rhs._repos + && _kinds == rhs._kinds ); + } + + bool operator!=( const PoolQuery::Impl & rhs ) const + { return ! operator==( rhs ); } + + public: /** Compile the regex. * Basically building the \ref _attrMatchList from strings. * \throws MatchException Any of the exceptions thrown by \ref AttrMatcher::compile. @@ -239,6 +325,7 @@ namespace zypp { return new Impl( *this ); } }; + /////////////////////////////////////////////////////////////////// struct MyInserter { @@ -409,7 +496,7 @@ attremptycheckend: _attrMatchList.push_back( AttrMatchData( it->attr, sat::AttrMatcher( rcstrings, cflags ), - it->predicate ) ); + it->predicate, it->predicateStr ) ); } else { @@ -656,16 +743,16 @@ attremptycheckend: break; } - // Match::OTHER indicates need to compile. - sat::AttrMatcher matcher( name, Match::OTHER ); + // Match::OTHER indicates need to compile + // (merge global search strings into name). + AttrMatchData attrMatchData( attr, sat::AttrMatcher( name, Match::OTHER ) ); - AttrMatchData::Predicate pred; if ( isDependencyAttribute( attr ) ) - pred = EditionRangePredicate( op, edition ); + attrMatchData.addPredicate( EditionRangePredicate( op, edition ) ); else - pred = SolvableRangePredicate( op, edition ); + attrMatchData.addPredicate( SolvableRangePredicate( op, edition ) ); - _pimpl->_uncompiledPredicated.push_back( AttrMatchData( attr, matcher, pred ) ); + _pimpl->_uncompiledPredicated.insert( attrMatchData ); } void PoolQuery::addDependency( const sat::SolvAttr & attr, Capability cap_r ) @@ -675,15 +762,14 @@ attremptycheckend: return; // Matches STRING per default. (won't get compiled!) - sat::AttrMatcher matcher( cap.name().asString() ); + AttrMatchData attrMatchData( attr, sat::AttrMatcher( cap.name().asString() ) ); - AttrMatchData::Predicate pred; if ( isDependencyAttribute( attr ) ) - pred = CapabilityMatchPredicate( cap_r ); + attrMatchData.addPredicate( CapabilityMatchPredicate( cap_r ) ); else - pred = SolvableRangePredicate( cap.op(), cap.ed() ); + attrMatchData.addPredicate( SolvableRangePredicate( cap.op(), cap.ed() ) ); - _pimpl->_uncompiledPredicated.push_back( AttrMatchData( attr, matcher, pred ) ); + _pimpl->_uncompiledPredicated.insert( attrMatchData ); } void PoolQuery::setEdition(const Edition & edition, const Rel & op) @@ -1156,25 +1242,8 @@ attremptycheckend: ostream & operator<<( ostream & str, const PoolQuery & obj ) { return str << obj.asString(); } - bool PoolQuery::operator==(const PoolQuery& a) const - { - if( flags() != a.flags() ) - return false; - if( a.matchWord() != matchWord()) - return false; - if( a.requireAll() != requireAll() ) - return false; - if ( a.kinds() != kinds() ) - return false; - if ( a.repos() != repos() ) - return false; - if(a.edition() != edition()) - return false; - if(a.editionRel() != editionRel()) - return false; - - return true; - } + bool PoolQuery::operator==( const PoolQuery & rhs ) const + { return *_pimpl == *rhs._pimpl; } /////////////////////////////////////////////////////////////////// namespace detail diff --git a/zypp/PoolQuery.h b/zypp/PoolQuery.h index 4238155..8f783fa 100644 --- a/zypp/PoolQuery.h +++ b/zypp/PoolQuery.h @@ -84,11 +84,9 @@ namespace zypp class PoolQuery : public sat::SolvIterMixin { public: - typedef std::set StrContainer; typedef std::set Kinds; + typedef std::set StrContainer; typedef std::map AttrRawStrMap; - typedef std::map AttrCompiledStrMap; - typedef std::map AttrRegexMap; typedef detail::PoolQueryIterator const_iterator; typedef unsigned int size_type; -- 2.7.4