[dali_1.3.48] Merge branch 'devel/master' 59/192359/1
authorRichard Huang <r.huang@samsung.com>
Fri, 2 Nov 2018 11:42:58 +0000 (11:42 +0000)
committerRichard Huang <r.huang@samsung.com>
Fri, 2 Nov 2018 11:42:58 +0000 (11:42 +0000)
Change-Id: I40bd049b9feae615c9641abddf23addc90eda52a

automated-tests/README.md
automated-tests/src/dali-toolkit/dali-toolkit-test-utils/dali-test-suite-utils.h
automated-tests/src/dali-toolkit/dali-toolkit-test-utils/test-application.cpp
automated-tests/src/dali-toolkit/dali-toolkit-test-utils/test-application.h
automated-tests/src/dali-toolkit/utc-Dali-LayoutingSettingAndRemoval.cpp
dali-toolkit/devel-api/controls/control-devel.h
dali-toolkit/internal/controls/control/control-data-impl.cpp
dali-toolkit/public-api/dali-toolkit-version.cpp
packaging/dali-toolkit.spec

index 0ca2dd0..ebc9e4f 100644 (file)
@@ -195,7 +195,6 @@ If you are adding test cases to existing files, then all you need to do is creat
       END_TEST;
     }
 
-
 Note that **there must be no extra whitespace in the method signature** (i.e., it must violate our coding convention and follow __exactly__ this pattern: `int UtcDaliMyTestcaseName(void)`), as it's parsed by an awk script to auto-generate the testcase arrays in the main header file.
 
 You can contine to use the TET api, e.g. `tet_infoline`, `tet_result` and our test check methods `DALI_TEST_CHECK`, `DALI_TEST_EQUALS`, etc.
@@ -205,6 +204,41 @@ If you need any non-test methods or variables, ensure they are wrapped in an ano
 If you are adding new test files, then you need to add the filename to the SET(TC_SOURCES...
 section of CMakeLists.txt (this is also parsed by an awk script prior to building)
 
+Good Practices
+--------------
+Use DALI_TEST_EQUALS to test actual value against expected value, like this:
+
+    DALI_TEST_EQUALS( actor.GetProperty< float >( Actor::Property::COLOR_ALPHA ), 0.9f, TEST_LOCATION );
+
+This will speed up debugging in case the test some day fails. There is also a variant to test that value is greater than expected:
+
+    DALI_TEST_GREATER( textureBindIndex[1], textureBindIndex[2], TEST_LOCATION );
+
+When doing negative tests where your code uses DALI_ASSERT_ALWAYS, use the DALI_TEST_ASSERTION macro, like below:
+
+    DALI_TEST_ASSERTION(
+    {
+        animation.AnimateTo( Property( actor, Actor::Property::PARENT_ORIGIN ), targetParentOrigin );
+    }, "IsPropertyAnimatable( index )" );
+
+This macro will catch the DALi Exception and check that the correct assert message was included. It will also fail the test in case the assert did not occur. It also reduces the amount of false positive error logging whilst the  is being thrown making it easier to see the real errors.
+
+Note, DALI_ASSERT_DEBUG cannot be tested as tests execute against release version of the code.
+
+Use additional scope to control the life of stack allocated objects, such as DALi handles
+
+    // try reparenting an orphaned child
+    {
+        Actor temporaryParent = Actor::New();
+        temporaryParent.Add( child );
+        DALI_TEST_EQUALS( parent2.GetChildCount(), 0u, TEST_LOCATION );
+    }
+    // temporaryParent has now died, reparent the orphaned child
+    parent2.Add( child );
+    DALI_TEST_EQUALS( parent2.GetChildCount(), 1u, TEST_LOCATION );
+
+Always test the output of your test by making your code fail!!!
+
 Debugging
 =========
 
index ed1a65f..70f4254 100644 (file)
@@ -344,6 +344,27 @@ inline void DALI_TEST_PRINT_ASSERT( DaliException& e )
   tet_printf("Assertion %s failed at %s\n", e.condition, e.location );
 }
 
