Salome HOME
Merge branch 'master' into abn/qtesting
authorabn <adrien.bruneton@cea.fr>
Thu, 14 Apr 2016 09:18:50 +0000 (11:18 +0200)
committerabn <adrien.bruneton@cea.fr>
Thu, 14 Apr 2016 09:18:50 +0000 (11:18 +0200)
28 files changed:
CMakeLists.txt
idl/MEDEventListener.idl
src/MEDCalc/CMakeLists.txt
src/MEDCalc/gui/CMakeLists.txt
src/MEDCalc/gui/DatasourceController.cxx
src/MEDCalc/gui/MEDModule.cxx
src/MEDCalc/gui/MEDModule.hxx
src/MEDCalc/gui/MED_msg_fr.ts
src/MEDCalc/gui/TestController.cxx [new file with mode: 0644]
src/MEDCalc/gui/TestController.hxx [new file with mode: 0644]
src/MEDCalc/gui/WorkspaceController.cxx
src/MEDCalc/gui/WorkspaceController.hxx
src/MEDCalc/gui/dialogs/WidgetPresentationParameters.hxx
src/MEDCalc/gui/test/README.txt [deleted file]
src/MEDCalc/gui/test/guiTester.pro [deleted file]
src/MEDCalc/test/CMakeLists.txt [new file with mode: 0644]
src/MEDCalc/test/README.txt [new file with mode: 0644]
src/MEDCalc/test/baselines/test_scalarmap.png [new file with mode: 0644]
src/MEDCalc/test/guiTester.pro [new file with mode: 0644]
src/MEDCalc/test/medcalc_testutils.py.in [new file with mode: 0644]
src/MEDCalc/test/medfiles/test_scalarmap.med [new file with mode: 0644]
src/MEDCalc/test/scenarios/test_scalarmap.xml [new file with mode: 0644]
src/MEDCalc/test/test_qttesting.py [new file with mode: 0644]
src/MEDCalc/test/test_scalarmap.py [new file with mode: 0644]
src/MEDCalc/tui/CMakeLists.txt
src/MEDCalc/tui/__init__.py
src/MEDCalc/tui/medevents.py
src/MEDCalc/tui/medtest.py [new file with mode: 0644]

index 54fbb953f70ae48fe801418bffede89b8bbc7149..bfdcca99ca6ad5a3131c22eb63ed8ce34b90b3af 100644 (file)
@@ -67,6 +67,7 @@ FIND_PACKAGE(SalomeOmniORB REQUIRED)
 INCLUDE(CMakeDependentOption)
 OPTION(SALOME_MED_ENABLE_PYTHON "Build PYTHON bindings." ON)
 OPTION(SALOME_MED_WITH_FILE_EXAMPLES "Install examples of files containing meshes and fields of different formats." ON)
+OPTION(SALOME_MED_WITH_QTTESTING "Build MED with QtTesting support." OFF)
 OPTION(SALOME_USE_MPI "(Use MPI containers) - For MED this triggers the build of ParaMEDMEM." ${_default_MPI})
 OPTION(SALOME_BUILD_GUI "Build GUI of MED." ON)
 OPTION(SALOME_BUILD_TESTS "Build MED tests." ON)
index 1181a6e1697dfd083c3cd9e4a86bc5f00ba6dd9d..77fcc8fa3e114c33e2e6e2dfc475f35a7bb8147e 100644 (file)
@@ -34,6 +34,8 @@ module MEDCALC
     EVENT_CLEAN_WORKSPACE,
     EVENT_ADD_DATASOURCE,
     EVENT_ADD_PRESENTATION,
+    EVENT_PLAY_TEST,
+    EVENT_QUIT_SALOME,
     EVENT_UNKNOWN
   };
 
index a0815a29fca2fabac4763f367882eab2a0ee255c..d6a1e4d3a8a25ec13c97dbbbe8ff04decc4a6687 100644 (file)
@@ -22,6 +22,11 @@ ADD_SUBDIRECTORY(res)
 
 IF(SALOME_BUILD_GUI)
   ADD_SUBDIRECTORY(gui)
+
+  IF(SALOME_MED_WITH_QTTESTING)  
+    ADD_SUBDIRECTORY(test)
+  ENDIF()
+  
 ENDIF()
 
 IF(SALOME_MED_ENABLE_PYTHON)
index b51c1432b4ef48d174f7a46ab5ecde1ec7cd714a..b33ab4dfc4f1ec6b4472f79b10a1d852c9335e11 100644 (file)
 # See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
 #
 
+IF(SALOME_MED_WITH_QTTESTING)
+  ADD_DEFINITIONS(-DMED_HAS_QTTESTING)
+ENDIF()
+
 ADD_DEFINITIONS(${MEDFILE_DEFINITIONS} ${XDR_DEFINITIONS} ${OMNIORB_DEFINITIONS})
 SET(QT_LIBS "${QT_LIBRARIES}")
 INCLUDE(UseQtExt)
 
 ADD_SUBDIRECTORY(dialogs)
 
+SET(MEDCALCGUI_SOURCES 
+    DatasourceController.cxx
+    factory.cxx
+    MEDEventListener_i.cxx
+    MEDModule.cxx
+    PresentationController.cxx
+    ProcessingController.cxx
+    WorkspaceController.cxx
+    XmedConsoleDriver.cxx
+    XmedDataModel.cxx
+)
 
