#define BOOST_TEST_MODULE ResStatus
-template<class _Tp, int N>
-inline _Tp * begin( _Tp (& _array)[N] ) { return _array; }
-
-template<class _Tp, int N>
-inline _Tp * end( _Tp (& _array)[N] ) { return _array + (sizeof(_array)/sizeof(_Tp)); }
-
-ResStatus::TransactByValue transactByValues[] = {
- ResStatus::USER, ResStatus::APPL_HIGH, ResStatus::APPL_LOW, ResStatus::SOLVER
-};
-
-ResStatus::TransactValue transactValues[] = {
- ResStatus::TRANSACT, ResStatus::KEEP_STATE, ResStatus::LOCKED
-};
-
-bool transactTo[] = { true, false };
-
BOOST_AUTO_TEST_CASE(Default)
{
{
}
}
+////////////////////////////////////////////////////////////////////////////////
+// tools
+////////////////////////////////////////////////////////////////////////////////
+template<class _Tp>
+inline const _Tp & max( const _Tp & lhs, const _Tp & rhs )
+{ return lhs < rhs ? rhs : lhs; }
+
+template<class _Tp, int N>
+inline _Tp * begin( _Tp (& _array)[N] ) { return _array; }
+
+template<class _Tp, int N>
+inline _Tp * end( _Tp (& _array)[N] ) { return _array + (sizeof(_array)/sizeof(_Tp)); }
+
+ResStatus::TransactByValue transactByValues[] = {
+ ResStatus::USER, ResStatus::APPL_HIGH, ResStatus::APPL_LOW, ResStatus::SOLVER
+};
+
+ResStatus::TransactValue transactValues[] = {
+ ResStatus::TRANSACT, ResStatus::KEEP_STATE, ResStatus::LOCKED
+};
+
+bool transactTo[] = {
+ true, false
+};
// Status transition like setTransact, setLock, setSoftTransact
typedef bool (ResStatus::* Transition)( bool, ResStatus::TransactByValue );
bool, ResStatus::TransactByValue, /* toState, toBy */
bool, ResStatus ); /* done, result */
+// build status and return whether the comination is supported. (e.g currently no LOCKED state below APPL_HIGH)
+inline bool initStatus( ResStatus::TransactValue fromState, ResStatus::TransactByValue fromBy, ResStatus & from )
+{
+ from = ResStatus();
+ if ( fromState == ResStatus::KEEP_STATE )
+ {
+ from.setSoftLock( fromBy );
+ }
+ else
+ {
+ from.setTransactValue( fromState, fromBy );
+ if ( fromState == ResStatus::LOCKED && ! from.isLocked() )
+ return false; // no lock at this level (by now just USER APPL_HIGH)
+ }
+ return true;
+}
+
void testTable( Transition transition, Evaluate evaluate )
{
// Table: For each causer combination (fromBy -> toBy) invoke transition:
//
// And evaluate the result.
//
- for ( ResStatus::TransactByValue * fromBy = begin( transactByValues ); fromBy != end( transactByValues ); ++fromBy )
+ for ( ResStatus::TransactByValue * toBy = begin( transactByValues ); toBy != end( transactByValues ); ++toBy )
{
- for ( ResStatus::TransactByValue * toBy = begin( transactByValues ); toBy != end( transactByValues ); ++toBy )
+ for ( ResStatus::TransactByValue * fromBy = begin( transactByValues ); fromBy != end( transactByValues ); ++fromBy )
{
+ INT << "=== " << *fromBy << " ==> " << *toBy << " ===" << endl;
for ( ResStatus::TransactValue * fromState = begin( transactValues ); fromState != end( transactValues ); ++fromState )
{
+ ResStatus from;
+ if ( ! initStatus( *fromState, *fromBy, from ) )
+ {
+ //WAR << "Unsupported ResStatus(" << *fromState << "," << *fromBy << ")" << endl;
+ continue; // Unsupported ResStatus
+ }
for ( bool * toState = begin( transactTo ); toState != end( transactTo ); ++toState )
{
- ResStatus from;
- from.setTransactValue( *fromState, *fromBy ); // NEEDS FIX!
-
ResStatus result( from );
bool done = (result.*transition)( *toState, *toBy );
-
+ if ( ! done )
+ BOOST_CHECK_EQUAL( from, result ); // status stays unchaged on failure!
evaluate( *fromState, *fromBy, *toState, *toBy, done, result );
}
}
}
}
-// Transitions succeeds always:
-#define CHECK_DONE_ALWAYS BOOST_CHECK_EQUAL( done, true )
+// BOOST_CHECK_EQUAL or BOOST_REQUIRE_EQUAL
+#define X BOOST_CHECK_EQUAL
+
+
+// Transition must succeeds always
+#define CHECK_DONE_ALWAYS X( done, true ); if ( ! done ) return
+
+// Transition succeeds if same or higher TransactByValue
+#define CHECK_DONE_IFCAUSER X( done, toBy >= fromBy ); if ( ! done ) return
+
+// Transition succeeds if a locker (APPL_HIGH or USER)
+#define CHECK_DONE_ALWAYS_IFLOCKER X( done, toBy >= ResStatus::APPL_HIGH ); if ( ! done ) return
+
+// Transition succeeds if a locker (APPL_HIGH or USER) and same or higher TransactByValue
+#define CHECK_DONE_IFCAUSER_ISLOCKER X( done, toBy >= max(fromBy,ResStatus::APPL_HIGH) ); if ( ! done ) return
+
+
+// Expected target state after transistion
+#define CHECK_STATE(NEW) X( result.getTransactValue(), ResStatus::NEW )
-// Transitions succeeds if same or higher TransactByValue:
-#define CHECK_DONE_IFCAUSER BOOST_CHECK_EQUAL( done, *toBy >= *fromBy )
+
+// Transition result: Remember the causer (i.e. may downgrade superior causer of previous state)
+#define CHECK_CAUSER_SET X( result.getTransactByValue(), toBy )
+
+// Transition result: Remember a superior causer
+#define CHECK_CAUSER_RAISED X( result.getTransactByValue(), max(fromBy,toBy) )
+
+// Transition result: Causer stays the same
+#define CHECK_CAUSER_STAYS X( result.getTransactByValue(), fromBy )
+
+// Transition result: Causer reset to least (SOLVER) level.
+#define CHECK_CAUSER_TO_SOLVER X( result.getTransactByValue(), ResStatus::SOLVER )
+
+
+////////////////////////////////////////////////////////////////////////////////
+// test cases (see BOOST_AUTO_TEST_CASE(transition))
+////////////////////////////////////////////////////////////////////////////////
+// All tests below should define 3 checks, abbrev. by defines
+//
+// CHECK_DONE_*: When does the tranaction succeed? (return if not)
+// CHECK_STATE( NEXT ): The state the transition leads to (if successfull)
+// CHECK_CAUSER_*: Changes to the remembered causer (if successfull)
+//
+
+#define DOCHECK( FROMSTATE, TOSTATE, C_DONE, C_STATE, C_CAUSER ) \
+ if ( ResStatus::FROMSTATE == fromState && TOSTATE == toState ) { C_DONE; CHECK_STATE( C_STATE ); C_CAUSER; }
void evaluateSetTransact( ResStatus::TransactValue fromState, ResStatus::TransactByValue fromBy,
bool toState, ResStatus::TransactByValue toBy,
bool done, ResStatus result )
{
ResStatus from;
- from.setTransactValue( fromState, fromBy );
+ initStatus( fromState, fromBy, from );
MIL << from << " =setTransact("<<toState<<","<<toBy<<")=>\t" << done << ":" << result << endl;
- switch ( fromState )
- {
- case ResStatus::TRANSACT:
- if ( toState )
- {
- }
- else
- {
- }
- break;
- case ResStatus::KEEP_STATE:
- if ( toState )
- {
- }
- else
- {
- }
- break;
- case ResStatus::LOCKED:
- if ( toState )
- {
- }
- else
- {
- }
- break;
- }
+ DOCHECK( TRANSACT, true, CHECK_DONE_ALWAYS, TRANSACT, CHECK_CAUSER_RAISED );
+ DOCHECK( TRANSACT, false, CHECK_DONE_IFCAUSER, KEEP_STATE, CHECK_CAUSER_RAISED ); // from transact into softlock
+ DOCHECK( KEEP_STATE, true, CHECK_DONE_ALWAYS, TRANSACT, CHECK_CAUSER_SET );
+ DOCHECK( KEEP_STATE, false, CHECK_DONE_ALWAYS, KEEP_STATE, CHECK_CAUSER_STAYS ); // keep is not raised to softlock
+ DOCHECK( LOCKED, true, CHECK_DONE_IFCAUSER, TRANSACT, CHECK_CAUSER_SET );
+ DOCHECK( LOCKED, false, CHECK_DONE_ALWAYS, LOCKED, CHECK_CAUSER_STAYS );
+}
+
+void evaluateSetSoftTransact( ResStatus::TransactValue fromState, ResStatus::TransactByValue fromBy,
+ bool toState, ResStatus::TransactByValue toBy,
+ bool done, ResStatus result )
+{
+ ResStatus from;
+ initStatus( fromState, fromBy, from );
+ MIL << from << " =setSoftTransact("<<toState<<","<<toBy<<")=>\t" << done << ":" << result << endl;
+
+ DOCHECK( TRANSACT, true, CHECK_DONE_ALWAYS, TRANSACT, CHECK_CAUSER_RAISED );
+ DOCHECK( TRANSACT, false, CHECK_DONE_IFCAUSER, KEEP_STATE, CHECK_CAUSER_RAISED ); // from transact into softlock
+ DOCHECK( KEEP_STATE, true, CHECK_DONE_IFCAUSER, TRANSACT, CHECK_CAUSER_SET ); // leaving KEEP requires sup. causer
+ DOCHECK( KEEP_STATE, false, CHECK_DONE_ALWAYS, KEEP_STATE, CHECK_CAUSER_STAYS ); // keep is not raised to softlock
+ DOCHECK( LOCKED, true, CHECK_DONE_IFCAUSER, TRANSACT, CHECK_CAUSER_SET );
+ DOCHECK( LOCKED, false, CHECK_DONE_ALWAYS, LOCKED, CHECK_CAUSER_STAYS );
+}
+
+// Check whether failures are ok and whether success lead to the correct state
+void evaluateSetLock( ResStatus::TransactValue fromState, ResStatus::TransactByValue fromBy,
+ bool toState, ResStatus::TransactByValue toBy,
+ bool done, ResStatus result )
+{
+ ResStatus from;
+ initStatus( fromState, fromBy, from );
+ MIL << from << " =setLock("<<toState<<","<<toBy<<")=>\t" << done << ":" << result << endl;
+
+ DOCHECK( TRANSACT, true, CHECK_DONE_IFCAUSER_ISLOCKER, LOCKED, CHECK_CAUSER_SET ); // transact is 'not locked'
+ DOCHECK( TRANSACT, false, CHECK_DONE_ALWAYS, TRANSACT, CHECK_CAUSER_STAYS );
+ DOCHECK( KEEP_STATE, true, CHECK_DONE_ALWAYS_IFLOCKER, LOCKED, CHECK_CAUSER_SET );
+ DOCHECK( KEEP_STATE, false, CHECK_DONE_ALWAYS, KEEP_STATE, CHECK_CAUSER_STAYS );
+ DOCHECK( LOCKED, true, CHECK_DONE_ALWAYS, LOCKED, CHECK_CAUSER_RAISED );
+ DOCHECK( LOCKED, false, CHECK_DONE_IFCAUSER, KEEP_STATE, CHECK_CAUSER_TO_SOLVER );
}
-#if 0
BOOST_AUTO_TEST_CASE(transition)
{
- base::LogControl::TmpLineWriter shutUp( new log::FileLineWriter( "/home/ma/zypp/BUILD/libzypp/devel/devel.ma/LOGFILE" ) );
+ //base::LogControl::TmpLineWriter shutUp( new log::FileLineWriter( "-" ) );
MIL << endl;
- testTable( &ResStatus::setTransact, &evaluateSetTransact );
+ testTable( &ResStatus::setTransact, &evaluateSetTransact );
+ testTable( &ResStatus::setSoftTransact, &evaluateSetSoftTransact );
+ testTable( &ResStatus::setLock, &evaluateSetLock );
}
-#endif