+/**
+ * Test that given piece of code triggers the right assertion
+ * Fails the test if the assert didn't occur.
+ * Turns off logging during the execution of the code to avoid excessive false positive log output from the assertions
+ * @param expressions code to execute
+ * @param assertstring the substring expected in the assert
+ */
+#define DALI_TEST_ASSERTION( expressions, assertstring ) \
+try \
+{ \
+  TestApplication::EnableLogging( false ); \
+  expressions; \
+  TestApplication::EnableLogging( true ); \
+  fprintf(stderr, "Test failed in %s, expected assert: '%s' didn't occur\n", __FILELINE__, assertstring ); \
+  tet_result(TET_FAIL); \
+  throw("TET_FAIL"); } \
+catch( Dali::DaliException& e ) \
+{ \
+  DALI_TEST_ASSERT( e, assertstring, TEST_LOCATION ); \
+}
+
 // Functor to test whether an Applied signal is emitted
 struct ConstraintAppliedCheck
 {
index a20ef6d..c953f50 100644 (file)
@@ -20,6 +20,7 @@
 namespace Dali
 {
 
+bool TestApplication::mLoggingEnabled = true;
 
 TestApplication::TestApplication( uint32_t surfaceWidth,
                                   uint32_t surfaceHeight,
@@ -77,30 +78,33 @@ void TestApplication::LogContext( bool start, const char* tag )
 {
   if( start )
   {
-    fprintf(stderr, "INFO: Trace Start: %s", tag);
+    fprintf(stderr, "INFO: Trace Start: %s\n", tag);
   }
   else
   {
-    fprintf(stderr, "INFO: Trace End: %s", tag);
+    fprintf(stderr, "INFO: Trace End: %s\n", tag);
   }
 }
 
 void TestApplication::LogMessage(Dali::Integration::Log::DebugPriority level, std::string& message)
 {
-  switch(level)
+  if( mLoggingEnabled )
   {
-    case Dali::Integration::Log::DebugInfo:
-      fprintf(stderr, "INFO: %s", message.c_str());
-      break;
-    case Dali::Integration::Log::DebugWarning:
-      fprintf(stderr, "WARN: %s", message.c_str());
-      break;
-    case Dali::Integration::Log::DebugError:
-      fprintf(stderr, "ERROR: %s", message.c_str());
-      break;
-    default:
-      fprintf(stderr, "DEFAULT: %s", message.c_str());
-      break;
+    switch(level)
+    {
+      case Dali::Integration::Log::DebugInfo:
+        fprintf(stderr, "INFO: %s", message.c_str());
+        break;
+      case Dali::Integration::Log::DebugWarning:
+        fprintf(stderr, "WARN: %s", message.c_str());
+        break;
+      case Dali::Integration::Log::DebugError:
+        fprintf(stderr, "ERROR: %s", message.c_str());
+        break;
+      default:
+        fprintf(stderr, "DEFAULT: %s", message.c_str());
+        break;
+    }
   }
 }
 
index 49f2b3c..d1e042d 100644 (file)
@@ -78,6 +78,10 @@ public:
   void ResetContext();
   bool GetRenderNeedsUpdate();
   uint32_t Wait( uint32_t durationToWait );
+  static void EnableLogging( bool enabled )
+  {
+    mLoggingEnabled = enabled;
+  }
 
 private:
   void DoUpdate( uint32_t intervalMilliseconds, const char* location=NULL );
@@ -101,6 +105,7 @@ protected:
   struct { uint32_t x; uint32_t y; } mDpi;
   uint32_t mLastVSyncTime;
   ResourcePolicy::DataRetention mDataRetentionPolicy;
+  static bool mLoggingEnabled;
 };
 
 } // Dali
index b55afd6..7e12c1c 100644 (file)
@@ -233,4 +233,85 @@ int UtcDaliLayoutingSettingAndRemoval_RemoveLayoutFromHbox(void)
   DALI_TEST_EQUALS( controls[1].GetProperty<Vector3>( Actor::Property::SIZE ), Vector3( 60.0f, 40.0f, 0.0f ), 0.0001f, TEST_LOCATION );
 
   END_TEST;
-}
\ No newline at end of file
+}
+
+int UtcDaliLayouting_SetLayoutAlreadyInUse(void)
+{
+  /*
+  1 ControlA (LinearLayoutA)
+  2 Add 3 children
+
+  3 ControlB (LinearLayoutA)
+  4 Add 4 children
+
+  Test number of children in each control/layout
+
+  LinearLayoutA should now have 4 children
+
+  ControlB should have 4 children too
+  ControlA should have 3 children.
+
+  */
+
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliLayouting_SetLayoutAlreadyInUse - Set layout belonging to controlA to controlB");
+
+  Stage stage = Stage::GetCurrent();
+
+  auto rootControl = Control::New();
+  auto absoluteLayout = AbsoluteLayout::New();
+  DevelControl::SetLayout( rootControl, absoluteLayout );
+  rootControl.SetName( "AbsoluteLayout" );
+  stage.Add( rootControl );
+
+  auto controlA = Control::New();
+  auto hboxLayout = LinearLayout::New();
+  controlA.SetName( "controlA");
+
+  rootControl.Add( controlA );
+
+  DevelControl::SetLayout( controlA, hboxLayout );
+
+  // Add child controls
+  std::vector< Control > controls;
+  controls.push_back( CreateLeafControl( 100, 100 ) );  // 0
+  controls.push_back( CreateLeafControl( 100, 100 ) );  // 1
+  controls.push_back( CreateLeafControl( 100, 100 ) );  // 2
+
+  for( auto&& iter : controls )
+  {
+    controlA.Add( iter );
+  }
+
+  // Ensure layouting happens
+  application.SendNotification();
+  application.Render();
+
+  tet_infoline("SetLayout to another control");
+
+  auto controlB = Control::New();
+  controlB.SetName( "controlB");
+
+  std::vector< Control > moreControls;
+  moreControls.push_back( CreateLeafControl( 100, 100 ) );  // 0
+  moreControls.push_back( CreateLeafControl( 100, 100 ) );  // 1
+  moreControls.push_back( CreateLeafControl( 100, 100 ) );  // 3
+  moreControls.push_back( CreateLeafControl( 100, 100 ) );  // 4
+
+  for( auto&& iter : moreControls )
+  {
+    controlB.Add( iter );
+  }
+
+  DevelControl::SetLayout( controlB, hboxLayout );  // Set hboxLayout used by ControlA to ControlB
+
+  // Ensure layouting happens
+  application.SendNotification();
+  application.Render();
+
+  tet_infoline("Get number of children in each control's layout");
+  DALI_TEST_EQUALS( ( LayoutGroup::DownCast( DevelControl::GetLayout( controlA ) ) ).GetChildCount(), 3 , TEST_LOCATION );
+  DALI_TEST_EQUALS( ( LayoutGroup::DownCast( DevelControl::GetLayout( controlB ) ) ).GetChildCount(), 4 , TEST_LOCATION );
+
+  END_TEST;
+}
index 52a0d4a..404a9ec 100755 (executable)
@@ -291,6 +291,9 @@ DALI_TOOLKIT_API Toolkit::LayoutItem GetLayout( Control control );
  * @param[in] layout Pointer to the layout
  * @note Providing an empty layout will remove the current layout and
  *       replace it with a BinLayout.