-FILE(GLOB MEDCALCGUI_SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/*.cxx")
+IF(SALOME_MED_WITH_QTTESTING)
+  LIST(APPEND MEDCALCGUI_SOURCES TestController.cxx)
+ENDIF()
 
 SET(MEDCALCGUI_HEADERS
   MEDModule.hxx
@@ -34,8 +51,12 @@ SET(MEDCALCGUI_HEADERS
   PresentationController.hxx
   ProcessingController.hxx
   )
-QT_WRAP_MOC(MEDCALCGUI_HEADERS_MOC ${MEDCALCGUI_HEADERS})
+IF(SALOME_MED_WITH_QTTESTING)
+  LIST(APPEND MEDCALCGUI_HEADERS TestController.hxx)
+ENDIF()
 
+QT_WRAP_MOC(MEDCALCGUI_HEADERS_MOC ${MEDCALCGUI_HEADERS})
 
 INCLUDE_DIRECTORIES(
   ${OMNIORB_INCLUDE_DIR} ${OMNIORB_INCLUDE_DIRS}
@@ -63,7 +84,7 @@ SET(MEDCALCGUITS_SOURCES
   MEDCALC_msg_ja.ts
 )
 
-SET(COMMON_FLAGS
+SET(link_libraries
   ${QT_MT_LIBRARIES}
   ${OMNIORB_LIBRARIES}
   ${PLATFORM_LIBRARIES}
@@ -88,11 +109,15 @@ SET(COMMON_FLAGS
   ${MEDCoupling_medcouplingremapper}
 )
 
+IF(SALOME_MED_WITH_QTTESTING)
+  LIST(APPEND link_libraries QtTesting)  # from ParaView
+ENDIF()
+
 ADD_LIBRARY(MEDCALCGUI SHARED ${MEDCALCGUI_SOURCES} ${MEDCALCGUI_HEADERS_MOC})
 IF(WITH_MEDMEMGUI)
   SET_TARGET_PROPERTIES(MEDCALCGUI PROPERTIES COMPILE_FLAGS "-D__WITH_MEDMEMGUI__")
 ENDIF(WITH_MEDMEMGUI)
-TARGET_LINK_LIBRARIES(MEDCALCGUI ${COMMON_FLAGS})
+TARGET_LINK_LIBRARIES(MEDCALCGUI ${link_libraries})
 
 INSTALL(TARGETS MEDCALCGUI DESTINATION ${SALOME_INSTALL_LIBS})
 QT_INSTALL_TS_RESOURCES("${MEDCALCGUITS_SOURCES}" "${SALOME_MED_INSTALL_RES_DATA}")
index a3f7cd0be7db6396f53d0767f64f43931b716ad0..ccfe685b27947ae983cef24c7ef5b05d594fddee 100644 (file)
@@ -45,6 +45,7 @@
 #include <QStringList>
 #include <QString>
 #include <QMessageBox>
+#include <QFileDialog>
 
 #include "DlgAlias.hxx"
 
@@ -121,6 +122,11 @@ DatasourceController::addDatasource(const char* filename)
   event->eventtype = DatasourceEvent::EVENT_ADD_DATASOURCE;
   event->objectalias = filename;
   emit datasourceSignal(event);
+//#ifdef MED_WITH_QTTESTING
+//  _dirtyAddDataSource = true;
+//  while(_dirtyAddDataSource)
+//    QApplication::processEvents();
+//#endif
 }
 // After above data source creation, python console emits a signal, forwarded by workspace, to update the GUI
 void
@@ -137,6 +143,10 @@ DatasourceController::updateTreeViewWithNewDatasource(const MEDCALC::DatasourceH
 
   // update Object browser
   _salomeModule->getApp()->updateObjectBrowser(true);
+
+//#ifdef MED_WITH_QTTESTING
+//  _dirtyAddDataSource = false;
+//#endif
 }
 
 void DatasourceController::OnAddDatasource()
@@ -149,10 +159,15 @@ void DatasourceController::OnAddDatasource()
   if ( SUIT_FileDlg::getLastVisitedPath().isEmpty() )
     anInitialPath = QDir::currentPath();
 
-  QStringList filenames = SUIT_FileDlg::getOpenFileNames( _salomeModule->getApp()->desktop(),
+//  QStringList filenames = SUIT_FileDlg::getOpenFileNames( _salomeModule->getApp()->desktop(),
+//                                                          anInitialPath,
+//                                                          filter,
+//                                                          tr("IMPORT_MED_FIELDS") );
+  // [ABN] the below to be compatible with QtTesting:
+  QStringList filenames = QFileDialog::getOpenFileNames( _salomeModule->getApp()->desktop(),
+                                                          tr("IMPORT_MED_FIELDS"),
                                                           anInitialPath,
-                                                          filter,
-                                                          tr("IMPORT_MED_FIELDS") );
+                                                          tr("FILE_FILTER_MED") );
 
   if ( filenames.count() <= 0 ) return;
   for ( QStringList::ConstIterator itFile = filenames.begin();
index c40bbe231b300f1c340483d29da6de13206ef4f9..7b8ffb2e1f495267b9b9312023165e56067c8627 100644 (file)
 #include "PVViewer_ViewModel.h"
 #endif
 
+#include <QTimer>
+
 #include <sstream>
 
 //! The only instance of the reference to engine
 MED_ORB::MED_Gen_var MEDModule::myEngine;
 
 MEDModule::MEDModule() :
-  SalomeApp_Module("MED"), _studyEditor(0), _datasourceController(0), _workspaceController(0), _presentationController(0), _processingController(0)
+  SalomeApp_Module("MED"), _studyEditor(0), _datasourceController(0), _workspaceController(0),
+  _presentationController(0), _processingController(0)
 {
   // Note also that we can't use the getApp() function here because
   // the initialize(...) function has not been called yet.
@@ -90,6 +93,15 @@ MEDModule::init()
   }
 }
 
+//void MEDModule::onEventLoopStarted()
+//{
+//  if(!getApp()->isMainEventLoopStarted())
+//    {
+//      QTimer::singleShot(100, this, SLOT(onEventLoopStarted()));
+//      return;
+//    }
+//}
+
 void
 MEDModule::initialize( CAM_Application* app )
 {
@@ -180,6 +192,10 @@ MEDModule::activateModule( SUIT_Study* theStudy )
   _presentationController->showDockWidgets(true);
   //this->setDockLayout(StandardApp_Module::DOCKLAYOUT_LEFT_VLARGE);
 
+  // Mark the start of the main event loop - important for test playback:
+//  QObject::connect(getApp(), SIGNAL(activated(SUIT_Application *)), this, SLOT(onEventLoopStarted(SUIT_Application *)));
+//  QTimer::singleShot(0, this, SLOT(onEventLoopStarted()));
+
   // return the activation status
   return bOk;
 }
@@ -222,6 +238,9 @@ MEDModule::createModuleWidgets() {
   _workspaceController->setDataModel(_xmedDataModel);
   _presentationController = new PresentationController(this);
   _processingController = new ProcessingController(this);
+#ifdef MED_HAS_QTTESTING
+  _testController = new TestController(this);
+#endif
 
   connect(_datasourceController, SIGNAL(datasourceSignal(const DatasourceEvent*)),
     _workspaceController, SLOT(processDatasourceEvent(const DatasourceEvent*)));
@@ -237,6 +256,11 @@ MEDModule::createModuleWidgets() {
 
   connect(_workspaceController, SIGNAL(workspaceSignal(const MEDCALC::MedEvent*)),
     _presentationController, SLOT(processWorkspaceEvent(const MEDCALC::MedEvent*)));
+
+#ifdef MED_HAS_QTTESTING
+  connect(_workspaceController, SIGNAL(workspaceSignal(const MEDCALC::MedEvent*)),
+    _testController, SLOT(processWorkspaceEvent(const MEDCALC::MedEvent*)));
+#endif
 }
 
 void
@@ -245,6 +269,9 @@ MEDModule::createModuleActions() {
   _workspaceController->createActions();
   _presentationController->createActions();
   _processingController->createActions();
+#ifdef MED_HAS_QTTESTING
+  _testController->createActions();
+#endif
 }
 
 int
@@ -262,9 +289,15 @@ MEDModule::createStandardAction(const QString& label,
   if ( effToolTip.isEmpty() )
     effToolTip = label;
 
+  QIcon ico;
+  if (iconName.isEmpty())
+    ico = QIcon();
+  else
+    ico = QIcon(resMgr->loadPixmap("MED", iconName));
+
   QAction* action = createAction(-1,
                                  label,
-                                 resMgr->loadPixmap("MED", iconName),
+                                 ico,
                                  label,
                                  effToolTip,
                                  0,
@@ -349,3 +382,16 @@ MEDModule::onDblClick(const QModelIndex& index)
   STDLOG("    - Presentation name: " + name);
 
 }
+
+void
+MEDModule::requestSALOMETermination() const
+{
+  STDLOG("Requesting SALOME termination!!");
+  SUIT_Session::session()->closeSession( SUIT_Session::DONT_SAVE, 1 );  // killServers = True
+}
+
+
+//bool MEDModule::hasMainEventLoopStarted() const
+//{
+//  return _eventLoopStarted;
+//}
index f05d6616e834e2d5b5c745e9831bff3886e7ce0c..4a2e01851234a9dd92d1565f4ce48ca4198e905a 100644 (file)
@@ -32,6 +32,7 @@
 #include "DatasourceController.hxx"
 #include "PresentationController.hxx"
 #include "ProcessingController.hxx"
+#include "TestController.hxx"
 
 #include <SALOMEconfig.h>
 #include CORBA_CLIENT_HEADER(MED_Gen)
@@ -82,6 +83,10 @@ public:
 
   inline SALOME_AppStudyEditor* getStudyEditor() { return _studyEditor; }
 
+  void requestSALOMETermination() const;
+
+//  bool hasMainEventLoopStarted() const;
+
 public slots:
   virtual bool activateModule(SUIT_Study* theStudy);
   virtual bool deactivateModule(SUIT_Study* theStudy);
@@ -90,6 +95,7 @@ public slots:
 private:
   void createModuleWidgets();
   void createModuleActions();
+
   static void init();
 
 private:
@@ -99,6 +105,9 @@ private:
   XmedDataModel* _xmedDataModel;
   PresentationController* _presentationController;
   ProcessingController* _processingController;
+#ifdef MED_HAS_QTTESTING
+  TestController * _testController;
+#endif
   static MED_ORB::MED_Gen_var myEngine;
 };
 
index f09dc6717584ab52ebe985a92deae7bf1c61b8f5..7481ad5a8c563170041cde48130aafebfff15fb0 100644 (file)
     </message>
     <message>
       <source>LAB_BLUE_TO_RED</source>
-      <translation>Arc-en-ciel blue vers rouge</translation>
+      <translation>Arc-en-ciel bleu vers rouge</translation>
     </message>
     <message>
       <source>LAB_COOL_TO_WARM</source>
diff --git a/src/MEDCalc/gui/TestController.cxx b/src/MEDCalc/gui/TestController.cxx
new file mode 100644 (file)
index 0000000..78bb46d
--- /dev/null
@@ -0,0 +1,209 @@
+// Copyright (C) 2016  CEA/DEN, EDF R&D
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+//
+// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
+//
+
+#include "TestController.hxx"
+#include "MEDModule.hxx"
+
+#include <Basics_Utils.hxx>  // STDLOG() macro
+
+#include <SUIT_Session.h>
+#include <SUIT_Desktop.h>
+
+#include <SALOMEconfig.h>
+#include CORBA_CLIENT_HEADER(MEDEventListener)
+
+#include <pqTestUtility.h>
+#include <pqXMLEventObserver.h>
+#include <pqXMLEventSource.h>
+
+#include <pqQVTKWidgetEventPlayer.h>
+#include <pqQVTKWidgetEventTranslator.h>
+
+#include <pqTabbedMultiViewWidget.h>
+#include <pqApplicationCore.h>
+#include <pqTestingReaction.h>
+#include <pqSaveScreenshotReaction.h>
+
+#include <QFileDialog>
+#include <QString>
+#include <QDir>
+#include <QIcon>
+#include <QTimer>
+#include <QEvent>
+
+class PlayTestEvent: public QEvent {
+public:
+  PlayTestEvent(QEvent::Type type, const std::string & filename): QEvent(type), _filename(filename) {}
+  virtual ~PlayTestEvent() {}
+  const std::string _filename;
+};
+
+TestController::TestController(MEDModule* mod):
+  _salomeModule(mod),
+  _desk(SUIT_Session::session()->activeApplication()->desktop()),
+  _tester(0), _lock_action(0),
+  _quitEventType(QEvent::registerEventType()),
+  _playEventType(QEvent::registerEventType()),
+  _aboutToPlayTest(false)
+{
+  STDLOG("Creating a TestController");
+  _tester = new pqTestUtility(_desk);
+  _tester->addEventObserver("xml", new pqXMLEventObserver(_desk));
+  _tester->addEventSource("xml", new pqXMLEventSource(_desk));
+}
+
+TestController::~TestController()
+{
+  if (_tester)
+    delete _tester;
+  _tester = 0;
+}
+
+void
+TestController::createActions() {
+  //
+  // Main actions
+  //
+  QString label   = tr("LAB_RECORD_TEST");
+  QString tooltip = tr("TIP_RECORD_TEST");
+  int actionId;
+  actionId = _salomeModule->createStandardAction(label,this, SLOT(onRecordTest()),QString(),tooltip);
+
+  // This action has to be placed in the general file menu
+  int menuId = _salomeModule->createMenu( tr( "MEN_FILE" ), -1,  1 );
+  _salomeModule->action(actionId)->setIconVisibleInMenu(false);
+  _salomeModule->createMenu(actionId, menuId, 60);
+
+  label   = tr("LAB_PLAY_TEST");
+  tooltip = tr("TIP_PLAY_TEST");
+  actionId = _salomeModule->createStandardAction(label,this, SLOT(onPlayTest()),QString(),tooltip);
+  _salomeModule->action(actionId)->setIconVisibleInMenu(false);
+  _salomeModule->createMenu(actionId, menuId, 70);
+
+  label   = tr("LAB_LOCK_TEST");
+  tooltip = tr("TIP_LOCK_TEST");
+  actionId = _salomeModule->createStandardAction(label,this, SLOT(onLockViewSize()),QString(),tooltip);
+  _salomeModule->action(actionId)->setIconVisibleInMenu(false);
+  _salomeModule->action(actionId)->setCheckable(true);
+  _lock_action = _salomeModule->action(actionId);
+  _salomeModule->createMenu(actionId, menuId, 70);
+
+  label   = tr("LAB_SNAP_TEST");
+  tooltip = tr("TIP_SNAP_TEST");
+  actionId = _salomeModule->createStandardAction(label,this, SLOT(onTakeSnapshot()),QString(),tooltip);
+  _salomeModule->action(actionId)->setIconVisibleInMenu(false);
+  _salomeModule->createMenu(actionId, menuId, 70);
+}
+
+void TestController::onRecordTest()
+{
+  QString fileName =
+      QFileDialog::getSaveFileName(_desk, "Save test", QString(), QString("XML file (*.xml)"));
+  if (!fileName.isEmpty())
+    {
+      QApplication::setActiveWindow(_desk); //mandatory otherwise record pop up doesn't show up
+      _tester->recordTests(fileName);
+    }
+}
+
+
+void TestController::onPlayTest()
+{
+  QString fileName =
+      QFileDialog::getOpenFileName(_desk, "Open test", QString(), QString("XML file (*.xml)"));
+  if (!fileName.isEmpty())
+    _tester->playTests(fileName);
+}
+
+void TestController::onLockViewSize() const
+{
+  pqTestingReaction::lockViewSize(_lock_action->isChecked());
+}
+
+void TestController::onTakeSnapshot() const
+{
+  pqSaveScreenshotReaction::saveScreenshot();
+}
+
+void TestController::onRequestTermination()
+{
+  // Check if test playing
+  if (_tester->playingTest() || _aboutToPlayTest)
+    {
+      QEvent * e = new QEvent((QEvent::Type)_quitEventType);
+      QApplication::postEvent(this, e);
+    }
+  else
+    {
+      _salomeModule->requestSALOMETermination();
+    }
+}
+
+void
+TestController::customEvent(QEvent * event)
+{
+  if (event->type() == _quitEventType)
+    {
+      if(!_salomeModule->getApp()->isMainEventLoopStarted())
+          // Repost (=delay)
+          QApplication::postEvent(this, new QEvent((QEvent::Type)_quitEventType));
+      else
+          onRequestTermination();
+    }
+  else if (event->type() == _playEventType)
+    {
+      PlayTestEvent * e = dynamic_cast<PlayTestEvent *>(event);
+      if (e)
+        {
+//          // Wait for main event loop to start:
+          if(!_salomeModule->getApp()->isMainEventLoopStarted())
+              // Repost (=delay)
+              QApplication::postEvent(this, new PlayTestEvent((QEvent::Type)_playEventType, e->_filename));
+          else
+            {
+              STDLOG("About to play test " << e->_filename);
+              _tester->playTests(e->_filename.c_str());
+              _aboutToPlayTest = false;
+              STDLOG("Done playing test " << e->_filename);
+            }
+        }
+    }
+  else
+    { QObject::customEvent(event);  }
+}
+
+void
+TestController::processWorkspaceEvent(const MEDCALC::MedEvent* event)
+{
+  if ( event->type == MEDCALC::EVENT_PLAY_TEST ) {
+      /* [ABN] Post an event. Indeed, calling the function directly would prevent the proper refresh of the
+       * GUI which also needs to go through the MED event loop (WorkspaceController::processWorkspaceEvent)
+       */
+      _aboutToPlayTest = true; // to prevent an early quit!
+      PlayTestEvent * e  = new PlayTestEvent((QEvent::Type)_playEventType, std::string(event->filename));
+      QApplication::postEvent(this, e);
+  }
+  else if ( event->type == MEDCALC::EVENT_QUIT_SALOME ) {
+      // [ABN] again: post as an event to give a chance to other events (piled up by test
+      // scenarios for example) to execute:
+      QEvent * e = new QEvent((QEvent::Type)_quitEventType);
+      QApplication::postEvent(this, e);
+  }
+}
+
diff --git a/src/MEDCalc/gui/TestController.hxx b/src/MEDCalc/gui/TestController.hxx
new file mode 100644 (file)
index 0000000..9f5acfd
--- /dev/null
@@ -0,0 +1,72 @@
+// Copyright (C) 2016  CEA/DEN, EDF R&D
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+//
+// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
+//
+
+#ifndef SRC_MEDCALC_GUI_TESTCONTROLLER_HXX_
+#define SRC_MEDCALC_GUI_TESTCONTROLLER_HXX_
+
+#include <QObject>
+#include <QString>
+
+class pqTestUtility;
+class MEDModule;
+class SUIT_Desktop;
+class QAction;
+namespace MEDCALC {
+  class MedEvent;
+};
+
+class TestController: public QObject {
+  Q_OBJECT
+
+public:
+  TestController(MEDModule* mod);
+  virtual ~TestController();
+
+  void createActions();
+
+
+
+protected:
+  virtual void customEvent(QEvent * event);
+
+public slots:
+  void processWorkspaceEvent(const MEDCALC::MedEvent* event);
+
+  void onRecordTest();
+  void onPlayTest();
+//  void onPlayTestFile();
+  void onLockViewSize() const;
+  void onTakeSnapshot() const;
+  void onRequestTermination();
+
+protected:
+  MEDModule* _salomeModule;
+  SUIT_Desktop * _desk;
+
+  pqTestUtility * _tester;
+  QAction * _lock_action;
+
+private:
+  const int _playEventType;
+  const int _quitEventType;
+
+  bool _aboutToPlayTest;
+};
+
+#endif /* SRC_MEDCALC_GUI_TESTCONTROLLER_HXX_ */
index cfb1b506e6610479cca1f89a5c1cb5d6b9e809f4..223eb7815cdd525aee6819d6888d244ce77fea4f 100644 (file)
@@ -35,6 +35,8 @@
 #include <SUIT_Desktop.h>
 #include <SUIT_ResourceMgr.h>
 
