ResStatus transition testcase
authorMichael Andres <ma@suse.de>
Mon, 2 Mar 2009 13:19:17 +0000 (14:19 +0100)
committerMichael Andres <ma@suse.de>
Mon, 2 Mar 2009 13:30:26 +0000 (14:30 +0100)
tests/zypp/ResStatus_test.cc
zypp/ResStatus.cc
zypp/ResStatus.h

index 5d74504..c18e92f 100644 (file)
@@ -3,22 +3,6 @@
 
 #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)
 {
   {
@@ -37,6 +21,30 @@ 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 );
@@ -46,6 +54,23 @@ typedef void (* Evaluate)( ResStatus::TransactValue, 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:
@@ -54,20 +79,25 @@ void testTable( Transition transition, Evaluate evaluate )
   //
   // 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 );
         }
       }
@@ -75,54 +105,107 @@ void testTable( Transition transition, Evaluate evaluate )
   }
 }
 
-// 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
index b3daad0..d59b6e0 100644 (file)
@@ -98,6 +98,32 @@ namespace zypp
     return str;
   }
 
+
+#define OUTS(X) case ResStatus::X: return str << #X; break
+
+  std::ostream & operator<<( std::ostream & str, ResStatus::TransactValue obj )
+  {
+    switch ( obj )
+    {
+      OUTS( KEEP_STATE );
+      OUTS( LOCKED );
+      OUTS( TRANSACT );
+    }
+    return str;
+  }
+
+  std::ostream & operator<<( std::ostream & str, ResStatus::TransactByValue obj )
+  {
+    switch ( obj )
+    {
+      OUTS( SOLVER );
+      OUTS( APPL_LOW );
+      OUTS( APPL_HIGH );
+      OUTS( USER );
+    }
+    return str;
+  }
+
   /////////////////////////////////////////////////////////////////
 } // namespace zypp
 ///////////////////////////////////////////////////////////////////
index 6a7962b..6cb25f7 100644 (file)
@@ -692,6 +692,12 @@ namespace zypp
   /** \relates ResStatus Stream output */
   std::ostream & operator<<( std::ostream & str, const ResStatus & obj );
 
+  /** \relates ResStatus Stream output */
+  std::ostream & operator<<( std::ostream & str, ResStatus::TransactValue obj );
+
+  /** \relates ResStatus Stream output */
+  std::ostream & operator<<( std::ostream & str, ResStatus::TransactByValue obj );
+
   /** \relates ResStatus */
   inline bool operator==( const ResStatus & lhs, const ResStatus & rhs )
   { return lhs._bitfield == rhs._bitfield; }