+ *       Setting a layout that has already been set will result in the
+ *       original control becoming a BinLayout.  Two Controls can not share
+ *       the same layout.
  */
 DALI_TOOLKIT_API void SetLayout( Internal::Control& control, Toolkit::LayoutItem layout );
 
index c5af35e..a8387ee 100755 (executable)
@@ -1441,15 +1441,35 @@ Toolkit::Internal::LayoutItemPtr Control::Impl::GetLayout() const
 
 void Control::Impl::SetLayout( Toolkit::Internal::LayoutItem& layout )
 {
-  DALI_LOG_INFO( gLogFilterLayout, Debug::Verbose, "Control::SetLayout control:%s  existing layout:%s\n",
+  DALI_LOG_INFO( gLogFilterLayout, Debug::Verbose, "Control::SetLayout control:%s  replacing existing layout:%s\n",
                                    mControlImpl.Self().GetName().c_str(),
                                    mLayout?"true":"false" );
+  // Check if layout already has an owner.
+  auto control = Toolkit::Control::DownCast( layout.GetOwner() );
+  if ( control )
+  {
+    // If the owner is not this control then the owning control can no longer own it.
+    Dali::Toolkit::Control handle( mControlImpl.GetOwner() );
+    if( control != handle )
+    {
+      DALI_LOG_INFO( gLogFilterLayout, Debug::Verbose, "Control::SetLayout Layout already in use, %s will now have a BinLayout\n",
+                                                        control.GetName().c_str() );
+      Toolkit::BinLayout binLayout = Toolkit::BinLayout::New();
+      // Previous owner of the layout gets a BinLayout instead of the layout.
+      DevelControl::SetLayout( control, binLayout ) ;
+    }
+    else
+    {
+      return; // layout is already set to this control.
+    }
+  }
 
   if( mLayout )
   {
     mLayout->Unparent();
     mLayout.Reset();
   }
+
   mLayout = &layout;
 
   auto controlHandle = Toolkit::Control::DownCast( mControlImpl.Self() ); // Get a handle of this control implementation without copying internals.
index 932fe48..245d4b7 100644 (file)
@@ -31,7 +31,7 @@ namespace Toolkit
 
 const unsigned int TOOLKIT_MAJOR_VERSION = 1;
 const unsigned int TOOLKIT_MINOR_VERSION = 3;
-const unsigned int TOOLKIT_MICRO_VERSION = 47;
+const unsigned int TOOLKIT_MICRO_VERSION = 48;
 const char * const TOOLKIT_BUILD_DATE    = __DATE__ " " __TIME__;
 
 #ifdef DEBUG_ENABLED
index 4c72035..77a78bf 100644 (file)
@@ -1,6 +1,6 @@
 Name:       dali-toolkit
 Summary:    Dali 3D engine Toolkit
-Version:    1.3.47
+Version:    1.3.48
 Release:    1
 Group:      System/Libraries
 License:    Apache-2.0 and BSD-3-Clause and MIT