+#include <QTimer>
+
 /*!
  * This class defines a DockWidget plugged in the SALOME application,
  * and containing a tree view for rendering a hierarchical data
@@ -308,7 +310,12 @@ void WorkspaceController::processMedEvent(const MEDCALC::MedEvent* event) {
   else if ( event->type == MEDCALC::EVENT_ADD_PRESENTATION ) {
     emit workspaceSignal(event); // forward to DatasourceController
   }
-
+  else if ( event->type == MEDCALC::EVENT_PLAY_TEST ) {
+    emit workspaceSignal(event); // forward to TestController
+  }
+  else if ( event->type == MEDCALC::EVENT_QUIT_SALOME ) {
+    emit workspaceSignal(event); // forward to TestController
+  }
 }
 
 /*!
index 5c69607673f702dcbb5a80bcbdbf7ddf97c57871..f85a068e4b4f68939f83f069a3b3dad677838d89 100644 (file)
@@ -65,6 +65,8 @@ public slots:
   void OnSaveWorkspace();
   void OnCleanWorkspace();
 
+  void onRequestTermination();
+
 signals:
   void workspaceSignal(const MEDCALC::MedEvent* event);
 
index 0f88157598db1635c24623018b6d757f97df5fb3..7187e2ee65dc75b0a138720a6b1300d79f2f6a28 100644 (file)
@@ -32,6 +32,7 @@
 class WidgetPresentationParameters : public QWidget
 {
   Q_OBJECT
+
 public:
   WidgetPresentationParameters(QWidget* parent = 0);
   virtual ~WidgetPresentationParameters() {}
diff --git a/src/MEDCalc/gui/test/README.txt b/src/MEDCalc/gui/test/README.txt
deleted file mode 100644 (file)
index 751cbf4..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-
-This is a simple Qt framework to test the dialog widgets.
-
-To build the project:
-* specify the sources files in the .pro file
-* run qmake, then make
-* run guiTester
-
-To clean the project:
-* run "make clean"
-* remove binary and Makefile
-  $ rm guiTester Makefile
diff --git a/src/MEDCalc/gui/test/guiTester.pro b/src/MEDCalc/gui/test/guiTester.pro
deleted file mode 100644 (file)
index 51f1f87..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-######################################################################
-# Automatically generated by qmake (2.01a) mer. oct. 6 14:46:48 2010
-######################################################################
-
-TEMPLATE = app
-TARGET = 
-DEPENDPATH += .
-INCLUDEPATH += . ../dialogs
-
-# Input
-HEADERS += ../dialogs/DlgAlias.h
-FORMS += ../dialogs/dlgAlias.ui
-SOURCES += ../dialogs/DlgAlias.cxx ../dialogs/dlgTester.cxx
diff --git a/src/MEDCalc/test/CMakeLists.txt b/src/MEDCalc/test/CMakeLists.txt
new file mode 100644 (file)
index 0000000..2a1326e
--- /dev/null
@@ -0,0 +1,48 @@
+# Copyright (C) 2012-2016  CEA/DEN, EDF R&D
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+#
+# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
+#
+
+SALOME_CONFIGURE_FILE(medcalc_testutils.py.in ${CMAKE_CURRENT_BINARY_DIR}/medcalc_testutils.py)
+
+SET(_test_scripts
+    test_qttesting.py    # main entry point
+    test_scalarmap.py
+)
+
+SET(_test_scenarii
+   scenarios/test_scalarmap.xml
+)
+
+SET(_test_baselines
+    baselines/test_scalarmap.png
+)
+
+SET(_test_files
+    medfiles/test_scalarmap.med
+)
+
+# Test rules - the test MEDCalcQtTesting must be run after install (since it starts SALOME) 
+ADD_TEST(MEDCalcQtTesting ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/test_qttesting.py)
+
+# Install rules
+SALOME_INSTALL_SCRIPTS("${_test_scripts}" ${SALOME_INSTALL_PYTHON}/tests)
+SALOME_INSTALL_SCRIPTS(${CMAKE_CURRENT_BINARY_DIR}/medcalc_testutils.py ${SALOME_INSTALL_PYTHON})
+INSTALL(FILES ${_test_scenarii} DESTINATION ${SALOME_MED_INSTALL_RES_DATA}/tests/scenarios)
+INSTALL(FILES ${_test_baselines} DESTINATION ${SALOME_MED_INSTALL_RES_DATA}/tests/baselines)
+INSTALL(FILES ${_test_files} DESTINATION ${SALOME_MED_INSTALL_RES_DATA}/tests/medfiles)
diff --git a/src/MEDCalc/test/README.txt b/src/MEDCalc/test/README.txt
new file mode 100644 (file)
index 0000000..ad68b0d
--- /dev/null
@@ -0,0 +1,25 @@
+test_qttesting.py
+=================
+
+Tests based on QtTesting framework from ParaView.
+Main entry point is test_qttesting.py.
+Each scenario is described in a XML file and can be recorded directly in the GUI via the "Record test" button. 
+
+A scneario must save a final screenshot of the ParaView view in a file located in the temp directory (TODO: review
+this). This file is compared against a baseline saved in the baselines subdirectory.
+
+
+guiTester.pro 
+=============
+
+This is a simple Qt framework to test the dialog widgets.
+
+To build the project:
+* specify the sources files in the .pro file
+* run qmake, then make
+* run guiTester
+
+To clean the project:
+* run "make clean"
+* remove binary and Makefile
+  $ rm guiTester Makefile
diff --git a/src/MEDCalc/test/baselines/test_scalarmap.png b/src/MEDCalc/test/baselines/test_scalarmap.png
new file mode 100644 (file)
index 0000000..3e827f4
Binary files /dev/null and b/src/MEDCalc/test/baselines/test_scalarmap.png differ
diff --git a/src/MEDCalc/test/guiTester.pro b/src/MEDCalc/test/guiTester.pro
new file mode 100644 (file)
index 0000000..51f1f87
--- /dev/null
@@ -0,0 +1,13 @@
+######################################################################
+# Automatically generated by qmake (2.01a) mer. oct. 6 14:46:48 2010
+######################################################################
+
+TEMPLATE = app
+TARGET = 
+DEPENDPATH += .
+INCLUDEPATH += . ../dialogs
+
+# Input
+HEADERS += ../dialogs/DlgAlias.h
+FORMS += ../dialogs/dlgAlias.ui
+SOURCES += ../dialogs/DlgAlias.cxx ../dialogs/dlgTester.cxx
diff --git a/src/MEDCalc/test/medcalc_testutils.py.in b/src/MEDCalc/test/medcalc_testutils.py.in
new file mode 100644 (file)
index 0000000..61fe9d1
--- /dev/null
@@ -0,0 +1,41 @@
+# Copyright (C) 2011-2016  CEA/DEN, EDF R&D
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+#
+# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
+#
+
+import os
+
+def __getRootDir():  
+  rootDir = os.environ.get("MED_ROOT_DIR", "")
+  return rootDir 
+
+def GetScriptDir():
+  relativeDir = "@SALOME_INSTALL_PYTHON@/tests"
+  return os.path.join(__getRootDir(), relativeDir)
+
+def GetScenarioDir():
+  relativeDir = "@SALOME_MED_INSTALL_RES_DATA@/tests/scenarios"
+  return os.path.join(__getRootDir(), relativeDir)
+
+def GetBaselineDir():
+  relativeDir = "@SALOME_MED_INSTALL_RES_DATA@/tests/baselines"
+  return os.path.join(__getRootDir(), relativeDir)
+def GetMEDFileDir():
+  relativeDir = "@SALOME_MED_INSTALL_RES_DATA@/tests/medfiles"
+  return os.path.join(__getRootDir(), relativeDir)
+  
diff --git a/src/MEDCalc/test/medfiles/test_scalarmap.med b/src/MEDCalc/test/medfiles/test_scalarmap.med
new file mode 100644 (file)
index 0000000..063a41d
Binary files /dev/null and b/src/MEDCalc/test/medfiles/test_scalarmap.med differ
diff --git a/src/MEDCalc/test/scenarios/test_scalarmap.xml b/src/MEDCalc/test/scenarios/test_scalarmap.xml
new file mode 100644 (file)
index 0000000..42a7210
--- /dev/null
@@ -0,0 +1,20 @@
+<?xml version="1.0" ?>
+<pqevents>
+  <pqevent object="1STD_TabDesktop0/1QMenuBar0" command="activate" arguments="Fic&amp;hier" />
+  <pqevent object="1QMenu0" command="activate" arguments="LAB_LOCK_TEST" />
+  <pqevent object="1STD_TabDesktop0/DatasourceToolbar/1QToolButton0" command="activate" arguments="" />
+  <pqevent object="Qt-subapplication-app" command="FilesOpen" arguments="/tmp/test_scalarmap.med" />
+  <pqevent object="1STD_TabDesktop0/objectBrowserDock/objectBrowser/1QtxTreeView0" command="expand" arguments="0.0" />
+  <pqevent object="1STD_TabDesktop0/objectBrowserDock/objectBrowser/1QtxTreeView0" command="expand" arguments="0.0.0.0" />
+  <pqevent object="1STD_TabDesktop0/objectBrowserDock/objectBrowser/1QtxTreeView0" command="expand" arguments="0.0.0.0.0.0" />
+  <pqevent object="1STD_TabDesktop0/objectBrowserDock/objectBrowser/1QtxTreeView0/qt_scrollarea_vcontainer/1QScrollBar0" command="mouseWheel" arguments="-120,0,0,88,5" />
+  <pqevent object="1STD_TabDesktop0/objectBrowserDock/objectBrowser/1QtxTreeView0/qt_scrollarea_vcontainer/1QScrollBar0" command="mouseWheel" arguments="-120,0,0,88,5" />
+  <pqevent object="1STD_TabDesktop0/objectBrowserDock/objectBrowser/1QtxTreeView0" command="setCurrent" arguments="0.0.0.0.0.0.0.0" />
+  <pqevent object="1STD_TabDesktop0/PresentationToolbar/1QToolButton0" command="activate" arguments="" />
+  <pqevent object="1STD_TabDesktop0/1QMenuBar0" command="activate" arguments="Fic&amp;hier" />
+  <pqevent object="1QMenu0" command="activate" arguments="LAB_SNAP_TEST" />
+  <pqevent object="1STD_TabDesktop0/SaveSnapshotDialog/ok" command="activate" arguments="" />
+  <pqevent object="1STD_TabDesktop0/FileSaveScreenshotDialog" command="key" arguments="16777248" />
+  <pqevent object="1STD_TabDesktop0/FileSaveScreenshotDialog/mainSplitter/widget/FileName" command="set_string" arguments="/tmp/test_scalarmap.png" />
+  <pqevent object="1STD_TabDesktop0/FileSaveScreenshotDialog/mainSplitter/widget/OK" command="activate" arguments="" />
+</pqevents>
diff --git a/src/MEDCalc/test/test_qttesting.py b/src/MEDCalc/test/test_qttesting.py
new file mode 100644 (file)
index 0000000..165f939
--- /dev/null
@@ -0,0 +1,110 @@
+# Copyright (C) 2011-2016  CEA/DEN, EDF R&D
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+#
+# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
+#
+# Author: A. Bruneton (CEA)
+
+import unittest, os, shutil
+from posixpath import basename
+
+class MEDGUITest(unittest.TestCase):
+  def __init__(self, methodName='runTest'):
+    unittest.TestCase.__init__(self, methodName=methodName)
+    self._tmpDir = ""
+    self._removeDir = True
+    
+  def setUp(self):
+    import tempfile
+    self._tmpDir = tempfile.mkdtemp(prefix="med_gui_tests_")
+    self._removeDir = True  # reset for each new test in the TestCase
+
+  def tearDown(self):
+    import shutil
+    unittest.TestCase.tearDown(self)
+    if self._removeDir:
+      shutil.rmtree(self._tmpDir, False)
+    
+  def getTestName(self):
+    """ Return name of the test being currently executed. """
+    return self.id().split(".")[-1]
+
+  def launchSalomeWithScript(self, scriptname):
+    """ TODO: review this - what is the nicest way to launch SALOME GUI from a Python script? """
+    import shutil, subprocess
+    from medcalc_testutils import GetScriptDir
+    # TODO: review this!
+    salomeCommand = os.path.join(os.environ.get("KERNEL_ROOT_DIR", ""), "bin", "salome", "runSalome.py")
+    args = "args:%s" % self._tmpDir
+    pth = os.path.join(GetScriptDir(), scriptname)
+    # Launch SALOME with the test script:
+    status = subprocess.call([salomeCommand, pth, args])
+    if status:
+      raise Exception("SALOME exited abnormally for this test!")
+
+  def compareSnapshot(self, basename):
+    """ Compare the screenshot in the current temporary test directory with the reference baseline.
+    Assert if not matching. """
+    import filecmp
+    from medcalc_testutils import GetBaselineDir
+    
+    base_pth = os.path.join(GetBaselineDir(), basename)
+    gen_path = os.path.join(self._tmpDir, basename)
+    print base_pth, gen_path
+    try:
+      ret = filecmp.cmp(base_pth, gen_path, shallow=False)
+    except OSError:
+      ret = False
+    if not ret:
+      # Keep file if comparison fails
+      self._removeDir = False
+      self.assertTrue(ret, "[%s] -- Failed screenshot equality, or unable to open baseline file - directory is kept alive: %s" % (self.getTestName(), self._tmpDir))
+    return ret
+
+  def prepareScenario(self, scenario, baseline, med_file):
+    """ Copy scenario to current temporary test dir and substitute paths inside """
+    from medcalc_testutils import GetScenarioDir, GetMEDFileDir
+    scen_path = os.path.join(GetScenarioDir(), scenario)
+    scen_pth2 = os.path.join(self._tmpDir, scenario)
+    try:
+      shutil.copy(scen_path, scen_pth2)
+    except IOError:
+      raise Exception("Could not copy test scenario '%s' to local test directory!" % scen_path)
+    with open(scen_pth2,'r') as f:
+      filedata = f.read()
+    filedata = filedata.replace("/tmp/%s" % baseline, "%s/%s" % (self._tmpDir, baseline))
+    filedata = filedata.replace("/tmp/%s" % med_file, os.path.join(GetMEDFileDir(), med_file))
+    with open(scen_pth2,'w') as f:
+      f.write(filedata)
+      
+  ##
+  ## Now the tests themselves
+  ##
+  def testScalarMap(self):
+    baseline = "test_scalarmap.png"
+    med_file = "test_scalarmap.med"  # will change
+    scenario = "test_scalarmap.xml"
+    self.prepareScenario(scenario, baseline, med_file)
+    self.launchSalomeWithScript("test_scalarmap.py")
+    self.compareSnapshot(baseline)
+
+
+if __name__ == "__main__":
+  suite = unittest.TestSuite()
+  suite.addTest(MEDGUITest('testScalarMap'))
+#  suite.addTest(MEDGUITest('testIsoContour'))
+  unittest.TextTestRunner().run(suite)
+
diff --git a/src/MEDCalc/test/test_scalarmap.py b/src/MEDCalc/test/test_scalarmap.py
new file mode 100644 (file)
index 0000000..0f6b069
--- /dev/null
@@ -0,0 +1,37 @@
+# Copyright (C) 2011-2016  CEA/DEN, EDF R&D
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+#
+# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
+#
+
+""" Test of the scalarmap. 
+
+This script is to be passed as an argument of the ./salome command and will be executed within the SALOME
+Python console.
+"""
+
+import os, sys
+import SalomePyQt
+from medcalc_testutils import GetScenarioDir
+
+sgPyQt = SalomePyQt.SalomePyQt()
+sgPyQt.activateModule('MED')
+
+import medcalc  # After module activation !!
+localTestDir = sys.argv[1]
+medcalc.PlayQtTestingScenario(os.path.join(localTestDir, 'test_scalarmap.xml'))
+
+#medcalc.RequestSALOMETermination()  # not equivalent to quit()! 
index f7eafee102ec355ba3eb3f2ec70c06f476ded1e8..ba1b5b810a0b39cca2b5fb8905ae433d15418bbf 100644 (file)
@@ -26,6 +26,7 @@ SET(PYFILES_TO_INSTALL
   medimages.py
   medio.py
   medpresentation.py
+  medtest.py
   )
 
 SALOME_INSTALL_SCRIPTS("${PYFILES_TO_INSTALL}" ${SALOME_INSTALL_PYTHON}/medcalc)
index 17cb536f4d7228bb86e6889d5a64e4c938967864..01f092cce296301d8fa98d5f873441563d2a96ca 100644 (file)
@@ -48,3 +48,8 @@ from medpresentation import MakePointSprite
 
 # Console commands
 import medconsole
+
+# Playing test scenarii
+from medtest import PlayQtTestingScenario
+from medtest import RequestSALOMETermination
+
index ac563982b7a4b35e7e6c5d1f861b0838e79087c9..6c3c28d711802337e8fae9466598fe60fab78736 100644 (file)
@@ -115,3 +115,9 @@ def notifyGui_addDatasource(filename):
 def notifyGui_addPresentation(fieldId, presId):
   __notifyGui(MEDCALC.EVENT_ADD_PRESENTATION, dataId=fieldId, presentationId=presId)
 #
+def notifyGui_playQtTestingScenario(filename):
+  __notifyGui(MEDCALC.EVENT_PLAY_TEST, filename=filename)
+#
+def notifyGui_termination():
+  __notifyGui(MEDCALC.EVENT_QUIT_SALOME)
+
diff --git a/src/MEDCalc/tui/medtest.py b/src/MEDCalc/tui/medtest.py
new file mode 100644 (file)
index 0000000..cc389ae
--- /dev/null
@@ -0,0 +1,26 @@
+# Copyright (C) 2011-2016  CEA/DEN, EDF R&D
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+#
+# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
+#
+
+def PlayQtTestingScenario(filename):
+  from medcalc.medevents import notifyGui_playQtTestingScenario
+  notifyGui_playQtTestingScenario(filename)
+
+def RequestSALOMETermination():
+  from medcalc.medevents import notifyGui_termination
+  notifyGui_termination()